[Analysis API] Treat inapplicable declarations safely (KTIJ-23458)

Make 'getClassOrObjectSymbol()' and 'getNamedClassOrObjectSymbol()'
return 'null' for inapplicable PSI declarations.
This commit is contained in:
Yan Zhulanow
2022-11-01 19:23:56 +09:00
committed by teamcity
parent 0a8b9c821c
commit 4d41ac09df
7 changed files with 30 additions and 20 deletions
@@ -87,8 +87,10 @@ internal class KtFe10SymbolProvider(
return KtFe10PsiAnonymousObjectSymbol(psi.objectDeclaration, analysisContext)
}
override fun getClassOrObjectSymbol(psi: KtClassOrObject): KtClassOrObjectSymbol {
return if (psi is KtObjectDeclaration && psi.isObjectLiteral()) {
override fun getClassOrObjectSymbol(psi: KtClassOrObject): KtClassOrObjectSymbol? {
return if (psi is KtEnumEntry) {
null
} else if (psi is KtObjectDeclaration && psi.isObjectLiteral()) {
KtFe10PsiAnonymousObjectSymbol(psi, analysisContext)
} else {
KtFe10PsiNamedClassOrObjectSymbol(psi, analysisContext)
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.analysis.utils.errors.buildErrorWithAttachment
import org.jetbrains.kotlin.analysis.utils.errors.withPsiEntry
import org.jetbrains.kotlin.psi.psiUtil.isObjectLiteral
internal class KtFirSymbolProvider(
override val analysisSession: KtFirAnalysisSession,
@@ -113,16 +114,22 @@ internal class KtFirSymbolProvider(
)
}
override fun getClassOrObjectSymbol(psi: KtClassOrObject): KtClassOrObjectSymbol {
val firClass = psi.resolveToFirClassLikeSymbol()
return firSymbolBuilder.classifierBuilder.buildClassOrObjectSymbol(firClass)
override fun getClassOrObjectSymbol(psi: KtClassOrObject): KtClassOrObjectSymbol? {
if (psi is KtEnumEntry) {
return null
}
val firSymbol = psi.resolveToFirClassLikeSymbol()
return firSymbolBuilder.classifierBuilder.buildClassOrObjectSymbol(firSymbol)
}
override fun getNamedClassOrObjectSymbol(psi: KtClassOrObject): KtNamedClassOrObjectSymbol? {
require(psi !is KtObjectDeclaration || psi.parent !is KtObjectLiteralExpression)
// A KtClassOrObject may also map to an FirEnumEntry. Hence, we need to return null in this case.
if (psi is KtEnumEntry) return null
return firSymbolBuilder.classifierBuilder.buildNamedClassOrObjectSymbol(psi.resolveToFirClassLikeSymbol() as FirRegularClassSymbol)
if (psi is KtEnumEntry || psi.isObjectLiteral()) {
return null
}
val firSymbol = psi.resolveToFirClassLikeSymbol() as FirRegularClassSymbol
return firSymbolBuilder.classifierBuilder.buildNamedClassOrObjectSymbol(firSymbol)
}
private fun KtClassOrObject.resolveToFirClassLikeSymbol(): FirClassSymbol<*> {
@@ -19,7 +19,7 @@ abstract class AbstractContainingDeclarationProviderByDelegatedMemberScopeTest :
val declaration = testServices.expressionMarkerProvider.getElementOfTypeAtCaret<KtClassOrObject>(ktFile)
val memberToContainingClass = analyseForTest(declaration) {
val symbol = declaration.getClassOrObjectSymbol()
val symbol = declaration.getClassOrObjectSymbol()!!
renderScopeWithParentDeclarations(symbol.getDelegatedMemberScope())
}
@@ -24,7 +24,7 @@ abstract class AbstractContainingDeclarationProviderByMemberScopeTest : Abstract
val declaration = testServices.expressionMarkerProvider.getElementOfTypeAtCaret<KtClassOrObject>(ktFile)
val memberToContainingClass = analyseForTest(declaration) {
val symbol = declaration.getClassOrObjectSymbol()
val symbol = declaration.getClassOrObjectSymbol()!!
renderScopeWithParentDeclarations(symbol.getMemberScope())
}
@@ -21,8 +21,8 @@ abstract class AbstractIsSubclassOfTest : AbstractAnalysisApiBasedSingleModuleTe
val actual = executeOnPooledThreadInReadAction {
analyseForTest(subClass) {
val subClassSymbol = subClass.getClassOrObjectSymbol()
val superClassSymbol = superClass.getClassOrObjectSymbol()
val subClassSymbol = subClass.getClassOrObjectSymbol()!!
val superClassSymbol = superClass.getClassOrObjectSymbol()!!
val isSubClass = subClassSymbol.isSubClassOf(superClassSymbol)
val isDirectSubClass = subClassSymbol.isDirectSubClassOf(superClassSymbol)
@@ -26,7 +26,7 @@ public abstract class KtSymbolProvider : KtAnalysisSessionComponent() {
is KtProperty -> getVariableSymbol(psi)
is KtClassOrObject -> {
val literalExpression = (psi as? KtObjectDeclaration)?.parent as? KtObjectLiteralExpression
literalExpression?.let(::getAnonymousObjectSymbol) ?: getClassOrObjectSymbol(psi)
literalExpression?.let(::getAnonymousObjectSymbol) ?: getClassOrObjectSymbol(psi)!!
}
is KtPropertyAccessor -> getPropertyAccessorSymbol(psi)
is KtClassInitializer -> getClassInitializerSymbol(psi)
@@ -45,7 +45,7 @@ public abstract class KtSymbolProvider : KtAnalysisSessionComponent() {
public abstract fun getAnonymousFunctionSymbol(psi: KtFunctionLiteral): KtAnonymousFunctionSymbol
public abstract fun getVariableSymbol(psi: KtProperty): KtVariableSymbol
public abstract fun getAnonymousObjectSymbol(psi: KtObjectLiteralExpression): KtAnonymousObjectSymbol
public abstract fun getClassOrObjectSymbol(psi: KtClassOrObject): KtClassOrObjectSymbol
public abstract fun getClassOrObjectSymbol(psi: KtClassOrObject): KtClassOrObjectSymbol?
public abstract fun getNamedClassOrObjectSymbol(psi: KtClassOrObject): KtNamedClassOrObjectSymbol?
public abstract fun getPropertyAccessorSymbol(psi: KtPropertyAccessor): KtPropertyAccessorSymbol
public abstract fun getClassInitializerSymbol(psi: KtClassInitializer): KtClassInitializerSymbol
@@ -115,10 +115,11 @@ public interface KtSymbolProviderMixIn : KtAnalysisSessionMixIn {
public fun KtObjectLiteralExpression.getAnonymousObjectSymbol(): KtAnonymousObjectSymbol =
withValidityAssertion { analysisSession.symbolProvider.getAnonymousObjectSymbol(this) }
public fun KtClassOrObject.getClassOrObjectSymbol(): KtClassOrObjectSymbol =
/** Returns a symbol for a given [KtClassOrObject]. Returns `null` for `KtEnumEntry` declarations. */
public fun KtClassOrObject.getClassOrObjectSymbol(): KtClassOrObjectSymbol? =
withValidityAssertion { analysisSession.symbolProvider.getClassOrObjectSymbol(this) }
/** Gets the corresponding class or object symbol or null if the given [KtClassOrObject] is an enum entry. */
/** Returns a symbol for a given named [KtClassOrObject]. Returns `null` for `KtEnumEntry` declarations and object literals. */
public fun KtClassOrObject.getNamedClassOrObjectSymbol(): KtNamedClassOrObjectSymbol? =
withValidityAssertion { analysisSession.symbolProvider.getNamedClassOrObjectSymbol(this) }
@@ -69,7 +69,7 @@ internal fun createSymbolLightClassNoCache(classOrObject: KtClassOrObject): KtLi
else -> {
analyzeForLightClasses(classOrObject) {
classOrObject.getClassOrObjectSymbol().createLightClassNoCache(classOrObject.manager)
classOrObject.getClassOrObjectSymbol()?.createLightClassNoCache(classOrObject.manager)
}
}
}
@@ -480,7 +480,7 @@ internal fun KtClassOrObject.checkIsInheritor(superClassOrigin: KtClassOrObject,
return false
}
val superClassSymbol = superClassOrigin.getClassOrObjectSymbol()
val superClassSymbol = superClassOrigin.getClassOrObjectSymbol() ?: return false
when (this) {
is KtEnumEntry -> {
@@ -498,7 +498,7 @@ internal fun KtClassOrObject.checkIsInheritor(superClassOrigin: KtClassOrObject,
else -> {
val subClassSymbol = this.getClassOrObjectSymbol()
if (subClassSymbol == superClassSymbol) return false
if (subClassSymbol == null || subClassSymbol == superClassSymbol) return false
return if (checkDeep) {
subClassSymbol.isSubClassOf(superClassSymbol)