[AA] KT-56617 Introduce shared equals/hashCode for class symbols
- Instead of spreading `equals` and `hashCode` implementations over `KtFirNamedClassOrObjectSymbol` and `KtFirPsiJavaClassSymbol`, this commit introduces a shared base class.
This commit is contained in:
committed by
Space Team
parent
c729435765
commit
1e43e8d975
+1
-34
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.analysis.api.fir.symbols
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.analysis.api.KtAnalysisApiInternals
|
||||
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
|
||||
import org.jetbrains.kotlin.analysis.api.base.KtContextReceiver
|
||||
import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
|
||||
import org.jetbrains.kotlin.analysis.api.fir.annotations.KtFirAnnotationListForDeclaration
|
||||
@@ -17,10 +16,7 @@ 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
|
||||
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.descriptors.Modality
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.descriptors.Visibility
|
||||
@@ -32,7 +28,7 @@ import org.jetbrains.kotlin.name.Name
|
||||
internal class KtFirNamedClassOrObjectSymbol(
|
||||
override val firSymbol: FirRegularClassSymbol,
|
||||
override val analysisSession: KtFirAnalysisSession,
|
||||
) : KtNamedClassOrObjectSymbol(), KtFirSymbol<FirRegularClassSymbol> {
|
||||
) : KtFirNamedClassOrObjectSymbolBase() {
|
||||
override val token: KtLifetimeToken get() = builder.token
|
||||
override val psi: PsiElement? by cached { firSymbol.findPsi() }
|
||||
|
||||
@@ -51,7 +47,6 @@ internal class KtFirNamedClassOrObjectSymbol(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* FirRegularClass visibility is not modified by STATUS only for Unknown, so it can be taken from RAW */
|
||||
override val visibility: Visibility
|
||||
get() = withValidityAssertion {
|
||||
@@ -83,10 +78,6 @@ internal class KtFirNamedClassOrObjectSymbol(
|
||||
}
|
||||
}
|
||||
|
||||
override val superTypes: List<KtType> by cached {
|
||||
firSymbol.superTypesAndAnnotationsListForRegularClass(builder)
|
||||
}
|
||||
|
||||
override val typeParameters = withValidityAssertion {
|
||||
firSymbol.createRegularKtTypeParameters(builder)
|
||||
}
|
||||
@@ -98,28 +89,4 @@ internal class KtFirNamedClassOrObjectSymbol(
|
||||
}
|
||||
|
||||
override val symbolKind: KtSymbolKind get() = withValidityAssertion { getSymbolKind() }
|
||||
|
||||
context(KtAnalysisSession)
|
||||
override fun createPointer(): KtSymbolPointer<KtNamedClassOrObjectSymbol> = withValidityAssertion {
|
||||
createNamedClassOrObjectSymbolPointer()
|
||||
}
|
||||
|
||||
/**
|
||||
* [KtFirNamedClassOrObjectSymbol] must be able to equal [KtFirPsiJavaClassSymbol].
|
||||
*/
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (other === this) return true
|
||||
|
||||
return when (other) {
|
||||
is KtFirNamedClassOrObjectSymbol -> symbolEquals(other)
|
||||
is KtFirPsiJavaClassSymbol -> other == this
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A non-local [KtFirNamedClassOrObjectSymbol] must have the same kind of hash code as [KtFirPsiJavaClassSymbol] so that they are
|
||||
* interchangeable in collections.
|
||||
*/
|
||||
override fun hashCode(): Int = classIdIfNonLocal?.hashCode() ?: symbolHashCode()
|
||||
}
|
||||
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.analysis.api.fir.symbols
|
||||
|
||||
import com.intellij.codeInsight.PsiEquivalenceUtil
|
||||
import com.intellij.psi.PsiClass
|
||||
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
|
||||
import org.jetbrains.kotlin.analysis.api.fir.symbols.pointers.KtFirClassLikeSymbolPointer
|
||||
import org.jetbrains.kotlin.analysis.api.fir.utils.cached
|
||||
import org.jetbrains.kotlin.analysis.api.lifetime.withValidityAssertion
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KtNamedClassOrObjectSymbol
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolKind
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.pointers.CanNotCreateSymbolPointerForLocalLibraryDeclarationException
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtPsiBasedSymbolPointer
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtSymbolPointer
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.pointers.UnsupportedSymbolKind
|
||||
import org.jetbrains.kotlin.analysis.api.types.KtType
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
|
||||
|
||||
/**
|
||||
* [KtFirNamedClassOrObjectSymbolBase] provides shared equality and hash code implementations for FIR-based named class or object symbols so
|
||||
* that symbols of different kinds can be compared and remain interchangeable.
|
||||
*/
|
||||
internal sealed class KtFirNamedClassOrObjectSymbolBase : KtNamedClassOrObjectSymbol(), KtFirSymbol<FirRegularClassSymbol> {
|
||||
/**
|
||||
* Whether [firSymbol] is computed lazily. Equality will fall back to PSI-equality if one of the symbols is lazy and both classes have
|
||||
* an associated [PsiClass].
|
||||
*/
|
||||
open val hasLazyFirSymbol: Boolean get() = false
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other == null || other !is KtFirNamedClassOrObjectSymbolBase) return false
|
||||
|
||||
if (hasLazyFirSymbol || other.hasLazyFirSymbol) {
|
||||
val psiClass = psi as? PsiClass ?: return symbolEquals(other)
|
||||
val otherPsiClass = other.psi as? PsiClass ?: return symbolEquals(other)
|
||||
return PsiEquivalenceUtil.areElementsEquivalent(psiClass, otherPsiClass)
|
||||
}
|
||||
return symbolEquals(other)
|
||||
}
|
||||
|
||||
/**
|
||||
* All kinds of non-local named class or object symbols must have the same kind of hash code. The class ID is the best option, as the
|
||||
* same class/object may be represented by multiple different symbols.
|
||||
*/
|
||||
override fun hashCode(): Int = classIdIfNonLocal?.hashCode() ?: symbolHashCode()
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Shared Operations
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
override val superTypes: List<KtType> by cached {
|
||||
firSymbol.superTypesAndAnnotationsListForRegularClass(builder)
|
||||
}
|
||||
|
||||
context(KtAnalysisSession)
|
||||
override fun createPointer(): KtSymbolPointer<KtNamedClassOrObjectSymbol> = withValidityAssertion {
|
||||
KtPsiBasedSymbolPointer.createForSymbolFromSource<KtNamedClassOrObjectSymbol>(this)?.let { return it }
|
||||
|
||||
return when (val symbolKind = symbolKind) {
|
||||
KtSymbolKind.LOCAL ->
|
||||
throw CanNotCreateSymbolPointerForLocalLibraryDeclarationException(classIdIfNonLocal?.asString() ?: name.asString())
|
||||
|
||||
KtSymbolKind.CLASS_MEMBER, KtSymbolKind.TOP_LEVEL ->
|
||||
KtFirClassLikeSymbolPointer(classIdIfNonLocal!!, KtNamedClassOrObjectSymbol::class)
|
||||
|
||||
else -> throw UnsupportedSymbolKind(this::class, symbolKind)
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
-29
@@ -5,10 +5,8 @@
|
||||
|
||||
package org.jetbrains.kotlin.analysis.api.fir.symbols
|
||||
|
||||
import com.intellij.codeInsight.PsiEquivalenceUtil
|
||||
import com.intellij.psi.PsiClass
|
||||
import org.jetbrains.kotlin.analysis.api.KtAnalysisApiInternals
|
||||
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
|
||||
import org.jetbrains.kotlin.analysis.api.annotations.KtAnnotationsList
|
||||
import org.jetbrains.kotlin.analysis.api.base.KtContextReceiver
|
||||
import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
|
||||
@@ -22,8 +20,6 @@ import org.jetbrains.kotlin.analysis.api.symbols.KtNamedClassOrObjectSymbol
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KtSymbolOrigin
|
||||
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
|
||||
@@ -45,7 +41,7 @@ import org.jetbrains.kotlin.name.Name
|
||||
internal class KtFirPsiJavaClassSymbol(
|
||||
override val psi: PsiClass,
|
||||
override val analysisSession: KtFirAnalysisSession,
|
||||
) : KtNamedClassOrObjectSymbol(), KtFirPsiSymbol<PsiClass, FirRegularClassSymbol> {
|
||||
) : KtFirNamedClassOrObjectSymbolBase(), KtFirPsiSymbol<PsiClass, FirRegularClassSymbol> {
|
||||
/**
|
||||
* [javaClass] is used to defer some properties to the compiler's view of a Java class.
|
||||
*/
|
||||
@@ -110,24 +106,11 @@ internal class KtFirPsiJavaClassSymbol(
|
||||
|
||||
override val contextReceivers: List<KtContextReceiver> get() = withValidityAssertion { emptyList() }
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (other === this) return true
|
||||
if (other == null || other !is KtNamedClassOrObjectSymbol) return false
|
||||
|
||||
val otherPsiClass = other.psi as? PsiClass ?: return false
|
||||
return PsiEquivalenceUtil.areElementsEquivalent(psi, otherPsiClass)
|
||||
}
|
||||
|
||||
/**
|
||||
* Since [PsiEquivalenceUtil] doesn't have a hash code function, we use the class ID as a conservative hash code.
|
||||
*
|
||||
* Also see [KtFirNamedClassOrObjectSymbol.hashCode], which must generate the same hash code for non-local classes.
|
||||
*/
|
||||
override fun hashCode(): Int = classIdIfNonLocal.hashCode()
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Slow Operations (requiring access to the underlying FIR class symbol)
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
override val hasLazyFirSymbol: Boolean get() = true
|
||||
|
||||
override val firSymbol: FirRegularClassSymbol by cached {
|
||||
val module = psi.getKtModule(analysisSession.project)
|
||||
val provider = analysisSession.firResolveSession.getSessionFor(module).firClassByPsiClassProvider
|
||||
@@ -139,10 +122,6 @@ internal class KtFirPsiJavaClassSymbol(
|
||||
firClassSymbol
|
||||
}
|
||||
|
||||
override val superTypes: List<KtType> by cached {
|
||||
firSymbol.superTypesAndAnnotationsListForRegularClass(builder)
|
||||
}
|
||||
|
||||
override val typeParameters: List<KtTypeParameterSymbol> by cached {
|
||||
if (hasTypeParameters) firSymbol.createRegularKtTypeParameters(builder)
|
||||
else emptyList()
|
||||
@@ -152,9 +131,4 @@ internal class KtFirPsiJavaClassSymbol(
|
||||
if (hasAnnotations) KtFirAnnotationListForDeclaration.create(firSymbol, analysisSession.useSiteSession, token)
|
||||
else KtEmptyAnnotationsList(token)
|
||||
}
|
||||
|
||||
context(KtAnalysisSession)
|
||||
override fun createPointer(): KtSymbolPointer<KtNamedClassOrObjectSymbol> = withValidityAssertion {
|
||||
createNamedClassOrObjectSymbolPointer()
|
||||
}
|
||||
}
|
||||
|
||||
-23
@@ -8,20 +8,12 @@
|
||||
package org.jetbrains.kotlin.analysis.api.fir.symbols
|
||||
|
||||
import org.jetbrains.kotlin.analysis.api.KtAnalysisApiInternals
|
||||
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
|
||||
import org.jetbrains.kotlin.analysis.api.KtInitializerValue
|
||||
import org.jetbrains.kotlin.analysis.api.base.KtContextReceiver
|
||||
import org.jetbrains.kotlin.analysis.api.fir.KtSymbolByFirBuilder
|
||||
import org.jetbrains.kotlin.analysis.api.fir.symbols.pointers.KtFirClassLikeSymbolPointer
|
||||
import org.jetbrains.kotlin.analysis.api.fir.utils.asKtInitializerValue
|
||||
import org.jetbrains.kotlin.analysis.api.impl.base.KtContextReceiverImpl
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KtNamedClassOrObjectSymbol
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KtValueParameterSymbol
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolKind
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.pointers.CanNotCreateSymbolPointerForLocalLibraryDeclarationException
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtPsiBasedSymbolPointer
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtSymbolPointer
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.pointers.UnsupportedSymbolKind
|
||||
import org.jetbrains.kotlin.analysis.api.types.KtType
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.LLFirResolveSession
|
||||
import org.jetbrains.kotlin.analysis.utils.printer.getElementTextInContext
|
||||
@@ -124,18 +116,3 @@ internal fun FirVariableSymbol<*>.getKtConstantInitializer(resolveSession: LLFir
|
||||
?.classKind == ClassKind.ANNOTATION_CLASS
|
||||
return firInitializer.asKtInitializerValue(moduleData.session, parentIsAnnotation)
|
||||
}
|
||||
|
||||
context(KtAnalysisSession)
|
||||
internal fun KtNamedClassOrObjectSymbol.createNamedClassOrObjectSymbolPointer(): KtSymbolPointer<KtNamedClassOrObjectSymbol> {
|
||||
KtPsiBasedSymbolPointer.createForSymbolFromSource<KtNamedClassOrObjectSymbol>(this)?.let { return it }
|
||||
|
||||
return when (val symbolKind = symbolKind) {
|
||||
KtSymbolKind.LOCAL ->
|
||||
throw CanNotCreateSymbolPointerForLocalLibraryDeclarationException(classIdIfNonLocal?.asString() ?: name.asString())
|
||||
|
||||
KtSymbolKind.CLASS_MEMBER, KtSymbolKind.TOP_LEVEL ->
|
||||
KtFirClassLikeSymbolPointer(classIdIfNonLocal!!, KtNamedClassOrObjectSymbol::class)
|
||||
|
||||
else -> throw UnsupportedSymbolKind(this::class, symbolKind)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user