From 1374bc8e2d48ae1fc494ec5077e66dd66ece5b18 Mon Sep 17 00:00:00 2001 From: Marco Pennekamp Date: Wed, 28 Feb 2024 21:35:59 +0100 Subject: [PATCH] [LL] Implement a common `LLSealedInheritorsProvider` - The new `LLSealedInheritorsProvider` is based on the previous sealed inheritors provider implementation in the IDE. It uses the new direct inheritors provider and the module dependents provider to implement the same functionality that was previously confined to the IDE. With this design we avoid duplication of complex logic such as the KMP handling in `searchInheritors`. - The implementation is designed to work in the production Standalone mode and the aforementioned services have already been implemented for Standalone in prior commits. Now we can get rid of the problematic `SealedClassInheritorsProviderForTests` and tests should more closely match production behavior. - In IDE mode tests, `LLSealedInheritorsProvider` is used with Standalone Analysis API provider implementations. This is in line with the rest of the test infrastructure, where Standalone AA providers are generally used, as IDE providers aren't available. - `KotlinSealedInheritorsProvider` is made obsolete by the common sealed inheritors provider. ^KT-66013 fixed ^KT-64505 fixed --- .../KotlinSealedInheritorsProvider.kt | 36 ------ .../StandaloneAnalysisAPISessionBuilder.kt | 12 -- .../compilation/classKinds.ir.txt | 2 +- ...hEnumFromDuplicatedLibrary.descriptors.txt | 12 +- ...annotationWithEnumFromDuplicatedLibrary.kt | 1 - ...edCallableWithImplicitType.descriptors.txt | 24 ++-- .../duplicatedCallableWithImplicitType.kt | 1 - .../LLSealedInheritorsProviderFactory.kt | 56 ---------- .../structure/sessionFactoryHelpers.kt | 4 +- .../providers/LLSealedInheritorsProvider.kt | 99 +++++++++++++++++ .../LLFirSealedClassInheritorsLazyResolver.kt | 6 +- .../annotationFromImplicitJavaType.kt | 1 - ...nFromImplicitJavaTypeWithJavaAnnotation.kt | 1 - ...licitTypeFromFunctionWithDuplicatedName.kt | 1 - .../AbstractLowLevelCompilerBasedTest.kt | 2 - ...sInheritorsCalculatorPreAnalysisHandler.kt | 105 ------------------ ...SealedInheritorsProviderFactoryForTests.kt | 47 -------- .../AnalysisApiFirTestServiceRegistrar.kt | 3 - ...ysisApiFirLibrarySourceTestConfigurator.kt | 3 - ...nalysisApiFirSourceLikeTestConfigurator.kt | 3 - 20 files changed, 123 insertions(+), 296 deletions(-) delete mode 100644 analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/KotlinSealedInheritorsProvider.kt delete mode 100644 analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/services/LLSealedInheritorsProviderFactory.kt create mode 100644 analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLSealedInheritorsProvider.kt delete mode 100644 analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/compiler/based/SealedClassesInheritorsCalculatorPreAnalysisHandler.kt delete mode 100644 analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/services/LLSealedInheritorsProviderFactoryForTests.kt diff --git a/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/KotlinSealedInheritorsProvider.kt b/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/KotlinSealedInheritorsProvider.kt deleted file mode 100644 index 39a101b2baf..00000000000 --- a/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/KotlinSealedInheritorsProvider.kt +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2010-2024 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.providers - -import com.intellij.openapi.project.Project -import org.jetbrains.kotlin.name.ClassId -import org.jetbrains.kotlin.psi.KtClass - -/** - * [KotlinSealedInheritorsProvider] provides a list of direct inheritors for sealed [KtClass]es (which may be a class or an interface). It - * may be created with [KotlinSealedInheritorsProviderFactory]. - * - * Implementations of this service should consider caching the results. The [KotlinSealedInheritorsProvider] is tied to the lifetime of its - * owning session, so it will be invalidated automatically with the session. - */ -public interface KotlinSealedInheritorsProvider { - /** - * Returns the sealed inheritors of [ktClass], which may be a class or an interface. [ktClass] is guaranteed to be sealed. - */ - public fun getSealedInheritors(ktClass: KtClass): List -} - -public interface KotlinSealedInheritorsProviderFactory { - /** - * Creates a [KotlinSealedInheritorsProvider] for a session. - */ - public fun createSealedInheritorsProvider(): KotlinSealedInheritorsProvider - - public companion object { - public fun getInstance(project: Project): KotlinSealedInheritorsProviderFactory? = - project.getService(KotlinSealedInheritorsProviderFactory::class.java) - } -} diff --git a/analysis/analysis-api-standalone/src/org/jetbrains/kotlin/analysis/api/standalone/StandaloneAnalysisAPISessionBuilder.kt b/analysis/analysis-api-standalone/src/org/jetbrains/kotlin/analysis/api/standalone/StandaloneAnalysisAPISessionBuilder.kt index 06f8f6287b4..b285ab0e091 100644 --- a/analysis/analysis-api-standalone/src/org/jetbrains/kotlin/analysis/api/standalone/StandaloneAnalysisAPISessionBuilder.kt +++ b/analysis/analysis-api-standalone/src/org/jetbrains/kotlin/analysis/api/standalone/StandaloneAnalysisAPISessionBuilder.kt @@ -16,7 +16,6 @@ import org.jetbrains.kotlin.analysis.api.standalone.base.project.structure.FirSt import org.jetbrains.kotlin.analysis.api.standalone.base.project.structure.KtStaticProjectStructureProvider import org.jetbrains.kotlin.analysis.api.standalone.base.project.structure.LLFirStandaloneLibrarySymbolProviderFactory import org.jetbrains.kotlin.analysis.api.standalone.base.project.structure.StandaloneProjectFactory -import org.jetbrains.kotlin.analysis.low.level.api.fir.api.services.LLSealedInheritorsProviderFactory import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.LLFirLibrarySymbolProviderFactory import org.jetbrains.kotlin.analysis.project.structure.KtSourceModule import org.jetbrains.kotlin.analysis.project.structure.builder.KtModuleProviderBuilder @@ -32,8 +31,6 @@ import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreProjectEnvironment import org.jetbrains.kotlin.cli.jvm.compiler.setupIdeaStandaloneExecution import org.jetbrains.kotlin.config.CompilerConfiguration import org.jetbrains.kotlin.extensions.ProjectExtensionDescriptor -import org.jetbrains.kotlin.fir.declarations.SealedClassInheritorsProvider -import org.jetbrains.kotlin.fir.declarations.SealedClassInheritorsProviderImpl import org.jetbrains.kotlin.load.kotlin.PackagePartProvider import org.jetbrains.kotlin.psi.KtFile import kotlin.contracts.ExperimentalContracts @@ -137,15 +134,6 @@ public class StandaloneAnalysisAPISessionBuilder( ) registerService(KotlinPackageProviderMerger::class.java, KotlinStaticPackageProviderMerger(this)) - registerService( - LLSealedInheritorsProviderFactory::class.java, - object : LLSealedInheritorsProviderFactory { - override fun createSealedInheritorsProvider(): SealedClassInheritorsProvider { - return SealedClassInheritorsProviderImpl - } - } - ) - registerService( PackagePartProviderFactory::class.java, KotlinStaticPackagePartProviderFactory(packagePartProvider) diff --git a/analysis/analysis-api/testData/components/compilerFacility/compilation/classKinds.ir.txt b/analysis/analysis-api/testData/components/compilerFacility/compilation/classKinds.ir.txt index c9748571e64..5ff35b6d447 100644 --- a/analysis/analysis-api/testData/components/compilerFacility/compilation/classKinds.ir.txt +++ b/analysis/analysis-api/testData/components/compilerFacility/compilation/classKinds.ir.txt @@ -52,8 +52,8 @@ MODULE_FRAGMENT CLASS CLASS name:Operation modality:SEALED visibility:public superTypes:[kotlin.Any] sealedSubclasses: CLASS CLASS name:Add modality:FINAL visibility:public superTypes:[.Operation] - CLASS CLASS name:Subtract modality:FINAL visibility:public superTypes:[.Operation] CLASS CLASS name:Negate modality:FINAL visibility:public superTypes:[.Operation] + CLASS CLASS name:Subtract modality:FINAL visibility:public superTypes:[.Operation] $this: VALUE_PARAMETER INSTANCE_RECEIVER name: type:.Operation CLASS CLASS name:Add modality:FINAL visibility:public superTypes:[.Operation] $this: VALUE_PARAMETER INSTANCE_RECEIVER name: type:.Operation.Add diff --git a/analysis/analysis-api/testData/components/diagnosticsProvider/diagnostics/annotationWithEnumFromDuplicatedLibrary.descriptors.txt b/analysis/analysis-api/testData/components/diagnosticsProvider/diagnostics/annotationWithEnumFromDuplicatedLibrary.descriptors.txt index d73ecf0277b..37dc712bc5f 100644 --- a/analysis/analysis-api/testData/components/diagnosticsProvider/diagnostics/annotationWithEnumFromDuplicatedLibrary.descriptors.txt +++ b/analysis/analysis-api/testData/components/diagnosticsProvider/diagnostics/annotationWithEnumFromDuplicatedLibrary.descriptors.txt @@ -1,7 +1,7 @@ Diagnostics from elements: - for PSI element of type KtConstructorCalleeExpression at (34,2-12) - NO_VALUE_FOR_PARAMETER text ranges: [(115,125)] - PSI: KtConstructorCalleeExpression at (34,2-12) - for PSI element of type KtNameReferenceExpression at (32,8-10) - UNRESOLVED_REFERENCE text ranges: [(94,96)] - PSI: KtNameReferenceExpression at (32,8-10) + for PSI element of type KtConstructorCalleeExpression at (33,2-12) + NO_VALUE_FOR_PARAMETER text ranges: [(114,124)] + PSI: KtConstructorCalleeExpression at (33,2-12) + for PSI element of type KtNameReferenceExpression at (31,8-10) + UNRESOLVED_REFERENCE text ranges: [(93,95)] + PSI: KtNameReferenceExpression at (31,8-10) diff --git a/analysis/analysis-api/testData/components/diagnosticsProvider/diagnostics/annotationWithEnumFromDuplicatedLibrary.kt b/analysis/analysis-api/testData/components/diagnosticsProvider/diagnostics/annotationWithEnumFromDuplicatedLibrary.kt index ee48b0be638..b0fe8c0b191 100644 --- a/analysis/analysis-api/testData/components/diagnosticsProvider/diagnostics/annotationWithEnumFromDuplicatedLibrary.kt +++ b/analysis/analysis-api/testData/components/diagnosticsProvider/diagnostics/annotationWithEnumFromDuplicatedLibrary.kt @@ -1,5 +1,4 @@ // ALLOW_KOTLIN_PACKAGE -// DISABLE_SEALED_INHERITOR_CALCULATOR // MODULE: lib1 // FILE: anno.kt package kotlin.annotation diff --git a/analysis/analysis-api/testData/components/diagnosticsProvider/diagnostics/duplicatedCallableWithImplicitType.descriptors.txt b/analysis/analysis-api/testData/components/diagnosticsProvider/diagnostics/duplicatedCallableWithImplicitType.descriptors.txt index c383bbc5d4c..992c77bbce8 100644 --- a/analysis/analysis-api/testData/components/diagnosticsProvider/diagnostics/duplicatedCallableWithImplicitType.descriptors.txt +++ b/analysis/analysis-api/testData/components/diagnosticsProvider/diagnostics/duplicatedCallableWithImplicitType.descriptors.txt @@ -1,13 +1,13 @@ Diagnostics from elements: - for PSI element of type KtCallExpression at (24,20) - (27,2) - TYPE_MISMATCH text ranges: [(98,160)] - PSI: KtCallExpression at (24,20) - (27,2) - for PSI element of type KtLambdaExpression at (24,24) - (27,2) - TYPE_MISMATCH text ranges: [(102,160)] - PSI: KtLambdaExpression at (24,24) - (27,2) - for PSI element of type KtNameReferenceExpression at (25,5-17) - UNRESOLVED_REFERENCE text ranges: [(108,120)] - PSI: KtNameReferenceExpression at (25,5-17) - for PSI element of type KtNameReferenceExpression at (26,5-34) - UNRESOLVED_REFERENCE text ranges: [(127,156)] - PSI: KtNameReferenceExpression at (26,5-34) + for PSI element of type KtCallExpression at (23,20) - (26,2) + TYPE_MISMATCH text ranges: [(97,159)] + PSI: KtCallExpression at (23,20) - (26,2) + for PSI element of type KtLambdaExpression at (23,24) - (26,2) + TYPE_MISMATCH text ranges: [(101,159)] + PSI: KtLambdaExpression at (23,24) - (26,2) + for PSI element of type KtNameReferenceExpression at (24,5-17) + UNRESOLVED_REFERENCE text ranges: [(107,119)] + PSI: KtNameReferenceExpression at (24,5-17) + for PSI element of type KtNameReferenceExpression at (25,5-34) + UNRESOLVED_REFERENCE text ranges: [(126,155)] + PSI: KtNameReferenceExpression at (25,5-34) diff --git a/analysis/analysis-api/testData/components/diagnosticsProvider/diagnostics/duplicatedCallableWithImplicitType.kt b/analysis/analysis-api/testData/components/diagnosticsProvider/diagnostics/duplicatedCallableWithImplicitType.kt index f7ad7f26aa2..2e57792d55c 100644 --- a/analysis/analysis-api/testData/components/diagnosticsProvider/diagnostics/duplicatedCallableWithImplicitType.kt +++ b/analysis/analysis-api/testData/components/diagnosticsProvider/diagnostics/duplicatedCallableWithImplicitType.kt @@ -1,4 +1,3 @@ -// DISABLE_SEALED_INHERITOR_CALCULATOR // MODULE: lib1 // FILE: dependency.kt package usage diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/services/LLSealedInheritorsProviderFactory.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/services/LLSealedInheritorsProviderFactory.kt deleted file mode 100644 index 8b79abe4451..00000000000 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/services/LLSealedInheritorsProviderFactory.kt +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2010-2021 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.low.level.api.fir.api.services - -import com.intellij.openapi.project.Project -import org.jetbrains.kotlin.analysis.providers.KotlinSealedInheritorsProvider -import org.jetbrains.kotlin.analysis.providers.KotlinSealedInheritorsProviderFactory -import org.jetbrains.kotlin.fir.declarations.FirRegularClass -import org.jetbrains.kotlin.fir.declarations.SealedClassInheritorsProvider -import org.jetbrains.kotlin.fir.psi -import org.jetbrains.kotlin.name.ClassId -import org.jetbrains.kotlin.psi.KtClass - -interface LLSealedInheritorsProviderFactory { - /** - * Creates a [SealedClassInheritorsProvider] for a session. A new [SealedClassInheritorsProvider] instance should be created on every - * call. - */ - fun createSealedInheritorsProvider(): SealedClassInheritorsProvider -} - -/** - * Creates a [SealedClassInheritorsProvider] for a session. - * - * Requires either [LLSealedInheritorsProviderFactory] or [KotlinSealedInheritorsProviderFactory] to be registered as a project service. - */ -internal fun createSealedInheritorsProvider(project: Project): SealedClassInheritorsProvider = - createFromLLProvider(project) - ?: createFromAnalysisApiProvider(project) - ?: error( - """ - Expected one of the following services to be registered with $project: - - ${LLSealedInheritorsProviderFactory::class.simpleName} - - ${KotlinSealedInheritorsProviderFactory::class.simpleName} - """.trimIndent() - ) - -private fun createFromLLProvider(project: Project): SealedClassInheritorsProvider? = - project.getService(LLSealedInheritorsProviderFactory::class.java)?.createSealedInheritorsProvider() - -private fun createFromAnalysisApiProvider(project: Project): SealedClassInheritorsProvider? = - KotlinSealedInheritorsProviderFactory.getInstance(project) - ?.createSealedInheritorsProvider() - ?.let(::LLSealedInheritorsProviderByAnalysisApiProvider) - -private class LLSealedInheritorsProviderByAnalysisApiProvider( - private val provider: KotlinSealedInheritorsProvider, -) : SealedClassInheritorsProvider() { - override fun getSealedClassInheritors(firClass: FirRegularClass): List { - val ktClass = firClass.psi as? KtClass ?: return emptyList() - return provider.getSealedInheritors(ktClass) - } -} diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/project/structure/sessionFactoryHelpers.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/project/structure/sessionFactoryHelpers.kt index 0d6e284372a..e1816e79651 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/project/structure/sessionFactoryHelpers.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/project/structure/sessionFactoryHelpers.kt @@ -8,11 +8,11 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure import com.intellij.openapi.project.Project import com.intellij.openapi.util.Disposer import org.jetbrains.kotlin.analysis.api.resolve.extensions.KtResolveExtensionProvider -import org.jetbrains.kotlin.analysis.low.level.api.fir.api.services.createSealedInheritorsProvider import org.jetbrains.kotlin.analysis.low.level.api.fir.compile.CodeFragmentScopeProvider import org.jetbrains.kotlin.analysis.low.level.api.fir.fir.caches.FirThreadSafeCachesFactory import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.LLFirIdePredicateBasedProvider import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.LLFirIdeRegisteredPluginAnnotations +import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.LLSealedInheritorsProvider import org.jetbrains.kotlin.analysis.low.level.api.fir.resolve.extensions.LLFirNonEmptyResolveExtensionTool import org.jetbrains.kotlin.analysis.low.level.api.fir.resolve.extensions.LLFirResolveExtensionTool import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirSession @@ -37,7 +37,7 @@ import org.jetbrains.kotlin.fir.session.FirSessionConfigurator @SessionConfiguration internal fun LLFirSession.registerIdeComponents(project: Project) { register(FirCachesFactory::class, FirThreadSafeCachesFactory) - register(SealedClassInheritorsProvider::class, createSealedInheritorsProvider(project)) + register(SealedClassInheritorsProvider::class, LLSealedInheritorsProvider(project)) register(FirExceptionHandler::class, LLFirExceptionHandler) register(CodeFragmentScopeProvider::class, CodeFragmentScopeProvider(this)) registerResolveExtensionTool() diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLSealedInheritorsProvider.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLSealedInheritorsProvider.kt new file mode 100644 index 00000000000..e42a884e466 --- /dev/null +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLSealedInheritorsProvider.kt @@ -0,0 +1,99 @@ +/* + * Copyright 2010-2024 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.low.level.api.fir.providers + +import com.intellij.openapi.project.Project +import com.intellij.psi.search.GlobalSearchScope +import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.llFirModuleData +import org.jetbrains.kotlin.analysis.project.structure.KotlinModuleDependentsProvider +import org.jetbrains.kotlin.analysis.project.structure.KtDanglingFileModule +import org.jetbrains.kotlin.analysis.providers.KotlinDirectInheritorsProvider +import org.jetbrains.kotlin.fir.declarations.FirClass +import org.jetbrains.kotlin.fir.declarations.FirRegularClass +import org.jetbrains.kotlin.fir.declarations.SealedClassInheritorsProvider +import org.jetbrains.kotlin.fir.declarations.SealedClassInheritorsProviderInternals +import org.jetbrains.kotlin.fir.declarations.sealedInheritorsAttr +import org.jetbrains.kotlin.fir.declarations.utils.classId +import org.jetbrains.kotlin.fir.declarations.utils.isExpect +import org.jetbrains.kotlin.fir.psi +import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.psi.KtClass +import java.util.concurrent.ConcurrentHashMap +import kotlin.collections.filter +import kotlin.collections.map +import kotlin.collections.mapNotNull +import kotlin.collections.plus +import kotlin.collections.sortedBy +import kotlin.let + +/** + * [LLSealedInheritorsProvider] is the LL FIR implementation of [SealedClassInheritorsProvider] for both the IDE and Standalone mode. + */ +@OptIn(SealedClassInheritorsProviderInternals::class) +internal class LLSealedInheritorsProvider(private val project: Project) : SealedClassInheritorsProvider() { + val cache = ConcurrentHashMap>() + + override fun getSealedClassInheritors(firClass: FirRegularClass): List { + // Classes from binary libraries which are deserialized from class files (but not stubs) will have their `sealedInheritorsAttr` set + // from metadata. + firClass.sealedInheritorsAttr?.let { return it.value } + + val classId = firClass.classId + + // Local classes cannot be sealed. + if (classId.isLocal) { + return emptyList() + } + + return cache.computeIfAbsent(classId) { searchInheritors(firClass) } + } + + /** + * Some notes about the search: + * + * - A Java class cannot legally extend a sealed Kotlin class (even in the same package), so we don't need to search for Java class + * inheritors. + * - Technically, we could use a package scope to narrow the search, but the search is already sufficiently narrow because it uses + * supertype indices and is confined to the current `KtModule` in most cases (except for 'expect' classes). Finding a `PsiPackage` + * for a `PackageScope` is not cheap, hence the decision to avoid it. If a `PackageScope` is needed in the future, it'd be best to + * extract a `PackageNameScope` which operates just with the qualified package name, to avoid `PsiPackage`. (At the time of writing, + * this is possible with the implementation of `PackageScope`.) + * - We ignore local classes to avoid lazy resolve contract violations. + * See KT-63795. + * - For `expect` declarations, the search scope includes all modules with a dependsOn dependency on the containing module. + * At the same time, `actual` declarations are restricted to the same module and require no special handling. + * See KT-45842. + * - KMP libraries are not yet supported. + * See KT-65591. + */ + private fun searchInheritors(firClass: FirClass): List { + val ktClass = firClass.psi as? KtClass ?: return emptyList() + + val ktModule = when (val classKtModule = firClass.llFirModuleData.ktModule) { + is KtDanglingFileModule -> classKtModule.contextModule + else -> classKtModule + } + + // `FirClass.isExpect` does not depend on the `STATUS` phase because it's already set during FIR building. + val scope = if (firClass.isExpect) { + val refinementDependents = KotlinModuleDependentsProvider.getInstance(project).getRefinementDependents(ktModule) + GlobalSearchScope.union(refinementDependents.map { it.contentScope } + ktModule.contentScope) + } else { + ktModule.contentScope + } + + return searchInScope(ktClass, firClass.classId, scope) + } + + private fun searchInScope(ktClass: KtClass, classId: ClassId, scope: GlobalSearchScope): List = + KotlinDirectInheritorsProvider.getInstance(project) + .getDirectKotlinInheritors(ktClass, scope, includeLocalInheritors = false) + .mapNotNull { it.getClassId() } + .filter { it.packageFqName == classId.packageFqName } + // Enforce a deterministic order on the result, e.g. for stable test output. + .sortedBy { it.toString() } + .ifEmpty { emptyList() } +} diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirSealedClassInheritorsLazyResolver.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirSealedClassInheritorsLazyResolver.kt index 168ffe765f1..43fdfc84d7d 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirSealedClassInheritorsLazyResolver.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirSealedClassInheritorsLazyResolver.kt @@ -21,11 +21,11 @@ internal object LLFirSealedClassInheritorsLazyResolver : LLFirLazyResolver(FirRe /** * This resolver is responsible for [SEALED_CLASS_INHERITORS][FirResolvePhase.SEALED_CLASS_INHERITORS] phase. * - * LL FIR use [LLSealedInheritorsProviderByAnalysisApiProvider][org.jetbrains.kotlin.analysis.low.level.api.fir.api.services.LLSealedInheritorsProviderByAnalysisApiProvider] + * LL FIR uses [LLSealedInheritorsProvider][org.jetbrains.kotlin.analysis.low.level.api.fir.providers.LLSealedInheritorsProvider] * instead of the compiler [SealedClassInheritorsProviderImpl][org.jetbrains.kotlin.fir.declarations.SealedClassInheritorsProviderImpl], - * so it does nothing during this phase as sealed class hierarchy will be provided later on demand. + * so it does nothing during this phase as sealed inheritors will be provided later on demand. * - * @see org.jetbrains.kotlin.analysis.low.level.api.fir.api.services.LLSealedInheritorsProviderFactory + * @see org.jetbrains.kotlin.analysis.low.level.api.fir.providers.LLSealedInheritorsProvider * @see org.jetbrains.kotlin.fir.declarations.SealedClassInheritorsProvider * @see FirResolvePhase.SEALED_CLASS_INHERITORS */ diff --git a/analysis/low-level-api-fir/testData/lazyResolve/annotationFromImplicitJavaType.kt b/analysis/low-level-api-fir/testData/lazyResolve/annotationFromImplicitJavaType.kt index 1ea17f598dd..54b19e22f4f 100644 --- a/analysis/low-level-api-fir/testData/lazyResolve/annotationFromImplicitJavaType.kt +++ b/analysis/low-level-api-fir/testData/lazyResolve/annotationFromImplicitJavaType.kt @@ -1,5 +1,4 @@ // SKIP_WHEN_OUT_OF_CONTENT_ROOT -// DISABLE_SEALED_INHERITOR_CALCULATOR // FILE: main.kt fun resolveMe(i: JavaInterface) = i.id diff --git a/analysis/low-level-api-fir/testData/lazyResolve/annotationFromImplicitJavaTypeWithJavaAnnotation.kt b/analysis/low-level-api-fir/testData/lazyResolve/annotationFromImplicitJavaTypeWithJavaAnnotation.kt index dfdcfdf7b4e..924cec1aa51 100644 --- a/analysis/low-level-api-fir/testData/lazyResolve/annotationFromImplicitJavaTypeWithJavaAnnotation.kt +++ b/analysis/low-level-api-fir/testData/lazyResolve/annotationFromImplicitJavaTypeWithJavaAnnotation.kt @@ -1,5 +1,4 @@ // SKIP_WHEN_OUT_OF_CONTENT_ROOT -// DISABLE_SEALED_INHERITOR_CALCULATOR // FILE: main.kt fun resolveMe(i: JavaInterface) = i.id diff --git a/analysis/low-level-api-fir/testData/lazyResolve/functions/implicitTypeFromFunctionWithDuplicatedName.kt b/analysis/low-level-api-fir/testData/lazyResolve/functions/implicitTypeFromFunctionWithDuplicatedName.kt index f4b17659c7f..4a67f8e4618 100644 --- a/analysis/low-level-api-fir/testData/lazyResolve/functions/implicitTypeFromFunctionWithDuplicatedName.kt +++ b/analysis/low-level-api-fir/testData/lazyResolve/functions/implicitTypeFromFunctionWithDuplicatedName.kt @@ -1,5 +1,4 @@ // SKIP_WHEN_OUT_OF_CONTENT_ROOT -// DISABLE_SEALED_INHERITOR_CALCULATOR // MODULE: lib1 // FILE: dependency.kt package usage diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/compiler/based/AbstractLowLevelCompilerBasedTest.kt b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/compiler/based/AbstractLowLevelCompilerBasedTest.kt index 2b78cc90afa..d3be7cb40d5 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/compiler/based/AbstractLowLevelCompilerBasedTest.kt +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/compiler/based/AbstractLowLevelCompilerBasedTest.kt @@ -52,8 +52,6 @@ abstract class AbstractLowLevelCompilerBasedTest : AbstractCompilerBasedTest() { configureTest(this) defaultConfiguration(this) registerAnalysisApiBaseTestServices(disposable, FirLowLevelCompilerBasedTestConfigurator) - useDirectives(SealedClassesInheritorsCalculatorPreAnalysisHandler.Directives) - usePreAnalysisHandlers(::SealedClassesInheritorsCalculatorPreAnalysisHandler) useAdditionalServices(service(::AnalysisApiFirDiagnosticCollectorService)) firHandlersStep { diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/compiler/based/SealedClassesInheritorsCalculatorPreAnalysisHandler.kt b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/compiler/based/SealedClassesInheritorsCalculatorPreAnalysisHandler.kt deleted file mode 100644 index 05286085929..00000000000 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/compiler/based/SealedClassesInheritorsCalculatorPreAnalysisHandler.kt +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright 2010-2024 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.low.level.api.fir.compiler.based - -import com.intellij.openapi.project.Project -import org.jetbrains.kotlin.analysis.low.level.api.fir.api.services.LLSealedInheritorsProviderFactory -import org.jetbrains.kotlin.analysis.low.level.api.fir.services.LLSealedInheritorsProviderFactoryForTests -import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirSessionCache -import org.jetbrains.kotlin.analysis.project.structure.KtModule -import org.jetbrains.kotlin.analysis.project.structure.ProjectStructureProvider -import org.jetbrains.kotlin.analysis.providers.KotlinDeclarationProviderFactory -import org.jetbrains.kotlin.analysis.providers.impl.KotlinStaticDeclarationProviderFactory -import org.jetbrains.kotlin.analysis.test.framework.project.structure.ktModuleProvider -import org.jetbrains.kotlin.analysis.test.framework.project.structure.mainModules -import org.jetbrains.kotlin.fir.declarations.FirRegularClass -import org.jetbrains.kotlin.fir.declarations.FirResolvePhase -import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider -import org.jetbrains.kotlin.fir.resolve.transformers.FirSealedClassInheritorsProcessor -import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhaseRecursively -import org.jetbrains.kotlin.name.ClassId -import org.jetbrains.kotlin.psi.KtClassOrObject -import org.jetbrains.kotlin.test.directives.model.DirectiveApplicability -import org.jetbrains.kotlin.test.directives.model.SimpleDirectivesContainer -import org.jetbrains.kotlin.test.services.PreAnalysisHandler -import org.jetbrains.kotlin.test.services.TestModuleStructure -import org.jetbrains.kotlin.test.services.TestServices -import org.jetbrains.kotlin.test.services.compilerConfigurationProvider - -class SealedClassesInheritorsCalculatorPreAnalysisHandler( - testServices: TestServices, -) : PreAnalysisHandler(testServices) { - - override fun preprocessModuleStructure(moduleStructure: TestModuleStructure) { - } - - // Manually process all inheritors of sealed classes so that SealedClassInheritorsProviderTestImpl can work correctly for tests. - // In the actual IDE, SealedClassInheritorsProviderIdeImpl works by finding inheritors from the index instead of doing a - // preprocessing of all files. Therefore, the IDE does not rely on such a pre-analysis pass of all files in the module. - override fun prepareSealedClassInheritors(moduleStructure: TestModuleStructure) { - if (Directives.DISABLE_SEALED_INHERITOR_CALCULATOR in moduleStructure.allDirectives) { - return - } - - val project = testServices.compilerConfigurationProvider.getProject(moduleStructure.modules.first()) - - val sealedInheritorsProviderFactory = - project.getService(LLSealedInheritorsProviderFactory::class.java) as? LLSealedInheritorsProviderFactoryForTests - ?: return - - val declarationProviderFactory = KotlinDeclarationProviderFactory.getInstance(project) as KotlinStaticDeclarationProviderFactory - val projectStructureProvider = project.getService(ProjectStructureProvider::class.java) - - val allKtClasses = declarationProviderFactory.getAllKtClasses() - val ktClassesByKtModule = allKtClasses.groupBy { projectStructureProvider.getModule(it, contextualModule = null) } - - for (ktTestModule in testServices.ktModuleProvider.mainModules) { - val ktClasses = ktClassesByKtModule[ktTestModule.ktModule] ?: continue - val sealedInheritors = collectSealedInheritorClassIds(ktTestModule.ktModule, ktClasses, project) - - sealedInheritorsProviderFactory.registerInheritors(ktTestModule.ktModule, sealedInheritors) - } - - // We request and cache sessions while collecting sealed inheritors. To not interfere with the test, we should invalidate all - // sessions. Note that, while we could get uncached sessions from `LLFirSessionCache`, dependency sessions will still be cached, so - // that is not really an alternative to invalidating sessions. - LLFirSessionCache.getInstance(project).removeAllSessions(includeLibraryModules = true) - } - - private fun collectSealedInheritorClassIds( - ktModule: KtModule, - ktClasses: List, - project: Project, - ): Map> { - val sealedInheritorsByFirClass = mutableMapOf>() - - ktClasses.forEach { ktClass -> - val classId = ktClass.getClassId() ?: return@forEach - - // Using a resolve session/source-preferred session will cause class stubs from binary libraries to be decompiled (which - // results in an exception since we don't have a decompiler for them). - val firSession = LLFirSessionCache.getInstance(project).getSession(ktModule, preferBinary = true) - val firClassSymbol = firSession.symbolProvider.getClassLikeSymbolByClassId(classId) ?: return@forEach - firClassSymbol.lazyResolveToPhaseRecursively(FirResolvePhase.TYPES) - - val inheritorsCollector = FirSealedClassInheritorsProcessor.InheritorsCollector(firSession) - firClassSymbol.fir.accept(inheritorsCollector, sealedInheritorsByFirClass) - } - - return buildMap { - sealedInheritorsByFirClass.forEach { firClass, classIds -> - put(firClass.symbol.classId, classIds.distinct()) - } - } - } - - object Directives : SimpleDirectivesContainer() { - val DISABLE_SEALED_INHERITOR_CALCULATOR by directive( - description = "Disable mock sealed class inheritor calculation", - applicability = DirectiveApplicability.Global - ) - } -} diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/services/LLSealedInheritorsProviderFactoryForTests.kt b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/services/LLSealedInheritorsProviderFactoryForTests.kt deleted file mode 100644 index ad793422819..00000000000 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/services/LLSealedInheritorsProviderFactoryForTests.kt +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2010-2022 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.low.level.api.fir.services - -import org.jetbrains.kotlin.analysis.low.level.api.fir.api.services.LLSealedInheritorsProviderFactory -import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.llFirModuleData -import org.jetbrains.kotlin.analysis.project.structure.KtDanglingFileModule -import org.jetbrains.kotlin.analysis.project.structure.KtModule -import org.jetbrains.kotlin.fir.declarations.FirRegularClass -import org.jetbrains.kotlin.fir.declarations.SealedClassInheritorsProvider -import org.jetbrains.kotlin.fir.declarations.SealedClassInheritorsProviderInternals -import org.jetbrains.kotlin.fir.declarations.sealedInheritorsAttr -import org.jetbrains.kotlin.fir.declarations.utils.classId -import org.jetbrains.kotlin.name.ClassId - -internal class LLSealedInheritorsProviderFactoryForTests : LLSealedInheritorsProviderFactory { - private val inheritorsByModule = mutableMapOf>>() - - fun registerInheritors(ktModule: KtModule, inheritors: Map>) { - inheritorsByModule[ktModule] = inheritors - } - - override fun createSealedInheritorsProvider(): SealedClassInheritorsProvider { - return SealedClassInheritorsProviderForTests(inheritorsByModule) - } -} - -private class SealedClassInheritorsProviderForTests( - private val inheritorsByModule: Map>> -) : SealedClassInheritorsProvider() { - @OptIn(SealedClassInheritorsProviderInternals::class) - override fun getSealedClassInheritors(firClass: FirRegularClass): List { - val ktModule = firClass.llFirModuleData.ktModule - val relevantModule = when (ktModule) { - is KtDanglingFileModule -> ktModule.contextModule - else -> ktModule - } - - // If the module is absent in the map, it's either a binary library that wasn't stub-indexed (e.g. in Standalone mode) or the module - // doesn't have any `.kt` files, in which case there cannot be sealed inheritors. `sealedInheritorsAttr` covers the binary library - // case, as class-based deserialization sets this attribute. - return inheritorsByModule[relevantModule]?.get(firClass.classId) ?: firClass.sealedInheritorsAttr?.value ?: emptyList() - } -} diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/test/base/AnalysisApiFirTestServiceRegistrar.kt b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/test/base/AnalysisApiFirTestServiceRegistrar.kt index 5201393c648..16233a20b96 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/test/base/AnalysisApiFirTestServiceRegistrar.kt +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/test/base/AnalysisApiFirTestServiceRegistrar.kt @@ -8,8 +8,6 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.test.base import com.intellij.mock.MockApplication import com.intellij.mock.MockProject import org.jetbrains.kotlin.analysis.api.standalone.base.project.structure.FirStandaloneServiceRegistrar -import org.jetbrains.kotlin.analysis.low.level.api.fir.api.services.LLSealedInheritorsProviderFactory -import org.jetbrains.kotlin.analysis.low.level.api.fir.services.LLSealedInheritorsProviderFactoryForTests import org.jetbrains.kotlin.analysis.low.level.api.fir.services.NoOpKtCompilerPluginsProvider import org.jetbrains.kotlin.analysis.low.level.api.fir.services.PackagePartProviderTestImpl import org.jetbrains.kotlin.analysis.project.structure.KtCompilerPluginsProvider @@ -30,7 +28,6 @@ object AnalysisApiFirTestServiceRegistrar : AnalysisApiTestServiceRegistrar() { FirStandaloneServiceRegistrar.registerProjectServices(project) project.apply { - registerService(LLSealedInheritorsProviderFactory::class.java, LLSealedInheritorsProviderFactoryForTests()) registerService(PackagePartProviderFactory::class.java, PackagePartProviderTestImpl(testServices)) registerService(KtCompilerPluginsProvider::class.java, NoOpKtCompilerPluginsProvider) } diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/test/configurators/AnalysisApiFirLibrarySourceTestConfigurator.kt b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/test/configurators/AnalysisApiFirLibrarySourceTestConfigurator.kt index f50cda6d7d0..2138eeb26c3 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/test/configurators/AnalysisApiFirLibrarySourceTestConfigurator.kt +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/test/configurators/AnalysisApiFirLibrarySourceTestConfigurator.kt @@ -10,7 +10,6 @@ import com.intellij.openapi.project.Project import org.jetbrains.kotlin.analysis.api.impl.base.test.configurators.AnalysisApiBaseTestServiceRegistrar import org.jetbrains.kotlin.analysis.api.impl.base.test.configurators.AnalysisApiDecompiledCodeTestServiceRegistrar import org.jetbrains.kotlin.analysis.api.impl.base.test.configurators.AnalysisApiLibraryBaseTestServiceRegistrar -import org.jetbrains.kotlin.analysis.low.level.api.fir.compiler.based.SealedClassesInheritorsCalculatorPreAnalysisHandler import org.jetbrains.kotlin.analysis.low.level.api.fir.test.base.AnalysisApiFirTestServiceRegistrar import org.jetbrains.kotlin.analysis.test.framework.project.structure.KtLibrarySourceTestModuleFactory import org.jetbrains.kotlin.analysis.test.framework.project.structure.KtTestModuleFactory @@ -40,8 +39,6 @@ object AnalysisApiFirLibrarySourceTestConfigurator : AnalysisApiTestConfigurator useAdditionalService { KtLibrarySourceTestModuleFactory } useAdditionalService { DispatchingTestModuleCompiler() } useAdditionalService { AnalysisApiIndexingConfiguration(AnalysisApiBinaryLibraryIndexingMode.INDEX_STUBS) } - useDirectives(SealedClassesInheritorsCalculatorPreAnalysisHandler.Directives) - usePreAnalysisHandlers(::SealedClassesInheritorsCalculatorPreAnalysisHandler) useConfigurators( ::AnalysisApiJvmEnvironmentConfigurator, ::JsEnvironmentConfigurator, diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/test/configurators/AnalysisApiFirSourceLikeTestConfigurator.kt b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/test/configurators/AnalysisApiFirSourceLikeTestConfigurator.kt index cc37ba8eace..88b925b871b 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/test/configurators/AnalysisApiFirSourceLikeTestConfigurator.kt +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/test/configurators/AnalysisApiFirSourceLikeTestConfigurator.kt @@ -9,7 +9,6 @@ import com.intellij.openapi.Disposable import com.intellij.openapi.project.Project import org.jetbrains.kotlin.analysis.api.impl.base.test.configurators.AnalysisApiBaseTestServiceRegistrar import org.jetbrains.kotlin.analysis.api.impl.base.test.configurators.AnalysisApiDecompiledCodeTestServiceRegistrar -import org.jetbrains.kotlin.analysis.low.level.api.fir.compiler.based.SealedClassesInheritorsCalculatorPreAnalysisHandler import org.jetbrains.kotlin.analysis.low.level.api.fir.test.base.AnalysisApiFirTestServiceRegistrar import org.jetbrains.kotlin.analysis.low.level.api.fir.test.base.configureOptionalTestCompilerPlugin import org.jetbrains.kotlin.analysis.test.framework.project.structure.KtTestModuleProjectStructure @@ -34,8 +33,6 @@ abstract class AnalysisApiFirSourceLikeTestConfigurator(override val analyseInDe override fun configureTest(builder: TestConfigurationBuilder, disposable: Disposable) { builder.apply { useAdditionalService { AnalysisApiIndexingConfiguration(AnalysisApiBinaryLibraryIndexingMode.INDEX_STUBS) } - useDirectives(SealedClassesInheritorsCalculatorPreAnalysisHandler.Directives) - usePreAnalysisHandlers(::SealedClassesInheritorsCalculatorPreAnalysisHandler) configureOptionalTestCompilerPlugin() useConfigurators( ::CommonEnvironmentConfigurator,