Split LightClassGenerationSupport into separate entities
LightClassGenerationSupport:
Includes utilities related to generating light classes
Primary client of this service are KtLight* implementation classes
KotlinAsJavaSupport:
Provides APIs to transform kotlin code into Psi* entities
Primary client of this service is JavaElementFinder
This commit is contained in:
+48
-41
@@ -23,6 +23,7 @@ import com.intellij.psi.impl.compiled.ClsClassImpl
|
||||
import com.intellij.psi.impl.compiled.ClsFileImpl
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import org.jetbrains.kotlin.asJava.KotlinAsJavaSupport
|
||||
import org.jetbrains.kotlin.asJava.LightClassBuilder
|
||||
import org.jetbrains.kotlin.asJava.LightClassGenerationSupport
|
||||
import org.jetbrains.kotlin.asJava.builder.ClsWrapperStubPsiFactory
|
||||
@@ -30,13 +31,14 @@ import org.jetbrains.kotlin.asJava.builder.InvalidLightClassDataHolder
|
||||
import org.jetbrains.kotlin.asJava.builder.LightClassDataHolder
|
||||
import org.jetbrains.kotlin.asJava.classes.*
|
||||
import org.jetbrains.kotlin.asJava.finder.JavaElementFinder
|
||||
import org.jetbrains.kotlin.asJava.toLightClass
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil
|
||||
import org.jetbrains.kotlin.fileClasses.javaFileFacadeFqName
|
||||
import org.jetbrains.kotlin.idea.caches.lightClasses.*
|
||||
import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo
|
||||
import org.jetbrains.kotlin.idea.caches.project.ModuleSourceInfo
|
||||
import org.jetbrains.kotlin.idea.caches.project.getModuleInfo
|
||||
import org.jetbrains.kotlin.idea.caches.lightClasses.*
|
||||
import org.jetbrains.kotlin.idea.decompiler.classFile.KtClsFile
|
||||
import org.jetbrains.kotlin.idea.decompiler.navigation.SourceNavigationHelper
|
||||
import org.jetbrains.kotlin.idea.stubindex.*
|
||||
@@ -51,9 +53,8 @@ import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
import org.jetbrains.kotlin.utils.sure
|
||||
import java.util.*
|
||||
|
||||
class IDELightClassGenerationSupport(private val project: Project) : LightClassGenerationSupport() {
|
||||
class IDELightClassGenerationSupport(project: Project) : LightClassGenerationSupport() {
|
||||
private val scopeFileComparator = JavaElementFinder.byClasspathComparator(GlobalSearchScope.allScope(project))
|
||||
private val psiManager: PsiManager = PsiManager.getInstance(project)
|
||||
|
||||
override fun createDataHolderForClass(classOrObject: KtClassOrObject, builder: LightClassBuilder): LightClassDataHolder.ForClass {
|
||||
return when {
|
||||
@@ -98,6 +99,45 @@ class IDELightClassGenerationSupport(private val project: Project) : LightClassG
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
override fun resolveToDescriptor(declaration: KtDeclaration): DeclarationDescriptor? {
|
||||
try {
|
||||
return declaration.resolveToDescriptorIfAny(BodyResolveMode.FULL)
|
||||
} catch (e: NoDescriptorForDeclarationException) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
override fun analyze(element: KtElement) = element.analyze(BodyResolveMode.PARTIAL)
|
||||
|
||||
override fun analyzeWithContent(element: KtClassOrObject) = element.analyzeWithContent()
|
||||
}
|
||||
|
||||
class IDEKotlinAsJavaSupport(private val project: Project): KotlinAsJavaSupport() {
|
||||
private val psiManager: PsiManager = PsiManager.getInstance(project)
|
||||
|
||||
override fun getFacadeNames(packageFqName: FqName, scope: GlobalSearchScope): Collection<String> {
|
||||
val facadeFilesInPackage = runReadAction {
|
||||
KotlinFileFacadeClassByPackageIndex.getInstance().get(packageFqName.asString(), project, scope)
|
||||
}
|
||||
return facadeFilesInPackage.map { it.javaFileFacadeFqName.shortName().asString() }
|
||||
}
|
||||
|
||||
override fun getFacadeClassesInPackage(packageFqName: FqName, scope: GlobalSearchScope): Collection<PsiClass> {
|
||||
val facadeFilesInPackage = runReadAction {
|
||||
KotlinFileFacadeClassByPackageIndex.getInstance().get(packageFqName.asString(), project, scope)
|
||||
}
|
||||
val groupedByFqNameAndModuleInfo = facadeFilesInPackage.groupBy {
|
||||
Pair(it.javaFileFacadeFqName, it.getModuleInfo())
|
||||
}
|
||||
|
||||
return groupedByFqNameAndModuleInfo.flatMap {
|
||||
val (key, files) = it
|
||||
val (fqName, moduleInfo) = key
|
||||
createLightClassForFileFacade(fqName, files, moduleInfo)
|
||||
}
|
||||
}
|
||||
|
||||
override fun findClassOrObjectDeclarations(fqName: FqName, searchScope: GlobalSearchScope): Collection<KtClassOrObject> {
|
||||
return runReadAction {
|
||||
KotlinFullClassNameIndex.getInstance().get(fqName.asString(), project, sourceAndClassFiles(searchScope, project))
|
||||
@@ -230,40 +270,6 @@ class IDELightClassGenerationSupport(private val project: Project) : LightClassG
|
||||
}
|
||||
}
|
||||
|
||||
override fun resolveToDescriptor(declaration: KtDeclaration): DeclarationDescriptor? {
|
||||
try {
|
||||
return declaration.resolveToDescriptorIfAny(BodyResolveMode.FULL)
|
||||
} catch (e: NoDescriptorForDeclarationException) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
override fun analyze(element: KtElement) = element.analyze(BodyResolveMode.PARTIAL)
|
||||
|
||||
override fun analyzeWithContent(element: KtClassOrObject) = element.analyzeWithContent()
|
||||
|
||||
override fun getFacadeNames(packageFqName: FqName, scope: GlobalSearchScope): Collection<String> {
|
||||
val facadeFilesInPackage = runReadAction {
|
||||
KotlinFileFacadeClassByPackageIndex.getInstance().get(packageFqName.asString(), project, scope)
|
||||
}
|
||||
return facadeFilesInPackage.map { it.javaFileFacadeFqName.shortName().asString() }
|
||||
}
|
||||
|
||||
override fun getFacadeClassesInPackage(packageFqName: FqName, scope: GlobalSearchScope): Collection<PsiClass> {
|
||||
val facadeFilesInPackage = runReadAction {
|
||||
KotlinFileFacadeClassByPackageIndex.getInstance().get(packageFqName.asString(), project, scope)
|
||||
}
|
||||
val groupedByFqNameAndModuleInfo = facadeFilesInPackage.groupBy {
|
||||
Pair(it.javaFileFacadeFqName, it.getModuleInfo())
|
||||
}
|
||||
|
||||
return groupedByFqNameAndModuleInfo.flatMap {
|
||||
val (key, files) = it
|
||||
val (fqName, moduleInfo) = key
|
||||
createLightClassForFileFacade(fqName, files, moduleInfo)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getLightClassForDecompiledClassOrObject(decompiledClassOrObject: KtClassOrObject): KtLightClassForDecompiledDeclaration? {
|
||||
if (decompiledClassOrObject is KtEnumEntry) {
|
||||
return null
|
||||
@@ -343,7 +349,8 @@ class IDELightClassGenerationSupport(private val project: Project) : LightClassG
|
||||
}
|
||||
}
|
||||
|
||||
class KtFileClassProviderImpl(val lightClassGenerationSupport: LightClassGenerationSupport) : KtFileClassProvider {
|
||||
|
||||
class KtFileClassProviderImpl(val kotlinAsJavaSupport: KotlinAsJavaSupport) : KtFileClassProvider {
|
||||
override fun getFileClasses(file: KtFile): Array<PsiClass> {
|
||||
// TODO We don't currently support finding light classes for scripts
|
||||
if (file.isCompiled || file.isScript()) {
|
||||
@@ -351,7 +358,7 @@ class KtFileClassProviderImpl(val lightClassGenerationSupport: LightClassGenerat
|
||||
}
|
||||
|
||||
val result = arrayListOf<PsiClass>()
|
||||
file.declarations.filterIsInstance<KtClassOrObject>().map { lightClassGenerationSupport.getLightClass(it) }.filterNotNullTo(result)
|
||||
file.declarations.filterIsInstance<KtClassOrObject>().map { it.toLightClass() }.filterNotNullTo(result)
|
||||
|
||||
val moduleInfo = file.getModuleInfo()
|
||||
val jvmClassInfo = JvmFileClassUtil.getFileClassInfoNoResolve(file)
|
||||
@@ -362,10 +369,10 @@ class KtFileClassProviderImpl(val lightClassGenerationSupport: LightClassGenerat
|
||||
listOf(KtLightClassForFacade.createForSyntheticFile(PsiManager.getInstance(file.project), fileClassFqName, file))
|
||||
|
||||
jvmClassInfo.withJvmMultifileClass ->
|
||||
lightClassGenerationSupport.getFacadeClasses(fileClassFqName, moduleInfo.contentScope())
|
||||
kotlinAsJavaSupport.getFacadeClasses(fileClassFqName, moduleInfo.contentScope())
|
||||
|
||||
file.hasTopLevelCallables() ->
|
||||
(lightClassGenerationSupport as IDELightClassGenerationSupport).createLightClassForFileFacade(
|
||||
(kotlinAsJavaSupport as IDEKotlinAsJavaSupport).createLightClassForFileFacade(
|
||||
fileClassFqName, listOf(file), moduleInfo
|
||||
)
|
||||
|
||||
|
||||
@@ -257,6 +257,9 @@
|
||||
<projectService serviceInterface="org.jetbrains.kotlin.asJava.LightClassGenerationSupport"
|
||||
serviceImplementation="org.jetbrains.kotlin.idea.caches.resolve.IDELightClassGenerationSupport"/>
|
||||
|
||||
<projectService serviceInterface="org.jetbrains.kotlin.asJava.KotlinAsJavaSupport"
|
||||
serviceImplementation="org.jetbrains.kotlin.idea.caches.resolve.IDEKotlinAsJavaSupport"/>
|
||||
|
||||
<projectService serviceInterface="org.jetbrains.kotlin.psi.KtFileClassProvider"
|
||||
serviceImplementation="org.jetbrains.kotlin.idea.caches.resolve.KtFileClassProviderImpl"/>
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ class KotlinLightClassInheritorTest : KotlinLightCodeInsightFixtureTestCase() {
|
||||
private fun doTestInheritorByText(text: String, superQName: String, checkDeep: Boolean) {
|
||||
val file = myFixture.configureByText("A.kt", text) as KtFile
|
||||
val jetClass = file.declarations.filterIsInstance<KtClass>().single()
|
||||
val psiClass = LightClassGenerationSupport.getInstance(project).getLightClass(jetClass)!!
|
||||
val psiClass = KotlinAsJavaSupport.getInstance(project).getLightClass(jetClass)!!
|
||||
val baseClass = JavaPsiFacade.getInstance(project).findClass(superQName, GlobalSearchScope.allScope(project))!!
|
||||
Assert.assertTrue(psiClass.isInheritor(baseClass, checkDeep))
|
||||
}
|
||||
|
||||
@@ -58,14 +58,14 @@ class KtFileLightClassTest : KotlinLightCodeInsightFixtureTestCase() {
|
||||
fun testNoFacadeForScript() {
|
||||
val file = myFixture.configureByText("foo.kts", "package foo") as KtFile
|
||||
assertEquals(0, file.classes.size)
|
||||
val facadeFiles = LightClassGenerationSupport.getInstance(project).findFilesForFacade(FqName("foo.FooKt"), GlobalSearchScope.allScope(project))
|
||||
val facadeFiles = KotlinAsJavaSupport.getInstance(project).findFilesForFacade(FqName("foo.FooKt"), GlobalSearchScope.allScope(project))
|
||||
assertEquals(0, facadeFiles.size)
|
||||
}
|
||||
|
||||
fun testNoFacadeForHeaderClass() {
|
||||
val file = myFixture.configureByText("foo.kt", "header fun foo(): Int") as KtFile
|
||||
assertEquals(0, file.classes.size)
|
||||
val facadeFiles = LightClassGenerationSupport.getInstance(project).findFilesForFacade(FqName("foo.FooKt"), GlobalSearchScope.allScope(project))
|
||||
val facadeFiles = KotlinAsJavaSupport.getInstance(project).findFilesForFacade(FqName("foo.FooKt"), GlobalSearchScope.allScope(project))
|
||||
assertEquals(0, facadeFiles.size)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user