[Analysis API] Treat inapplicable declarations safely (KTIJ-23458)
Make 'getClassOrObjectSymbol()' and 'getNamedClassOrObjectSymbol()' return 'null' for inapplicable PSI declarations.
This commit is contained in:
+4
-2
@@ -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)
|
||||||
|
|||||||
+14
-7
@@ -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<*> {
|
||||||
|
|||||||
+1
-1
@@ -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())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -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())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -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)
|
||||||
|
|||||||
+5
-4
@@ -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) }
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user