Skip to content

Commit fafd987

Browse files
authored
Merge pull request #3554 from square/bquenaudon.2026-03-23.parsing
Read quoted string when expecting an import
2 parents 5eea608 + 8d73b78 commit fafd987

3 files changed

Lines changed: 33 additions & 6 deletions

File tree

wire-schema/src/commonMain/kotlin/com/squareup/wire/schema/internal/parser/ProtoParser.kt

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -115,10 +115,15 @@ class ProtoParser internal constructor(
115115
}
116116

117117
label == "import" && context.permitsImport() -> {
118-
when (val importString = reader.readString()) {
119-
"weak" -> weakImports.add(reader.readString())
120-
"public" -> publicImports.add(reader.readString())
121-
else -> imports.add(importString)
118+
val peeked = reader.peekChar()
119+
if (peeked == '"' || peeked == '\'') {
120+
imports.add(reader.readQuotedString())
121+
} else {
122+
when (reader.readString()) {
123+
"weak" -> weakImports.add(reader.readQuotedString())
124+
"public" -> publicImports.add(reader.readQuotedString())
125+
else -> throw reader.unexpected("expected quoted string", location)
126+
}
122127
}
123128
reader.require(';')
124129
null

wire-schema/src/commonMain/kotlin/com/squareup/wire/schema/internal/parser/SyntaxReader.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ class SyntaxReader(
5252
return data[pos]
5353
}
5454

55+
/** Note that although the name suggests otherwise, this does consume the char if it finds it. */
5556
fun peekChar(c: Char): Boolean {
5657
return when (peekChar()) {
5758
c -> {
@@ -79,7 +80,7 @@ class SyntaxReader(
7980

8081
fun readQuotedString(): String {
8182
var startQuote = readChar()
82-
check(startQuote == '"' || startQuote == '\'')
83+
expect(startQuote == '"' || startQuote == '\'') { "expected quoted string" }
8384
val result = StringBuilder()
8485
while (pos < data.size) {
8586
var c = data[pos++]

wire-schema/src/commonTest/kotlin/com/squareup/wire/schema/internal/parser/ProtoParserTest.kt

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ import assertk.assertThat
1919
import assertk.assertions.containsOnly
2020
import assertk.assertions.hasMessage
2121
import assertk.assertions.isEqualTo
22+
import assertk.assertions.isInstanceOf
2223
import assertk.assertions.isNull
23-
import assertk.assertions.message
2424
import assertk.assertions.messageContains
2525
import com.squareup.wire.Syntax.PROTO_2
2626
import com.squareup.wire.Syntax.PROTO_3
@@ -32,6 +32,7 @@ import com.squareup.wire.schema.internal.MAX_TAG_VALUE
3232
import com.squareup.wire.schema.internal.parser.OptionElement.Kind
3333
import com.squareup.wire.schema.internal.parser.OptionElement.OptionPrimitive
3434
import kotlin.test.Test
35+
import kotlin.test.assertFails
3536
import kotlin.test.fail
3637

3738
class ProtoParserTest {
@@ -1500,6 +1501,26 @@ class ProtoParserTest {
15001501
assertThat(ProtoParser.parse(location, proto)).isEqualTo(expected)
15011502
}
15021503

1504+
@Test
1505+
fun unquotedImportThrows() {
1506+
val expected = assertFails {
1507+
ProtoParser.parse(location, "import src/test/resources/unittest_import.proto;\n")
1508+
}
1509+
assertThat(expected).isInstanceOf<IllegalStateException>().hasMessage(
1510+
"Syntax error in file.proto:1:1: expected quoted string",
1511+
)
1512+
}
1513+
1514+
@Test
1515+
fun unquotedWeakImportThrows() {
1516+
val expected = assertFails {
1517+
ProtoParser.parse(location, "import weak src/test/resources/unittest_import.proto;\n")
1518+
}
1519+
assertThat(expected).isInstanceOf<IllegalStateException>().hasMessage(
1520+
"Syntax error in file.proto:1:14: expected quoted string",
1521+
)
1522+
}
1523+
15031524
@Test
15041525
fun extend() {
15051526
val proto = """

0 commit comments

Comments
 (0)