KTIJ-664 [SealedClassInheritorsProvider]: IDE-specific implementation
This commit is contained in:
+3
-2
@@ -56,7 +56,8 @@ class CompositeResolverForModuleFactory(
|
||||
moduleContext: ModuleContext,
|
||||
moduleContent: ModuleContent<M>,
|
||||
resolverForProject: ResolverForProject<M>,
|
||||
languageVersionSettings: LanguageVersionSettings
|
||||
languageVersionSettings: LanguageVersionSettings,
|
||||
sealedInheritorsProvider: SealedClassInheritorsProvider
|
||||
): ResolverForModule {
|
||||
val (moduleInfo, syntheticFiles, moduleContentScope) = moduleContent
|
||||
val project = moduleContext.project
|
||||
@@ -178,7 +179,7 @@ class CompositeResolverForModuleFactory(
|
||||
}
|
||||
|
||||
// Called by all normal containers set-ups
|
||||
configureModule(moduleContext, targetPlatform, analyzerServices, trace, languageVersionSettings)
|
||||
configureModule(moduleContext, targetPlatform, analyzerServices, trace, languageVersionSettings,)
|
||||
configureStandardResolveComponents()
|
||||
useInstance(moduleContentScope)
|
||||
useInstance(declarationProviderFactory)
|
||||
|
||||
+3
-1
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.js.resolve.JsPlatformAnalyzerServices
|
||||
import org.jetbrains.kotlin.platform.idePlatformKind
|
||||
import org.jetbrains.kotlin.platform.js.JsPlatforms
|
||||
import org.jetbrains.kotlin.resolve.BindingTraceContext
|
||||
import org.jetbrains.kotlin.resolve.SealedClassInheritorsProvider
|
||||
import org.jetbrains.kotlin.resolve.TargetEnvironment
|
||||
import org.jetbrains.kotlin.resolve.lazy.ResolveSession
|
||||
import org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactoryService
|
||||
@@ -38,7 +39,8 @@ class JsResolverForModuleFactory(
|
||||
moduleContext: ModuleContext,
|
||||
moduleContent: ModuleContent<M>,
|
||||
resolverForProject: ResolverForProject<M>,
|
||||
languageVersionSettings: LanguageVersionSettings
|
||||
languageVersionSettings: LanguageVersionSettings,
|
||||
sealedInheritorsProvider: SealedClassInheritorsProvider
|
||||
): ResolverForModule {
|
||||
val (moduleInfo, syntheticFiles, moduleContentScope) = moduleContent
|
||||
val project = moduleContext.project
|
||||
|
||||
+3
-1
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo
|
||||
import org.jetbrains.kotlin.idea.caches.project.getNullableModuleInfo
|
||||
import org.jetbrains.kotlin.idea.compiler.IDELanguageSettingsProvider
|
||||
import org.jetbrains.kotlin.idea.project.IdeaEnvironment
|
||||
import org.jetbrains.kotlin.idea.compiler.IdeSealedClassInheritorsProvider
|
||||
import org.jetbrains.kotlin.idea.project.findAnalyzerServices
|
||||
import org.jetbrains.kotlin.idea.project.useCompositeAnalysis
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaClass
|
||||
@@ -83,7 +84,8 @@ class IdeaResolverForProject(
|
||||
projectContext.withModule(descriptor),
|
||||
moduleContent,
|
||||
this,
|
||||
languageVersionSettings
|
||||
languageVersionSettings,
|
||||
sealedInheritorsProvider = IdeSealedClassInheritorsProvider
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.idea.compiler
|
||||
|
||||
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.toLightClass
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.containingPackage
|
||||
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
|
||||
|
||||
object IdeSealedClassInheritorsProvider : SealedClassInheritorsProvider() {
|
||||
|
||||
override fun computeSealedSubclasses(
|
||||
sealedClass: ClassDescriptor,
|
||||
allowSealedInheritorsInDifferentFilesOfSamePackage: Boolean
|
||||
): Collection<ClassDescriptor> {
|
||||
|
||||
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 containingPackage = sealedClass.containingPackage() ?: return emptyList()
|
||||
val psiPackage = JavaDirectoryService.getInstance().getPackage(sealedKtClass.containingFile.containingDirectory)
|
||||
?: JavaPsiFacade.getInstance(sealedKtClass.project).findPackage(containingPackage.asString())
|
||||
?: return emptyList()
|
||||
val packageScope = PackageScope(psiPackage, false, false)
|
||||
moduleSourceScope.intersectWith(packageScope)
|
||||
} else {
|
||||
GlobalSearchScope.fileScope(sealedKtClass.containingFile) // Kotlin version prior to 1.5
|
||||
}
|
||||
|
||||
val lightClass = sealedKtClass.toLightClass() ?: return emptyList()
|
||||
val searchParameters = SearchParameters(lightClass, searchScope, false, true, false)
|
||||
|
||||
return ClassInheritorsSearch.search(searchParameters)
|
||||
.map mapper@{
|
||||
val resolutionFacade = it.javaResolutionFacade() ?: return@mapper null
|
||||
it.resolveToDescriptor(resolutionFacade)
|
||||
}.filterNotNull()
|
||||
.sortedBy(ClassDescriptor::getName) // order needs to be stable (at least for tests)
|
||||
}
|
||||
}
|
||||
+3
-1
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.platform.TargetPlatform
|
||||
import org.jetbrains.kotlin.platform.idePlatformKind
|
||||
import org.jetbrains.kotlin.platform.konan.NativePlatforms
|
||||
import org.jetbrains.kotlin.resolve.CodeAnalyzerInitializer
|
||||
import org.jetbrains.kotlin.resolve.SealedClassInheritorsProvider
|
||||
import org.jetbrains.kotlin.resolve.TargetEnvironment
|
||||
import org.jetbrains.kotlin.resolve.konan.platform.NativePlatformAnalyzerServices
|
||||
import org.jetbrains.kotlin.resolve.lazy.ResolveSession
|
||||
@@ -32,7 +33,8 @@ class NativeResolverForModuleFactory(
|
||||
moduleContext: ModuleContext,
|
||||
moduleContent: ModuleContent<M>,
|
||||
resolverForProject: ResolverForProject<M>,
|
||||
languageVersionSettings: LanguageVersionSettings
|
||||
languageVersionSettings: LanguageVersionSettings,
|
||||
sealedInheritorsProvider: SealedClassInheritorsProvider
|
||||
): ResolverForModule {
|
||||
|
||||
val declarationProviderFactory = createDeclarationProviderFactory(
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
// COMPILER_ARGUMENTS: -XXLanguage:+SealedInterfaces -XXLanguage:+FreedomForSealedClasses
|
||||
|
||||
package sealed
|
||||
|
||||
sealed class SealedDeclarationClass {
|
||||
class AClass: SealedDeclarationClass()
|
||||
}
|
||||
|
||||
sealed interface SealedDeclarationInterface {
|
||||
class A: SealedDeclarationInterface
|
||||
}
|
||||
|
||||
class B: SealedDeclarationInterface
|
||||
class BClass: SealedDeclarationClass()
|
||||
@@ -0,0 +1,35 @@
|
||||
// COMPILER_ARGUMENTS: -XXLanguage:+SealedInterfaces -XXLanguage:+FreedomForSealedClasses
|
||||
package sealed
|
||||
|
||||
class C: SealedDeclarationInterface {}
|
||||
class CClass: SealedDeclarationClass() {}
|
||||
|
||||
class D: SealedDeclarationInterface {
|
||||
class E: SealedDeclarationInterface {
|
||||
class F: SealedDeclarationInterface
|
||||
}
|
||||
}
|
||||
|
||||
class DClass: SealedDeclarationClass() {
|
||||
class EClass: SealedDeclarationClass() {
|
||||
class FClass: SealedDeclarationClass()
|
||||
}
|
||||
}
|
||||
|
||||
fun checkWhenNone(value: SealedDeclarationInterface): Int = <error descr="[NO_ELSE_IN_WHEN] 'when' expression must be exhaustive, add necessary 'is A', 'is B', 'is C', 'is D', 'is E', 'is F' branches or 'else' branch instead">when</error> (<warning descr="[UNUSED_EXPRESSION] The expression is unused">value</warning>) {
|
||||
}
|
||||
|
||||
fun checkWhenNone(value: SealedDeclarationClass): Int = <error descr="[NO_ELSE_IN_WHEN] 'when' expression must be exhaustive, add necessary 'is AClass', 'is BClass', 'is CClass', 'is DClass', 'is EClass', 'is FClass' branches or 'else' branch instead">when</error> (<warning descr="[UNUSED_EXPRESSION] The expression is unused">value</warning>) {
|
||||
}
|
||||
|
||||
fun checkWhenOneMissing(value: SealedDeclarationInterface): Int = <error descr="[NO_ELSE_IN_WHEN] 'when' expression must be exhaustive, add necessary 'is D', 'is E', 'is F' branches or 'else' branch instead">when</error> (value) {
|
||||
is SealedDeclarationInterface.A -> 1
|
||||
is B -> 2
|
||||
is C -> 3
|
||||
}
|
||||
|
||||
fun checkWhenOneMissing(value: SealedDeclarationClass): Int = <error descr="[NO_ELSE_IN_WHEN] 'when' expression must be exhaustive, add necessary 'is DClass', 'is EClass', 'is FClass' branches or 'else' branch instead">when</error> (value) {
|
||||
is SealedDeclarationClass.AClass -> 1
|
||||
is BClass -> 2
|
||||
is CClass -> 3
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// COMPILER_ARGUMENTS: -XXLanguage:+SealedInterfaces -XXLanguage:+FreedomForSealedClasses
|
||||
package sealed.otherpackage
|
||||
import sealed.SealedDeclarationInterface
|
||||
import sealed.SealedDeclarationClass
|
||||
|
||||
class D: <error descr="[SEALED_INHERITOR_IN_DIFFERENT_PACKAGE] Inheritor of sealed class or interface declared in package sealed but it must be in package {2} where base class is declared">SealedDeclarationInterface</error>
|
||||
class DClass: <error descr="[SEALED_INHERITOR_IN_DIFFERENT_PACKAGE] Inheritor of sealed class or interface declared in package sealed but it must be in package {2} where base class is declared">SealedDeclarationClass</error>()
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.checkers
|
||||
|
||||
import com.intellij.testFramework.LightProjectDescriptor
|
||||
import org.jetbrains.kotlin.test.JUnit3WithIdeaConfigurationRunner
|
||||
import org.jetbrains.kotlin.test.TestMetadata
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@TestMetadata("idea/testData/checker/sealed")
|
||||
@RunWith(JUnit3WithIdeaConfigurationRunner::class)
|
||||
class PsiCheckerSealedTest : AbstractPsiCheckerTest() {
|
||||
|
||||
fun testOutsideOfPackageInheritors() {
|
||||
doTest(
|
||||
"SealedOutsidePackageInheritors.kt", // opened in the test editor
|
||||
"SealedDeclaration.kt"
|
||||
)
|
||||
}
|
||||
|
||||
fun testWhenExhaustiveness() {
|
||||
doTest(
|
||||
"SealedInheritors.kt", // opened in the test editor
|
||||
"SealedDeclaration.kt"
|
||||
)
|
||||
}
|
||||
|
||||
override fun getProjectDescriptor(): LightProjectDescriptor = getProjectDescriptorFromTestName()
|
||||
}
|
||||
Reference in New Issue
Block a user