FIR IDE: make equality of KtSymbol/KtType stable

This commit is contained in:
Tianyu Geng
2021-08-13 14:21:37 -07:00
committed by Ilya Kirillov
parent 6b57621863
commit 7306f1c3f1
23 changed files with 157 additions and 2 deletions
@@ -6,10 +6,28 @@
package org.jetbrains.kotlin.idea.frontend.api.symbols.markers
import org.jetbrains.kotlin.idea.frontend.api.ValidityTokenOwner
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtCallableSymbol
import org.jetbrains.kotlin.idea.frontend.api.types.KtType
public abstract class KtTypeAndAnnotations : ValidityTokenOwner {
public abstract val type: KtType
public abstract val annotations: List<KtAnnotationCall>
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as KtTypeAndAnnotations
if (token != other.token) return false
if (type != other.type) return false
if (annotations != other.annotations) return false
return true
}
override fun hashCode(): Int {
var result = token.hashCode()
result = 31 * result + type.hashCode()
result = 31 * result + annotations.hashCode()
return result
}
}
@@ -53,4 +53,7 @@ internal class KtFirAnonymousFunctionSymbol(
KtPsiBasedSymbolPointer.createForSymbolFromSource(this)?.let { return it }
error("Could not create a pointer for anonymous function from library")
}
override fun equals(other: Any?): Boolean = symbolEquals(other)
override fun hashCode(): Int = symbolHashCode()
}
@@ -46,4 +46,7 @@ internal class KtFirAnonymousObjectSymbol(
override fun createPointer(): KtSymbolPointer<KtAnonymousObjectSymbol> =
KtPsiBasedSymbolPointer.createForSymbolFromSource(this)
?: throw CanNotCreateSymbolPointerForLocalLibraryDeclarationException("Cannot create pointer for KtFirAnonymousObjectSymbol")
override fun equals(other: Any?): Boolean = symbolEquals(other)
override fun hashCode(): Int = symbolHashCode()
}
@@ -39,4 +39,18 @@ internal class KtFirBackingFieldSymbol(
override fun createPointer(): KtSymbolPointer<KtBackingFieldSymbol> {
return KtFirBackingFieldSymbolPointer(owningProperty.createPointer())
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as KtFirBackingFieldSymbol
if (this.token != other.token) return false
return this.propertyFirRef == other.propertyFirRef
}
override fun hashCode(): Int {
return propertyFirRef.hashCode() * 31 + token.hashCode()
}
}
@@ -87,4 +87,7 @@ internal class KtFirConstructorSymbol(
?: error("ClassId should present for member declaration")
return KtFirConstructorSymbolPointer(ownerClassId, isPrimary, firRef.withFir { it.createSignature() })
}
override fun equals(other: Any?): Boolean = symbolEquals(other)
override fun hashCode(): Int = symbolHashCode()
}
@@ -55,4 +55,7 @@ internal class KtFirEnumEntrySymbol(
)
}
}
override fun equals(other: Any?): Boolean = symbolEquals(other)
override fun hashCode(): Int = symbolHashCode()
}
@@ -38,4 +38,7 @@ internal class KtFirFileSymbol(
override val annotations: List<KtAnnotationCall> by cached { firRef.toAnnotationsList() }
override fun containsAnnotation(classId: ClassId): Boolean = firRef.containsAnnotation(classId)
override val annotationClassIds: Collection<ClassId> by cached { firRef.getAnnotationClassIds() }
override fun equals(other: Any?): Boolean = symbolEquals(other)
override fun hashCode(): Int = symbolHashCode()
}
@@ -120,4 +120,7 @@ internal class KtFirFunctionSymbol(
)
}
}
override fun equals(other: Any?): Boolean = symbolEquals(other)
override fun hashCode(): Int = symbolHashCode()
}
@@ -50,4 +50,7 @@ internal class KtFirJavaFieldSymbol(
override fun createPointer(): KtSymbolPointer<KtJavaFieldSymbol> {
TODO("Creating pointers for java fields is not supported yet")
}
override fun equals(other: Any?): Boolean = symbolEquals(other)
override fun hashCode(): Int = symbolHashCode()
}
@@ -129,4 +129,7 @@ internal class KtFirKotlinPropertySymbol(
KtSymbolKind.LOCAL -> throw CanNotCreateSymbolPointerForLocalLibraryDeclarationException(name.asString())
}
}
override fun equals(other: Any?): Boolean = symbolEquals(other)
override fun hashCode(): Int = symbolHashCode()
}
@@ -49,4 +49,7 @@ internal class KtFirLocalVariableSymbol(
KtPsiBasedSymbolPointer.createForSymbolFromSource(this)?.let { return it }
throw CanNotCreateSymbolPointerForLocalLibraryDeclarationException(name.asString())
}
override fun equals(other: Any?): Boolean = symbolEquals(other)
override fun hashCode(): Int = symbolHashCode()
}
@@ -114,4 +114,7 @@ internal class KtFirNamedClassOrObjectSymbol(
}
return KtFirClassOrObjectInLibrarySymbolPointer(classIdIfNonLocal!!)
}
override fun equals(other: Any?): Boolean = symbolEquals(other)
override fun hashCode(): Int = symbolHashCode()
}
@@ -38,6 +38,24 @@ class KtFirPackageSymbol(
check(session is KtFirAnalysisSession)
session.firSymbolBuilder.createPackageSymbolIfOneExists(fqName)
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as KtFirPackageSymbol
if (fqName != other.fqName) return false
if (token != other.token) return false
return true
}
override fun hashCode(): Int {
var result = fqName.hashCode()
result = 31 * result + token.hashCode()
return result
}
}
class KtPackage(
@@ -67,4 +67,7 @@ internal class KtFirPropertyGetterSymbol(
KtPsiBasedSymbolPointer.createForSymbolFromSource(this)?.let { return it }
TODO("Creating pointers for getters from library is not supported yet")
}
override fun equals(other: Any?): Boolean = symbolEquals(other)
override fun hashCode(): Int = symbolHashCode()
}
@@ -74,4 +74,7 @@ internal class KtFirPropertySetterSymbol(
KtPsiBasedSymbolPointer.createForSymbolFromSource(this)?.let { return it }
TODO("Creating pointers for setters from library is not supported yet")
}
override fun equals(other: Any?): Boolean = symbolEquals(other)
override fun hashCode(): Int = symbolHashCode()
}
@@ -24,6 +24,13 @@ internal interface KtFirSymbol<out F : FirDeclaration> : KtSymbol, ValidityToken
override val origin: KtSymbolOrigin get() = firRef.withFir { it.ktSymbolOrigin() }
}
internal fun KtFirSymbol<*>.symbolEquals(other: Any?): Boolean {
if (other !is KtFirSymbol<*>) return false
if (this.token != other.token) return false
return this.firRef == other.firRef
}
internal fun KtFirSymbol<*>.symbolHashCode(): Int = firRef.hashCode() * 31 + token.hashCode()
private tailrec fun FirDeclaration.ktSymbolOrigin(): KtSymbolOrigin = when (origin) {
FirDeclarationOrigin.Source -> {
@@ -93,4 +93,7 @@ internal class KtFirSyntheticJavaPropertySymbol(
override fun createPointer(): KtSymbolPointer<KtSyntheticJavaPropertySymbol> {
TODO("pointers to KtSyntheticJavaPropertySymbol is not supported yet")
}
override fun equals(other: Any?): Boolean = symbolEquals(other)
override fun hashCode(): Int = symbolHashCode()
}
@@ -42,4 +42,7 @@ internal class KtFirTypeAliasSymbol(
KtPsiBasedSymbolPointer.createForSymbolFromSource(this)?.let { return it }
TODO("Creating symbols for library typealiases is not supported yet")
}
override fun equals(other: Any?): Boolean = symbolEquals(other)
override fun hashCode(): Int = symbolHashCode()
}
@@ -44,4 +44,7 @@ internal class KtFirTypeParameterSymbol(
KtPsiBasedSymbolPointer.createForSymbolFromSource(this)?.let { return it }
TODO("Creating symbols for library type parameters is not supported yet")
}
override fun equals(other: Any?): Boolean = symbolEquals(other)
override fun hashCode(): Int = symbolHashCode()
}
@@ -52,4 +52,7 @@ internal class KtFirValueParameterSymbol(
KtPsiBasedSymbolPointer.createForSymbolFromSource(this)?.let { return it }
TODO("Creating pointers for functions parameters from library is not supported yet")
}
override fun equals(other: Any?): Boolean = symbolEquals(other)
override fun hashCode(): Int = symbolHashCode()
}
@@ -43,4 +43,14 @@ internal class KtFirAnnotationCall(
KtNamedConstantValue(name, expression.convertConstantExpression())
}
}
override fun equals(other: Any?): Boolean {
if (other !is KtFirAnnotationCall) return false
if (this.token != other.token) return false
return annotationCallRef == other.annotationCallRef
}
override fun hashCode(): Int {
return token.hashCode() * 31 + annotationCallRef.hashCode()
}
}
@@ -9,7 +9,9 @@ import org.jetbrains.kotlin.fir.resolve.inference.isSuspendFunctionType
import org.jetbrains.kotlin.fir.resolve.inference.receiverType
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
import org.jetbrains.kotlin.idea.frontend.api.*
import org.jetbrains.kotlin.idea.frontend.api.KtTypeArgument
import org.jetbrains.kotlin.idea.frontend.api.KtTypeArgumentWithVariance
import org.jetbrains.kotlin.idea.frontend.api.ValidityTokenOwner
import org.jetbrains.kotlin.idea.frontend.api.fir.KtSymbolByFirBuilder
import org.jetbrains.kotlin.idea.frontend.api.fir.utils.cached
import org.jetbrains.kotlin.idea.frontend.api.fir.utils.weakRef
@@ -17,6 +19,7 @@ import org.jetbrains.kotlin.idea.frontend.api.symbols.KtClassLikeSymbol
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtTypeParameterSymbol
import org.jetbrains.kotlin.idea.frontend.api.tokens.ValidityToken
import org.jetbrains.kotlin.idea.frontend.api.types.*
import org.jetbrains.kotlin.idea.frontend.api.withValidityAssertion
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name
@@ -24,6 +27,14 @@ internal interface KtFirType : ValidityTokenOwner {
val coneType: ConeKotlinType
}
private fun KtFirType.typeEquals(other: Any?): Boolean {
if (other !is KtFirType) return false
if (this.token != other.token) return false
return this.coneType == other.coneType
}
private fun KtFirType.typeHashcode(): Int = token.hashCode() * 31 + coneType.hashCode()
internal class KtFirUsualClassType(
_coneType: ConeClassLikeTypeImpl,
override val token: ValidityToken,
@@ -45,6 +56,8 @@ internal class KtFirUsualClassType(
override val nullability: KtTypeNullability get() = withValidityAssertion { KtTypeNullability.create(coneType.canBeNull) }
override fun asStringForDebugging(): String = withValidityAssertion { coneType.render() }
override fun equals(other: Any?) = typeEquals(other)
override fun hashCode() = typeHashcode()
}
internal class KtFirFunctionalType(
@@ -96,6 +109,8 @@ internal class KtFirFunctionalType(
get() = withValidityAssertion { (typeArguments.last() as KtTypeArgumentWithVariance).type }
override fun asStringForDebugging(): String = withValidityAssertion { coneType.render() }
override fun equals(other: Any?) = typeEquals(other)
override fun hashCode() = typeHashcode()
}
internal class KtFirClassErrorType(
@@ -106,6 +121,8 @@ internal class KtFirClassErrorType(
override val error: String get() = withValidityAssertion { coneType.diagnostic.reason }
override fun asStringForDebugging(): String = withValidityAssertion { coneType.render() }
override fun equals(other: Any?) = typeEquals(other)
override fun hashCode() = typeHashcode()
}
internal class KtFirCapturedType(
@@ -114,6 +131,8 @@ internal class KtFirCapturedType(
) : KtCapturedType(), KtFirType {
override val coneType by weakRef(_coneType)
override fun asStringForDebugging(): String = withValidityAssertion { coneType.render() }
override fun equals(other: Any?) = typeEquals(other)
override fun hashCode() = typeHashcode()
}
internal class KtFirDefinitelyNotNullType(
@@ -127,6 +146,8 @@ internal class KtFirDefinitelyNotNullType(
override val original: KtType by cached { builder.typeBuilder.buildKtType(this.coneType.original) }
override fun asStringForDebugging(): String = withValidityAssertion { coneType.render() }
override fun equals(other: Any?) = typeEquals(other)
override fun hashCode() = typeHashcode()
}
internal class KtFirTypeParameterType(
@@ -145,6 +166,8 @@ internal class KtFirTypeParameterType(
override val nullability: KtTypeNullability get() = withValidityAssertion { KtTypeNullability.create(coneType.canBeNull) }
override fun asStringForDebugging(): String = withValidityAssertion { coneType.render() }
override fun equals(other: Any?) = typeEquals(other)
override fun hashCode() = typeHashcode()
}
internal class KtFirFlexibleType(
@@ -158,6 +181,8 @@ internal class KtFirFlexibleType(
override val lowerBound: KtType by cached { builder.typeBuilder.buildKtType(coneType.lowerBound) }
override val upperBound: KtType by cached { builder.typeBuilder.buildKtType(coneType.upperBound) }
override fun asStringForDebugging(): String = withValidityAssertion { coneType.render() }
override fun equals(other: Any?) = typeEquals(other)
override fun hashCode() = typeHashcode()
}
internal class KtFirIntersectionType(
@@ -173,4 +198,6 @@ internal class KtFirIntersectionType(
}
override fun asStringForDebugging(): String = withValidityAssertion { coneType.render() }
override fun equals(other: Any?) = typeEquals(other)
override fun hashCode() = typeHashcode()
}
@@ -66,6 +66,19 @@ internal class FirRefWithValidityCheck<out D : FirDeclaration>(fir: D, resolveSt
ValidityAwareCachedValue(token) {
withFirByType(type) { fir -> createValue(fir) }
}
override fun equals(other: Any?): Boolean {
if (other !is FirRefWithValidityCheck<*>) return false
return getRefFir() == other.getRefFir() && this.token == other.token
}
override fun hashCode(): Int {
return getRefFir().hashCode() * 31 + token.hashCode()
}
private fun getRefFir(): FirDeclaration {
return firWeakRef.get() ?: throw EntityWasGarbageCollectedException("FirElement")
}
}
@Suppress("NOTHING_TO_INLINE")