FIR LC: add supports for decompiled declarations
This commit is contained in:
committed by
Ilya Kirillov
parent
aa87524513
commit
09f5ec7bd3
@@ -12,6 +12,7 @@ dependencies {
|
||||
implementation(project(":analysis:analysis-api"))
|
||||
implementation(project(":analysis:analysis-internal-utils"))
|
||||
implementation(project(":analysis:project-structure"))
|
||||
implementation(project(":analysis:decompiled:light-classes-for-decompiled"))
|
||||
implementation(intellijCore())
|
||||
}
|
||||
|
||||
|
||||
+24
-20
@@ -8,7 +8,10 @@ package org.jetbrains.kotlin.light.classes.symbol
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.PsiClass
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import org.jetbrains.kotlin.analysis.project.structure.*
|
||||
import org.jetbrains.kotlin.analysis.decompiled.light.classes.DecompiledLightClassesFactory
|
||||
import org.jetbrains.kotlin.analysis.project.structure.KtLibraryModule
|
||||
import org.jetbrains.kotlin.analysis.project.structure.KtSourceModule
|
||||
import org.jetbrains.kotlin.analysis.project.structure.getKtModule
|
||||
import org.jetbrains.kotlin.analysis.providers.createDeclarationProvider
|
||||
import org.jetbrains.kotlin.analysis.providers.createPackageProvider
|
||||
import org.jetbrains.kotlin.asJava.KotlinAsJavaSupport
|
||||
@@ -20,7 +23,10 @@ import org.jetbrains.kotlin.light.classes.symbol.classes.getOrCreateFirLightClas
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.parentOrNull
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
import org.jetbrains.kotlin.psi.KtElement
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi.KtScript
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty
|
||||
|
||||
class IDEKotlinAsJavaFirSupport(private val project: Project) : KotlinAsJavaSupport() {
|
||||
@@ -62,14 +68,9 @@ class IDEKotlinAsJavaFirSupport(private val project: Project) : KotlinAsJavaSupp
|
||||
override fun findClassOrObjectDeclarations(fqName: FqName, searchScope: GlobalSearchScope): Collection<KtClassOrObject> =
|
||||
fqName.toClassIdSequence().flatMap {
|
||||
project.createDeclarationProvider(searchScope).getClassesByClassId(it)
|
||||
}.filter {
|
||||
//TODO Do not return LC came from LibrarySources
|
||||
when (it.getKtModule(project)) {
|
||||
is KtLibrarySourceModule -> false
|
||||
is KtNotUnderContentRootModule -> false
|
||||
else -> true
|
||||
}
|
||||
}.toSet()
|
||||
}
|
||||
.filter { it.isFromSourceOrLibraryBinary(project) }
|
||||
.toSet()
|
||||
|
||||
override fun packageExists(fqName: FqName, scope: GlobalSearchScope): Boolean =
|
||||
project.createPackageProvider(scope).doKotlinPackageExists(fqName)
|
||||
@@ -80,8 +81,11 @@ class IDEKotlinAsJavaFirSupport(private val project: Project) : KotlinAsJavaSupp
|
||||
.map { fqn.child(it) }
|
||||
|
||||
override fun getLightClass(classOrObject: KtClassOrObject): KtLightClass? {
|
||||
if (!classOrObject.isFromSource()) return null
|
||||
return getOrCreateFirLightClass(classOrObject)
|
||||
return when (classOrObject.getKtModule(project)) {
|
||||
is KtSourceModule -> getOrCreateFirLightClass(classOrObject)
|
||||
is KtLibraryModule -> DecompiledLightClassesFactory.getLightClassForDecompiledClassOrObject(classOrObject, project)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
override fun getLightClassForScript(script: KtScript): KtLightClass =
|
||||
@@ -105,7 +109,7 @@ class IDEKotlinAsJavaFirSupport(private val project: Project) : KotlinAsJavaSupp
|
||||
project.createDeclarationProvider(scope)
|
||||
.getFacadeFilesInPackage(packageFqName)
|
||||
.asSequence()
|
||||
.filter { it.isFromSource() }
|
||||
.filter { it.isFromSourceOrLibraryBinary(project) }
|
||||
.groupBy { it.javaFileFacadeFqName }
|
||||
.mapNotNull {
|
||||
project.getService(SymbolLightClassFacadeCache::class.java)
|
||||
@@ -115,13 +119,13 @@ class IDEKotlinAsJavaFirSupport(private val project: Project) : KotlinAsJavaSupp
|
||||
override fun getFacadeNames(packageFqName: FqName, scope: GlobalSearchScope): Collection<String> =
|
||||
project.createDeclarationProvider(scope)
|
||||
.getFacadeFilesInPackage(packageFqName)
|
||||
.filter { it.isFromSource() }
|
||||
.filter { it.isFromSourceOrLibraryBinary(project) }
|
||||
.mapTo(mutableSetOf()) { it.javaFileFacadeFqName.shortName().asString() }
|
||||
|
||||
override fun findFilesForFacade(facadeFqName: FqName, scope: GlobalSearchScope): Collection<KtFile> {
|
||||
return project.createDeclarationProvider(scope)
|
||||
.findFilesForFacade(facadeFqName)
|
||||
.filter { it.isFromSource() }
|
||||
.filter { it.isFromSourceOrLibraryBinary(project) }
|
||||
}
|
||||
|
||||
override fun getFakeLightClass(classOrObject: KtClassOrObject): KtFakeLightClass =
|
||||
@@ -132,10 +136,10 @@ class IDEKotlinAsJavaFirSupport(private val project: Project) : KotlinAsJavaSupp
|
||||
}
|
||||
|
||||
|
||||
private fun KtElement.isFromSource(): Boolean {
|
||||
if (this is KtFile && isCompiled) {
|
||||
// small optimisation to not invoke expensive getKtModule
|
||||
return false
|
||||
private fun KtElement.isFromSourceOrLibraryBinary(project: Project): Boolean {
|
||||
return when (getKtModule(project)) {
|
||||
is KtSourceModule -> true
|
||||
is KtLibraryModule -> true
|
||||
else -> false
|
||||
}
|
||||
return getKtModule(project) is KtSourceModule
|
||||
}
|
||||
+33
-9
@@ -6,28 +6,35 @@
|
||||
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.decompiler.psi.file.KtClsFile
|
||||
import org.jetbrains.kotlin.analysis.providers.createProjectWideOutOfBlockModificationTracker
|
||||
import org.jetbrains.kotlin.light.classes.symbol.FirLightClassForFacade
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.analysis.utils.caches.*
|
||||
import org.jetbrains.kotlin.analysis.utils.collections.ConcurrentMapBasedCache
|
||||
import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade
|
||||
import org.jetbrains.kotlin.fileClasses.javaFileFacadeFqName
|
||||
import org.jetbrains.kotlin.light.classes.symbol.FirLightClassForFacade
|
||||
import org.jetbrains.kotlin.light.classes.symbol.decompiled.KtLightClassForDecompiledFacade
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
class SymbolLightClassFacadeCache(project: Project) {
|
||||
class SymbolLightClassFacadeCache(private val project: Project) {
|
||||
private val cache by softCachedValue(
|
||||
project,
|
||||
project.createProjectWideOutOfBlockModificationTracker()
|
||||
) {
|
||||
ConcurrentHashMap<FacadeKey, FirLightClassForFacade>()
|
||||
ConcurrentMapBasedCache<FacadeKey, KtLightClassForFacade?>(ConcurrentHashMap())
|
||||
}
|
||||
|
||||
fun getOrCreateSymbolLightFacade(
|
||||
ktFiles: List<KtFile>,
|
||||
facadeClassFqName: FqName,
|
||||
): FirLightClassForFacade? {
|
||||
): KtLightClassForFacade? {
|
||||
if (ktFiles.isEmpty()) return null
|
||||
val key = FacadeKey(facadeClassFqName, ktFiles.toSet())
|
||||
return cache.computeIfAbsent(key) {
|
||||
return cache.getOrPut(key) {
|
||||
getOrCreateFirLightFacadeNoCache(ktFiles, facadeClassFqName)
|
||||
}
|
||||
}
|
||||
@@ -35,9 +42,26 @@ class SymbolLightClassFacadeCache(project: Project) {
|
||||
private fun getOrCreateFirLightFacadeNoCache(
|
||||
ktFiles: List<KtFile>,
|
||||
facadeClassFqName: FqName,
|
||||
): FirLightClassForFacade {
|
||||
): KtLightClassForFacade? {
|
||||
val firstFile = ktFiles.first()
|
||||
return FirLightClassForFacade(firstFile.manager, facadeClassFqName, ktFiles)
|
||||
return when {
|
||||
ktFiles.none { it.isCompiled } ->
|
||||
return FirLightClassForFacade(firstFile.manager, facadeClassFqName, ktFiles)
|
||||
ktFiles.all { it.isCompiled } -> {
|
||||
val file = ktFiles.firstOrNull { it.javaFileFacadeFqName == facadeClassFqName } as? KtClsFile
|
||||
?: error("Can't find the representative decompiled file for $facadeClassFqName")
|
||||
val classOrObject = file.declarations.filterIsInstance<KtClassOrObject>().singleOrNull()
|
||||
val clsDelegate = DecompiledLightClassesFactory.createClsJavaClassFromVirtualFile(
|
||||
mirrorFile = file,
|
||||
classFile = file.virtualFile,
|
||||
correspondingClassOrObject = classOrObject,
|
||||
project = project,
|
||||
) ?: return null
|
||||
KtLightClassForDecompiledFacade(clsDelegate, clsDelegate.parent, file, classOrObject, ktFiles)
|
||||
}
|
||||
else ->
|
||||
error("Source and compiled files are mixed: $ktFiles}")
|
||||
}
|
||||
}
|
||||
|
||||
private data class FacadeKey(val fqName: FqName, val files: Set<KtFile>)
|
||||
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.decompiled
|
||||
|
||||
import com.intellij.psi.PsiClass
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.analysis.decompiled.light.classes.KtLightClassForDecompiledDeclaration
|
||||
import org.jetbrains.kotlin.analysis.decompiler.psi.file.KtClsFile
|
||||
import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade
|
||||
import org.jetbrains.kotlin.fileClasses.javaFileFacadeFqName
|
||||
import org.jetbrains.kotlin.load.java.structure.LightClassOriginKind
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
|
||||
internal class KtLightClassForDecompiledFacade(
|
||||
override val clsDelegate: PsiClass,
|
||||
clsParent: PsiElement,
|
||||
file: KtClsFile,
|
||||
kotlinOrigin: KtClassOrObject?,
|
||||
override val files: Collection<KtFile>,
|
||||
) : KtLightClassForDecompiledDeclaration(clsDelegate, clsParent, file, kotlinOrigin), KtLightClassForFacade {
|
||||
override fun getName(): String = super<KtLightClassForFacade>.getName()
|
||||
|
||||
override val facadeClassFqName: FqName = file.javaFileFacadeFqName
|
||||
|
||||
override val originKind: LightClassOriginKind
|
||||
get() = LightClassOriginKind.BINARY
|
||||
}
|
||||
Reference in New Issue
Block a user