Don't build light classes for local classes with parse errors (KT-24323, EA-107235)
Also use checks for building light classes in `getLightClassDataHolder`.
This commit is contained in:
+55
-25
@@ -26,6 +26,7 @@ import com.intellij.psi.*
|
||||
import com.intellij.psi.impl.PsiSubstitutorImpl
|
||||
import com.intellij.psi.impl.java.stubs.PsiJavaFileStub
|
||||
import com.intellij.psi.impl.source.PsiImmediateClassType
|
||||
import com.intellij.psi.impl.source.tree.TreeUtil
|
||||
import com.intellij.psi.scope.PsiScopeProcessor
|
||||
import com.intellij.psi.search.SearchScope
|
||||
import com.intellij.psi.stubs.IStubElementType
|
||||
@@ -34,6 +35,7 @@ import com.intellij.psi.util.CachedValue
|
||||
import com.intellij.psi.util.CachedValueProvider
|
||||
import com.intellij.psi.util.CachedValuesManager
|
||||
import com.intellij.psi.util.PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT
|
||||
import com.intellij.psi.util.PsiUtilCore
|
||||
import com.intellij.util.IncorrectOperationException
|
||||
import com.intellij.util.containers.ContainerUtil
|
||||
import org.jetbrains.annotations.NonNls
|
||||
@@ -345,34 +347,23 @@ abstract class KtLightClassForSourceDeclaration(protected val classOrObject: KtC
|
||||
return null
|
||||
}
|
||||
|
||||
if (classOrObject is KtObjectDeclaration && classOrObject.isObjectLiteral()) {
|
||||
if (classOrObject.containingFile.virtualFile == null) return null
|
||||
return when {
|
||||
classOrObject is KtObjectDeclaration && classOrObject.isObjectLiteral() ->
|
||||
KtLightClassForAnonymousDeclaration(classOrObject)
|
||||
|
||||
return KtLightClassForAnonymousDeclaration(classOrObject)
|
||||
classOrObject.isLocal ->
|
||||
KtLightClassForLocalDeclaration(classOrObject)
|
||||
|
||||
else ->
|
||||
KtLightClassImpl(classOrObject)
|
||||
}
|
||||
|
||||
if (isEnumEntryWithoutBody(classOrObject)) {
|
||||
return null
|
||||
}
|
||||
|
||||
if (classOrObject.isLocal) {
|
||||
if (classOrObject.containingFile.virtualFile == null) return null
|
||||
|
||||
return KtLightClassForLocalDeclaration(classOrObject)
|
||||
}
|
||||
|
||||
|
||||
return KtLightClassImpl(classOrObject)
|
||||
}
|
||||
|
||||
private fun isEnumEntryWithoutBody(classOrObject: KtClassOrObject): Boolean {
|
||||
if (classOrObject !is KtEnumEntry) {
|
||||
return false
|
||||
}
|
||||
return classOrObject.getBody()?.declarations?.isEmpty() ?: true
|
||||
}
|
||||
|
||||
fun getLightClassDataHolder(classOrObject: KtClassOrObject): LightClassDataHolder.ForClass {
|
||||
if (classOrObject.shouldNotBeVisibleAsLightClass()) {
|
||||
return InvalidLightClassDataHolder
|
||||
}
|
||||
|
||||
return classOrObject.containingKtFile.script?.let { KtLightClassForScript.getLightClassCachedValue(it).value } ?:
|
||||
getLightClassCachedValue(classOrObject).value
|
||||
}
|
||||
@@ -516,5 +507,44 @@ fun KtClassOrObject.defaultJavaAncestorQualifiedName(): String? {
|
||||
}
|
||||
}
|
||||
|
||||
fun KtClassOrObject.shouldNotBeVisibleAsLightClass() =
|
||||
parentsWithSelf.filterIsInstance<KtClassOrObject>().any { it.hasExpectModifier() }
|
||||
fun KtClassOrObject.shouldNotBeVisibleAsLightClass(): Boolean {
|
||||
if (parentsWithSelf.filterIsInstance<KtClassOrObject>().any { it.hasExpectModifier() }) {
|
||||
return true
|
||||
}
|
||||
|
||||
if (isLocal) {
|
||||
if (containingFile.virtualFile == null) return true
|
||||
if (hasParseErrorsAround(this) || PsiUtilCore.hasErrorElementChild(this)) return true
|
||||
}
|
||||
|
||||
if (isEnumEntryWithoutBody(this)) {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
private fun isEnumEntryWithoutBody(classOrObject: KtClassOrObject): Boolean {
|
||||
if (classOrObject !is KtEnumEntry) {
|
||||
return false
|
||||
}
|
||||
return classOrObject.getBody()?.declarations?.isEmpty() ?: true
|
||||
}
|
||||
|
||||
private fun hasParseErrorsAround(psi: PsiElement): Boolean {
|
||||
val node = psi.node ?: return false
|
||||
|
||||
TreeUtil.nextLeaf(node)?.let { nextLeaf ->
|
||||
if (nextLeaf.elementType == TokenType.ERROR_ELEMENT || nextLeaf.treePrev?.elementType == TokenType.ERROR_ELEMENT) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
TreeUtil.prevLeaf(node)?.let { prevLeaf ->
|
||||
if (prevLeaf.elementType == TokenType.ERROR_ELEMENT || prevLeaf.treeNext?.elementType == TokenType.ERROR_ELEMENT) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user