From f45af5ea0e0a92f6f81d18528482d7b56c697c94 Mon Sep 17 00:00:00 2001 From: Andrei Klunnyi Date: Fri, 19 Feb 2021 18:42:59 +0100 Subject: [PATCH] KT-44821 [Sealed Interfaces]: when-exhaustiveness failure in IDE Compiler check for 'when' exhaustiveness requires that module descriptors of a sealed class and its inheritors are the same (reference identity matters). Prior to this commit and under some conditions they were not. Details follow below. Resolution related data structures (resolution facades) are organized into trees (sdks, libs, and modules have their own nodes/facades, module/class descriptors are stored inside). And the trees themselves are put into a map associating so called PlatformAnalysisSettings and GlobalFacades (plays a role of a root). PlatformAnalysisSettings is an abstraction describing target platform and sdk of a module. The more combinations exist for a project the more facades are used. Please, see KotlinCacheService for more details. So why a module can have multiple ModuleDescriptor-s? Every tree mentioned above is an isolated resolution environment containing its own instances of the outer world descriptors. Say, if a project has modules X, Y, Z and we consider X then all three might have their own vision of X, i.e. 3 descriptors exist at a time. What descriptor instance does compiler get? The path starts when the user opens a file in the editor and highlighting pass starts (see usages of ResolutionUtils#analyzeWithAllCompilerChecks). Module descriptor stored in the resolution tree of the file's module gets injected into the compiler's context. Starting from this moment compiler sees other modules through the prism of a single resolution facade (tree). Descriptors residing outside are alien. This commit allows IdeSealedClassInheritorsProvider to figure out what PlatformAnalysisSettings are associated with the resolution facade (read ModuleDescriptor) seen by the compiler. Later on the same facade is used to provide correct instances of sealed inheritors back to the compiler. --- .../analyzer/AbstractResolverForProject.kt | 9 ++- .../resolve/ResolutionAnchorProvider.kt | 8 +-- .../caches/resolve/KotlinCacheService.kt | 4 +- .../resolve/PlatformAnalysisSettings.kt | 22 +++++++ .../caches/resolve/IdeaResolverForProject.kt | 25 ++++++-- .../caches/resolve/KotlinCacheServiceImpl.kt | 60 +++++++++---------- .../caches/resolve/ProjectResolutionFacade.kt | 7 +-- .../IdeSealedClassInheritorsProvider.kt | 33 +++++++--- 8 files changed, 105 insertions(+), 63 deletions(-) create mode 100644 idea/ide-common/src/org/jetbrains/kotlin/caches/resolve/PlatformAnalysisSettings.kt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/analyzer/AbstractResolverForProject.kt b/compiler/frontend/src/org/jetbrains/kotlin/analyzer/AbstractResolverForProject.kt index 1e07157dc1f..9067ec4f15e 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/analyzer/AbstractResolverForProject.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/analyzer/AbstractResolverForProject.kt @@ -12,8 +12,6 @@ import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.resolve.RESOLUTION_ANCHOR_PROVIDER_CAPABILITY -import org.jetbrains.kotlin.resolve.ResolutionAnchorProvider import org.jetbrains.kotlin.utils.checkWithAttachment abstract class AbstractResolverForProject( @@ -22,8 +20,7 @@ abstract class AbstractResolverForProject( modules: Collection, protected val fallbackModificationTracker: ModificationTracker? = null, private val delegateResolver: ResolverForProject = EmptyResolverForProject(), - private val packageOracleFactory: PackageOracleFactory = PackageOracleFactory.OptimisticFactory, - protected val resolutionAnchorProvider: ResolutionAnchorProvider = ResolutionAnchorProvider.Default, + private val packageOracleFactory: PackageOracleFactory = PackageOracleFactory.OptimisticFactory ) : ResolverForProject() { protected class ModuleData( @@ -196,13 +193,15 @@ abstract class AbstractResolverForProject( return moduleData } + protected open fun getAdditionalCapabilities(): Map, Any?> = emptyMap() + private fun createModuleDescriptor(module: M): ModuleData { val moduleDescriptor = ModuleDescriptorImpl( module.name, projectContext.storageManager, builtInsForModule(module), module.platform, - module.capabilities + listOf(RESOLUTION_ANCHOR_PROVIDER_CAPABILITY to resolutionAnchorProvider), + module.capabilities + getAdditionalCapabilities(), module.stableName, ) moduleInfoByDescriptor[moduleDescriptor] = module diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/ResolutionAnchorProvider.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/ResolutionAnchorProvider.kt index 0d628410af8..45ec3c898c5 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/ResolutionAnchorProvider.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/ResolutionAnchorProvider.kt @@ -9,13 +9,7 @@ import org.jetbrains.kotlin.descriptors.ModuleCapability import org.jetbrains.kotlin.descriptors.ModuleDescriptor interface ResolutionAnchorProvider { - fun getResolutionAnchor(moduleDescriptor: ModuleDescriptor): ModuleDescriptor? = null - - companion object { - val Default: ResolutionAnchorProvider = object : ResolutionAnchorProvider { - override fun getResolutionAnchor(moduleDescriptor: ModuleDescriptor): ModuleDescriptor? = null - } - } + fun getResolutionAnchor(moduleDescriptor: ModuleDescriptor): ModuleDescriptor? } val RESOLUTION_ANCHOR_PROVIDER_CAPABILITY = ModuleCapability("ResolutionAnchorProvider") diff --git a/idea/ide-common/src/org/jetbrains/kotlin/caches/resolve/KotlinCacheService.kt b/idea/ide-common/src/org/jetbrains/kotlin/caches/resolve/KotlinCacheService.kt index 2e34d91ed1b..09d791d4efe 100644 --- a/idea/ide-common/src/org/jetbrains/kotlin/caches/resolve/KotlinCacheService.kt +++ b/idea/ide-common/src/org/jetbrains/kotlin/caches/resolve/KotlinCacheService.kt @@ -21,8 +21,8 @@ import com.intellij.openapi.project.Project import com.intellij.psi.PsiFile import org.jetbrains.kotlin.analyzer.ModuleInfo import org.jetbrains.kotlin.idea.resolve.ResolutionFacade -import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.platform.TargetPlatform +import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.resolve.diagnostics.KotlinSuppressCache interface KotlinCacheService { @@ -36,4 +36,6 @@ interface KotlinCacheService { fun getSuppressionCache(): KotlinSuppressCache fun getResolutionFacadeByModuleInfo(moduleInfo: ModuleInfo, platform: TargetPlatform): ResolutionFacade? + + fun getResolutionFacadeByModuleInfo(moduleInfo: ModuleInfo, settings: PlatformAnalysisSettings): ResolutionFacade? } \ No newline at end of file diff --git a/idea/ide-common/src/org/jetbrains/kotlin/caches/resolve/PlatformAnalysisSettings.kt b/idea/ide-common/src/org/jetbrains/kotlin/caches/resolve/PlatformAnalysisSettings.kt new file mode 100644 index 00000000000..e4a1dc19707 --- /dev/null +++ b/idea/ide-common/src/org/jetbrains/kotlin/caches/resolve/PlatformAnalysisSettings.kt @@ -0,0 +1,22 @@ +/* + * 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.caches.resolve + +/** + * Regulates which sources should be analyzed together. + * + * There are exactly two descendants, which are in strong one-to-one correspondence with [ResolutionModeComponent.Mode] (meaning + * that after checking value of ResolutionMode, it's safe to downcast settings instance to the respective type): + * - [PlatformAnalysisSettingsImpl] should be used iff we're working under [Mode.SEPARATE], and will create separate + * facade for each platforms, sdk, builtIns settings and other stuff. + * This is the old and stable mode, which should be used by default. + * + * - [CompositeAnalysisSettings] should be used iff we're working under [Mode.COMPOSITE], and will analyze all sources + * together, in one facade. + * This mode is new and experimental, and works only together with TypeRefinement facilities in the compiler's frontend. + * This mode is currently enabled only for HMPP projects + */ +interface PlatformAnalysisSettings \ No newline at end of file diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IdeaResolverForProject.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IdeaResolverForProject.kt index a9e07b5b3d4..265c9f7a28b 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IdeaResolverForProject.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IdeaResolverForProject.kt @@ -6,7 +6,6 @@ package org.jetbrains.kotlin.idea.caches.resolve import com.intellij.openapi.components.ServiceManager -import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.util.ModificationTracker import org.jetbrains.kotlin.analyzer.* import org.jetbrains.kotlin.analyzer.common.CommonAnalysisParameters @@ -14,6 +13,7 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.caches.resolve.* import org.jetbrains.kotlin.context.ProjectContext import org.jetbrains.kotlin.context.withModule +import org.jetbrains.kotlin.descriptors.ModuleCapability import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl import org.jetbrains.kotlin.idea.caches.project.* @@ -32,6 +32,7 @@ import org.jetbrains.kotlin.platform.isCommon import org.jetbrains.kotlin.platform.jvm.JvmPlatforms import org.jetbrains.kotlin.platform.jvm.isJvm import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.resolve.RESOLUTION_ANCHOR_PROVIDER_CAPABILITY import org.jetbrains.kotlin.resolve.ResolutionAnchorProvider import org.jetbrains.kotlin.resolve.jvm.JvmPlatformParameters @@ -42,20 +43,34 @@ class IdeaResolverForProject( private val syntheticFilesByModule: Map>, delegateResolver: ResolverForProject, fallbackModificationTracker: ModificationTracker? = null, - // TODO(dsavvinov): this is needed only for non-composite analysis, extract separate resolver implementation instead - private val constantSdkDependencyIfAny: SdkInfo? = null + private val settings: PlatformAnalysisSettings ) : AbstractResolverForProject( debugName, projectContext, modules, fallbackModificationTracker, delegateResolver, - ServiceManager.getService(projectContext.project, IdePackageOracleFactory::class.java), - ServiceManager.getService(projectContext.project, ResolutionAnchorProvider::class.java) + ServiceManager.getService(projectContext.project, IdePackageOracleFactory::class.java) ) { + + companion object { + val PLATFORM_ANALYSIS_SETTINGS = ModuleCapability("PlatformAnalysisSettings") + } + + private val resolutionAnchorProvider = ServiceManager.getService(projectContext.project, ResolutionAnchorProvider::class.java) + + private val constantSdkDependencyIfAny: SdkInfo? = + if (settings is PlatformAnalysisSettingsImpl) settings.sdk?.let { SdkInfo(projectContext.project, it) } else null + private val builtInsCache: BuiltInsCache = (delegateResolver as? IdeaResolverForProject)?.builtInsCache ?: BuiltInsCache(projectContext, this) + override fun getAdditionalCapabilities(): Map, Any?> { + return super.getAdditionalCapabilities() + + (PLATFORM_ANALYSIS_SETTINGS to settings) + + (RESOLUTION_ANCHOR_PROVIDER_CAPABILITY to resolutionAnchorProvider) + } + override fun sdkDependency(module: IdeaModuleInfo): SdkInfo? { if (projectContext.project.useCompositeAnalysis) { require(constantSdkDependencyIfAny == null) { "Shouldn't pass SDK dependency manually for composite analysis mode" } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/KotlinCacheServiceImpl.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/KotlinCacheServiceImpl.kt index ca4cf51cfab..5c9576558f1 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/KotlinCacheServiceImpl.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/KotlinCacheServiceImpl.kt @@ -37,6 +37,7 @@ import org.jetbrains.kotlin.analyzer.ResolverForProject.Companion.resolverForSdk import org.jetbrains.kotlin.analyzer.ResolverForProject.Companion.resolverForSpecialInfoName import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.caches.resolve.KotlinCacheService +import org.jetbrains.kotlin.caches.resolve.PlatformAnalysisSettings import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.context.GlobalContext import org.jetbrains.kotlin.context.GlobalContextImpl @@ -66,41 +67,24 @@ import org.jetbrains.kotlin.utils.addToStdlib.sumByLong internal val LOG = Logger.getInstance(KotlinCacheService::class.java) -/** - * Regulates which sources should be analyzed together. - * - * There are exactly two descendants, which are in strong one-to-one correspondence with [ResolutionModeComponent.Mode] (meaning - * that after checking value of ResolutionMode, it's safe to downcast settings instance to the respective type): - * - [PlatformAnalysisSettingsImpl] should be used iff we're working under [Mode.SEPARATE], and will create separate - * facade for each platforms, sdk, builtIns settings and other stuff. - * This is the old and stable mode, which should be used by default. - * - * - [CompositeAnalysisSettings] should be used iff we're working under [Mode.COMPOSITE], and will analyze all sources - * together, in one facade. - * This mode is new and experimental, and works only together with TypeRefinement facilities in the compiler's frontend. - * This mode is currently enabled only for HMPP projects - */ -sealed class PlatformAnalysisSettings { - companion object { - fun create( - project: Project, - platform: TargetPlatform, - sdk: Sdk?, - isAdditionalBuiltInFeaturesSupported: Boolean - ) = if (project.useCompositeAnalysis) - CompositeAnalysisSettings - else - PlatformAnalysisSettingsImpl(platform, sdk, isAdditionalBuiltInFeaturesSupported) - } -} - data class PlatformAnalysisSettingsImpl( val platform: TargetPlatform, val sdk: Sdk?, val isAdditionalBuiltInFeaturesSupported: Boolean, -) : PlatformAnalysisSettings() +) : PlatformAnalysisSettings + +object CompositeAnalysisSettings : PlatformAnalysisSettings + +fun createPlatformAnalysisSettings( + project: Project, + platform: TargetPlatform, + sdk: Sdk?, + isAdditionalBuiltInFeaturesSupported: Boolean +) = if (project.useCompositeAnalysis) + CompositeAnalysisSettings +else + PlatformAnalysisSettingsImpl(platform, sdk, isAdditionalBuiltInFeaturesSupported) -object CompositeAnalysisSettings : PlatformAnalysisSettings() class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService { override fun getResolutionFacade(elements: List): ResolutionFacade { @@ -144,7 +128,7 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService { ): ProjectResolutionFacade { val sdk = dependenciesModuleInfo.sdk val platform = JvmPlatforms.defaultJvmPlatform // TODO: Js scripts? - val settings = PlatformAnalysisSettings.create(project, platform, sdk, true) + val settings = createPlatformAnalysisSettings(project, platform, sdk, true) val dependenciesForScriptDependencies = listOf( LibraryModificationTracker.getInstance(project), @@ -217,7 +201,7 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService { ) } - private fun IdeaModuleInfo.platformSettings(targetPlatform: TargetPlatform) = PlatformAnalysisSettings.create( + private fun IdeaModuleInfo.platformSettings(targetPlatform: TargetPlatform) = createPlatformAnalysisSettings( this@KotlinCacheServiceImpl.project, targetPlatform, sdk, supportsAdditionalBuiltInsMembers(this@KotlinCacheServiceImpl.project) ) @@ -469,6 +453,13 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService { private fun getResolutionFacadeByModuleInfo(moduleInfo: IdeaModuleInfo, platform: TargetPlatform): ResolutionFacade { val settings = moduleInfo.platformSettings(platform) + return getResolutionFacadeByModuleInfoAndSettings(moduleInfo, settings) + } + + private fun getResolutionFacadeByModuleInfoAndSettings( + moduleInfo: IdeaModuleInfo, + settings: PlatformAnalysisSettings + ): ResolutionFacade { val projectFacade = when (moduleInfo) { is ScriptDependenciesInfo.ForProject, is ScriptDependenciesSourceInfo.ForProject -> facadeForScriptDependenciesForProject @@ -481,6 +472,11 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService { override fun getResolutionFacadeByModuleInfo(moduleInfo: ModuleInfo, platform: TargetPlatform): ResolutionFacade? = (moduleInfo as? IdeaModuleInfo)?.let { getResolutionFacadeByModuleInfo(it, platform) } + override fun getResolutionFacadeByModuleInfo(moduleInfo: ModuleInfo, settings: PlatformAnalysisSettings): ResolutionFacade? { + val ideaModuleInfo = moduleInfo as? IdeaModuleInfo ?: return null + return getResolutionFacadeByModuleInfoAndSettings(ideaModuleInfo, settings) + } + private fun Collection.filterNotInProjectSource(moduleInfo: IdeaModuleInfo): Set { return mapNotNull { if (it is KtCodeFragment) it.getContextFile() else it diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/ProjectResolutionFacade.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/ProjectResolutionFacade.kt index 416bd50016b..50750a43a97 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/ProjectResolutionFacade.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/ProjectResolutionFacade.kt @@ -14,6 +14,7 @@ import com.intellij.psi.util.CachedValueProvider import com.intellij.psi.util.CachedValuesManager import com.intellij.util.containers.SLRUCache import org.jetbrains.kotlin.analyzer.* +import org.jetbrains.kotlin.caches.resolve.PlatformAnalysisSettings import org.jetbrains.kotlin.context.GlobalContextImpl import org.jetbrains.kotlin.context.withProject import org.jetbrains.kotlin.descriptors.ModuleDescriptor @@ -116,17 +117,15 @@ internal class ProjectResolutionFacade( val modulesToCreateResolversFor = allModuleInfos.filter(moduleFilter) - val resolverForProject = IdeaResolverForProject( + return IdeaResolverForProject( resolverDebugName, globalContext.withProject(project), modulesToCreateResolversFor, syntheticFilesByModule, delegateResolverForProject, if (invalidateOnOOCB) KotlinModificationTrackerService.getInstance(project).outOfBlockModificationTracker else null, - constantSdkDependencyIfAny = if (settings is PlatformAnalysisSettingsImpl) settings.sdk?.let { SdkInfo(project, it) } else null + settings ) - - return resolverForProject } internal fun resolverForModuleInfo(moduleInfo: IdeaModuleInfo) = cachedResolverForProject.resolverForModule(moduleInfo) diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/compiler/IdeSealedClassInheritorsProvider.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/compiler/IdeSealedClassInheritorsProvider.kt index 493726659fd..9760f4f9240 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/compiler/IdeSealedClassInheritorsProvider.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/compiler/IdeSealedClassInheritorsProvider.kt @@ -6,20 +6,27 @@ package org.jetbrains.kotlin.idea.compiler import com.intellij.openapi.module.Module -import com.intellij.psi.* -import com.intellij.psi.search.* +import com.intellij.openapi.project.Project +import com.intellij.psi.JavaDirectoryService +import com.intellij.psi.PsiPackage +import com.intellij.psi.search.GlobalSearchScope +import com.intellij.psi.search.PackageScope +import com.intellij.psi.search.SearchScope import com.intellij.psi.search.searches.ClassInheritorsSearch import com.intellij.psi.search.searches.ClassInheritorsSearch.SearchParameters +import org.jetbrains.kotlin.analyzer.ModuleInfo import org.jetbrains.kotlin.analyzer.moduleInfo import org.jetbrains.kotlin.asJava.KotlinAsJavaSupport import org.jetbrains.kotlin.asJava.toLightClass +import org.jetbrains.kotlin.caches.resolve.KotlinCacheService import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.descriptors.containingPackage import org.jetbrains.kotlin.idea.caches.project.ModuleSourceInfo import org.jetbrains.kotlin.idea.caches.project.implementedDescriptors -import org.jetbrains.kotlin.idea.caches.resolve.util.javaResolutionFacade +import org.jetbrains.kotlin.idea.caches.resolve.IdeaResolverForProject.Companion.PLATFORM_ANALYSIS_SETTINGS import org.jetbrains.kotlin.idea.caches.resolve.util.resolveToDescriptor +import org.jetbrains.kotlin.idea.resolve.ResolutionFacade import org.jetbrains.kotlin.idea.util.module import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi import org.jetbrains.kotlin.psi.KtClass @@ -36,6 +43,9 @@ object IdeSealedClassInheritorsProvider : SealedClassInheritorsProvider() { ): Collection { val sealedKtClass = sealedClass.findPsi() as? KtClass ?: return emptyList() + val project = sealedKtClass.project + val moduleDescriptor = sealedClass.module + val searchScope: SearchScope = if (allowSealedInheritorsInDifferentFilesOfSamePackage) { val module = sealedKtClass.module ?: return emptyList() @@ -46,7 +56,7 @@ object IdeSealedClassInheritorsProvider : SealedClassInheritorsProvider() { val mppAwareSearchScope = GlobalSearchScope.union(modulesScope) val containingPackage = sealedClass.containingPackage() ?: return emptyList() - val psiPackage = KotlinJavaPsiFacade.getInstance(sealedKtClass.project) + val psiPackage = KotlinJavaPsiFacade.getInstance(project) .findPackage(containingPackage.asString(), GlobalSearchScope.moduleScope(module)) ?: getPackageViaDirectoryService(sealedKtClass) ?: return emptyList() @@ -57,15 +67,14 @@ object IdeSealedClassInheritorsProvider : SealedClassInheritorsProvider() { GlobalSearchScope.fileScope(sealedKtClass.containingFile) // Kotlin version prior to 1.5 } - val kotlinAsJavaSupport = KotlinAsJavaSupport.getInstance(sealedKtClass.project) + val kotlinAsJavaSupport = KotlinAsJavaSupport.getInstance(project) val lightClass = sealedKtClass.toLightClass() ?: kotlinAsJavaSupport.getFakeLightClass(sealedKtClass) val searchParameters = SearchParameters(lightClass, searchScope, false, true, false) + val resolutionFacade = getResolutionFacade(moduleDescriptor, project) ?: return emptyList() + return ClassInheritorsSearch.search(searchParameters) - .map mapper@{ - val resolutionFacade = it.javaResolutionFacade() ?: return@mapper null - it.resolveToDescriptor(resolutionFacade) - }.filterNotNull() + .mapNotNull { it.resolveToDescriptor(resolutionFacade) } .sortedBy(ClassDescriptor::getName) // order needs to be stable (at least for tests) } @@ -78,4 +87,10 @@ object IdeSealedClassInheritorsProvider : SealedClassInheritorsProvider() { val directory = ktClass.containingFile.containingDirectory ?: return null return JavaDirectoryService.getInstance().getPackage(directory) } +} + +private fun getResolutionFacade(moduleDescriptor: ModuleDescriptor, project: Project): ResolutionFacade? { + val analysisSettings = moduleDescriptor.getCapability(PLATFORM_ANALYSIS_SETTINGS) ?: return null + val moduleInfo = moduleDescriptor.getCapability(ModuleInfo.Capability) ?: return null + return KotlinCacheService.getInstance(project).getResolutionFacadeByModuleInfo(moduleInfo, analysisSettings) } \ No newline at end of file