From 9ff439e39ef9f9c93eca08a538942d09a7c6da2b Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Thu, 6 Oct 2016 16:05:38 +0300 Subject: [PATCH] Change annotations parsing in bodies of operators This change only matters in cases of if/when/for/while having braceless blocks Annotations on them are parsed now as on block-level expressions, i.e. they're attached to the whole expression --- .../parsing/KotlinExpressionParsing.java | 17 +- .../suppress/oneWarning/onBlockStatement.kt | 30 +++ .../annotation/at/blockLevelExpressions.kt | 27 +- .../annotation/at/blockLevelExpressions.txt | 250 ++++++++++++++++-- grammar/src/control.grm | 13 +- grammar/src/expressions.grm | 4 + grammar/src/when.grm | 6 +- 7 files changed, 315 insertions(+), 32 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/parsing/KotlinExpressionParsing.java b/compiler/frontend/src/org/jetbrains/kotlin/parsing/KotlinExpressionParsing.java index e459879f85a..ff6a165900a 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/parsing/KotlinExpressionParsing.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/parsing/KotlinExpressionParsing.java @@ -1237,7 +1237,7 @@ public class KotlinExpressionParsing extends AbstractKotlinParsing { /* * statement * : declaration - * : annotations expression + * : blockLevelExpression * ; */ private void parseStatement(boolean isScriptTopLevel) { @@ -1247,20 +1247,25 @@ public class KotlinExpressionParsing extends AbstractKotlinParsing { } else if (isScriptTopLevel){ PsiBuilder.Marker scriptInitializer = mark(); - parseStatementLevelExpression(); + parseBlockLevelExpression(); scriptInitializer.done(SCRIPT_INITIALIZER); } else { - parseStatementLevelExpression(); + parseBlockLevelExpression(); } } } - private void parseStatementLevelExpression() { + /* + * blockLevelExpression + * : annotations expression + * ; + */ + private void parseBlockLevelExpression() { if (at(AT)) { PsiBuilder.Marker expression = mark(); myKotlinParsing.parseAnnotations(DEFAULT); - parseStatementLevelExpression(); + parseBlockLevelExpression(); expression.done(ANNOTATED_EXPRESSION); return; } @@ -1424,7 +1429,7 @@ public class KotlinExpressionParsing extends AbstractKotlinParsing { private void parseControlStructureBody() { if (!parseAnnotatedLambda(/* preferBlock = */true)) { - parseExpression(); + parseBlockLevelExpression(); } } diff --git a/compiler/testData/diagnostics/tests/suppress/oneWarning/onBlockStatement.kt b/compiler/testData/diagnostics/tests/suppress/oneWarning/onBlockStatement.kt index 7b86ddf44b5..ea92127ae1b 100644 --- a/compiler/testData/diagnostics/tests/suppress/oneWarning/onBlockStatement.kt +++ b/compiler/testData/diagnostics/tests/suppress/oneWarning/onBlockStatement.kt @@ -14,6 +14,36 @@ fun foo(x: Array, y: IntArray, block: (T, Int) -> Int) { i += block(x[0] as T, "" as Int).toInt() } + if (i != 1) + @Suppress("UNCHECKED_CAST") + i += block(x[0] as T, "" as Int).toInt() + + if (i != 2) + @Suppress("UNCHECKED_CAST") + i += block(x[0] as T, "" as Int).toInt() + else + @Suppress("UNCHECKED_CAST") + i += block(x[1] as T, "" as Int).toInt() + + while (i != 1) + @Suppress("UNCHECKED_CAST") + i += block(x[0] as T, "" as Int).toInt() + + do + @Suppress("UNCHECKED_CAST") + i += block(x[0] as T, "" as Int).toInt() + while (i != 1) + + for (j in 1..100) + @Suppress("UNCHECKED_CAST") + i += block(x[0] as T, "" as Int).toInt() + + when (i) { + 1 -> + @Suppress("UNCHECKED_CAST") + i += block(x[0] as T, "" as Int).toInt() + } + val l: () -> Unit = { @Suppress("UNCHECKED_CAST") i += block(x[0] as T, "" as Int).toInt() diff --git a/compiler/testData/psi/annotation/at/blockLevelExpressions.kt b/compiler/testData/psi/annotation/at/blockLevelExpressions.kt index 7fa18e13ea6..e4de8a6f3be 100644 --- a/compiler/testData/psi/annotation/at/blockLevelExpressions.kt +++ b/compiler/testData/psi/annotation/at/blockLevelExpressions.kt @@ -14,10 +14,35 @@ fun foo() { } for (i in 1..100) - // annotation is attached to `x4` @ann4 x4 += foo4() + if (1 > 2) + @ann41 + x41 += foo41() + + if (3 > 4) + @ann42 + x42 += foo42() + else + @ann43 + x43 += foo43() + + while (true) + @ann44 + x44 += foo44() + + do + @ann + x45 += foo45() + while (true) + + when (1) { + 1 -> + @ann46 + x46 += foo46() + } + a.filter { @ann5 x5 += foo5() diff --git a/compiler/testData/psi/annotation/at/blockLevelExpressions.txt b/compiler/testData/psi/annotation/at/blockLevelExpressions.txt index 18bf53a35dc..26469341858 100644 --- a/compiler/testData/psi/annotation/at/blockLevelExpressions.txt +++ b/compiler/testData/psi/annotation/at/blockLevelExpressions.txt @@ -150,31 +150,245 @@ JetFile: blockLevelExpressions.kt PsiElement(INTEGER_LITERAL)('100') PsiElement(RPAR)(')') PsiWhiteSpace('\n ') - PsiComment(EOL_COMMENT)('// annotation is attached to `x4`') - PsiWhiteSpace('\n ') BODY - BINARY_EXPRESSION - ANNOTATED_EXPRESSION - ANNOTATION_ENTRY - PsiElement(AT)('@') - CONSTRUCTOR_CALLEE - TYPE_REFERENCE - USER_TYPE - REFERENCE_EXPRESSION - PsiElement(IDENTIFIER)('ann4') - PsiWhiteSpace('\n ') + ANNOTATED_EXPRESSION + ANNOTATION_ENTRY + PsiElement(AT)('@') + CONSTRUCTOR_CALLEE + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('ann4') + PsiWhiteSpace('\n ') + BINARY_EXPRESSION REFERENCE_EXPRESSION PsiElement(IDENTIFIER)('x4') + PsiWhiteSpace(' ') + OPERATION_REFERENCE + PsiElement(PLUSEQ)('+=') + PsiWhiteSpace(' ') + CALL_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('foo4') + VALUE_ARGUMENT_LIST + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') + PsiWhiteSpace('\n\n ') + IF + PsiElement(if)('if') + PsiWhiteSpace(' ') + PsiElement(LPAR)('(') + CONDITION + BINARY_EXPRESSION + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('1') PsiWhiteSpace(' ') OPERATION_REFERENCE - PsiElement(PLUSEQ)('+=') + PsiElement(GT)('>') PsiWhiteSpace(' ') - CALL_EXPRESSION + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('2') + PsiElement(RPAR)(')') + PsiWhiteSpace('\n ') + THEN + ANNOTATED_EXPRESSION + ANNOTATION_ENTRY + PsiElement(AT)('@') + CONSTRUCTOR_CALLEE + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('ann41') + PsiWhiteSpace('\n ') + BINARY_EXPRESSION REFERENCE_EXPRESSION - PsiElement(IDENTIFIER)('foo4') - VALUE_ARGUMENT_LIST - PsiElement(LPAR)('(') - PsiElement(RPAR)(')') + PsiElement(IDENTIFIER)('x41') + PsiWhiteSpace(' ') + OPERATION_REFERENCE + PsiElement(PLUSEQ)('+=') + PsiWhiteSpace(' ') + CALL_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('foo41') + VALUE_ARGUMENT_LIST + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') + PsiWhiteSpace('\n\n ') + IF + PsiElement(if)('if') + PsiWhiteSpace(' ') + PsiElement(LPAR)('(') + CONDITION + BINARY_EXPRESSION + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('3') + PsiWhiteSpace(' ') + OPERATION_REFERENCE + PsiElement(GT)('>') + PsiWhiteSpace(' ') + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('4') + PsiElement(RPAR)(')') + PsiWhiteSpace('\n ') + THEN + ANNOTATED_EXPRESSION + ANNOTATION_ENTRY + PsiElement(AT)('@') + CONSTRUCTOR_CALLEE + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('ann42') + PsiWhiteSpace('\n ') + BINARY_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('x42') + PsiWhiteSpace(' ') + OPERATION_REFERENCE + PsiElement(PLUSEQ)('+=') + PsiWhiteSpace(' ') + CALL_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('foo42') + VALUE_ARGUMENT_LIST + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') + PsiWhiteSpace('\n ') + PsiElement(else)('else') + PsiWhiteSpace('\n ') + ELSE + ANNOTATED_EXPRESSION + ANNOTATION_ENTRY + PsiElement(AT)('@') + CONSTRUCTOR_CALLEE + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('ann43') + PsiWhiteSpace('\n ') + BINARY_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('x43') + PsiWhiteSpace(' ') + OPERATION_REFERENCE + PsiElement(PLUSEQ)('+=') + PsiWhiteSpace(' ') + CALL_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('foo43') + VALUE_ARGUMENT_LIST + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') + PsiWhiteSpace('\n\n ') + WHILE + PsiElement(while)('while') + PsiWhiteSpace(' ') + PsiElement(LPAR)('(') + CONDITION + BOOLEAN_CONSTANT + PsiElement(true)('true') + PsiElement(RPAR)(')') + PsiWhiteSpace('\n ') + BODY + ANNOTATED_EXPRESSION + ANNOTATION_ENTRY + PsiElement(AT)('@') + CONSTRUCTOR_CALLEE + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('ann44') + PsiWhiteSpace('\n ') + BINARY_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('x44') + PsiWhiteSpace(' ') + OPERATION_REFERENCE + PsiElement(PLUSEQ)('+=') + PsiWhiteSpace(' ') + CALL_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('foo44') + VALUE_ARGUMENT_LIST + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') + PsiWhiteSpace('\n\n ') + DO_WHILE + PsiElement(do)('do') + PsiWhiteSpace('\n ') + BODY + ANNOTATED_EXPRESSION + ANNOTATION_ENTRY + PsiElement(AT)('@') + CONSTRUCTOR_CALLEE + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('ann') + PsiWhiteSpace('\n ') + BINARY_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('x45') + PsiWhiteSpace(' ') + OPERATION_REFERENCE + PsiElement(PLUSEQ)('+=') + PsiWhiteSpace(' ') + CALL_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('foo45') + VALUE_ARGUMENT_LIST + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') + PsiWhiteSpace('\n ') + PsiElement(while)('while') + PsiWhiteSpace(' ') + PsiElement(LPAR)('(') + CONDITION + BOOLEAN_CONSTANT + PsiElement(true)('true') + PsiElement(RPAR)(')') + PsiWhiteSpace('\n\n ') + WHEN + PsiElement(when)('when') + PsiWhiteSpace(' ') + PsiElement(LPAR)('(') + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('1') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + PsiElement(LBRACE)('{') + PsiWhiteSpace('\n ') + WHEN_ENTRY + WHEN_CONDITION_WITH_EXPRESSION + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('1') + PsiWhiteSpace(' ') + PsiElement(ARROW)('->') + PsiWhiteSpace('\n ') + ANNOTATED_EXPRESSION + ANNOTATION_ENTRY + PsiElement(AT)('@') + CONSTRUCTOR_CALLEE + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('ann46') + PsiWhiteSpace('\n ') + BINARY_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('x46') + PsiWhiteSpace(' ') + OPERATION_REFERENCE + PsiElement(PLUSEQ)('+=') + PsiWhiteSpace(' ') + CALL_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('foo46') + VALUE_ARGUMENT_LIST + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') + PsiWhiteSpace('\n ') + PsiElement(RBRACE)('}') PsiWhiteSpace('\n\n ') DOT_QUALIFIED_EXPRESSION REFERENCE_EXPRESSION diff --git a/grammar/src/control.grm b/grammar/src/control.grm index 07391728509..878365c97dd 100644 --- a/grammar/src/control.grm +++ b/grammar/src/control.grm @@ -4,8 +4,13 @@ See [Control structures](control-flow.html) */ +controlStructureBody + : block + : blockLevelExpression + ; + if - : "if" "(" expression ")" expression SEMI? ("else" expression)? + : "if" "(" expression ")" controlStructureBody SEMI? ("else" controlStructureBody)? ; try @@ -27,13 +32,13 @@ loop ; for - : "for" "(" annotations (multipleVariableDeclarations | variableDeclarationEntry) "in" expression ")" expression + : "for" "(" annotations (multipleVariableDeclarations | variableDeclarationEntry) "in" expression ")" controlStructureBody ; while - : "while" "(" expression ")" expression + : "while" "(" expression ")" controlStructureBody ; doWhile - : "do" expression "while" "(" expression ")" + : "do" controlStructureBody "while" "(" expression ")" ; diff --git a/grammar/src/expressions.grm b/grammar/src/expressions.grm index fd1fd525c59..11ec82abad4 100644 --- a/grammar/src/expressions.grm +++ b/grammar/src/expressions.grm @@ -172,6 +172,10 @@ declaration statement : declaration + : blockLevelExpression + ; + +blockLevelExpression : annotations expression ; diff --git a/grammar/src/when.grm b/grammar/src/when.grm index 4849d4b9829..e8d01b78957 100644 --- a/grammar/src/when.grm +++ b/grammar/src/when.grm @@ -12,12 +12,12 @@ when // TODO : consider empty after -> whenEntry - : whenCondition{","} "->" expression SEMI - : "else" "->" expression SEMI + : whenCondition{","} "->" controlStructureBody SEMI + : "else" "->" controlStructureBody SEMI ; whenCondition : expression : ("in" | "!in") expression : ("is" | "!is") isRHS - ; \ No newline at end of file + ;