[lc] introduce KotlinAsJavaSupportBase with new common facade logic
^KT-53543
This commit is contained in:
+49
-54
@@ -6,20 +6,24 @@
|
||||
package org.jetbrains.kotlin.light.classes.symbol
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.ModificationTracker
|
||||
import com.intellij.psi.PsiClass
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import org.jetbrains.kotlin.analysis.decompiled.light.classes.DecompiledLightClassesFactory
|
||||
import org.jetbrains.kotlin.analysis.project.structure.KtLibraryModule
|
||||
import org.jetbrains.kotlin.analysis.project.structure.KtModule
|
||||
import org.jetbrains.kotlin.analysis.project.structure.KtSourceModule
|
||||
import org.jetbrains.kotlin.analysis.project.structure.getKtModule
|
||||
import org.jetbrains.kotlin.analysis.providers.createAllLibrariesModificationTracker
|
||||
import org.jetbrains.kotlin.analysis.providers.createDeclarationProvider
|
||||
import org.jetbrains.kotlin.analysis.providers.createModuleWithoutDependenciesOutOfBlockModificationTracker
|
||||
import org.jetbrains.kotlin.analysis.providers.createPackageProvider
|
||||
import org.jetbrains.kotlin.asJava.KotlinAsJavaSupport
|
||||
import org.jetbrains.kotlin.asJava.KotlinAsJavaSupportBase
|
||||
import org.jetbrains.kotlin.asJava.classes.KtFakeLightClass
|
||||
import org.jetbrains.kotlin.asJava.classes.KtLightClass
|
||||
import org.jetbrains.kotlin.fileClasses.javaFileFacadeFqName
|
||||
import org.jetbrains.kotlin.light.classes.symbol.caches.SymbolLightClassFacadeCache
|
||||
import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade
|
||||
import org.jetbrains.kotlin.light.classes.symbol.classes.SymbolBasedFakeLightClass
|
||||
import org.jetbrains.kotlin.light.classes.symbol.classes.SymbolLightClassForFacade
|
||||
import org.jetbrains.kotlin.light.classes.symbol.classes.analyzeForLightClasses
|
||||
import org.jetbrains.kotlin.light.classes.symbol.classes.getOrCreateSymbolLightClass
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
@@ -30,7 +34,7 @@ import org.jetbrains.kotlin.psi.KtElement
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi.KtScript
|
||||
|
||||
class SymbolKotlinAsJavaSupport(private val project: Project) : KotlinAsJavaSupport() {
|
||||
class SymbolKotlinAsJavaSupport(project: Project) : KotlinAsJavaSupportBase<KtModule>(project) {
|
||||
override fun findClassOrObjectDeclarationsInPackage(
|
||||
packageFqName: FqName,
|
||||
searchScope: GlobalSearchScope
|
||||
@@ -40,13 +44,18 @@ class SymbolKotlinAsJavaSupport(private val project: Project) : KotlinAsJavaSupp
|
||||
}
|
||||
}
|
||||
|
||||
override fun findFilesForPackage(fqName: FqName, searchScope: GlobalSearchScope): Collection<KtFile> =
|
||||
buildSet {
|
||||
addAll(project.createDeclarationProvider(searchScope).getFacadeFilesInPackage(fqName))
|
||||
findClassOrObjectDeclarationsInPackage(fqName, searchScope).mapTo(this) {
|
||||
it.containingKtFile
|
||||
}
|
||||
override fun findFilesForPackage(packageFqName: FqName, searchScope: GlobalSearchScope): Collection<KtFile> = buildSet {
|
||||
addAll(project.createDeclarationProvider(searchScope).findFilesForFacadeByPackage(packageFqName))
|
||||
findClassOrObjectDeclarationsInPackage(packageFqName, searchScope).mapTo(this) {
|
||||
it.containingKtFile
|
||||
}
|
||||
}
|
||||
|
||||
override fun findFilesForFacadeByPackage(packageFqName: FqName, searchScope: GlobalSearchScope): Collection<KtFile> {
|
||||
return project.createDeclarationProvider(searchScope)
|
||||
.findFilesForFacadeByPackage(packageFqName)
|
||||
.filter { it.isFromSourceOrLibraryBinary(project) }
|
||||
}
|
||||
|
||||
private fun FqName.toClassIdSequence(): Sequence<ClassId> {
|
||||
var currentName = shortNameOrSpecial()
|
||||
@@ -88,64 +97,50 @@ class SymbolKotlinAsJavaSupport(private val project: Project) : KotlinAsJavaSupp
|
||||
}
|
||||
}
|
||||
|
||||
override fun getLightClassForScript(script: KtScript): KtLightClass =
|
||||
error("Should not be called")
|
||||
override fun getLightClassForScript(script: KtScript): KtLightClass = error("Should not be called")
|
||||
|
||||
override fun getFacadeClasses(facadeFqName: FqName, scope: GlobalSearchScope): Collection<PsiClass> {
|
||||
val filesForFacade = findFilesForFacade(facadeFqName, scope)
|
||||
override fun KtFile.findModule(): KtModule = getKtModule(project)
|
||||
|
||||
return getFacadeClassesForFiles(facadeFqName, filesForFacade)
|
||||
override fun createInstanceOfDecompiledLightFacade(
|
||||
facadeFqName: FqName,
|
||||
files: List<KtFile>,
|
||||
module: KtModule,
|
||||
): KtLightClassForFacade? = DecompiledLightClassesFactory.createLightFacadeForDecompiledKotlinFile(project, facadeFqName, files)
|
||||
|
||||
override fun tracker(file: KtFile): ModificationTracker = when (val module = file.getKtModule(project)) {
|
||||
is KtSourceModule -> module.createModuleWithoutDependenciesOutOfBlockModificationTracker(project)
|
||||
is KtLibraryModule -> project.createAllLibrariesModificationTracker()
|
||||
else -> super.tracker(file)
|
||||
}
|
||||
|
||||
override fun getScriptClasses(scriptFqName: FqName, scope: GlobalSearchScope): Collection<PsiClass> =
|
||||
error("Should not be called")
|
||||
override fun createInstanceOfLightFacade(
|
||||
facadeFqName: FqName,
|
||||
files: List<KtFile>,
|
||||
module: KtModule,
|
||||
): KtLightClassForFacade = analyzeForLightClasses(files.first()) {
|
||||
SymbolLightClassForFacade(facadeFqName, files)
|
||||
}
|
||||
|
||||
override val KtModule.contentSearchScope: GlobalSearchScope get() = this.contentScope
|
||||
|
||||
override fun facadeIsApplicable(module: KtModule, file: KtFile): Boolean = module.isFromSourceOrLibraryBinary()
|
||||
|
||||
override fun getScriptClasses(scriptFqName: FqName, scope: GlobalSearchScope): Collection<PsiClass> = error("Should not be called")
|
||||
|
||||
override fun getKotlinInternalClasses(fqName: FqName, scope: GlobalSearchScope): Collection<PsiClass> =
|
||||
emptyList() //TODO Implement if necessary for symbol
|
||||
|
||||
override fun getFacadeClassesInPackage(packageFqName: FqName, scope: GlobalSearchScope): Collection<PsiClass> =
|
||||
project.createDeclarationProvider(scope)
|
||||
.getFacadeFilesInPackage(packageFqName)
|
||||
.asSequence()
|
||||
.filter { it.isFromSourceOrLibraryBinary(project) }
|
||||
.groupBy { it.javaFileFacadeFqName }
|
||||
.flatMap { (fqName, files) -> getFacadeClassesForFiles(fqName, files) }
|
||||
|
||||
override fun getFacadeNames(packageFqName: FqName, scope: GlobalSearchScope): Collection<String> =
|
||||
project.createDeclarationProvider(scope)
|
||||
.getFacadeFilesInPackage(packageFqName)
|
||||
.filter { it.isFromSourceOrLibraryBinary(project) }
|
||||
.mapTo(mutableSetOf()) { it.javaFileFacadeFqName.shortName().asString() }
|
||||
|
||||
override fun findFilesForFacade(facadeFqName: FqName, scope: GlobalSearchScope): Collection<KtFile> {
|
||||
return project.createDeclarationProvider(scope)
|
||||
override fun findFilesForFacade(facadeFqName: FqName, searchScope: GlobalSearchScope): Collection<KtFile> {
|
||||
return project.createDeclarationProvider(searchScope)
|
||||
.findFilesForFacade(facadeFqName)
|
||||
.filter { it.isFromSourceOrLibraryBinary(project) }
|
||||
}
|
||||
|
||||
override fun getFakeLightClass(classOrObject: KtClassOrObject): KtFakeLightClass =
|
||||
SymbolBasedFakeLightClass(classOrObject)
|
||||
override fun getFakeLightClass(classOrObject: KtClassOrObject): KtFakeLightClass = SymbolBasedFakeLightClass(classOrObject)
|
||||
|
||||
override fun createFacadeForSyntheticFile(facadeClassFqName: FqName, file: KtFile): PsiClass =
|
||||
TODO("Not implemented")
|
||||
private fun KtElement.isFromSourceOrLibraryBinary(project: Project): Boolean = getKtModule(project).isFromSourceOrLibraryBinary()
|
||||
|
||||
private fun getFacadeClassesForFiles(facadeFqName: FqName, allFiles: Collection<KtFile>): Collection<PsiClass> {
|
||||
if (allFiles.isEmpty()) return emptyList()
|
||||
val filesByModule = allFiles.groupBy { it.getKtModule(project) }
|
||||
|
||||
val lightClassFacadeCache = project.getService(SymbolLightClassFacadeCache::class.java)
|
||||
|
||||
return filesByModule.mapNotNull { (module, files) ->
|
||||
analyzeForLightClasses(module) {
|
||||
lightClassFacadeCache.getOrCreateSymbolLightFacade(files, facadeFqName)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun KtElement.isFromSourceOrLibraryBinary(project: Project): Boolean {
|
||||
return when (getKtModule(project)) {
|
||||
private fun KtModule.isFromSourceOrLibraryBinary() = when (this) {
|
||||
is KtSourceModule -> true
|
||||
is KtLibraryModule -> true
|
||||
else -> false
|
||||
|
||||
-62
@@ -1,62 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2022 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.light.classes.symbol.caches
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import org.jetbrains.kotlin.analysis.decompiled.light.classes.DecompiledLightClassesFactory
|
||||
import org.jetbrains.kotlin.analysis.providers.createProjectWideOutOfBlockModificationTracker
|
||||
import org.jetbrains.kotlin.analysis.utils.caches.getValue
|
||||
import org.jetbrains.kotlin.analysis.utils.caches.softCachedValue
|
||||
import org.jetbrains.kotlin.analysis.utils.collections.ConcurrentMapBasedCache
|
||||
import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade
|
||||
import org.jetbrains.kotlin.light.classes.symbol.classes.SymbolLightClassForFacade
|
||||
import org.jetbrains.kotlin.light.classes.symbol.classes.analyzeForLightClasses
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
class SymbolLightClassFacadeCache(private val project: Project) {
|
||||
private val cache by softCachedValue(
|
||||
project,
|
||||
project.createProjectWideOutOfBlockModificationTracker()
|
||||
) {
|
||||
ConcurrentMapBasedCache<FacadeKey, KtLightClassForFacade?>(ConcurrentHashMap())
|
||||
}
|
||||
|
||||
fun getOrCreateSymbolLightFacade(
|
||||
ktFiles: List<KtFile>,
|
||||
facadeClassFqName: FqName,
|
||||
): KtLightClassForFacade? {
|
||||
val ktFilesWithoutScript = ktFiles.filterNot { it.isScript() }
|
||||
if (ktFilesWithoutScript.isEmpty()) return null
|
||||
val key = FacadeKey(facadeClassFqName, ktFilesWithoutScript.toSet())
|
||||
return cache.getOrPut(key) {
|
||||
getOrCreateSymbolLightFacadeNoCache(ktFilesWithoutScript, facadeClassFqName)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getOrCreateSymbolLightFacadeNoCache(
|
||||
ktFiles: List<KtFile>,
|
||||
facadeClassFqName: FqName,
|
||||
): KtLightClassForFacade? {
|
||||
val firstFile = ktFiles.first()
|
||||
return when {
|
||||
ktFiles.none { it.isCompiled } ->
|
||||
analyzeForLightClasses(firstFile) {
|
||||
SymbolLightClassForFacade(firstFile.manager, facadeClassFqName, ktFiles)
|
||||
}
|
||||
|
||||
ktFiles.all { it.isCompiled } -> {
|
||||
DecompiledLightClassesFactory.createLightFacadeForDecompiledKotlinFile(project, facadeClassFqName, ktFiles)
|
||||
}
|
||||
|
||||
else ->
|
||||
error("Source and compiled files are mixed: $ktFiles}")
|
||||
}
|
||||
}
|
||||
|
||||
private data class FacadeKey(val fqName: FqName, val files: Set<KtFile>)
|
||||
}
|
||||
+5
-10
@@ -40,10 +40,9 @@ import org.jetbrains.kotlin.psi.KtFile
|
||||
|
||||
context(KtAnalysisSession)
|
||||
class SymbolLightClassForFacade(
|
||||
manager: PsiManager,
|
||||
override val facadeClassFqName: FqName,
|
||||
override val files: Collection<KtFile>
|
||||
) : SymbolLightClassBase(manager), KtLightClassForFacade {
|
||||
) : SymbolLightClassBase(files.first().manager), KtLightClassForFacade {
|
||||
|
||||
init {
|
||||
require(files.isNotEmpty())
|
||||
@@ -158,17 +157,13 @@ class SymbolLightClassForFacade(
|
||||
|
||||
override fun getOwnMethods() = _ownMethods
|
||||
|
||||
override fun copy(): SymbolLightClassForFacade =
|
||||
SymbolLightClassForFacade(manager, facadeClassFqName, files)
|
||||
override fun copy(): SymbolLightClassForFacade = SymbolLightClassForFacade(facadeClassFqName, files)
|
||||
|
||||
private val packageFqName: FqName =
|
||||
facadeClassFqName.parent()
|
||||
private val packageFqName: FqName = facadeClassFqName.parent()
|
||||
|
||||
private val modifierList: PsiModifierList =
|
||||
LightModifierList(manager, KotlinLanguage.INSTANCE, PsiModifier.PUBLIC, PsiModifier.FINAL)
|
||||
private val modifierList: PsiModifierList = LightModifierList(manager, KotlinLanguage.INSTANCE, PsiModifier.PUBLIC, PsiModifier.FINAL)
|
||||
|
||||
private val implementsList: LightEmptyImplementsList =
|
||||
LightEmptyImplementsList(manager)
|
||||
private val implementsList: LightEmptyImplementsList = LightEmptyImplementsList(manager)
|
||||
|
||||
private val packageClsFile = FakeFileForLightClass(
|
||||
firstFileInFacade,
|
||||
|
||||
Reference in New Issue
Block a user