diff --git a/compiler/psi/src/org/jetbrains/kotlin/parsing/KotlinParsing.java b/compiler/psi/src/org/jetbrains/kotlin/parsing/KotlinParsing.java index 0ae41c29bd8..1e1a020a354 100644 --- a/compiler/psi/src/org/jetbrains/kotlin/parsing/KotlinParsing.java +++ b/compiler/psi/src/org/jetbrains/kotlin/parsing/KotlinParsing.java @@ -424,7 +424,12 @@ public class KotlinParsing extends AbstractKotlinParsing { declType = FUN; } - if (declType == null) { + if (declType == null && at(IMPORT_KEYWORD)) { + error("imports are only allowed in the beginning of file"); + parseImportDirectives(); + decl.drop(); + } + else if (declType == null) { errorAndAdvance("Expecting a top level declaration"); decl.drop(); } diff --git a/compiler/psi/src/org/jetbrains/kotlin/psi/KtFile.kt b/compiler/psi/src/org/jetbrains/kotlin/psi/KtFile.kt index fde5e476148..726d4f273d5 100644 --- a/compiler/psi/src/org/jetbrains/kotlin/psi/KtFile.kt +++ b/compiler/psi/src/org/jetbrains/kotlin/psi/KtFile.kt @@ -22,6 +22,7 @@ import com.intellij.openapi.fileTypes.FileType import com.intellij.psi.* import com.intellij.psi.stubs.StubElement import com.intellij.psi.util.PsiTreeUtil +import com.intellij.util.ArrayFactory import com.intellij.util.FileContentUtilCore import com.intellij.util.IncorrectOperationException import org.jetbrains.kotlin.KtNodeTypes @@ -54,13 +55,16 @@ open class KtFile(viewProvider: FileViewProvider, val isCompiled: Boolean) : private var pathCached: String? = null val importList: KtImportList? - get() = findChildByTypeOrClass(KtStubElementTypes.IMPORT_LIST, KtImportList::class.java) + get() = importLists.firstOrNull() + + private val importLists: Array + get() = findChildrenByTypeOrClass(KtStubElementTypes.IMPORT_LIST, KtImportList::class.java) val fileAnnotationList: KtFileAnnotationList? get() = findChildByTypeOrClass(KtStubElementTypes.FILE_ANNOTATION_LIST, KtFileAnnotationList::class.java) open val importDirectives: List - get() = importList?.imports ?: emptyList() + get() = importLists.flatMap { it.imports } // scripts have no package directive, all other files must have package directives val packageDirective: KtPackageDirective? @@ -154,6 +158,19 @@ open class KtFile(viewProvider: FileViewProvider, val isCompiled: Boolean) : return findChildByClass(elementClass) } + fun >> findChildrenByTypeOrClass( + elementType: KtPlaceHolderStubElementType, + elementClass: Class + ): Array { + val stub = stub + if (stub != null) { + val arrayFactory: ArrayFactory = elementType.arrayFactory + return stub.getChildrenByType(elementType, arrayFactory) + } + return findChildrenByClass(elementClass) + } + + fun findImportByAlias(name: String): KtImportDirective? = importDirectives.firstOrNull { name == it.aliasName } diff --git a/compiler/testData/diagnostics/tests/imports/twoImportLists.kt b/compiler/testData/diagnostics/tests/imports/twoImportLists.kt new file mode 100644 index 00000000000..83f36c6a5fc --- /dev/null +++ b/compiler/testData/diagnostics/tests/imports/twoImportLists.kt @@ -0,0 +1,105 @@ +// !WITH_NEW_INFERENCE +// FILE:a.kt +package a + +<<< FOOO +import b.B //class +import b.foo //function +import b.ext //extension function +import b.value //property +import b.C.Companion.bar //function from companion object +import b.C.Companion.cValue //property from companion object +import b.constant.fff //function from val +import b.constant.dValue //property from val +import smth.illegal +import b.C.smth.illegal + +<<<HEAD +import b.bar.smth +import b.bar.* +import b.unr.unr.unr +import unr.unr.unr +import b.constant +import b.E.Companion.f //val from companion object + +fun test(arg: B) { + foo(value) + arg.ext() + + bar() + foo(cValue) + + fff(dValue) + + constant.fff(constant.dValue) + + f.f() +} + +// FILE:b.kt +package b + +class B() {} + +fun foo(i: Int) = i + +fun B.ext() {} + +val value = 0 + +class C() { + companion object { + fun bar() {} + val cValue = 1 + } +} + +class D() { + fun fff(s: String) = s + val dValue = "w" +} + +val constant = D() + +class E() { + companion object { + val f = F() + } +} + +class F() { + fun f() {} +} + +fun bar() {} + +//FILE:c.kt +package c + +import c.C.* + +object C { + fun f() { + } + val i = 348 +} + +fun foo() { + if (i == 3) f() +} + +//FILE:d.kt +package d + +import d.A.Companion.B +import d.A.Companion.C + +val b : B = B() +val c : B = C + +class A() { + companion object { + open class B() {} + object C : B() {} + } +} diff --git a/compiler/testData/diagnostics/tests/imports/twoImportLists.txt b/compiler/testData/diagnostics/tests/imports/twoImportLists.txt new file mode 100644 index 00000000000..c875a83e7e5 --- /dev/null +++ b/compiler/testData/diagnostics/tests/imports/twoImportLists.txt @@ -0,0 +1,114 @@ +package + +package a { + public fun test(/*0*/ arg: b.B): kotlin.Unit +} + +package b { + public val constant: b.D + public val value: kotlin.Int = 0 + public fun bar(): kotlin.Unit + public fun foo(/*0*/ i: kotlin.Int): kotlin.Int + public fun b.B.ext(): kotlin.Unit + + public final class B { + public constructor B() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + + public final class C { + public constructor C() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + public companion object Companion { + private constructor Companion() + public final val cValue: kotlin.Int = 1 + public final fun bar(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + } + + public final class D { + public constructor D() + public final val dValue: kotlin.String = "w" + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public final fun fff(/*0*/ s: kotlin.String): kotlin.String + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + + public final class E { + public constructor E() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + public companion object Companion { + private constructor Companion() + public final val f: b.F + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + } + + public final class F { + public constructor F() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public final fun f(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } +} + +package c { + public fun foo(): kotlin.Unit + + public object C { + private constructor C() + public final val i: kotlin.Int = 348 + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public final fun f(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } +} + +package d { + public val b: d.A.Companion.B + public val c: d.A.Companion.B + + public final class A { + public constructor A() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + public companion object Companion { + private constructor Companion() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + public open class B { + public constructor B() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + + public object C : d.A.Companion.B { + private constructor C() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + } + } +} diff --git a/compiler/testData/psi/FileStart_ERR.txt b/compiler/testData/psi/FileStart_ERR.txt index bc430fe2284..0e22e68e59b 100644 --- a/compiler/testData/psi/FileStart_ERR.txt +++ b/compiler/testData/psi/FileStart_ERR.txt @@ -14,9 +14,12 @@ KtFile: FileStart_ERR.kt PsiElement(DOT)('.') PsiErrorElement:Expecting a top level declaration PsiElement(IDENTIFIER)('bar') + PsiErrorElement:imports are only allowed in the beginning of file + PsiWhiteSpace('\n') - PsiErrorElement:Expecting a top level declaration - PsiElement(IDENTIFIER)('import') - PsiWhiteSpace(' ') - PsiErrorElement:Expecting a top level declaration - PsiElement(IDENTIFIER)('foo') \ No newline at end of file + IMPORT_LIST + IMPORT_DIRECTIVE + PsiElement(import)('import') + PsiWhiteSpace(' ') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('foo') diff --git a/compiler/testData/psi/recovery/importsWithConflict.kt b/compiler/testData/psi/recovery/importsWithConflict.kt new file mode 100644 index 00000000000..e0cdbf05e8a --- /dev/null +++ b/compiler/testData/psi/recovery/importsWithConflict.kt @@ -0,0 +1,14 @@ +package a + +import a1 +<<>> BAR + +fun bar() {} + +import a2 +import a4.df + +fun foo() {} diff --git a/compiler/testData/psi/recovery/importsWithConflict.txt b/compiler/testData/psi/recovery/importsWithConflict.txt new file mode 100644 index 00000000000..09438ea05f7 --- /dev/null +++ b/compiler/testData/psi/recovery/importsWithConflict.txt @@ -0,0 +1,90 @@ +KtFile: importsWithConflict.kt + PACKAGE_DIRECTIVE + PsiElement(package)('package') + PsiWhiteSpace(' ') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('a') + PsiWhiteSpace('\n\n') + IMPORT_LIST + IMPORT_DIRECTIVE + PsiElement(import)('import') + PsiWhiteSpace(' ') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('a1') + PsiWhiteSpace('\n') + PsiErrorElement:Expecting a top level declaration + PsiElement(LT)('<') + PsiErrorElement:Expecting a top level declaration + PsiElement(LT)('<') + PsiErrorElement:Expecting a top level declaration + PsiElement(LT)('<') + PsiErrorElement:Expecting a top level declaration + PsiElement(IDENTIFIER)('HEAD') + PsiErrorElement:imports are only allowed in the beginning of file + + PsiWhiteSpace('\n') + IMPORT_LIST + IMPORT_DIRECTIVE + PsiElement(import)('import') + PsiWhiteSpace(' ') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('a2') + PsiWhiteSpace('\n') + IMPORT_DIRECTIVE + PsiElement(import)('import') + PsiWhiteSpace(' ') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('a3') + PsiWhiteSpace('\n') + PsiErrorElement:Expecting a top level declaration + PsiElement(GT)('>') + PsiErrorElement:Expecting a top level declaration + PsiElement(GT)('>') + PsiErrorElement:Expecting a top level declaration + PsiElement(GT)('>') + PsiWhiteSpace(' ') + PsiErrorElement:Expecting a top level declaration + PsiElement(IDENTIFIER)('BAR') + PsiWhiteSpace('\n\n') + FUN + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('bar') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + BLOCK + PsiElement(LBRACE)('{') + PsiElement(RBRACE)('}') + PsiErrorElement:imports are only allowed in the beginning of file + + PsiWhiteSpace('\n\n') + IMPORT_LIST + IMPORT_DIRECTIVE + PsiElement(import)('import') + PsiWhiteSpace(' ') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('a2') + PsiWhiteSpace('\n') + IMPORT_DIRECTIVE + PsiElement(import)('import') + PsiWhiteSpace(' ') + DOT_QUALIFIED_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('a4') + PsiElement(DOT)('.') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('df') + PsiWhiteSpace('\n\n') + FUN + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('foo') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + BLOCK + PsiElement(LBRACE)('{') + PsiElement(RBRACE)('}') diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index ef4805ff8ad..60d319da981 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -9071,6 +9071,11 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { runTest("compiler/testData/diagnostics/tests/imports/TopLevelClassVsPackage.kt"); } + @TestMetadata("twoImportLists.kt") + public void testTwoImportLists() throws Exception { + runTest("compiler/testData/diagnostics/tests/imports/twoImportLists.kt"); + } + @TestMetadata("WrongImport.kt") public void testWrongImport() throws Exception { runTest("compiler/testData/diagnostics/tests/imports/WrongImport.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java index 057156e64e5..d8621ff8a48 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java @@ -9071,6 +9071,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing runTest("compiler/testData/diagnostics/tests/imports/TopLevelClassVsPackage.kt"); } + @TestMetadata("twoImportLists.kt") + public void testTwoImportLists() throws Exception { + runTest("compiler/testData/diagnostics/tests/imports/twoImportLists.kt"); + } + @TestMetadata("WrongImport.kt") public void testWrongImport() throws Exception { runTest("compiler/testData/diagnostics/tests/imports/WrongImport.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/parsing/ParsingTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/parsing/ParsingTestGenerated.java index f24b758e123..810af25a327 100644 --- a/compiler/tests/org/jetbrains/kotlin/parsing/ParsingTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/parsing/ParsingTestGenerated.java @@ -2013,6 +2013,11 @@ public class ParsingTestGenerated extends AbstractParsingTest { runTest("compiler/testData/psi/recovery/ImportRecovery.kt"); } + @TestMetadata("importsWithConflict.kt") + public void testImportsWithConflict() throws Exception { + runTest("compiler/testData/psi/recovery/importsWithConflict.kt"); + } + @TestMetadata("IncompleteAccessor1.kt") public void testIncompleteAccessor1() throws Exception { runTest("compiler/testData/psi/recovery/IncompleteAccessor1.kt");