-
Notifications
You must be signed in to change notification settings - Fork 5.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Lexer] Fix wrong interaction backtick + multi-dollar interpolation
^KT-71073 Fixed ^KT-68971 Fixed
- Loading branch information
1 parent
0a833b0
commit 2608d3a
Showing
7 changed files
with
665 additions
and
289 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
244 changes: 123 additions & 121 deletions
244
compiler/psi/src/org/jetbrains/kotlin/lexer/_JetLexer.java
Large diffs are not rendered by default.
Oops, something went wrong.
166 changes: 83 additions & 83 deletions
166
compiler/testData/diagnostics/tests/DisabledMultiDollarInterpolation.fir.txt
Large diffs are not rendered by default.
Oops, something went wrong.
166 changes: 83 additions & 83 deletions
166
compiler/testData/diagnostics/tests/EnabledMultiDollarInterpolation.fir.txt
Large diffs are not rendered by default.
Oops, something went wrong.
36 changes: 36 additions & 0 deletions
36
compiler/testData/psi/stringTemplates/MultiDollarBacktick.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
fun parserBug() { | ||
// No closing backtick — not an identifier | ||
""" | ||
${"${"$`identifier"}"} "}"} | ||
""".trimIndent() | ||
|
||
// Two backticks — everything inside is an identifier | ||
""" | ||
${"${"$`identifier"}"} `"}"} | ||
""".trimIndent() | ||
|
||
// Escaped dollar, not an identifier | ||
""" | ||
${"${"\$`identifier"}"} `"}"} | ||
""".trimIndent() | ||
|
||
// Innermost string should not grab too much | ||
""" | ||
${"${$$$"$$`identifier"}"} `"}"} | ||
""".trimIndent() | ||
|
||
// Three dollars is the escape sequence, everything inside the backticks is an identifier | ||
""" | ||
${"${$$$"$$$`identifier"}"} `"}"} | ||
""".trimIndent() | ||
|
||
// Without the closing backtick the innermost string stops where expected | ||
""" | ||
${"${$$$"$$`identifier"}"} "}"} | ||
""".trimIndent() | ||
|
||
// on simple strings | ||
$$$"$$`identifier" | ||
"${$$$"$$`identifier"} | ||
"${$$$"$$$`identifier`"} | ||
} |
331 changes: 331 additions & 0 deletions
331
compiler/testData/psi/stringTemplates/MultiDollarBacktick.txt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,331 @@ | ||
KtFile: MultiDollarBacktick.kt | ||
PACKAGE_DIRECTIVE | ||
<empty list> | ||
IMPORT_LIST | ||
<empty list> | ||
FUN | ||
PsiElement(fun)('fun') | ||
PsiWhiteSpace(' ') | ||
PsiElement(IDENTIFIER)('parserBug') | ||
VALUE_PARAMETER_LIST | ||
PsiElement(LPAR)('(') | ||
PsiElement(RPAR)(')') | ||
PsiWhiteSpace(' ') | ||
BLOCK | ||
PsiElement(LBRACE)('{') | ||
PsiWhiteSpace('\n ') | ||
PsiComment(EOL_COMMENT)('// No closing backtick — not an identifier') | ||
PsiWhiteSpace('\n ') | ||
DOT_QUALIFIED_EXPRESSION | ||
STRING_TEMPLATE | ||
PsiElement(OPEN_QUOTE)('"""') | ||
LITERAL_STRING_TEMPLATE_ENTRY | ||
PsiElement(REGULAR_STRING_PART)('\n') | ||
LITERAL_STRING_TEMPLATE_ENTRY | ||
PsiElement(REGULAR_STRING_PART)(' ') | ||
LONG_STRING_TEMPLATE_ENTRY | ||
PsiElement(LONG_TEMPLATE_ENTRY_START)('${') | ||
STRING_TEMPLATE | ||
PsiElement(OPEN_QUOTE)('"') | ||
LONG_STRING_TEMPLATE_ENTRY | ||
PsiElement(LONG_TEMPLATE_ENTRY_START)('${') | ||
STRING_TEMPLATE | ||
PsiElement(OPEN_QUOTE)('"') | ||
LITERAL_STRING_TEMPLATE_ENTRY | ||
PsiElement(REGULAR_STRING_PART)('$') | ||
LITERAL_STRING_TEMPLATE_ENTRY | ||
PsiElement(REGULAR_STRING_PART)('`identifier') | ||
PsiElement(CLOSING_QUOTE)('"') | ||
PsiElement(LONG_TEMPLATE_ENTRY_END)('}') | ||
PsiElement(CLOSING_QUOTE)('"') | ||
PsiElement(LONG_TEMPLATE_ENTRY_END)('}') | ||
LITERAL_STRING_TEMPLATE_ENTRY | ||
PsiElement(REGULAR_STRING_PART)(' ') | ||
LITERAL_STRING_TEMPLATE_ENTRY | ||
PsiElement(REGULAR_STRING_PART)('"') | ||
LITERAL_STRING_TEMPLATE_ENTRY | ||
PsiElement(REGULAR_STRING_PART)('}') | ||
LITERAL_STRING_TEMPLATE_ENTRY | ||
PsiElement(REGULAR_STRING_PART)('"') | ||
LITERAL_STRING_TEMPLATE_ENTRY | ||
PsiElement(REGULAR_STRING_PART)('}') | ||
LITERAL_STRING_TEMPLATE_ENTRY | ||
PsiElement(REGULAR_STRING_PART)('\n') | ||
LITERAL_STRING_TEMPLATE_ENTRY | ||
PsiElement(REGULAR_STRING_PART)(' ') | ||
PsiElement(CLOSING_QUOTE)('"""') | ||
PsiElement(DOT)('.') | ||
CALL_EXPRESSION | ||
REFERENCE_EXPRESSION | ||
PsiElement(IDENTIFIER)('trimIndent') | ||
VALUE_ARGUMENT_LIST | ||
PsiElement(LPAR)('(') | ||
PsiElement(RPAR)(')') | ||
PsiWhiteSpace('\n\n ') | ||
PsiComment(EOL_COMMENT)('// Two backticks — everything inside is an identifier') | ||
PsiWhiteSpace('\n ') | ||
DOT_QUALIFIED_EXPRESSION | ||
STRING_TEMPLATE | ||
PsiElement(OPEN_QUOTE)('"""') | ||
LITERAL_STRING_TEMPLATE_ENTRY | ||
PsiElement(REGULAR_STRING_PART)('\n') | ||
LITERAL_STRING_TEMPLATE_ENTRY | ||
PsiElement(REGULAR_STRING_PART)(' ') | ||
LONG_STRING_TEMPLATE_ENTRY | ||
PsiElement(LONG_TEMPLATE_ENTRY_START)('${') | ||
STRING_TEMPLATE | ||
PsiElement(OPEN_QUOTE)('"') | ||
LONG_STRING_TEMPLATE_ENTRY | ||
PsiElement(LONG_TEMPLATE_ENTRY_START)('${') | ||
STRING_TEMPLATE | ||
PsiElement(OPEN_QUOTE)('"') | ||
SHORT_STRING_TEMPLATE_ENTRY | ||
PsiElement(SHORT_TEMPLATE_ENTRY_START)('$') | ||
REFERENCE_EXPRESSION | ||
PsiElement(IDENTIFIER)('`identifier"}"} `') | ||
PsiElement(CLOSING_QUOTE)('"') | ||
PsiElement(LONG_TEMPLATE_ENTRY_END)('}') | ||
PsiElement(CLOSING_QUOTE)('"') | ||
PsiElement(LONG_TEMPLATE_ENTRY_END)('}') | ||
LITERAL_STRING_TEMPLATE_ENTRY | ||
PsiElement(REGULAR_STRING_PART)('\n') | ||
LITERAL_STRING_TEMPLATE_ENTRY | ||
PsiElement(REGULAR_STRING_PART)(' ') | ||
PsiElement(CLOSING_QUOTE)('"""') | ||
PsiElement(DOT)('.') | ||
CALL_EXPRESSION | ||
REFERENCE_EXPRESSION | ||
PsiElement(IDENTIFIER)('trimIndent') | ||
VALUE_ARGUMENT_LIST | ||
PsiElement(LPAR)('(') | ||
PsiElement(RPAR)(')') | ||
PsiWhiteSpace('\n\n ') | ||
PsiComment(EOL_COMMENT)('// Escaped dollar, not an identifier') | ||
PsiWhiteSpace('\n ') | ||
DOT_QUALIFIED_EXPRESSION | ||
STRING_TEMPLATE | ||
PsiElement(OPEN_QUOTE)('"""') | ||
LITERAL_STRING_TEMPLATE_ENTRY | ||
PsiElement(REGULAR_STRING_PART)('\n') | ||
LITERAL_STRING_TEMPLATE_ENTRY | ||
PsiElement(REGULAR_STRING_PART)(' ') | ||
LONG_STRING_TEMPLATE_ENTRY | ||
PsiElement(LONG_TEMPLATE_ENTRY_START)('${') | ||
STRING_TEMPLATE | ||
PsiElement(OPEN_QUOTE)('"') | ||
LONG_STRING_TEMPLATE_ENTRY | ||
PsiElement(LONG_TEMPLATE_ENTRY_START)('${') | ||
STRING_TEMPLATE | ||
PsiElement(OPEN_QUOTE)('"') | ||
ESCAPE_STRING_TEMPLATE_ENTRY | ||
PsiElement(ESCAPE_SEQUENCE)('\$') | ||
LITERAL_STRING_TEMPLATE_ENTRY | ||
PsiElement(REGULAR_STRING_PART)('`identifier') | ||
PsiElement(CLOSING_QUOTE)('"') | ||
PsiElement(LONG_TEMPLATE_ENTRY_END)('}') | ||
PsiElement(CLOSING_QUOTE)('"') | ||
PsiElement(LONG_TEMPLATE_ENTRY_END)('}') | ||
LITERAL_STRING_TEMPLATE_ENTRY | ||
PsiElement(REGULAR_STRING_PART)(' `') | ||
LITERAL_STRING_TEMPLATE_ENTRY | ||
PsiElement(REGULAR_STRING_PART)('"') | ||
LITERAL_STRING_TEMPLATE_ENTRY | ||
PsiElement(REGULAR_STRING_PART)('}') | ||
LITERAL_STRING_TEMPLATE_ENTRY | ||
PsiElement(REGULAR_STRING_PART)('"') | ||
LITERAL_STRING_TEMPLATE_ENTRY | ||
PsiElement(REGULAR_STRING_PART)('}') | ||
LITERAL_STRING_TEMPLATE_ENTRY | ||
PsiElement(REGULAR_STRING_PART)('\n') | ||
LITERAL_STRING_TEMPLATE_ENTRY | ||
PsiElement(REGULAR_STRING_PART)(' ') | ||
PsiElement(CLOSING_QUOTE)('"""') | ||
PsiElement(DOT)('.') | ||
CALL_EXPRESSION | ||
REFERENCE_EXPRESSION | ||
PsiElement(IDENTIFIER)('trimIndent') | ||
VALUE_ARGUMENT_LIST | ||
PsiElement(LPAR)('(') | ||
PsiElement(RPAR)(')') | ||
PsiWhiteSpace('\n\n ') | ||
PsiComment(EOL_COMMENT)('// Innermost string should not grab too much') | ||
PsiWhiteSpace('\n ') | ||
DOT_QUALIFIED_EXPRESSION | ||
STRING_TEMPLATE | ||
PsiElement(OPEN_QUOTE)('"""') | ||
LITERAL_STRING_TEMPLATE_ENTRY | ||
PsiElement(REGULAR_STRING_PART)('\n') | ||
LITERAL_STRING_TEMPLATE_ENTRY | ||
PsiElement(REGULAR_STRING_PART)(' ') | ||
LONG_STRING_TEMPLATE_ENTRY | ||
PsiElement(LONG_TEMPLATE_ENTRY_START)('${') | ||
STRING_TEMPLATE | ||
PsiElement(OPEN_QUOTE)('"') | ||
LONG_STRING_TEMPLATE_ENTRY | ||
PsiElement(LONG_TEMPLATE_ENTRY_START)('${') | ||
STRING_TEMPLATE | ||
PsiElement(INTERPOLATION_PREFIX)('$$$') | ||
PsiElement(OPEN_QUOTE)('"') | ||
LITERAL_STRING_TEMPLATE_ENTRY | ||
PsiElement(REGULAR_STRING_PART)('$$') | ||
LITERAL_STRING_TEMPLATE_ENTRY | ||
PsiElement(REGULAR_STRING_PART)('`identifier') | ||
PsiElement(CLOSING_QUOTE)('"') | ||
PsiElement(LONG_TEMPLATE_ENTRY_END)('}') | ||
PsiElement(CLOSING_QUOTE)('"') | ||
PsiElement(LONG_TEMPLATE_ENTRY_END)('}') | ||
LITERAL_STRING_TEMPLATE_ENTRY | ||
PsiElement(REGULAR_STRING_PART)(' `') | ||
LITERAL_STRING_TEMPLATE_ENTRY | ||
PsiElement(REGULAR_STRING_PART)('"') | ||
LITERAL_STRING_TEMPLATE_ENTRY | ||
PsiElement(REGULAR_STRING_PART)('}') | ||
LITERAL_STRING_TEMPLATE_ENTRY | ||
PsiElement(REGULAR_STRING_PART)('"') | ||
LITERAL_STRING_TEMPLATE_ENTRY | ||
PsiElement(REGULAR_STRING_PART)('}') | ||
LITERAL_STRING_TEMPLATE_ENTRY | ||
PsiElement(REGULAR_STRING_PART)('\n') | ||
LITERAL_STRING_TEMPLATE_ENTRY | ||
PsiElement(REGULAR_STRING_PART)(' ') | ||
PsiElement(CLOSING_QUOTE)('"""') | ||
PsiElement(DOT)('.') | ||
CALL_EXPRESSION | ||
REFERENCE_EXPRESSION | ||
PsiElement(IDENTIFIER)('trimIndent') | ||
VALUE_ARGUMENT_LIST | ||
PsiElement(LPAR)('(') | ||
PsiElement(RPAR)(')') | ||
PsiWhiteSpace('\n\n ') | ||
PsiComment(EOL_COMMENT)('// Three dollars is the escape sequence, everything inside the backticks is an identifier') | ||
PsiWhiteSpace('\n ') | ||
DOT_QUALIFIED_EXPRESSION | ||
STRING_TEMPLATE | ||
PsiElement(OPEN_QUOTE)('"""') | ||
LITERAL_STRING_TEMPLATE_ENTRY | ||
PsiElement(REGULAR_STRING_PART)('\n') | ||
LITERAL_STRING_TEMPLATE_ENTRY | ||
PsiElement(REGULAR_STRING_PART)(' ') | ||
LONG_STRING_TEMPLATE_ENTRY | ||
PsiElement(LONG_TEMPLATE_ENTRY_START)('${') | ||
STRING_TEMPLATE | ||
PsiElement(OPEN_QUOTE)('"') | ||
LONG_STRING_TEMPLATE_ENTRY | ||
PsiElement(LONG_TEMPLATE_ENTRY_START)('${') | ||
STRING_TEMPLATE | ||
PsiElement(INTERPOLATION_PREFIX)('$$$') | ||
PsiElement(OPEN_QUOTE)('"') | ||
SHORT_STRING_TEMPLATE_ENTRY | ||
PsiElement(SHORT_TEMPLATE_ENTRY_START)('$$$') | ||
REFERENCE_EXPRESSION | ||
PsiElement(IDENTIFIER)('`identifier"}"} `') | ||
PsiElement(CLOSING_QUOTE)('"') | ||
PsiElement(LONG_TEMPLATE_ENTRY_END)('}') | ||
PsiElement(CLOSING_QUOTE)('"') | ||
PsiElement(LONG_TEMPLATE_ENTRY_END)('}') | ||
LITERAL_STRING_TEMPLATE_ENTRY | ||
PsiElement(REGULAR_STRING_PART)('\n') | ||
LITERAL_STRING_TEMPLATE_ENTRY | ||
PsiElement(REGULAR_STRING_PART)(' ') | ||
PsiElement(CLOSING_QUOTE)('"""') | ||
PsiElement(DOT)('.') | ||
CALL_EXPRESSION | ||
REFERENCE_EXPRESSION | ||
PsiElement(IDENTIFIER)('trimIndent') | ||
VALUE_ARGUMENT_LIST | ||
PsiElement(LPAR)('(') | ||
PsiElement(RPAR)(')') | ||
PsiWhiteSpace('\n\n ') | ||
PsiComment(EOL_COMMENT)('// Without the closing backtick the innermost string stops where expected') | ||
PsiWhiteSpace('\n ') | ||
DOT_QUALIFIED_EXPRESSION | ||
STRING_TEMPLATE | ||
PsiElement(OPEN_QUOTE)('"""') | ||
LITERAL_STRING_TEMPLATE_ENTRY | ||
PsiElement(REGULAR_STRING_PART)('\n') | ||
LITERAL_STRING_TEMPLATE_ENTRY | ||
PsiElement(REGULAR_STRING_PART)(' ') | ||
LONG_STRING_TEMPLATE_ENTRY | ||
PsiElement(LONG_TEMPLATE_ENTRY_START)('${') | ||
STRING_TEMPLATE | ||
PsiElement(OPEN_QUOTE)('"') | ||
LONG_STRING_TEMPLATE_ENTRY | ||
PsiElement(LONG_TEMPLATE_ENTRY_START)('${') | ||
STRING_TEMPLATE | ||
PsiElement(INTERPOLATION_PREFIX)('$$$') | ||
PsiElement(OPEN_QUOTE)('"') | ||
LITERAL_STRING_TEMPLATE_ENTRY | ||
PsiElement(REGULAR_STRING_PART)('$$') | ||
LITERAL_STRING_TEMPLATE_ENTRY | ||
PsiElement(REGULAR_STRING_PART)('`identifier') | ||
PsiElement(CLOSING_QUOTE)('"') | ||
PsiElement(LONG_TEMPLATE_ENTRY_END)('}') | ||
PsiElement(CLOSING_QUOTE)('"') | ||
PsiElement(LONG_TEMPLATE_ENTRY_END)('}') | ||
LITERAL_STRING_TEMPLATE_ENTRY | ||
PsiElement(REGULAR_STRING_PART)(' ') | ||
LITERAL_STRING_TEMPLATE_ENTRY | ||
PsiElement(REGULAR_STRING_PART)('"') | ||
LITERAL_STRING_TEMPLATE_ENTRY | ||
PsiElement(REGULAR_STRING_PART)('}') | ||
LITERAL_STRING_TEMPLATE_ENTRY | ||
PsiElement(REGULAR_STRING_PART)('"') | ||
LITERAL_STRING_TEMPLATE_ENTRY | ||
PsiElement(REGULAR_STRING_PART)('}') | ||
LITERAL_STRING_TEMPLATE_ENTRY | ||
PsiElement(REGULAR_STRING_PART)('\n') | ||
LITERAL_STRING_TEMPLATE_ENTRY | ||
PsiElement(REGULAR_STRING_PART)(' ') | ||
PsiElement(CLOSING_QUOTE)('"""') | ||
PsiElement(DOT)('.') | ||
CALL_EXPRESSION | ||
REFERENCE_EXPRESSION | ||
PsiElement(IDENTIFIER)('trimIndent') | ||
VALUE_ARGUMENT_LIST | ||
PsiElement(LPAR)('(') | ||
PsiElement(RPAR)(')') | ||
PsiWhiteSpace('\n\n ') | ||
PsiComment(EOL_COMMENT)('// on simple strings') | ||
PsiWhiteSpace('\n ') | ||
STRING_TEMPLATE | ||
PsiElement(INTERPOLATION_PREFIX)('$$$') | ||
PsiElement(OPEN_QUOTE)('"') | ||
LITERAL_STRING_TEMPLATE_ENTRY | ||
PsiElement(REGULAR_STRING_PART)('$$') | ||
LITERAL_STRING_TEMPLATE_ENTRY | ||
PsiElement(REGULAR_STRING_PART)('`identifier') | ||
PsiElement(CLOSING_QUOTE)('"') | ||
PsiWhiteSpace('\n ') | ||
STRING_TEMPLATE | ||
PsiElement(OPEN_QUOTE)('"') | ||
LONG_STRING_TEMPLATE_ENTRY | ||
PsiElement(LONG_TEMPLATE_ENTRY_START)('${') | ||
STRING_TEMPLATE | ||
PsiElement(INTERPOLATION_PREFIX)('$$$') | ||
PsiElement(OPEN_QUOTE)('"') | ||
LITERAL_STRING_TEMPLATE_ENTRY | ||
PsiElement(REGULAR_STRING_PART)('$$') | ||
LITERAL_STRING_TEMPLATE_ENTRY | ||
PsiElement(REGULAR_STRING_PART)('`identifier') | ||
PsiElement(CLOSING_QUOTE)('"') | ||
PsiElement(LONG_TEMPLATE_ENTRY_END)('}') | ||
PsiErrorElement:Expecting '"' | ||
<empty list> | ||
PsiWhiteSpace('\n ') | ||
STRING_TEMPLATE | ||
PsiElement(OPEN_QUOTE)('"') | ||
LONG_STRING_TEMPLATE_ENTRY | ||
PsiElement(LONG_TEMPLATE_ENTRY_START)('${') | ||
STRING_TEMPLATE | ||
PsiElement(INTERPOLATION_PREFIX)('$$$') | ||
PsiElement(OPEN_QUOTE)('"') | ||
SHORT_STRING_TEMPLATE_ENTRY | ||
PsiElement(SHORT_TEMPLATE_ENTRY_START)('$$$') | ||
REFERENCE_EXPRESSION | ||
PsiElement(IDENTIFIER)('`identifier`') | ||
PsiElement(CLOSING_QUOTE)('"') | ||
PsiElement(LONG_TEMPLATE_ENTRY_END)('}') | ||
PsiErrorElement:Expecting '"' | ||
<empty list> | ||
PsiWhiteSpace('\n') | ||
PsiElement(RBRACE)('}') |
Oops, something went wrong.