[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) return KtFe10PsiAnonymousObjectSymbol(psi.objectDeclaration, analysisContext)
} }
override fun getClassOrObjectSymbol(psi: KtClassOrObject): KtClassOrObjectSymbol { override fun getClassOrObjectSymbol(psi: KtClassOrObject): KtClassOrObjectSymbol? {
return if (psi is KtObjectDeclaration && psi.isObjectLiteral()) { return if (psi is KtEnumEntry) {
null
} else if (psi is KtObjectDeclaration && psi.isObjectLiteral()) {
KtFe10PsiAnonymousObjectSymbol(psi, analysisContext) KtFe10PsiAnonymousObjectSymbol(psi, analysisContext)
} else { } else {
KtFe10PsiNamedClassOrObjectSymbol(psi, analysisContext) KtFe10PsiNamedClassOrObjectSymbol(psi, analysisContext)
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.analysis.utils.errors.buildErrorWithAttachment import org.jetbrains.kotlin.analysis.utils.errors.buildErrorWithAttachment
import org.jetbrains.kotlin.analysis.utils.errors.withPsiEntry import org.jetbrains.kotlin.analysis.utils.errors.withPsiEntry
import org.jetbrains.kotlin.psi.psiUtil.isObjectLiteral
internal class KtFirSymbolProvider( internal class KtFirSymbolProvider(
override val analysisSession: KtFirAnalysisSession, override val analysisSession: KtFirAnalysisSession,
@@ -113,16 +114,22 @@ internal class KtFirSymbolProvider(
) )
} }
override fun getClassOrObjectSymbol(psi: KtClassOrObject): KtClassOrObjectSymbol { override fun getClassOrObjectSymbol(psi: KtClassOrObject): KtClassOrObjectSymbol? {
val firClass = psi.resolveToFirClassLikeSymbol() if (psi is KtEnumEntry) {
return firSymbolBuilder.classifierBuilder.buildClassOrObjectSymbol(firClass) return null
}
val firSymbol = psi.resolveToFirClassLikeSymbol()
return firSymbolBuilder.classifierBuilder.buildClassOrObjectSymbol(firSymbol)
} }
override fun getNamedClassOrObjectSymbol(psi: KtClassOrObject): KtNamedClassOrObjectSymbol? { override fun getNamedClassOrObjectSymbol(psi: KtClassOrObject): KtNamedClassOrObjectSymbol? {
require(psi !is KtObjectDeclaration || psi.parent !is KtObjectLiteralExpression) if (psi is KtEnumEntry || psi.isObjectLiteral()) {
// A KtClassOrObject may also map to an FirEnumEntry. Hence, we need to return null in this case. return null
if (psi is KtEnumEntry) return null }
return firSymbolBuilder.classifierBuilder.buildNamedClassOrObjectSymbol(psi.resolveToFirClassLikeSymbol() as FirRegularClassSymbol)
val firSymbol = psi.resolveToFirClassLikeSymbol() as FirRegularClassSymbol
return firSymbolBuilder.classifierBuilder.buildNamedClassOrObjectSymbol(firSymbol)
} }
private fun KtClassOrObject.resolveToFirClassLikeSymbol(): FirClassSymbol<*> { private fun KtClassOrObject.resolveToFirClassLikeSymbol(): FirClassSymbol<*> {
@@ -19,7 +19,7 @@ abstract class AbstractContainingDeclarationProviderByDelegatedMemberScopeTest :
val declaration = testServices.expressionMarkerProvider.getElementOfTypeAtCaret<KtClassOrObject>(ktFile) val declaration = testServices.expressionMarkerProvider.getElementOfTypeAtCaret<KtClassOrObject>(ktFile)
val memberToContainingClass = analyseForTest(declaration) { val memberToContainingClass = analyseForTest(declaration) {
val symbol = declaration.getClassOrObjectSymbol() val symbol = declaration.getClassOrObjectSymbol()!!
renderScopeWithParentDeclarations(symbol.getDelegatedMemberScope()) renderScopeWithParentDeclarations(symbol.getDelegatedMemberScope())
} }
@@ -24,7 +24,7 @@ abstract class AbstractContainingDeclarationProviderByMemberScopeTest : Abstract
val declaration = testServices.expressionMarkerProvider.getElementOfTypeAtCaret<KtClassOrObject>(ktFile) val declaration = testServices.expressionMarkerProvider.getElementOfTypeAtCaret<KtClassOrObject>(ktFile)
val memberToContainingClass = analyseForTest(declaration) { val memberToContainingClass = analyseForTest(declaration) {
val symbol = declaration.getClassOrObjectSymbol() val symbol = declaration.getClassOrObjectSymbol()!!
renderScopeWithParentDeclarations(symbol.getMemberScope()) renderScopeWithParentDeclarations(symbol.getMemberScope())
} }
@@ -21,8 +21,8 @@ abstract class AbstractIsSubclassOfTest : AbstractAnalysisApiBasedSingleModuleTe
val actual = executeOnPooledThreadInReadAction { val actual = executeOnPooledThreadInReadAction {
analyseForTest(subClass) { analyseForTest(subClass) {
val subClassSymbol = subClass.getClassOrObjectSymbol() val subClassSymbol = subClass.getClassOrObjectSymbol()!!
val superClassSymbol = superClass.getClassOrObjectSymbol() val superClassSymbol = superClass.getClassOrObjectSymbol()!!
val isSubClass = subClassSymbol.isSubClassOf(superClassSymbol) val isSubClass = subClassSymbol.isSubClassOf(superClassSymbol)
val isDirectSubClass = subClassSymbol.isDirectSubClassOf(superClassSymbol) val isDirectSubClass = subClassSymbol.isDirectSubClassOf(superClassSymbol)
@@ -26,7 +26,7 @@ public abstract class KtSymbolProvider : KtAnalysisSessionComponent() {
is KtProperty -> getVariableSymbol(psi) is KtProperty -> getVariableSymbol(psi)
is KtClassOrObject -> { is KtClassOrObject -> {
val literalExpression = (psi as? KtObjectDeclaration)?.parent as? KtObjectLiteralExpression val literalExpression = (psi as? KtObjectDeclaration)?.parent as? KtObjectLiteralExpression
literalExpression?.let(::getAnonymousObjectSymbol) ?: getClassOrObjectSymbol(psi) literalExpression?.let(::getAnonymousObjectSymbol) ?: getClassOrObjectSymbol(psi)!!
} }
is KtPropertyAccessor -> getPropertyAccessorSymbol(psi) is KtPropertyAccessor -> getPropertyAccessorSymbol(psi)
is KtClassInitializer -> getClassInitializerSymbol(psi) is KtClassInitializer -> getClassInitializerSymbol(psi)
@@ -45,7 +45,7 @@ public abstract class KtSymbolProvider : KtAnalysisSessionComponent() {
public abstract fun getAnonymousFunctionSymbol(psi: KtFunctionLiteral): KtAnonymousFunctionSymbol public abstract fun getAnonymousFunctionSymbol(psi: KtFunctionLiteral): KtAnonymousFunctionSymbol
public abstract fun getVariableSymbol(psi: KtProperty): KtVariableSymbol public abstract fun getVariableSymbol(psi: KtProperty): KtVariableSymbol
public abstract fun getAnonymousObjectSymbol(psi: KtObjectLiteralExpression): KtAnonymousObjectSymbol 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 getNamedClassOrObjectSymbol(psi: KtClassOrObject): KtNamedClassOrObjectSymbol?
public abstract fun getPropertyAccessorSymbol(psi: KtPropertyAccessor): KtPropertyAccessorSymbol public abstract fun getPropertyAccessorSymbol(psi: KtPropertyAccessor): KtPropertyAccessorSymbol
public abstract fun getClassInitializerSymbol(psi: KtClassInitializer): KtClassInitializerSymbol public abstract fun getClassInitializerSymbol(psi: KtClassInitializer): KtClassInitializerSymbol
@@ -115,10 +115,11 @@ public interface KtSymbolProviderMixIn : KtAnalysisSessionMixIn {
public fun KtObjectLiteralExpression.getAnonymousObjectSymbol(): KtAnonymousObjectSymbol = public fun KtObjectLiteralExpression.getAnonymousObjectSymbol(): KtAnonymousObjectSymbol =
withValidityAssertion { analysisSession.symbolProvider.getAnonymousObjectSymbol(this) } 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) } 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? = public fun KtClassOrObject.getNamedClassOrObjectSymbol(): KtNamedClassOrObjectSymbol? =
withValidityAssertion { analysisSession.symbolProvider.getNamedClassOrObjectSymbol(this) } withValidityAssertion { analysisSession.symbolProvider.getNamedClassOrObjectSymbol(this) }
@@ -69,7 +69,7 @@ internal fun createSymbolLightClassNoCache(classOrObject: KtClassOrObject): KtLi
else -> { else -> {
analyzeForLightClasses(classOrObject) { analyzeForLightClasses(classOrObject) {
classOrObject.getClassOrObjectSymbol().createLightClassNoCache(classOrObject.manager) classOrObject.getClassOrObjectSymbol()?.createLightClassNoCache(classOrObject.manager)
} }
} }
} }
@@ -480,7 +480,7 @@ internal fun KtClassOrObject.checkIsInheritor(superClassOrigin: KtClassOrObject,
return false return false
} }
val superClassSymbol = superClassOrigin.getClassOrObjectSymbol() val superClassSymbol = superClassOrigin.getClassOrObjectSymbol() ?: return false
when (this) { when (this) {
is KtEnumEntry -> { is KtEnumEntry -> {
@@ -498,7 +498,7 @@ internal fun KtClassOrObject.checkIsInheritor(superClassOrigin: KtClassOrObject,
else -> { else -> {
val subClassSymbol = this.getClassOrObjectSymbol() val subClassSymbol = this.getClassOrObjectSymbol()
if (subClassSymbol == superClassSymbol) return false if (subClassSymbol == null || subClassSymbol == superClassSymbol) return false
return if (checkDeep) { return if (checkDeep) {
subClassSymbol.isSubClassOf(superClassSymbol) subClassSymbol.isSubClassOf(superClassSymbol)