diff --git a/compiler/frontend/src/org/jetbrains/kotlin/parsing/CommentBinders.kt b/compiler/frontend/src/org/jetbrains/kotlin/parsing/CommentBinders.kt index 0843dc1d78a..763828854b0 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/parsing/CommentBinders.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/parsing/CommentBinders.kt @@ -17,13 +17,13 @@ package org.jetbrains.kotlin.parsing import com.intellij.lang.WhitespacesAndCommentsBinder +import com.intellij.openapi.util.text.StringUtil import com.intellij.psi.tree.IElementType import org.jetbrains.kotlin.lexer.KtTokens -import com.intellij.openapi.util.text.StringUtil object PrecedingCommentsBinder : WhitespacesAndCommentsBinder { - - override fun getEdgePosition(tokens: List, atStreamEdge: Boolean, getter: WhitespacesAndCommentsBinder.TokenTextGetter): Int { + override fun getEdgePosition( + tokens: List, atStreamEdge: Boolean, getter: WhitespacesAndCommentsBinder.TokenTextGetter): Int { if (tokens.isEmpty()) return 0 // 1. bind doc comment @@ -53,8 +53,8 @@ object PrecedingCommentsBinder : WhitespacesAndCommentsBinder { } object PrecedingDocCommentsBinder : WhitespacesAndCommentsBinder { - - override fun getEdgePosition(tokens: List, atStreamEdge: Boolean, getter: WhitespacesAndCommentsBinder.TokenTextGetter): Int { + override fun getEdgePosition( + tokens: List, atStreamEdge: Boolean, getter: WhitespacesAndCommentsBinder.TokenTextGetter): Int { if (tokens.isEmpty()) return 0 for (idx in tokens.indices.reversed()) { @@ -67,8 +67,8 @@ object PrecedingDocCommentsBinder : WhitespacesAndCommentsBinder { // Binds comments on the same line object TrailingCommentsBinder : WhitespacesAndCommentsBinder { - - override fun getEdgePosition(tokens: List, atStreamEdge: Boolean, getter: WhitespacesAndCommentsBinder.TokenTextGetter): Int { + override fun getEdgePosition( + tokens: List, atStreamEdge: Boolean, getter: WhitespacesAndCommentsBinder.TokenTextGetter): Int { if (tokens.isEmpty()) return 0 var result = 0 @@ -87,8 +87,30 @@ object TrailingCommentsBinder : WhitespacesAndCommentsBinder { } } +private class AllCommentsBinder(val isTrailing: Boolean) : WhitespacesAndCommentsBinder { + override fun getEdgePosition( + tokens: List, atStreamEdge: Boolean, getter: WhitespacesAndCommentsBinder.TokenTextGetter): Int { + if (tokens.isEmpty()) return 0 + + val size = tokens.size + + // Skip comment if needed. Expect that there can't be several consecutive comments + val endToken = tokens[if (isTrailing) size - 1 else 0] + val shift = if (endToken == KtTokens.WHITE_SPACE) 1 else 0 + + return if (isTrailing) size - shift else shift + } +} + +@JvmField +val PRECEDING_ALL_COMMENTS_BINDER: WhitespacesAndCommentsBinder = AllCommentsBinder(false) + +@JvmField +val TRAILING_ALL_COMMENTS_BINDER: WhitespacesAndCommentsBinder = AllCommentsBinder(true) + object DoNotBindAnything : WhitespacesAndCommentsBinder { - override fun getEdgePosition(tokens: List, atStreamEdge: Boolean, getter: WhitespacesAndCommentsBinder.TokenTextGetter): Int { + override fun getEdgePosition( + tokens: List, atStreamEdge: Boolean, getter: WhitespacesAndCommentsBinder.TokenTextGetter): Int { return 0 } } \ No newline at end of file diff --git a/compiler/frontend/src/org/jetbrains/kotlin/parsing/KotlinExpressionParsing.java b/compiler/frontend/src/org/jetbrains/kotlin/parsing/KotlinExpressionParsing.java index d475d5fac04..2999cde433c 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/parsing/KotlinExpressionParsing.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/parsing/KotlinExpressionParsing.java @@ -1091,7 +1091,9 @@ public class KotlinExpressionParsing extends AbstractKotlinParsing { else { PsiBuilder.Marker body = mark(); parseStatements(); + body.done(BLOCK); + body.setCustomEdgeTokenBinders(CommentBindersKt.PRECEDING_ALL_COMMENTS_BINDER, CommentBindersKt.TRAILING_ALL_COMMENTS_BINDER); expect(RBRACE, "Expecting '}'"); literal.done(FUNCTION_LITERAL); diff --git a/compiler/testData/cfg-variables/bugs/localObjectInConstructor.instructions b/compiler/testData/cfg-variables/bugs/localObjectInConstructor.instructions index efbf048f03f..0dc5d0dc039 100644 --- a/compiler/testData/cfg-variables/bugs/localObjectInConstructor.instructions +++ b/compiler/testData/cfg-variables/bugs/localObjectInConstructor.instructions @@ -305,30 +305,30 @@ sink: } --------------------- L3: - 2 INIT: in: {some=D} out: {some=D} - 3 mark(if (state) state = true println(state)) + 2 INIT: in: {some=D} out: {some=D} + 3 mark(if (state) state = true println(state) // OK) mark(if (state) state = true) magic[IMPLICIT_RECEIVER](state) -> r(state|) -> - jf(L5|) USE: in: {state=READ} out: {state=READ} + jf(L5|) USE: in: {state=READ} out: {state=READ} magic[IMPLICIT_RECEIVER](state) -> - r(true) -> USE: in: {state=WRITTEN_AFTER_READ} out: {state=WRITTEN_AFTER_READ} - w(state|, ) USE: in: {state=READ} out: {state=WRITTEN_AFTER_READ} + r(true) -> USE: in: {state=WRITTEN_AFTER_READ} out: {state=WRITTEN_AFTER_READ} + w(state|, ) USE: in: {state=READ} out: {state=WRITTEN_AFTER_READ} jmp(L6) L5 [else branch]: read (Unit) L6 ['if' expression result]: merge(if (state) state = true|!) -> - magic[IMPLICIT_RECEIVER](state) -> USE: in: {state=READ} out: {state=READ} - r(state|) -> USE: in: {} out: {state=READ} + magic[IMPLICIT_RECEIVER](state) -> USE: in: {state=READ} out: {state=READ} + r(state|) -> USE: in: {} out: {state=READ} mark(println(state)) call(println(state), println|) -> L4: 2 error: - INIT: in: {} out: {} + INIT: in: {} out: {} sink: - INIT: in: {some=I?} out: {some=I?} USE: in: {} out: {} + INIT: in: {some=I?} out: {some=I?} USE: in: {} out: {} ===================== == exec == fun exec(f: () -> T): T = f() @@ -391,30 +391,30 @@ sink: } --------------------- L3: - 2 INIT: in: {some=D} out: {some=D} - 3 mark(if (state) state = true println(state)) + 2 INIT: in: {some=D} out: {some=D} + 3 mark(if (state) state = true println(state) // must be initialized) mark(if (state) state = true) magic[IMPLICIT_RECEIVER](state) -> r(state|) -> - jf(L5|) USE: in: {state=READ} out: {state=READ} + jf(L5|) USE: in: {state=READ} out: {state=READ} magic[IMPLICIT_RECEIVER](state) -> - r(true) -> USE: in: {state=WRITTEN_AFTER_READ} out: {state=WRITTEN_AFTER_READ} - w(state|, ) INIT: in: {some=D} out: {some=D, state=I} USE: in: {state=READ} out: {state=WRITTEN_AFTER_READ} - jmp(L6) INIT: in: {some=D, state=I} out: {some=D, state=I} + r(true) -> USE: in: {state=WRITTEN_AFTER_READ} out: {state=WRITTEN_AFTER_READ} + w(state|, ) INIT: in: {some=D} out: {some=D, state=I} USE: in: {state=READ} out: {state=WRITTEN_AFTER_READ} + jmp(L6) INIT: in: {some=D, state=I} out: {some=D, state=I} L5 [else branch]: - read (Unit) INIT: in: {some=D} out: {some=D} + read (Unit) INIT: in: {some=D} out: {some=D} L6 ['if' expression result]: - merge(if (state) state = true|!) -> INIT: in: {some=D, state=I} out: {some=D, state=I} - magic[IMPLICIT_RECEIVER](state) -> USE: in: {state=READ} out: {state=READ} - r(state|) -> USE: in: {} out: {state=READ} + merge(if (state) state = true|!) -> INIT: in: {some=D, state=I} out: {some=D, state=I} + magic[IMPLICIT_RECEIVER](state) -> USE: in: {state=READ} out: {state=READ} + r(state|) -> USE: in: {} out: {state=READ} mark(println(state)) call(println(state), println|) -> L4: 2 error: - INIT: in: {} out: {} + INIT: in: {} out: {} sink: - INIT: in: {some=I?, state=I} out: {some=I?, state=I} USE: in: {} out: {} + INIT: in: {some=I?, state=I} out: {some=I?, state=I} USE: in: {} out: {} ===================== == Demo5 == class Demo5 { diff --git a/compiler/testData/cfg-variables/bugs/localObjectInConstructor.values b/compiler/testData/cfg-variables/bugs/localObjectInConstructor.values index dce307e1670..2fb99acd580 100644 --- a/compiler/testData/cfg-variables/bugs/localObjectInConstructor.values +++ b/compiler/testData/cfg-variables/bugs/localObjectInConstructor.values @@ -164,16 +164,16 @@ true : Boolean println(state) // OK } --------------------- - : Demo3 NEW: magic[IMPLICIT_RECEIVER](state) -> - : Demo3 NEW: magic[IMPLICIT_RECEIVER](state) -> - : Demo3 NEW: magic[IMPLICIT_RECEIVER](state) -> -state : Boolean NEW: r(state|) -> -true : Boolean NEW: r(true) -> -state = true !: * -if (state) state = true : * NEW: merge(if (state) state = true|!) -> -state : * NEW: r(state|) -> -println(state) : * NEW: call(println(state), println|) -> -if (state) state = true println(state) : * COPY + : Demo3 NEW: magic[IMPLICIT_RECEIVER](state) -> + : Demo3 NEW: magic[IMPLICIT_RECEIVER](state) -> + : Demo3 NEW: magic[IMPLICIT_RECEIVER](state) -> +state : Boolean NEW: r(state|) -> +true : Boolean NEW: r(true) -> +state = true !: * +if (state) state = true : * NEW: merge(if (state) state = true|!) -> +state : * NEW: r(state|) -> +println(state) : * NEW: call(println(state), println|) -> +if (state) state = true println(state) // OK : * COPY ===================== == exec == fun exec(f: () -> T): T = f() @@ -206,16 +206,16 @@ true : B println(state) // must be initialized } --------------------- - : Demo4 NEW: magic[IMPLICIT_RECEIVER](state) -> - : Demo4 NEW: magic[IMPLICIT_RECEIVER](state) -> - : Demo4 NEW: magic[IMPLICIT_RECEIVER](state) -> -state : Boolean NEW: r(state|) -> -true : Boolean NEW: r(true) -> -state = true !: * -if (state) state = true : * NEW: merge(if (state) state = true|!) -> -state : * NEW: r(state|) -> -println(state) : * NEW: call(println(state), println|) -> -if (state) state = true println(state) : * COPY + : Demo4 NEW: magic[IMPLICIT_RECEIVER](state) -> + : Demo4 NEW: magic[IMPLICIT_RECEIVER](state) -> + : Demo4 NEW: magic[IMPLICIT_RECEIVER](state) -> +state : Boolean NEW: r(state|) -> +true : Boolean NEW: r(true) -> +state = true !: * +if (state) state = true : * NEW: merge(if (state) state = true|!) -> +state : * NEW: r(state|) -> +println(state) : * NEW: call(println(state), println|) -> +if (state) state = true println(state) // must be initialized : * COPY ===================== == Demo5 == class Demo5 { diff --git a/compiler/testData/cfg/deadCode/notLocalReturn.instructions b/compiler/testData/cfg/deadCode/notLocalReturn.instructions index 61cdde38bd5..c768cf5ac4b 100644 --- a/compiler/testData/cfg/deadCode/notLocalReturn.instructions +++ b/compiler/testData/cfg/deadCode/notLocalReturn.instructions @@ -58,15 +58,15 @@ sink: --------------------- L3: 3 - 4 mark(return nonLocal) + 4 mark(return nonLocal //unreachable) r(nonLocal) -> - ret(*|) L1 NEXT:[] + ret(*|) L1 NEXT:[] L4: - 3 NEXT:[] PREV:[] + 3 NEXT:[] PREV:[] error: - PREV:[] + PREV:[] sink: - PREV:[, ] + PREV:[, ] ===================== == doSomething == fun doSomething() {} diff --git a/compiler/testData/cfg/deadCode/notLocalReturn.values b/compiler/testData/cfg/deadCode/notLocalReturn.values index 2ab80110922..3408d06cc18 100644 --- a/compiler/testData/cfg/deadCode/notLocalReturn.values +++ b/compiler/testData/cfg/deadCode/notLocalReturn.values @@ -26,9 +26,9 @@ return "NON_LOCAL_FAILED $localResult" return nonLocal //unreachable } --------------------- -nonLocal : String NEW: r(nonLocal) -> -return nonLocal !: * -return nonLocal !: * COPY +nonLocal : String NEW: r(nonLocal) -> +return nonLocal !: * +return nonLocal //unreachable !: * COPY ===================== == doSomething == fun doSomething() {} diff --git a/compiler/testData/psi/CommentsBindingInLambda.kt b/compiler/testData/psi/CommentsBindingInLambda.kt new file mode 100644 index 00000000000..f16d4cc20e9 --- /dev/null +++ b/compiler/testData/psi/CommentsBindingInLambda.kt @@ -0,0 +1,38 @@ +val la1 = { + // start + // start 1 + foo() + + // middle + + foo() + + // end +} + +val la2 = { + /**/ +} + +val la3 = { + /** */ +} + +val la4 = { + /** Should be under block */ + + /** Should be under property */ + val some = 1 +} + +val la5 = { + /** */ + /** */ +} + +val la6 = /*1*/ {/*2*/ a /*3*/ -> /*4*/ +} + +val la7 = {/**/} + +fun foo() {} diff --git a/compiler/testData/psi/CommentsBindingInLambda.txt b/compiler/testData/psi/CommentsBindingInLambda.txt new file mode 100644 index 00000000000..59f53d6e252 --- /dev/null +++ b/compiler/testData/psi/CommentsBindingInLambda.txt @@ -0,0 +1,191 @@ +JetFile: CommentsBindingInLambda.kt + PACKAGE_DIRECTIVE + + IMPORT_LIST + + PROPERTY + PsiElement(val)('val') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('la1') + PsiWhiteSpace(' ') + PsiElement(EQ)('=') + PsiWhiteSpace(' ') + LAMBDA_EXPRESSION + FUNCTION_LITERAL + PsiElement(LBRACE)('{') + PsiWhiteSpace('\n ') + BLOCK + PsiComment(EOL_COMMENT)('// start') + PsiWhiteSpace('\n ') + PsiComment(EOL_COMMENT)('// start 1') + PsiWhiteSpace('\n ') + CALL_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('foo') + VALUE_ARGUMENT_LIST + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') + PsiWhiteSpace('\n\n ') + PsiComment(EOL_COMMENT)('// middle') + PsiWhiteSpace('\n\n ') + CALL_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('foo') + VALUE_ARGUMENT_LIST + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') + PsiWhiteSpace('\n\n ') + PsiComment(EOL_COMMENT)('// end') + PsiWhiteSpace('\n') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n\n') + PROPERTY + PsiElement(val)('val') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('la2') + PsiWhiteSpace(' ') + PsiElement(EQ)('=') + PsiWhiteSpace(' ') + LAMBDA_EXPRESSION + FUNCTION_LITERAL + PsiElement(LBRACE)('{') + PsiWhiteSpace('\n ') + BLOCK + PsiComment(BLOCK_COMMENT)('/**/') + PsiWhiteSpace('\n') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n\n') + PROPERTY + PsiElement(val)('val') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('la3') + PsiWhiteSpace(' ') + PsiElement(EQ)('=') + PsiWhiteSpace(' ') + LAMBDA_EXPRESSION + FUNCTION_LITERAL + PsiElement(LBRACE)('{') + PsiWhiteSpace('\n ') + BLOCK + KDoc + PsiElement(KDOC_START)('/**') + KDOC_SECTION + PsiElement(KDOC_TEXT)(' ') + PsiElement(KDOC_END)('*/') + PsiWhiteSpace('\n') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n\n') + PROPERTY + PsiElement(val)('val') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('la4') + PsiWhiteSpace(' ') + PsiElement(EQ)('=') + PsiWhiteSpace(' ') + LAMBDA_EXPRESSION + FUNCTION_LITERAL + PsiElement(LBRACE)('{') + PsiWhiteSpace('\n ') + BLOCK + KDoc + PsiElement(KDOC_START)('/**') + KDOC_SECTION + PsiElement(KDOC_TEXT)(' Should be under block ') + PsiElement(KDOC_END)('*/') + PsiWhiteSpace('\n\n ') + PROPERTY + KDoc + PsiElement(KDOC_START)('/**') + KDOC_SECTION + PsiElement(KDOC_TEXT)(' Should be under property ') + PsiElement(KDOC_END)('*/') + PsiWhiteSpace('\n ') + PsiElement(val)('val') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('some') + PsiWhiteSpace(' ') + PsiElement(EQ)('=') + PsiWhiteSpace(' ') + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('1') + PsiWhiteSpace('\n') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n\n') + PROPERTY + PsiElement(val)('val') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('la5') + PsiWhiteSpace(' ') + PsiElement(EQ)('=') + PsiWhiteSpace(' ') + LAMBDA_EXPRESSION + FUNCTION_LITERAL + PsiElement(LBRACE)('{') + PsiWhiteSpace('\n ') + BLOCK + KDoc + PsiElement(KDOC_START)('/**') + KDOC_SECTION + PsiElement(KDOC_TEXT)(' ') + PsiElement(KDOC_END)('*/') + PsiWhiteSpace('\n ') + KDoc + PsiElement(KDOC_START)('/**') + KDOC_SECTION + PsiElement(KDOC_TEXT)(' ') + PsiElement(KDOC_END)('*/') + PsiWhiteSpace('\n') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n\n') + PROPERTY + PsiElement(val)('val') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('la6') + PsiWhiteSpace(' ') + PsiElement(EQ)('=') + PsiWhiteSpace(' ') + PsiComment(BLOCK_COMMENT)('/*1*/') + PsiWhiteSpace(' ') + LAMBDA_EXPRESSION + FUNCTION_LITERAL + PsiElement(LBRACE)('{') + PsiComment(BLOCK_COMMENT)('/*2*/') + PsiWhiteSpace(' ') + VALUE_PARAMETER_LIST + VALUE_PARAMETER + PsiElement(IDENTIFIER)('a') + PsiWhiteSpace(' ') + PsiComment(BLOCK_COMMENT)('/*3*/') + PsiWhiteSpace(' ') + PsiElement(ARROW)('->') + PsiWhiteSpace(' ') + BLOCK + PsiComment(BLOCK_COMMENT)('/*4*/') + PsiWhiteSpace('\n') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n\n') + PROPERTY + PsiElement(val)('val') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('la7') + PsiWhiteSpace(' ') + PsiElement(EQ)('=') + PsiWhiteSpace(' ') + LAMBDA_EXPRESSION + FUNCTION_LITERAL + PsiElement(LBRACE)('{') + BLOCK + PsiComment(BLOCK_COMMENT)('/**/') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n\n') + FUN + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('foo') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + BLOCK + PsiElement(LBRACE)('{') + PsiElement(RBRACE)('}') \ No newline at end of file diff --git a/compiler/testData/psi/CommentsBindingInStatementBlock.kt b/compiler/testData/psi/CommentsBindingInStatementBlock.kt new file mode 100644 index 00000000000..6bef62272d2 --- /dev/null +++ b/compiler/testData/psi/CommentsBindingInStatementBlock.kt @@ -0,0 +1,21 @@ +fun test() { + if (true) {/*start-end*/} + + if (true) { + /*start-end*/ + } + + if (true) { + /*start*/ + /*end*/ + } + + if (true) { + /*start*/ + + /** doc */ + val a = 12 + + /*end*/ + } +} \ No newline at end of file diff --git a/compiler/testData/psi/CommentsBindingInStatementBlock.txt b/compiler/testData/psi/CommentsBindingInStatementBlock.txt new file mode 100644 index 00000000000..fbd8481703c --- /dev/null +++ b/compiler/testData/psi/CommentsBindingInStatementBlock.txt @@ -0,0 +1,103 @@ +JetFile: CommentsBindingInStatementBlock.kt + PACKAGE_DIRECTIVE + + IMPORT_LIST + + FUN + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('test') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + BLOCK + PsiElement(LBRACE)('{') + PsiWhiteSpace('\n ') + IF + PsiElement(if)('if') + PsiWhiteSpace(' ') + PsiElement(LPAR)('(') + CONDITION + BOOLEAN_CONSTANT + PsiElement(true)('true') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + THEN + BLOCK + PsiElement(LBRACE)('{') + PsiComment(BLOCK_COMMENT)('/*start-end*/') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n\n ') + IF + PsiElement(if)('if') + PsiWhiteSpace(' ') + PsiElement(LPAR)('(') + CONDITION + BOOLEAN_CONSTANT + PsiElement(true)('true') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + THEN + BLOCK + PsiElement(LBRACE)('{') + PsiWhiteSpace('\n ') + PsiComment(BLOCK_COMMENT)('/*start-end*/') + PsiWhiteSpace('\n ') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n\n ') + IF + PsiElement(if)('if') + PsiWhiteSpace(' ') + PsiElement(LPAR)('(') + CONDITION + BOOLEAN_CONSTANT + PsiElement(true)('true') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + THEN + BLOCK + PsiElement(LBRACE)('{') + PsiWhiteSpace('\n ') + PsiComment(BLOCK_COMMENT)('/*start*/') + PsiWhiteSpace('\n ') + PsiComment(BLOCK_COMMENT)('/*end*/') + PsiWhiteSpace('\n ') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n\n ') + IF + PsiElement(if)('if') + PsiWhiteSpace(' ') + PsiElement(LPAR)('(') + CONDITION + BOOLEAN_CONSTANT + PsiElement(true)('true') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + THEN + BLOCK + PsiElement(LBRACE)('{') + PsiWhiteSpace('\n ') + PsiComment(BLOCK_COMMENT)('/*start*/') + PsiWhiteSpace('\n\n ') + PROPERTY + KDoc + PsiElement(KDOC_START)('/**') + KDOC_SECTION + PsiElement(KDOC_TEXT)(' doc ') + PsiElement(KDOC_END)('*/') + PsiWhiteSpace('\n ') + PsiElement(val)('val') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('a') + PsiWhiteSpace(' ') + PsiElement(EQ)('=') + PsiWhiteSpace(' ') + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('12') + PsiWhiteSpace('\n\n ') + PsiComment(BLOCK_COMMENT)('/*end*/') + PsiWhiteSpace('\n ') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n') + PsiElement(RBRACE)('}') \ No newline at end of file diff --git a/compiler/testData/psi/LineCommentsInBlock.kt b/compiler/testData/psi/LineCommentsInBlock.kt new file mode 100644 index 00000000000..562aff54fd7 --- /dev/null +++ b/compiler/testData/psi/LineCommentsInBlock.kt @@ -0,0 +1,12 @@ +fun test() { + // start + foo() + + // middle + + foo() + + // end +} + +fun foo() {} diff --git a/compiler/testData/psi/LineCommentsInBlock.txt b/compiler/testData/psi/LineCommentsInBlock.txt new file mode 100644 index 00000000000..89480845bb7 --- /dev/null +++ b/compiler/testData/psi/LineCommentsInBlock.txt @@ -0,0 +1,49 @@ +JetFile: LineCommentsInBlock.kt + PACKAGE_DIRECTIVE + + IMPORT_LIST + + FUN + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('test') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + BLOCK + PsiElement(LBRACE)('{') + PsiWhiteSpace('\n ') + PsiComment(EOL_COMMENT)('// start') + PsiWhiteSpace('\n ') + CALL_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('foo') + VALUE_ARGUMENT_LIST + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') + PsiWhiteSpace('\n\n ') + PsiComment(EOL_COMMENT)('// middle') + PsiWhiteSpace('\n\n ') + CALL_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('foo') + VALUE_ARGUMENT_LIST + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') + PsiWhiteSpace('\n\n ') + PsiComment(EOL_COMMENT)('// end') + PsiWhiteSpace('\n') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n\n') + FUN + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('foo') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + BLOCK + PsiElement(LBRACE)('{') + PsiElement(RBRACE)('}') \ No newline at end of file diff --git a/compiler/testData/psi/annotation/lambda.txt b/compiler/testData/psi/annotation/lambda.txt index 8ca15cbec5d..623ae24b30f 100644 --- a/compiler/testData/psi/annotation/lambda.txt +++ b/compiler/testData/psi/annotation/lambda.txt @@ -61,9 +61,9 @@ JetFile: lambda.kt FUNCTION_LITERAL PsiElement(LBRACE)('{') PsiWhiteSpace(' ') - PsiComment(EOL_COMMENT)('// parsed as array access') - PsiWhiteSpace('\n ') BLOCK + PsiComment(EOL_COMMENT)('// parsed as array access') + PsiWhiteSpace('\n ') CALL_EXPRESSION REFERENCE_EXPRESSION PsiElement(IDENTIFIER)('print') diff --git a/compiler/testData/psi/newLabels/recovery.txt b/compiler/testData/psi/newLabels/recovery.txt index df55033d683..06f605fb07c 100644 --- a/compiler/testData/psi/newLabels/recovery.txt +++ b/compiler/testData/psi/newLabels/recovery.txt @@ -33,9 +33,9 @@ JetFile: recovery.kt FUNCTION_LITERAL PsiElement(LBRACE)('{') PsiWhiteSpace(' ') - PsiComment(EOL_COMMENT)('// should be no space after c') - PsiWhiteSpace('\n ') BLOCK + PsiComment(EOL_COMMENT)('// should be no space after c') + PsiWhiteSpace('\n ') RETURN PsiElement(return)('return') PsiWhiteSpace(' ') @@ -61,9 +61,9 @@ JetFile: recovery.kt FUNCTION_LITERAL PsiElement(LBRACE)('{') PsiWhiteSpace(' ') - PsiComment(EOL_COMMENT)('// no label identifier') - PsiWhiteSpace('\n ') BLOCK + PsiComment(EOL_COMMENT)('// no label identifier') + PsiWhiteSpace('\n ') RETURN PsiElement(return)('return') PsiWhiteSpace(' ') @@ -94,9 +94,9 @@ JetFile: recovery.kt FUNCTION_LITERAL PsiElement(LBRACE)('{') PsiWhiteSpace(' ') - PsiComment(EOL_COMMENT)('// should be no space after loop2') - PsiWhiteSpace('\n ') BLOCK + PsiComment(EOL_COMMENT)('// should be no space after loop2') + PsiWhiteSpace('\n ') RETURN PsiElement(return)('return') PsiErrorElement:Label must be named diff --git a/compiler/tests/org/jetbrains/kotlin/parsing/ParsingTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/parsing/ParsingTestGenerated.java index afba30be033..ef0609667fa 100644 --- a/compiler/tests/org/jetbrains/kotlin/parsing/ParsingTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/parsing/ParsingTestGenerated.java @@ -127,6 +127,18 @@ public class ParsingTestGenerated extends AbstractParsingTest { doParsingTest(fileName); } + @TestMetadata("CommentsBindingInLambda.kt") + public void testCommentsBindingInLambda() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/psi/CommentsBindingInLambda.kt"); + doParsingTest(fileName); + } + + @TestMetadata("CommentsBindingInStatementBlock.kt") + public void testCommentsBindingInStatementBlock() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/psi/CommentsBindingInStatementBlock.kt"); + doParsingTest(fileName); + } + @TestMetadata("Constructors.kt") public void testConstructors() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/psi/Constructors.kt"); @@ -541,6 +553,12 @@ public class ParsingTestGenerated extends AbstractParsingTest { doParsingTest(fileName); } + @TestMetadata("LineCommentsInBlock.kt") + public void testLineCommentsInBlock() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/psi/LineCommentsInBlock.kt"); + doParsingTest(fileName); + } + @TestMetadata("LocalDeclarations.kt") public void testLocalDeclarations() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/psi/LocalDeclarations.kt"); diff --git a/idea/testData/intentions/loopToCallChain/firstOrNull/ifAssign_preserveComments.kt.after b/idea/testData/intentions/loopToCallChain/firstOrNull/ifAssign_preserveComments.kt.after index 742de73db6d..a5a9d334e7b 100644 --- a/idea/testData/intentions/loopToCallChain/firstOrNull/ifAssign_preserveComments.kt.after +++ b/idea/testData/intentions/loopToCallChain/firstOrNull/ifAssign_preserveComments.kt.after @@ -4,7 +4,8 @@ fun foo(list: List) { // string should be non-empty // save it into result - val result: String? = list.firstOrNull { // search for first non-empty string in the list + val result: String? = list.firstOrNull { + // search for first non-empty string in the list it.length > 0 } } \ No newline at end of file