KT-44487 [Sealed Interfaces]: sealed-inheritors-provider for MPP
This commit is contained in:
@@ -134,9 +134,10 @@ fun createContainerForBodyResolve(
|
||||
statementFilter: StatementFilter,
|
||||
analyzerServices: PlatformDependentAnalyzerServices,
|
||||
languageVersionSettings: LanguageVersionSettings,
|
||||
moduleStructureOracle: ModuleStructureOracle
|
||||
moduleStructureOracle: ModuleStructureOracle,
|
||||
sealedProvider: SealedClassInheritorsProvider = CliSealedClassInheritorsProvider
|
||||
): StorageComponentContainer = createContainer("BodyResolve", analyzerServices) {
|
||||
configureModule(moduleContext, platform, analyzerServices, bindingTrace, languageVersionSettings)
|
||||
configureModule(moduleContext, platform, analyzerServices, bindingTrace, languageVersionSettings, sealedProvider)
|
||||
|
||||
useInstance(statementFilter)
|
||||
|
||||
@@ -156,10 +157,10 @@ fun createContainerForLazyBodyResolve(
|
||||
analyzerServices: PlatformDependentAnalyzerServices,
|
||||
languageVersionSettings: LanguageVersionSettings,
|
||||
moduleStructureOracle: ModuleStructureOracle,
|
||||
mainFunctionDetectorFactory: MainFunctionDetector.Factory
|
||||
mainFunctionDetectorFactory: MainFunctionDetector.Factory,
|
||||
sealedProvider: SealedClassInheritorsProvider = CliSealedClassInheritorsProvider
|
||||
): StorageComponentContainer = createContainer("LazyBodyResolve", analyzerServices) {
|
||||
configureModule(moduleContext, platform, analyzerServices, bindingTrace, languageVersionSettings)
|
||||
|
||||
configureModule(moduleContext, platform, analyzerServices, bindingTrace, languageVersionSettings, sealedProvider)
|
||||
useInstance(mainFunctionDetectorFactory)
|
||||
useInstance(kotlinCodeAnalyzer)
|
||||
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.java.di.configureJavaSpecificComponents
|
||||
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.project.IdeaEnvironment
|
||||
import org.jetbrains.kotlin.load.java.lazy.ModuleClassResolver
|
||||
@@ -189,7 +190,7 @@ class CompositeResolverForModuleFactory(
|
||||
}
|
||||
|
||||
// Called by all normal containers set-ups
|
||||
configureModule(moduleContext, targetPlatform, analyzerServices, trace, languageVersionSettings,)
|
||||
configureModule(moduleContext, targetPlatform, analyzerServices, trace, languageVersionSettings, IdeSealedClassInheritorsProvider)
|
||||
configureStandardResolveComponents()
|
||||
useInstance(moduleContentScope)
|
||||
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.inBlockModifications
|
||||
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.findAnalyzerServices
|
||||
import org.jetbrains.kotlin.idea.project.languageVersionSettings
|
||||
@@ -482,8 +483,9 @@ private object KotlinResolveDataProvider {
|
||||
targetPlatform.findAnalyzerServices(project),
|
||||
analyzableElement.languageVersionSettings,
|
||||
IdeaModuleStructureOracle(),
|
||||
IdeMainFunctionDetectorFactory()
|
||||
).get<LazyTopDownAnalyzer>()
|
||||
IdeMainFunctionDetectorFactory(),
|
||||
IdeSealedClassInheritorsProvider
|
||||
).get<LazyTopDownAnalyzer>()
|
||||
|
||||
lazyTopDownAnalyzer.analyzeDeclarations(TopDownAnalysisMode.TopLevelDeclarations, listOf(analyzableElement))
|
||||
} finally {
|
||||
|
||||
+27
-5
@@ -5,19 +5,27 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.compiler
|
||||
|
||||
import com.intellij.openapi.module.ModuleManager
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.search.*
|
||||
import com.intellij.psi.search.searches.ClassInheritorsSearch
|
||||
import com.intellij.psi.search.searches.ClassInheritorsSearch.SearchParameters
|
||||
import org.jetbrains.kotlin.asJava.KotlinAsJavaSupport
|
||||
import org.jetbrains.kotlin.asJava.toLightClass
|
||||
import org.jetbrains.kotlin.codegen.JvmCodegenUtil
|
||||
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.implementedDescriptors
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.util.javaResolutionFacade
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.util.resolveToDescriptor
|
||||
import org.jetbrains.kotlin.idea.util.module
|
||||
import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi
|
||||
import org.jetbrains.kotlin.psi.KtClass
|
||||
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() {
|
||||
|
||||
@@ -29,18 +37,28 @@ object IdeSealedClassInheritorsProvider : SealedClassInheritorsProvider() {
|
||||
val sealedKtClass = sealedClass.findPsi() as? KtClass ?: return emptyList()
|
||||
val searchScope: SearchScope = if (allowSealedInheritorsInDifferentFilesOfSamePackage) {
|
||||
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 psiPackage = getPackageViaDirectoryService(sealedKtClass)
|
||||
?: JavaPsiFacade.getInstance(sealedKtClass.project).findPackage(containingPackage.asString())
|
||||
val psiPackage = KotlinJavaPsiFacade.getInstance(sealedKtClass.project)
|
||||
.findPackage(containingPackage.asString(), GlobalSearchScope.moduleScope(module))
|
||||
?: getPackageViaDirectoryService(sealedKtClass)
|
||||
?: return emptyList()
|
||||
val packageScope = PackageScope(psiPackage, false, false)
|
||||
moduleSourceScope.intersectWith(packageScope)
|
||||
|
||||
mppAwareSearchScope.intersectWith(packageScope)
|
||||
} else {
|
||||
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)
|
||||
|
||||
return ClassInheritorsSearch.search(searchParameters)
|
||||
@@ -51,6 +69,10 @@ object IdeSealedClassInheritorsProvider : SealedClassInheritorsProvider() {
|
||||
.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? {
|
||||
val directory = ktClass.containingFile.containingDirectory ?: return null
|
||||
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.KotlinCodeBlockModificationListenerCompat
|
||||
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.name.Name
|
||||
import org.jetbrains.kotlin.platform.TargetPlatform
|
||||
@@ -785,7 +785,8 @@ class ResolveElementCache(
|
||||
statementFilter,
|
||||
targetPlatform.findAnalyzerServices(file.project),
|
||||
file.languageVersionSettings,
|
||||
IdeaModuleStructureOracle()
|
||||
IdeaModuleStructureOracle(),
|
||||
IdeSealedClassInheritorsProvider
|
||||
).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 {
|
||||
runTest("idea/testData/multiplatform/weaklyIncompatibleActualInIntermediateModule/");
|
||||
}
|
||||
|
||||
@TestMetadata("whenExhaustivenessForSealed")
|
||||
public void testWhenExhaustivenessForSealed() throws Exception {
|
||||
runTest("idea/testData/multiplatform/whenExhaustivenessForSealed/");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user