KT-44487 [Sealed Interfaces]: sealed-inheritors-provider for MPP
This commit is contained in:
@@ -134,9 +134,10 @@ fun createContainerForBodyResolve(
|
|||||||
statementFilter: StatementFilter,
|
statementFilter: StatementFilter,
|
||||||
analyzerServices: PlatformDependentAnalyzerServices,
|
analyzerServices: PlatformDependentAnalyzerServices,
|
||||||
languageVersionSettings: LanguageVersionSettings,
|
languageVersionSettings: LanguageVersionSettings,
|
||||||
moduleStructureOracle: ModuleStructureOracle
|
moduleStructureOracle: ModuleStructureOracle,
|
||||||
|
sealedProvider: SealedClassInheritorsProvider = CliSealedClassInheritorsProvider
|
||||||
): StorageComponentContainer = createContainer("BodyResolve", analyzerServices) {
|
): StorageComponentContainer = createContainer("BodyResolve", analyzerServices) {
|
||||||
configureModule(moduleContext, platform, analyzerServices, bindingTrace, languageVersionSettings)
|
configureModule(moduleContext, platform, analyzerServices, bindingTrace, languageVersionSettings, sealedProvider)
|
||||||
|
|
||||||
useInstance(statementFilter)
|
useInstance(statementFilter)
|
||||||
|
|
||||||
@@ -156,10 +157,10 @@ fun createContainerForLazyBodyResolve(
|
|||||||
analyzerServices: PlatformDependentAnalyzerServices,
|
analyzerServices: PlatformDependentAnalyzerServices,
|
||||||
languageVersionSettings: LanguageVersionSettings,
|
languageVersionSettings: LanguageVersionSettings,
|
||||||
moduleStructureOracle: ModuleStructureOracle,
|
moduleStructureOracle: ModuleStructureOracle,
|
||||||
mainFunctionDetectorFactory: MainFunctionDetector.Factory
|
mainFunctionDetectorFactory: MainFunctionDetector.Factory,
|
||||||
|
sealedProvider: SealedClassInheritorsProvider = CliSealedClassInheritorsProvider
|
||||||
): StorageComponentContainer = createContainer("LazyBodyResolve", analyzerServices) {
|
): StorageComponentContainer = createContainer("LazyBodyResolve", analyzerServices) {
|
||||||
configureModule(moduleContext, platform, analyzerServices, bindingTrace, languageVersionSettings)
|
configureModule(moduleContext, platform, analyzerServices, bindingTrace, languageVersionSettings, sealedProvider)
|
||||||
|
|
||||||
useInstance(mainFunctionDetectorFactory)
|
useInstance(mainFunctionDetectorFactory)
|
||||||
useInstance(kotlinCodeAnalyzer)
|
useInstance(kotlinCodeAnalyzer)
|
||||||
useInstance(kotlinCodeAnalyzer.fileScopeProvider)
|
useInstance(kotlinCodeAnalyzer.fileScopeProvider)
|
||||||
|
|||||||
+2
-1
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.frontend.di.configureModule
|
|||||||
import org.jetbrains.kotlin.frontend.di.configureStandardResolveComponents
|
import org.jetbrains.kotlin.frontend.di.configureStandardResolveComponents
|
||||||
import org.jetbrains.kotlin.frontend.java.di.configureJavaSpecificComponents
|
import org.jetbrains.kotlin.frontend.java.di.configureJavaSpecificComponents
|
||||||
import org.jetbrains.kotlin.frontend.java.di.initializeJavaSpecificComponents
|
import org.jetbrains.kotlin.frontend.java.di.initializeJavaSpecificComponents
|
||||||
|
import org.jetbrains.kotlin.idea.compiler.IdeSealedClassInheritorsProvider
|
||||||
import org.jetbrains.kotlin.idea.configuration.IdeBuiltInsLoadingState
|
import org.jetbrains.kotlin.idea.configuration.IdeBuiltInsLoadingState
|
||||||
import org.jetbrains.kotlin.idea.project.IdeaEnvironment
|
import org.jetbrains.kotlin.idea.project.IdeaEnvironment
|
||||||
import org.jetbrains.kotlin.load.java.lazy.ModuleClassResolver
|
import org.jetbrains.kotlin.load.java.lazy.ModuleClassResolver
|
||||||
@@ -189,7 +190,7 @@ class CompositeResolverForModuleFactory(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Called by all normal containers set-ups
|
// Called by all normal containers set-ups
|
||||||
configureModule(moduleContext, targetPlatform, analyzerServices, trace, languageVersionSettings,)
|
configureModule(moduleContext, targetPlatform, analyzerServices, trace, languageVersionSettings, IdeSealedClassInheritorsProvider)
|
||||||
configureStandardResolveComponents()
|
configureStandardResolveComponents()
|
||||||
useInstance(moduleContentScope)
|
useInstance(moduleContentScope)
|
||||||
useInstance(declarationProviderFactory)
|
useInstance(declarationProviderFactory)
|
||||||
|
|||||||
+4
-2
@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.idea.caches.project.getModuleInfo
|
|||||||
import org.jetbrains.kotlin.idea.caches.trackers.clearInBlockModifications
|
import org.jetbrains.kotlin.idea.caches.trackers.clearInBlockModifications
|
||||||
import org.jetbrains.kotlin.idea.caches.trackers.inBlockModifications
|
import org.jetbrains.kotlin.idea.caches.trackers.inBlockModifications
|
||||||
import org.jetbrains.kotlin.idea.compiler.IdeMainFunctionDetectorFactory
|
import org.jetbrains.kotlin.idea.compiler.IdeMainFunctionDetectorFactory
|
||||||
|
import org.jetbrains.kotlin.idea.compiler.IdeSealedClassInheritorsProvider
|
||||||
import org.jetbrains.kotlin.idea.project.IdeaModuleStructureOracle
|
import org.jetbrains.kotlin.idea.project.IdeaModuleStructureOracle
|
||||||
import org.jetbrains.kotlin.idea.project.findAnalyzerServices
|
import org.jetbrains.kotlin.idea.project.findAnalyzerServices
|
||||||
import org.jetbrains.kotlin.idea.project.languageVersionSettings
|
import org.jetbrains.kotlin.idea.project.languageVersionSettings
|
||||||
@@ -482,8 +483,9 @@ private object KotlinResolveDataProvider {
|
|||||||
targetPlatform.findAnalyzerServices(project),
|
targetPlatform.findAnalyzerServices(project),
|
||||||
analyzableElement.languageVersionSettings,
|
analyzableElement.languageVersionSettings,
|
||||||
IdeaModuleStructureOracle(),
|
IdeaModuleStructureOracle(),
|
||||||
IdeMainFunctionDetectorFactory()
|
IdeMainFunctionDetectorFactory(),
|
||||||
).get<LazyTopDownAnalyzer>()
|
IdeSealedClassInheritorsProvider
|
||||||
|
).get<LazyTopDownAnalyzer>()
|
||||||
|
|
||||||
lazyTopDownAnalyzer.analyzeDeclarations(TopDownAnalysisMode.TopLevelDeclarations, listOf(analyzableElement))
|
lazyTopDownAnalyzer.analyzeDeclarations(TopDownAnalysisMode.TopLevelDeclarations, listOf(analyzableElement))
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
+27
-5
@@ -5,19 +5,27 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.idea.compiler
|
package org.jetbrains.kotlin.idea.compiler
|
||||||
|
|
||||||
|
import com.intellij.openapi.module.ModuleManager
|
||||||
import com.intellij.psi.*
|
import com.intellij.psi.*
|
||||||
import com.intellij.psi.search.*
|
import com.intellij.psi.search.*
|
||||||
import com.intellij.psi.search.searches.ClassInheritorsSearch
|
import com.intellij.psi.search.searches.ClassInheritorsSearch
|
||||||
import com.intellij.psi.search.searches.ClassInheritorsSearch.SearchParameters
|
import com.intellij.psi.search.searches.ClassInheritorsSearch.SearchParameters
|
||||||
|
import org.jetbrains.kotlin.asJava.KotlinAsJavaSupport
|
||||||
import org.jetbrains.kotlin.asJava.toLightClass
|
import org.jetbrains.kotlin.asJava.toLightClass
|
||||||
|
import org.jetbrains.kotlin.codegen.JvmCodegenUtil
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.containingPackage
|
import org.jetbrains.kotlin.descriptors.containingPackage
|
||||||
|
import org.jetbrains.kotlin.idea.caches.project.implementedDescriptors
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.util.javaResolutionFacade
|
import org.jetbrains.kotlin.idea.caches.resolve.util.javaResolutionFacade
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.util.resolveToDescriptor
|
import org.jetbrains.kotlin.idea.caches.resolve.util.resolveToDescriptor
|
||||||
import org.jetbrains.kotlin.idea.util.module
|
import org.jetbrains.kotlin.idea.util.module
|
||||||
import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi
|
import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi
|
||||||
import org.jetbrains.kotlin.psi.KtClass
|
import org.jetbrains.kotlin.psi.KtClass
|
||||||
import org.jetbrains.kotlin.resolve.SealedClassInheritorsProvider
|
import org.jetbrains.kotlin.resolve.SealedClassInheritorsProvider
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||||
|
import org.jetbrains.kotlin.resolve.jvm.KotlinJavaPsiFacade
|
||||||
|
import org.jetbrains.kotlin.types.typeUtil.closure
|
||||||
|
|
||||||
object IdeSealedClassInheritorsProvider : SealedClassInheritorsProvider() {
|
object IdeSealedClassInheritorsProvider : SealedClassInheritorsProvider() {
|
||||||
|
|
||||||
@@ -29,18 +37,28 @@ object IdeSealedClassInheritorsProvider : SealedClassInheritorsProvider() {
|
|||||||
val sealedKtClass = sealedClass.findPsi() as? KtClass ?: return emptyList()
|
val sealedKtClass = sealedClass.findPsi() as? KtClass ?: return emptyList()
|
||||||
val searchScope: SearchScope = if (allowSealedInheritorsInDifferentFilesOfSamePackage) {
|
val searchScope: SearchScope = if (allowSealedInheritorsInDifferentFilesOfSamePackage) {
|
||||||
val module = sealedKtClass.module ?: return emptyList()
|
val module = sealedKtClass.module ?: return emptyList()
|
||||||
val moduleSourceScope = GlobalSearchScope.moduleScope(module)
|
val moduleManager = ModuleManager.getInstance(sealedKtClass.project)
|
||||||
|
|
||||||
|
val modulesScope = sealedClass.module.listCommonModulesIfAny().toMutableList()
|
||||||
|
.apply { add(sealedClass.module) }
|
||||||
|
.mapNotNull { moduleManager.findModuleByName(JvmCodegenUtil.getModuleName(it))?.moduleScope }
|
||||||
|
|
||||||
|
val mppAwareSearchScope = GlobalSearchScope.union(modulesScope)
|
||||||
|
|
||||||
val containingPackage = sealedClass.containingPackage() ?: return emptyList()
|
val containingPackage = sealedClass.containingPackage() ?: return emptyList()
|
||||||
val psiPackage = getPackageViaDirectoryService(sealedKtClass)
|
val psiPackage = KotlinJavaPsiFacade.getInstance(sealedKtClass.project)
|
||||||
?: JavaPsiFacade.getInstance(sealedKtClass.project).findPackage(containingPackage.asString())
|
.findPackage(containingPackage.asString(), GlobalSearchScope.moduleScope(module))
|
||||||
|
?: getPackageViaDirectoryService(sealedKtClass)
|
||||||
?: return emptyList()
|
?: return emptyList()
|
||||||
val packageScope = PackageScope(psiPackage, false, false)
|
val packageScope = PackageScope(psiPackage, false, false)
|
||||||
moduleSourceScope.intersectWith(packageScope)
|
|
||||||
|
mppAwareSearchScope.intersectWith(packageScope)
|
||||||
} else {
|
} else {
|
||||||
GlobalSearchScope.fileScope(sealedKtClass.containingFile) // Kotlin version prior to 1.5
|
GlobalSearchScope.fileScope(sealedKtClass.containingFile) // Kotlin version prior to 1.5
|
||||||
}
|
}
|
||||||
|
|
||||||
val lightClass = sealedKtClass.toLightClass() ?: return emptyList()
|
val kotlinAsJavaSupport = KotlinAsJavaSupport.getInstance(sealedKtClass.project)
|
||||||
|
val lightClass = sealedKtClass.toLightClass() ?: kotlinAsJavaSupport.getFakeLightClass(sealedKtClass)
|
||||||
val searchParameters = SearchParameters(lightClass, searchScope, false, true, false)
|
val searchParameters = SearchParameters(lightClass, searchScope, false, true, false)
|
||||||
|
|
||||||
return ClassInheritorsSearch.search(searchParameters)
|
return ClassInheritorsSearch.search(searchParameters)
|
||||||
@@ -51,6 +69,10 @@ object IdeSealedClassInheritorsProvider : SealedClassInheritorsProvider() {
|
|||||||
.sortedBy(ClassDescriptor::getName) // order needs to be stable (at least for tests)
|
.sortedBy(ClassDescriptor::getName) // order needs to be stable (at least for tests)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun ModuleDescriptor.listCommonModulesIfAny(): Collection<ModuleDescriptor> {
|
||||||
|
return implementedDescriptors.closure { it.implementedDescriptors }
|
||||||
|
}
|
||||||
|
|
||||||
private fun getPackageViaDirectoryService(ktClass: KtClass): PsiPackage? {
|
private fun getPackageViaDirectoryService(ktClass: KtClass): PsiPackage? {
|
||||||
val directory = ktClass.containingFile.containingDirectory ?: return null
|
val directory = ktClass.containingFile.containingDirectory ?: return null
|
||||||
return JavaDirectoryService.getInstance().getPackage(directory)
|
return JavaDirectoryService.getInstance().getPackage(directory)
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ import org.jetbrains.kotlin.idea.caches.resolve.util.analyzeControlFlow
|
|||||||
import org.jetbrains.kotlin.idea.caches.trackers.KotlinCodeBlockModificationListener
|
import org.jetbrains.kotlin.idea.caches.trackers.KotlinCodeBlockModificationListener
|
||||||
import org.jetbrains.kotlin.idea.caches.trackers.KotlinCodeBlockModificationListenerCompat
|
import org.jetbrains.kotlin.idea.caches.trackers.KotlinCodeBlockModificationListenerCompat
|
||||||
import org.jetbrains.kotlin.idea.caches.trackers.inBlockModificationCount
|
import org.jetbrains.kotlin.idea.caches.trackers.inBlockModificationCount
|
||||||
import org.jetbrains.kotlin.idea.compiler.IdeMainFunctionDetectorFactory
|
import org.jetbrains.kotlin.idea.compiler.IdeSealedClassInheritorsProvider
|
||||||
import org.jetbrains.kotlin.idea.util.application.isUnitTestMode
|
import org.jetbrains.kotlin.idea.util.application.isUnitTestMode
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.platform.TargetPlatform
|
import org.jetbrains.kotlin.platform.TargetPlatform
|
||||||
@@ -785,7 +785,8 @@ class ResolveElementCache(
|
|||||||
statementFilter,
|
statementFilter,
|
||||||
targetPlatform.findAnalyzerServices(file.project),
|
targetPlatform.findAnalyzerServices(file.project),
|
||||||
file.languageVersionSettings,
|
file.languageVersionSettings,
|
||||||
IdeaModuleStructureOracle()
|
IdeaModuleStructureOracle(),
|
||||||
|
IdeSealedClassInheritorsProvider
|
||||||
).get()
|
).get()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
expect sealed class <!LINE_MARKER("descr='Is subclassed by CommonAImplTestClass CommonImplTestClass PlatformAXImplTestClass PlatformAYImplTestClass'")!>TestClass<!>()
|
||||||
|
class CommonImplTestClass: TestClass()
|
||||||
|
|
||||||
|
|
||||||
|
fun checkCommon(t: TestClass): Int = when (t) {
|
||||||
|
is CommonImplTestClass -> 0
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
class CommonAImplTestClass: <!SEALED_INHERITOR_IN_DIFFERENT_MODULE!>TestClass<!>()
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
MODULE common { platform=[JVM, JS, Native]; additionalCompilerArgs=: -XXLanguage:+SealedInterfaces -XXLanguage:+AllowSealedInheritorsInDifferentFilesOfSamePackage }
|
||||||
|
MODULE commonA { platform=[JVM]; additionalCompilerArgs=: -XXLanguage:+SealedInterfaces -XXLanguage:+AllowSealedInheritorsInDifferentFilesOfSamePackage }
|
||||||
|
MODULE platformAX { platform=[JVM]; additionalCompilerArgs=: -XXLanguage:+SealedInterfaces -XXLanguage:+AllowSealedInheritorsInDifferentFilesOfSamePackage }
|
||||||
|
MODULE platformAY { platform=[JVM]; additionalCompilerArgs=: -XXLanguage:+SealedInterfaces -XXLanguage:+AllowSealedInheritorsInDifferentFilesOfSamePackage }
|
||||||
|
|
||||||
|
commonA -> common { kind=DEPENDS_ON }
|
||||||
|
platformAX -> commonA { kind=DEPENDS_ON }
|
||||||
|
platformAY -> commonA { kind=DEPENDS_ON }
|
||||||
+8
@@ -0,0 +1,8 @@
|
|||||||
|
actual sealed class <!LINE_MARKER("descr='Is subclassed by PlatformAXImplTestClass'")!>TestClass<!> actual constructor() {}
|
||||||
|
class PlatformAXImplTestClass: TestClass()
|
||||||
|
|
||||||
|
fun checkCommonAX(t: TestClass): Int = when (t) {
|
||||||
|
is CommonImplTestClass -> 0
|
||||||
|
is CommonAImplTestClass -> 1
|
||||||
|
is PlatformAXImplTestClass -> 2
|
||||||
|
}
|
||||||
+8
@@ -0,0 +1,8 @@
|
|||||||
|
actual sealed class <!LINE_MARKER("descr='Is subclassed by PlatformAYImplTestClass'")!>TestClass<!> actual constructor() {}
|
||||||
|
class PlatformAYImplTestClass: TestClass()
|
||||||
|
|
||||||
|
fun checkCommonAY(t: TestClass): Int = when (t) {
|
||||||
|
is CommonImplTestClass -> 0
|
||||||
|
is CommonAImplTestClass -> 1
|
||||||
|
is PlatformAYImplTestClass -> 2
|
||||||
|
}
|
||||||
Generated
+5
@@ -268,4 +268,9 @@ public class MultiplatformAnalysisTestGenerated extends AbstractMultiplatformAna
|
|||||||
public void testWeaklyIncompatibleActualInIntermediateModule() throws Exception {
|
public void testWeaklyIncompatibleActualInIntermediateModule() throws Exception {
|
||||||
runTest("idea/testData/multiplatform/weaklyIncompatibleActualInIntermediateModule/");
|
runTest("idea/testData/multiplatform/weaklyIncompatibleActualInIntermediateModule/");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("whenExhaustivenessForSealed")
|
||||||
|
public void testWhenExhaustivenessForSealed() throws Exception {
|
||||||
|
runTest("idea/testData/multiplatform/whenExhaustivenessForSealed/");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user