diff --git a/compiler/frontend/src/org/jetbrains/kotlin/parsing/KotlinParsing.java b/compiler/frontend/src/org/jetbrains/kotlin/parsing/KotlinParsing.java index d14913c618f..32b9b4a8262 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/parsing/KotlinParsing.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/parsing/KotlinParsing.java @@ -231,8 +231,8 @@ public class KotlinParsing extends AbstractKotlinParsing { parseFileAnnotationList(FILE_ANNOTATIONS_WHEN_PACKAGE_OMITTED); packageDirective = mark(); packageDirective.done(PACKAGE_DIRECTIVE); - // this is necessary to allow comments at the start of the file to be bound to the first declaration - packageDirective.setCustomEdgeTokenBinders(DoNotBindAnything.INSTANCE, null); + // Need to skip everything but shebang comment to allow comments at the start of the file to be bound to the first declaration. + packageDirective.setCustomEdgeTokenBinders(BindFirstShebangWithWhitespaceOnly.INSTANCE, null); } parseImportDirectives(); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/parsing/KotlinWhitespaceAndCommentsBinders.kt b/compiler/frontend/src/org/jetbrains/kotlin/parsing/KotlinWhitespaceAndCommentsBinders.kt index c31c7d3e838..ab7856a07d2 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/parsing/KotlinWhitespaceAndCommentsBinders.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/parsing/KotlinWhitespaceAndCommentsBinders.kt @@ -115,6 +115,17 @@ object DoNotBindAnything : WhitespacesAndCommentsBinder { } } +object BindFirstShebangWithWhitespaceOnly : WhitespacesAndCommentsBinder { + override fun getEdgePosition( + tokens: List, atStreamEdge: Boolean, getter: WhitespacesAndCommentsBinder.TokenTextGetter): Int { + if (tokens.firstOrNull() == KtTokens.SHEBANG_COMMENT) { + return if (tokens.getOrNull(1) == KtTokens.WHITE_SPACE) 2 else 1 + } + + return 0 + } +} + class BindAll(val isTrailing: Boolean) : WhitespacesAndCommentsBinder { override fun getEdgePosition( tokens: List, atStreamEdge: Boolean, getter: WhitespacesAndCommentsBinder.TokenTextGetter): Int { diff --git a/compiler/testData/psi/script/Shebang.txt b/compiler/testData/psi/script/Shebang.txt index 192a9a621e3..c4e2f32bbde 100644 --- a/compiler/testData/psi/script/Shebang.txt +++ b/compiler/testData/psi/script/Shebang.txt @@ -1,12 +1,12 @@ KtFile: Shebang.kts + PsiComment(SHEBANG_COMMENT)('#!/usr/bin/env kotlin') + PsiWhiteSpace('\n\n') PACKAGE_DIRECTIVE IMPORT_LIST SCRIPT BLOCK - PsiComment(SHEBANG_COMMENT)('#!/usr/bin/env kotlin') - PsiWhiteSpace('\n\n') SCRIPT_INITIALIZER CALL_EXPRESSION REFERENCE_EXPRESSION diff --git a/compiler/testData/psi/script/ShebangWithImports.kts b/compiler/testData/psi/script/ShebangWithImports.kts new file mode 100644 index 00000000000..16f227f2f4a --- /dev/null +++ b/compiler/testData/psi/script/ShebangWithImports.kts @@ -0,0 +1,5 @@ +#!/usr/bin/env kotlin + +import test + +println(args) diff --git a/compiler/testData/psi/script/ShebangWithImports.txt b/compiler/testData/psi/script/ShebangWithImports.txt new file mode 100644 index 00000000000..a28505271a0 --- /dev/null +++ b/compiler/testData/psi/script/ShebangWithImports.txt @@ -0,0 +1,24 @@ +KtFile: ShebangWithImports.kts + PsiComment(SHEBANG_COMMENT)('#!/usr/bin/env kotlin') + PsiWhiteSpace('\n\n') + PACKAGE_DIRECTIVE + + IMPORT_LIST + IMPORT_DIRECTIVE + PsiElement(import)('import') + PsiWhiteSpace(' ') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('test') + SCRIPT + BLOCK + PsiWhiteSpace('\n\n') + SCRIPT_INITIALIZER + CALL_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('println') + VALUE_ARGUMENT_LIST + PsiElement(LPAR)('(') + VALUE_ARGUMENT + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('args') + PsiElement(RPAR)(')') \ No newline at end of file diff --git a/compiler/testData/psi/script/ShebangWithPackage.kts b/compiler/testData/psi/script/ShebangWithPackage.kts new file mode 100644 index 00000000000..5e99ff12b61 --- /dev/null +++ b/compiler/testData/psi/script/ShebangWithPackage.kts @@ -0,0 +1,5 @@ +#!/usr/bin/env kotlin + +package test + +println(args) diff --git a/compiler/testData/psi/script/ShebangWithPackage.txt b/compiler/testData/psi/script/ShebangWithPackage.txt new file mode 100644 index 00000000000..ff7706ee84a --- /dev/null +++ b/compiler/testData/psi/script/ShebangWithPackage.txt @@ -0,0 +1,23 @@ +KtFile: ShebangWithPackage.kts + PsiComment(SHEBANG_COMMENT)('#!/usr/bin/env kotlin') + PsiWhiteSpace('\n\n') + PACKAGE_DIRECTIVE + PsiElement(package)('package') + PsiWhiteSpace(' ') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('test') + IMPORT_LIST + + SCRIPT + BLOCK + PsiWhiteSpace('\n\n') + SCRIPT_INITIALIZER + CALL_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('println') + VALUE_ARGUMENT_LIST + PsiElement(LPAR)('(') + VALUE_ARGUMENT + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('args') + PsiElement(RPAR)(')') \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/parsing/ParsingTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/parsing/ParsingTestGenerated.java index b0e5cf44e75..5bb7f979734 100644 --- a/compiler/tests/org/jetbrains/kotlin/parsing/ParsingTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/parsing/ParsingTestGenerated.java @@ -2719,6 +2719,18 @@ public class ParsingTestGenerated extends AbstractParsingTest { doParsingTest(fileName); } + @TestMetadata("ShebangWithImports.kts") + public void testShebangWithImports() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/psi/script/ShebangWithImports.kts"); + doParsingTest(fileName); + } + + @TestMetadata("ShebangWithPackage.kts") + public void testShebangWithPackage() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/psi/script/ShebangWithPackage.kts"); + doParsingTest(fileName); + } + @TestMetadata("SimpleScript.kts") public void testSimpleScript() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/psi/script/SimpleScript.kts");