Add recovery for import lists in the middle of the file
Note, that it only works for top-level declarations ^KT-7185 Fixed
This commit is contained in:
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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<out KtImportList>
|
||||
get() = findChildrenByTypeOrClass(KtStubElementTypes.IMPORT_LIST, KtImportList::class.java)
|
||||
|
||||
val fileAnnotationList: KtFileAnnotationList?
|
||||
get() = findChildByTypeOrClass(KtStubElementTypes.FILE_ANNOTATION_LIST, KtFileAnnotationList::class.java)
|
||||
|
||||
open val importDirectives: List<KtImportDirective>
|
||||
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 <T : KtElementImplStub<out StubElement<*>>> findChildrenByTypeOrClass(
|
||||
elementType: KtPlaceHolderStubElementType<T>,
|
||||
elementClass: Class<T>
|
||||
): Array<out T> {
|
||||
val stub = stub
|
||||
if (stub != null) {
|
||||
val arrayFactory: ArrayFactory<T> = elementType.arrayFactory
|
||||
return stub.getChildrenByType(elementType, arrayFactory)
|
||||
}
|
||||
return findChildrenByClass(elementClass)
|
||||
}
|
||||
|
||||
|
||||
fun findImportByAlias(name: String): KtImportDirective? =
|
||||
importDirectives.firstOrNull { name == it.aliasName }
|
||||
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
// !WITH_NEW_INFERENCE
|
||||
// FILE:a.kt
|
||||
package a
|
||||
|
||||
<!OI;SYNTAX!><<!><!OI;SYNTAX!><<!><!OI;SYNTAX!><<!> <!OI;SYNTAX!>FOOO<!><!OI;SYNTAX!><!>
|
||||
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.<!UNRESOLVED_REFERENCE!>constant<!>.<!DEBUG_INFO_MISSING_UNRESOLVED!>fff<!> //function from val
|
||||
import b.<!UNRESOLVED_REFERENCE!>constant<!>.<!DEBUG_INFO_MISSING_UNRESOLVED!>dValue<!> //property from val
|
||||
import <!UNRESOLVED_REFERENCE!>smth<!>.<!DEBUG_INFO_MISSING_UNRESOLVED!>illegal<!>
|
||||
import b.C.<!UNRESOLVED_REFERENCE!>smth<!>.<!DEBUG_INFO_MISSING_UNRESOLVED!>illegal<!>
|
||||
|
||||
<!OI;SYNTAX!><<!><!OI;SYNTAX!><<!><!OI;SYNTAX!><<!><!OI;SYNTAX!>HEAD<!><!OI;SYNTAX!><!>
|
||||
import b.<!UNRESOLVED_REFERENCE!>bar<!>.<!DEBUG_INFO_MISSING_UNRESOLVED!>smth<!>
|
||||
import b.<!UNRESOLVED_REFERENCE!>bar<!>.*
|
||||
import b.<!UNRESOLVED_REFERENCE!>unr<!>.<!DEBUG_INFO_MISSING_UNRESOLVED!>unr<!>.<!DEBUG_INFO_MISSING_UNRESOLVED!>unr<!>
|
||||
import <!UNRESOLVED_REFERENCE!>unr<!>.<!DEBUG_INFO_MISSING_UNRESOLVED!>unr<!>.<!DEBUG_INFO_MISSING_UNRESOLVED!>unr<!>
|
||||
import b.constant
|
||||
import b.E.Companion.f //val from companion object
|
||||
|
||||
fun test(arg: B) {
|
||||
foo(value)
|
||||
arg.ext()
|
||||
|
||||
bar()
|
||||
foo(cValue)
|
||||
|
||||
<!UNRESOLVED_REFERENCE!>fff<!>(<!UNRESOLVED_REFERENCE!>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.<!CANNOT_ALL_UNDER_IMPORT_FROM_SINGLETON!>C<!>.*
|
||||
|
||||
object C {
|
||||
fun f() {
|
||||
}
|
||||
val i = 348
|
||||
}
|
||||
|
||||
fun foo() {
|
||||
if (<!UNRESOLVED_REFERENCE!>i<!> <!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>==<!> 3) <!UNRESOLVED_REFERENCE!>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() {}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+8
-5
@@ -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
|
||||
<empty list>
|
||||
PsiWhiteSpace('\n')
|
||||
PsiErrorElement:Expecting a top level declaration
|
||||
PsiElement(IDENTIFIER)('import')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiErrorElement:Expecting a top level declaration
|
||||
PsiElement(IDENTIFIER)('foo')
|
||||
IMPORT_LIST
|
||||
IMPORT_DIRECTIVE
|
||||
PsiElement(import)('import')
|
||||
PsiWhiteSpace(' ')
|
||||
REFERENCE_EXPRESSION
|
||||
PsiElement(IDENTIFIER)('foo')
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
package a
|
||||
|
||||
import a1
|
||||
<<<HEAD
|
||||
import a2
|
||||
import a3
|
||||
>>> BAR
|
||||
|
||||
fun bar() {}
|
||||
|
||||
import a2
|
||||
import a4.df
|
||||
|
||||
fun foo() {}
|
||||
@@ -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
|
||||
<empty list>
|
||||
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
|
||||
<empty list>
|
||||
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)('}')
|
||||
@@ -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");
|
||||
|
||||
Generated
+5
@@ -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");
|
||||
|
||||
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user