diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirVisibilityChecker.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirVisibilityChecker.kt index 908f4daec4f..27741ed1b53 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirVisibilityChecker.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirVisibilityChecker.kt @@ -82,13 +82,6 @@ internal class KtFirVisibilityChecker( * Returns `null` if visibility cannot be decided by the heuristic. */ private fun KtFirPsiJavaClassSymbol.isVisibleByPsi(useSiteFile: KtFirFileSymbol): Boolean? { - val classId = classIdIfNonLocal - if (classId == null) { - // Local classes are only visible in their containing method. Since we're checking the visibility for a Kotlin file, a local - // class from Java can never be accessible. - return false - } - when (visibility) { Visibilities.Private -> // Private classes from Java cannot be accessed from Kotlin. @@ -101,7 +94,7 @@ internal class KtFirVisibilityChecker( } JavaVisibilities.PackageVisibility -> { - val isSamePackage = classId.packageFqName == useSiteFile.firSymbol.fir.packageFqName + val isSamePackage = classIdIfNonLocal.packageFqName == useSiteFile.firSymbol.fir.packageFqName if (!isSamePackage) return false return when (val outerClass = this.outerClass) { diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirNamedClassOrObjectSymbol.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirNamedClassOrObjectSymbol.kt index 70157fbee43..b34bec3c04b 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirNamedClassOrObjectSymbol.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirNamedClassOrObjectSymbol.kt @@ -10,7 +10,6 @@ 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.KtSymbolByFirBuilder import org.jetbrains.kotlin.analysis.api.fir.annotations.KtFirAnnotationListForDeclaration import org.jetbrains.kotlin.analysis.api.fir.findPsi import org.jetbrains.kotlin.analysis.api.fir.utils.cached @@ -105,6 +104,22 @@ internal class KtFirNamedClassOrObjectSymbol( createNamedClassOrObjectSymbolPointer() } - override fun equals(other: Any?): Boolean = symbolEquals(other) - override fun hashCode(): Int = symbolHashCode() + /** + * [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() } diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirPsiJavaClassSymbol.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirPsiJavaClassSymbol.kt index 2ee56a5de8f..1ab5e123eda 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirPsiJavaClassSymbol.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirPsiJavaClassSymbol.kt @@ -46,12 +46,6 @@ internal class KtFirPsiJavaClassSymbol( override val psi: PsiClass, override val analysisSession: KtFirAnalysisSession, ) : KtNamedClassOrObjectSymbol(), KtFirPsiSymbol { - init { - require(psi.qualifiedName != null) { - "${KtFirPsiJavaClassSymbol::class.simpleName} requires a PSI class with a qualified name." - } - } - /** * [javaClass] is used to defer some properties to the compiler's view of a Java class. */ @@ -59,20 +53,17 @@ internal class KtFirPsiJavaClassSymbol( override val name: Name = withValidityAssertion { javaClass.name } - override val classIdIfNonLocal: ClassId? by cached { psi.classIdIfNonLocal } - - private val qualifiedName: String - get() = withValidityAssertion { psi.qualifiedName!! } + override val classIdIfNonLocal: ClassId = withValidityAssertion { + psi.classIdIfNonLocal ?: error("${KtFirPsiJavaClassSymbol::class.simpleName} requires a non-local PSI class.") + } override val origin: KtSymbolOrigin get() = withValidityAssertion { KtSymbolOrigin.JAVA } override val symbolKind: KtSymbolKind get() = withValidityAssertion { - val classId = classIdIfNonLocal when { - classId == null -> KtSymbolKind.LOCAL - classId.outerClassId != null -> KtSymbolKind.CLASS_MEMBER + classIdIfNonLocal.outerClassId != null -> KtSymbolKind.CLASS_MEMBER else -> KtSymbolKind.TOP_LEVEL } } @@ -88,7 +79,7 @@ internal class KtFirPsiJavaClassSymbol( get() = withValidityAssertion { javaClass.visibility } override val isInner: Boolean - get() = withValidityAssertion { classIdIfNonLocal?.outerClassId != null && !javaClass.isStatic } + get() = withValidityAssertion { classIdIfNonLocal.outerClassId != null && !javaClass.isStatic } val outerClass: KtFirPsiJavaClassSymbol? get() = withValidityAssertion { @@ -128,9 +119,11 @@ internal class KtFirPsiJavaClassSymbol( } /** - * Since [PsiEquivalenceUtil] doesn't have a hash code function, we use the class's fully qualified name as a conservative hash code. + * 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 = qualifiedName.hashCode() + override fun hashCode(): Int = classIdIfNonLocal.hashCode() //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Slow Operations (requiring access to the underlying FIR class symbol)