[Analysis API] Fix compiler-internal type leaks in the API surface During migration from components to context parameters, compiler-internal types of a few methods got unintentionally exposed in the public API surface. Even though affected classes are annotated with '@KaImplementationDetail', technically the classes are still accessible (with an opt-in). The commit moves implementations directly to bridges, eliminating the need in 'KaInternals...' wiring. ^KT-86591 ^KT-87552 Fixed
diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KaFirJavaInteroperabilityComponent.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KaFirJavaInteroperabilityComponent.kt index f045532..9a23703 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KaFirJavaInteroperabilityComponent.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KaFirJavaInteroperabilityComponent.kt
@@ -48,7 +48,6 @@ import org.jetbrains.kotlin.fileClasses.javaFileFacadeFqName import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.backend.jvm.FirJvmTypeMapper -import org.jetbrains.kotlin.fir.backend.jvm.jvmTypeMapper import org.jetbrains.kotlin.fir.declarations.DirectDeclarationsAccess import org.jetbrains.kotlin.fir.declarations.FirProperty import org.jetbrains.kotlin.fir.declarations.hasAnnotation @@ -86,21 +85,11 @@ import org.jetbrains.kotlin.types.model.RigidTypeMarker import org.jetbrains.kotlin.types.updateArgumentModeFromAnnotations import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull -import org.jetbrains.org.objectweb.asm.Type internal class KaFirJavaInteroperabilityComponent( override val analysisSessionProvider: () -> KaFirSession, ) : KaBaseSessionComponent<KaFirSession>(), KaInternalsJavaInteroperabilityComponent, KaFirSessionComponent { - private val jvmTypeMapper: FirJvmTypeMapper by lazy { - when { - analysisSession.targetPlatform.has<JvmPlatform>() -> rootModuleSession.jvmTypeMapper - else -> { - // Type mapper is not registered in non-JVM sessions. - // Here we use its custom instance for generating Java-like types in multiplatform source-sets. - FirJvmTypeMapper(rootModuleSession) - } - } - } + private val jvmTypeMapper: FirJvmTypeMapper by lazy { createFirJvmTypeMapper(analysisSession) } /** * [useSitePosition] is used as pure psi, so there is no need to validate it. @@ -289,10 +278,6 @@ return jvmTypeMapper.mapType(type.coneType, TypeMappingMode.DEFAULT, sw = null, unresolvedQualifierRemapper = null).descriptor } - override fun mapToJvmType(type: KaType, mode: TypeMappingMode): Type = withValidityAssertion { - return jvmTypeMapper.mapType(type.coneType, mode, sw = null, unresolvedQualifierRemapper = null) - } - override fun isPrimitiveBacked(type: KaType): Boolean = withValidityAssertion { if (analysisSession.targetPlatform.has<JvmPlatform>()) { return jvmTypeMapper.isPrimitiveBacked(type.coneType)
diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KaFirSymbolRelationProvider.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KaFirSymbolRelationProvider.kt index 95a22e1..a6b0b29 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KaFirSymbolRelationProvider.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KaFirSymbolRelationProvider.kt
@@ -487,26 +487,6 @@ } } - override fun getImplementationStatus( - symbol: KaCallableSymbol, - parentClassSymbol: KaClassSymbol, - ): ImplementationStatus? = symbol.withValidityAssertion { - if (symbol is KaReceiverParameterSymbol) return null - - require(symbol is KaFirSymbol<*>) - require(parentClassSymbol is KaFirSymbol<*>) - - // Inspecting implementation status requires resolving to status - val memberFir = symbol.firSymbol.fir as? FirCallableDeclaration ?: return null - val parentClassFir = parentClassSymbol.firSymbol.fir as? FirClass ?: return null - memberFir.lazyResolveToPhase(FirResolvePhase.STATUS) - - val scopeSession = symbol.analysisSession.getScopeSessionFor(symbol.analysisSession.firSession) - return with(SessionHolderImpl(rootModuleSession, scopeSession)) { - memberFir.symbol.getImplementationStatus(parentClassFir.symbol) - } - } - override fun implementationState( symbol: KaCallableSymbol, implementerClassSymbol: KaClassSymbol,
diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/bridges/KaJavaInteroperabilityComponentBridge.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/bridges/KaJavaInteroperabilityComponentBridge.kt index 1700ae9..99f905c 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/bridges/KaJavaInteroperabilityComponentBridge.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/bridges/KaJavaInteroperabilityComponentBridge.kt
@@ -11,13 +11,17 @@ import com.intellij.psi.PsiType import org.jetbrains.kotlin.analysis.api.components.KaJavaInteroperabilityComponent import org.jetbrains.kotlin.analysis.api.fir.KaFirSession +import org.jetbrains.kotlin.analysis.api.fir.components.KaFirSessionComponent +import org.jetbrains.kotlin.analysis.api.fir.components.createFirJvmTypeMapper import org.jetbrains.kotlin.analysis.api.impl.base.components.KaBaseSessionComponent import org.jetbrains.kotlin.analysis.api.internals.KaInternalsJavaInteroperabilityComponent +import org.jetbrains.kotlin.analysis.api.lifetime.withValidityAssertion import org.jetbrains.kotlin.analysis.api.symbols.KaCallableSymbol import org.jetbrains.kotlin.analysis.api.symbols.KaNamedClassSymbol import org.jetbrains.kotlin.analysis.api.symbols.KaPropertySymbol import org.jetbrains.kotlin.analysis.api.types.KaType import org.jetbrains.kotlin.analysis.api.types.KaTypeMappingMode +import org.jetbrains.kotlin.fir.backend.jvm.FirJvmTypeMapper import org.jetbrains.kotlin.load.kotlin.TypeMappingMode import org.jetbrains.kotlin.name.Name import org.jetbrains.org.objectweb.asm.Type @@ -30,10 +34,12 @@ internal class KaJavaInteroperabilityComponentBridge( override val analysisSessionProvider: () -> KaFirSession, -) : KaBaseSessionComponent<KaFirSession>(), KaJavaInteroperabilityComponent { +) : KaBaseSessionComponent<KaFirSession>(), KaJavaInteroperabilityComponent, KaFirSessionComponent { private val proxy: KaInternalsJavaInteroperabilityComponent get() = analysisSession.javaInteroperabilityComponent + private val jvmTypeMapper: FirJvmTypeMapper by lazy { createFirJvmTypeMapper(analysisSession) } + // Migrated callables — routed through the public endpoints. override fun PsiType.asKaType(useSitePosition: PsiElement): KaType? = @@ -76,8 +82,9 @@ ) @Deprecated("Use 'mapToJvmTypeDescriptor' instead.", level = DeprecationLevel.HIDDEN) - override fun KaType.mapToJvmType(mode: TypeMappingMode): Type = - proxy.mapToJvmType(this, mode) + override fun KaType.mapToJvmType(mode: TypeMappingMode): Type = withValidityAssertion { + jvmTypeMapper.mapType(coneType, mode, sw = null, unresolvedQualifierRemapper = null) + } override val KaPropertySymbol.javaGetterName: Name get() = proxy.javaGetterName(this)
diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/bridges/KaSymbolRelationProviderBridge.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/bridges/KaSymbolRelationProviderBridge.kt index 42de05c..0ff59e1 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/bridges/KaSymbolRelationProviderBridge.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/bridges/KaSymbolRelationProviderBridge.kt
@@ -10,11 +10,19 @@ import org.jetbrains.kotlin.analysis.api.components.KaSymbolRelationProvider import org.jetbrains.kotlin.analysis.api.fir.KaFirSession import org.jetbrains.kotlin.analysis.api.fir.components.KaFirSessionComponent +import org.jetbrains.kotlin.analysis.api.fir.symbols.KaFirSymbol import org.jetbrains.kotlin.analysis.api.impl.base.components.KaBaseSessionComponent import org.jetbrains.kotlin.analysis.api.internals.KaInternalsSymbolRelationProvider +import org.jetbrains.kotlin.analysis.api.lifetime.withValidityAssertion import org.jetbrains.kotlin.analysis.api.projectStructure.KaModule import org.jetbrains.kotlin.analysis.api.symbols.* import org.jetbrains.kotlin.platform.TargetPlatform +import org.jetbrains.kotlin.fir.analysis.checkers.getImplementationStatus +import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration +import org.jetbrains.kotlin.fir.declarations.FirClass +import org.jetbrains.kotlin.fir.declarations.FirResolvePhase +import org.jetbrains.kotlin.fir.resolve.SessionHolderImpl +import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase import org.jetbrains.kotlin.util.ImplementationStatus import org.jetbrains.kotlin.analysis.api.symbols.KaCallableImplementationState as KaEndpointCallableImplementationState import org.jetbrains.kotlin.analysis.api.symbols.allOverriddenSymbols as allOverriddenSymbolsEndpoint @@ -89,9 +97,23 @@ @KaExperimentalApi @Deprecated("Use 'implementationState()' instead", level = DeprecationLevel.HIDDEN) - override fun KaCallableSymbol.getImplementationStatus(parentClassSymbol: KaClassSymbol): ImplementationStatus? { - return proxy.getImplementationStatus(this, parentClassSymbol) - } + override fun KaCallableSymbol.getImplementationStatus(parentClassSymbol: KaClassSymbol): ImplementationStatus? = + withValidityAssertion { + if (this is KaReceiverParameterSymbol) return null + + require(this is KaFirSymbol<*>) + require(parentClassSymbol is KaFirSymbol<*>) + + // Inspecting implementation status requires resolving to status + val memberFir = firSymbol.fir as? FirCallableDeclaration ?: return null + val parentClassFir = parentClassSymbol.firSymbol.fir as? FirClass ?: return null + memberFir.lazyResolveToPhase(FirResolvePhase.STATUS) + + val scopeSession = analysisSession.getScopeSessionFor(analysisSession.firSession) + with(SessionHolderImpl(rootModuleSession, scopeSession)) { + memberFir.symbol.getImplementationStatus(parentClassFir.symbol) + } + } @KaExperimentalApi override fun KaCallableSymbol.implementationState(implementerClassSymbol: KaClassSymbol): KaCallableImplementationState? =
diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/firJvmTypeMapper.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/firJvmTypeMapper.kt new file mode 100644 index 0000000..03bc77e --- /dev/null +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/firJvmTypeMapper.kt
@@ -0,0 +1,26 @@ +/* + * Copyright 2010-2026 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.components + +import org.jetbrains.kotlin.analysis.api.fir.KaFirSession +import org.jetbrains.kotlin.fir.backend.jvm.FirJvmTypeMapper +import org.jetbrains.kotlin.fir.backend.jvm.jvmTypeMapper +import org.jetbrains.kotlin.platform.has +import org.jetbrains.kotlin.platform.jvm.JvmPlatform + +/** + * Creates a [FirJvmTypeMapper] for the given [analysisSession]. + * + * The type mapper is only registered in JVM sessions. For non-JVM sessions, a custom instance is created so that Java-like types can still + * be generated for multiplatform source sets. + */ +internal fun createFirJvmTypeMapper(analysisSession: KaFirSession): FirJvmTypeMapper { + val rootModuleSession = analysisSession.resolutionFacade.useSiteFirSession + return when { + analysisSession.targetPlatform.has<JvmPlatform>() -> rootModuleSession.jvmTypeMapper + else -> FirJvmTypeMapper(rootModuleSession) + } +}
diff --git a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/internals/KaInternalsJavaInteroperabilityComponent.kt b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/internals/KaInternalsJavaInteroperabilityComponent.kt index c7dccd2..d610688 100644 --- a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/internals/KaInternalsJavaInteroperabilityComponent.kt +++ b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/internals/KaInternalsJavaInteroperabilityComponent.kt
@@ -15,9 +15,7 @@ import org.jetbrains.kotlin.analysis.api.symbols.KaPropertySymbol import org.jetbrains.kotlin.analysis.api.types.KaType import org.jetbrains.kotlin.analysis.api.types.KaTypeMappingMode -import org.jetbrains.kotlin.load.kotlin.TypeMappingMode import org.jetbrains.kotlin.name.Name -import org.jetbrains.org.objectweb.asm.Type @KaImplementationDetail @SubclassOptInRequired(KaImplementationDetail::class) @@ -37,8 +35,6 @@ public fun mapToJvmTypeDescriptor(type: KaType): String - public fun mapToJvmType(type: KaType, mode: TypeMappingMode): Type - public fun isPrimitiveBacked(type: KaType): Boolean public fun namedClassSymbol(psiClass: PsiClass): KaNamedClassSymbol?
diff --git a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/internals/KaInternalsSymbolRelationProvider.kt b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/internals/KaInternalsSymbolRelationProvider.kt index 112dd9b..a2901f9 100644 --- a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/internals/KaInternalsSymbolRelationProvider.kt +++ b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/internals/KaInternalsSymbolRelationProvider.kt
@@ -10,7 +10,6 @@ import org.jetbrains.kotlin.analysis.api.projectStructure.KaModule import org.jetbrains.kotlin.analysis.api.symbols.* import org.jetbrains.kotlin.platform.TargetPlatform -import org.jetbrains.kotlin.util.ImplementationStatus @KaImplementationDetail @SubclassOptInRequired(KaImplementationDetail::class) @@ -43,8 +42,6 @@ public fun intersectionOverriddenSymbols(symbol: KaCallableSymbol): List<KaCallableSymbol> - public fun getImplementationStatus(symbol: KaCallableSymbol, parentClassSymbol: KaClassSymbol): ImplementationStatus? - @KaExperimentalApi public fun implementationState(symbol: KaCallableSymbol, implementerClassSymbol: KaClassSymbol): KaCallableImplementationState?
diff --git a/prepare/analysis-api/kotlin-analysis-api-surface/api/analysis-api-surface.classpath-issues b/prepare/analysis-api/kotlin-analysis-api-surface/api/analysis-api-surface.classpath-issues index 8d87296..e69de29 100644 --- a/prepare/analysis-api/kotlin-analysis-api-surface/api/analysis-api-surface.classpath-issues +++ b/prepare/analysis-api/kotlin-analysis-api-surface/api/analysis-api-surface.classpath-issues
@@ -1,3 +0,0 @@ -org/jetbrains/kotlin/load/kotlin/TypeMappingMode -org/jetbrains/kotlin/util/ImplementationStatus -org/jetbrains/org/objectweb/asm/Type \ No newline at end of file