[AA] KT-56617 Optimize deprecation calculation for Java class symbols
- Most Java classes aren't deprecated. To avoid building `firSymbol` in such cases, this commit adds a simple heuristic which checks the class's annotations for the presence of one of the deprecation annotations recognized by the Kotlin compiler. - Note that annotations are compared via simple names, so there is a slight margin of error. However, comparing class IDs is more costly in my tests, because getting an annotation's class ID is not as cheap as getting its simple name.
This commit is contained in:
committed by
Space Team
parent
d5933f28ab
commit
f9fb718b37
+18
-9
@@ -8,23 +8,17 @@ package org.jetbrains.kotlin.analysis.api.fir.components
|
||||
import org.jetbrains.kotlin.analysis.api.components.KtSymbolInfoProvider
|
||||
import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
|
||||
import org.jetbrains.kotlin.analysis.api.fir.symbols.*
|
||||
import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirBackingFieldSymbol
|
||||
import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirSymbol
|
||||
import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirSyntheticJavaPropertySymbol
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KtPropertySymbol
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol
|
||||
import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeToken
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KtClassOrObjectSymbol
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KtPropertySymbol
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KtReceiverParameterSymbol
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol
|
||||
import org.jetbrains.kotlin.analysis.utils.errors.requireIsInstance
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
|
||||
import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.getAllowedAnnotationTargets
|
||||
import org.jetbrains.kotlin.fir.declarations.FirProperty
|
||||
import org.jetbrains.kotlin.fir.declarations.getDeprecationForCallSite
|
||||
import org.jetbrains.kotlin.fir.declarations.getJvmNameFromAnnotation
|
||||
import org.jetbrains.kotlin.fir.declarations.hasAnnotation
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.languageVersionSettings
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||
@@ -41,6 +35,12 @@ internal class KtFirSymbolInfoProvider(
|
||||
override fun getDeprecation(symbol: KtSymbol): DeprecationInfo? {
|
||||
if (symbol is KtFirBackingFieldSymbol || symbol is KtFirPackageSymbol || symbol is KtReceiverParameterSymbol) return null
|
||||
require(symbol is KtFirSymbol<*>) { "${this::class}" }
|
||||
|
||||
// Optimization: Avoid building `firSymbol` of `KtFirPsiJavaClassSymbol` if it definitely isn't deprecated.
|
||||
if (symbol is KtFirPsiJavaClassSymbol && !symbol.mayHaveDeprecation()) {
|
||||
return null
|
||||
}
|
||||
|
||||
return when (val firSymbol = symbol.firSymbol) {
|
||||
is FirPropertySymbol -> {
|
||||
firSymbol.getDeprecationForCallSite(apiVersion, AnnotationUseSiteTarget.PROPERTY)
|
||||
@@ -51,6 +51,15 @@ internal class KtFirSymbolInfoProvider(
|
||||
}
|
||||
}
|
||||
|
||||
private fun KtFirPsiJavaClassSymbol.mayHaveDeprecation(): Boolean {
|
||||
if (!hasAnnotations) return false
|
||||
|
||||
// Check the simple names of the Java annotations. While presence of such an annotation name does not prove deprecation, it is a
|
||||
// necessary condition for it. Type aliases are not a problem here: Java code cannot access Kotlin type aliases. (Currently,
|
||||
// deprecation annotation type aliases do not work in Kotlin, either, but this might change in the future.)
|
||||
return annotationSimpleNames.any { it != null && it in deprecationAnnotationSimpleNames }
|
||||
}
|
||||
|
||||
override fun getDeprecation(symbol: KtSymbol, annotationUseSiteTarget: AnnotationUseSiteTarget?): DeprecationInfo? {
|
||||
require(symbol is KtFirSymbol<*>)
|
||||
return if (annotationUseSiteTarget != null) {
|
||||
|
||||
+15
-11
@@ -16,7 +16,6 @@ import org.jetbrains.kotlin.analysis.api.fir.annotations.KtFirAnnotationListForD
|
||||
import org.jetbrains.kotlin.analysis.api.fir.utils.cached
|
||||
import org.jetbrains.kotlin.analysis.api.impl.base.annotations.KtEmptyAnnotationsList
|
||||
import org.jetbrains.kotlin.analysis.api.impl.base.symbols.toKtClassKind
|
||||
import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeToken
|
||||
import org.jetbrains.kotlin.analysis.api.lifetime.withValidityAssertion
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KtClassKind
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KtNamedClassOrObjectSymbol
|
||||
@@ -25,19 +24,18 @@ import org.jetbrains.kotlin.analysis.api.symbols.KtTypeParameterSymbol
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolKind
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtSymbolPointer
|
||||
import org.jetbrains.kotlin.analysis.api.types.KtType
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.firClassByPsiClassProvider
|
||||
import org.jetbrains.kotlin.analysis.project.structure.getKtModule
|
||||
import org.jetbrains.kotlin.analysis.utils.classIdIfNonLocal
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.descriptors.Visibility
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.analysis.project.structure.getKtModule
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.firClassByPsiClassProvider
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
|
||||
import org.jetbrains.kotlin.analysis.utils.classIdIfNonLocal
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.fir.java.classKind
|
||||
import org.jetbrains.kotlin.fir.java.modality
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaClass
|
||||
import org.jetbrains.kotlin.load.java.structure.impl.JavaClassImpl
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
/**
|
||||
* Implements [KtNamedClassOrObjectSymbol] for a Java class. The underlying [firSymbol] is built lazily and only when needed. Many simple
|
||||
@@ -105,7 +103,13 @@ internal class KtFirPsiJavaClassSymbol(
|
||||
}
|
||||
|
||||
val hasTypeParameters: Boolean
|
||||
get() = withValidityAssertion { javaClass.typeParameters.isNotEmpty() }
|
||||
get() = withValidityAssertion { psi.typeParameters.isNotEmpty() }
|
||||
|
||||
val annotationSimpleNames: List<String?>
|
||||
get() = withValidityAssertion { psi.annotations.map { it.nameReferenceElement?.referenceName } }
|
||||
|
||||
val hasAnnotations: Boolean
|
||||
get() = withValidityAssertion { psi.annotations.isNotEmpty() }
|
||||
|
||||
override val isData: Boolean get() = withValidityAssertion { false }
|
||||
override val isInline: Boolean get() = withValidityAssertion { false }
|
||||
@@ -152,8 +156,8 @@ internal class KtFirPsiJavaClassSymbol(
|
||||
}
|
||||
|
||||
override val annotationsList: KtAnnotationsList by cached {
|
||||
if (javaClass.annotations.isEmpty()) KtEmptyAnnotationsList(token)
|
||||
else KtFirAnnotationListForDeclaration.create(firSymbol, analysisSession.useSiteSession, token)
|
||||
if (hasAnnotations) KtFirAnnotationListForDeclaration.create(firSymbol, analysisSession.useSiteSession, token)
|
||||
else KtEmptyAnnotationsList(token)
|
||||
}
|
||||
|
||||
context(KtAnalysisSession)
|
||||
|
||||
@@ -178,6 +178,12 @@ private fun FirAnnotation.getDeprecationLevel(): DeprecationLevelValue? {
|
||||
return DeprecationLevelValue.values().find { it.name == targetName }
|
||||
}
|
||||
|
||||
val deprecationAnnotationSimpleNames: Set<String> = setOf(
|
||||
StandardClassIds.Annotations.Deprecated.shortClassName.asString(),
|
||||
StandardClassIds.Annotations.Java.Deprecated.shortClassName.asString(),
|
||||
StandardClassIds.Annotations.SinceKotlin.shortClassName.asString(),
|
||||
)
|
||||
|
||||
private fun List<FirAnnotation>.extractDeprecationAnnotationInfoPerUseSite(
|
||||
session: FirSession, fromJava: Boolean
|
||||
): DeprecationAnnotationInfoPerUseSiteStorage {
|
||||
|
||||
Reference in New Issue
Block a user