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:
Denis Zharkov
2018-12-21 13:53:10 +03:00
parent e6710b6fa2
commit 65e6e21d0f
10 changed files with 371 additions and 8 deletions
@@ -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 }