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-api"))
|
||||||
implementation(project(":analysis:analysis-internal-utils"))
|
implementation(project(":analysis:analysis-internal-utils"))
|
||||||
implementation(project(":analysis:project-structure"))
|
implementation(project(":analysis:project-structure"))
|
||||||
|
implementation(project(":analysis:decompiled:light-classes-for-decompiled"))
|
||||||
implementation(intellijCore())
|
implementation(intellijCore())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+24
-20
@@ -8,7 +8,10 @@ package org.jetbrains.kotlin.light.classes.symbol
|
|||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.psi.PsiClass
|
import com.intellij.psi.PsiClass
|
||||||
import com.intellij.psi.search.GlobalSearchScope
|
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.createDeclarationProvider
|
||||||
import org.jetbrains.kotlin.analysis.providers.createPackageProvider
|
import org.jetbrains.kotlin.analysis.providers.createPackageProvider
|
||||||
import org.jetbrains.kotlin.asJava.KotlinAsJavaSupport
|
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.ClassId
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.name.parentOrNull
|
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
|
import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty
|
||||||
|
|
||||||
class IDEKotlinAsJavaFirSupport(private val project: Project) : KotlinAsJavaSupport() {
|
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> =
|
override fun findClassOrObjectDeclarations(fqName: FqName, searchScope: GlobalSearchScope): Collection<KtClassOrObject> =
|
||||||
fqName.toClassIdSequence().flatMap {
|
fqName.toClassIdSequence().flatMap {
|
||||||
project.createDeclarationProvider(searchScope).getClassesByClassId(it)
|
project.createDeclarationProvider(searchScope).getClassesByClassId(it)
|
||||||
}.filter {
|
}
|
||||||
//TODO Do not return LC came from LibrarySources
|
.filter { it.isFromSourceOrLibraryBinary(project) }
|
||||||
when (it.getKtModule(project)) {
|
.toSet()
|
||||||
is KtLibrarySourceModule -> false
|
|
||||||
is KtNotUnderContentRootModule -> false
|
|
||||||
else -> true
|
|
||||||
}
|
|
||||||
}.toSet()
|
|
||||||
|
|
||||||
override fun packageExists(fqName: FqName, scope: GlobalSearchScope): Boolean =
|
override fun packageExists(fqName: FqName, scope: GlobalSearchScope): Boolean =
|
||||||
project.createPackageProvider(scope).doKotlinPackageExists(fqName)
|
project.createPackageProvider(scope).doKotlinPackageExists(fqName)
|
||||||
@@ -80,8 +81,11 @@ class IDEKotlinAsJavaFirSupport(private val project: Project) : KotlinAsJavaSupp
|
|||||||
.map { fqn.child(it) }
|
.map { fqn.child(it) }
|
||||||
|
|
||||||
override fun getLightClass(classOrObject: KtClassOrObject): KtLightClass? {
|
override fun getLightClass(classOrObject: KtClassOrObject): KtLightClass? {
|
||||||
if (!classOrObject.isFromSource()) return null
|
return when (classOrObject.getKtModule(project)) {
|
||||||
return getOrCreateFirLightClass(classOrObject)
|
is KtSourceModule -> getOrCreateFirLightClass(classOrObject)
|
||||||
|
is KtLibraryModule -> DecompiledLightClassesFactory.getLightClassForDecompiledClassOrObject(classOrObject, project)
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getLightClassForScript(script: KtScript): KtLightClass =
|
override fun getLightClassForScript(script: KtScript): KtLightClass =
|
||||||
@@ -105,7 +109,7 @@ class IDEKotlinAsJavaFirSupport(private val project: Project) : KotlinAsJavaSupp
|
|||||||
project.createDeclarationProvider(scope)
|
project.createDeclarationProvider(scope)
|
||||||
.getFacadeFilesInPackage(packageFqName)
|
.getFacadeFilesInPackage(packageFqName)
|
||||||
.asSequence()
|
.asSequence()
|
||||||
.filter { it.isFromSource() }
|
.filter { it.isFromSourceOrLibraryBinary(project) }
|
||||||
.groupBy { it.javaFileFacadeFqName }
|
.groupBy { it.javaFileFacadeFqName }
|
||||||
.mapNotNull {
|
.mapNotNull {
|
||||||
project.getService(SymbolLightClassFacadeCache::class.java)
|
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> =
|
override fun getFacadeNames(packageFqName: FqName, scope: GlobalSearchScope): Collection<String> =
|
||||||
project.createDeclarationProvider(scope)
|
project.createDeclarationProvider(scope)
|
||||||
.getFacadeFilesInPackage(packageFqName)
|
.getFacadeFilesInPackage(packageFqName)
|
||||||
.filter { it.isFromSource() }
|
.filter { it.isFromSourceOrLibraryBinary(project) }
|
||||||
.mapTo(mutableSetOf()) { it.javaFileFacadeFqName.shortName().asString() }
|
.mapTo(mutableSetOf()) { it.javaFileFacadeFqName.shortName().asString() }
|
||||||
|
|
||||||
override fun findFilesForFacade(facadeFqName: FqName, scope: GlobalSearchScope): Collection<KtFile> {
|
override fun findFilesForFacade(facadeFqName: FqName, scope: GlobalSearchScope): Collection<KtFile> {
|
||||||
return project.createDeclarationProvider(scope)
|
return project.createDeclarationProvider(scope)
|
||||||
.findFilesForFacade(facadeFqName)
|
.findFilesForFacade(facadeFqName)
|
||||||
.filter { it.isFromSource() }
|
.filter { it.isFromSourceOrLibraryBinary(project) }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getFakeLightClass(classOrObject: KtClassOrObject): KtFakeLightClass =
|
override fun getFakeLightClass(classOrObject: KtClassOrObject): KtFakeLightClass =
|
||||||
@@ -132,10 +136,10 @@ class IDEKotlinAsJavaFirSupport(private val project: Project) : KotlinAsJavaSupp
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun KtElement.isFromSource(): Boolean {
|
private fun KtElement.isFromSourceOrLibraryBinary(project: Project): Boolean {
|
||||||
if (this is KtFile && isCompiled) {
|
return when (getKtModule(project)) {
|
||||||
// small optimisation to not invoke expensive getKtModule
|
is KtSourceModule -> true
|
||||||
return false
|
is KtLibraryModule -> true
|
||||||
|
else -> false
|
||||||
}
|
}
|
||||||
return getKtModule(project) is KtSourceModule
|
|
||||||
}
|
}
|
||||||
+33
-9
@@ -6,28 +6,35 @@
|
|||||||
package org.jetbrains.kotlin.light.classes.symbol.caches
|
package org.jetbrains.kotlin.light.classes.symbol.caches
|
||||||
|
|
||||||
import com.intellij.openapi.project.Project
|
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.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.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
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
|
||||||
class SymbolLightClassFacadeCache(project: Project) {
|
class SymbolLightClassFacadeCache(private val project: Project) {
|
||||||
private val cache by softCachedValue(
|
private val cache by softCachedValue(
|
||||||
project,
|
project,
|
||||||
project.createProjectWideOutOfBlockModificationTracker()
|
project.createProjectWideOutOfBlockModificationTracker()
|
||||||
) {
|
) {
|
||||||
ConcurrentHashMap<FacadeKey, FirLightClassForFacade>()
|
ConcurrentMapBasedCache<FacadeKey, KtLightClassForFacade?>(ConcurrentHashMap())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getOrCreateSymbolLightFacade(
|
fun getOrCreateSymbolLightFacade(
|
||||||
ktFiles: List<KtFile>,
|
ktFiles: List<KtFile>,
|
||||||
facadeClassFqName: FqName,
|
facadeClassFqName: FqName,
|
||||||
): FirLightClassForFacade? {
|
): KtLightClassForFacade? {
|
||||||
if (ktFiles.isEmpty()) return null
|
if (ktFiles.isEmpty()) return null
|
||||||
val key = FacadeKey(facadeClassFqName, ktFiles.toSet())
|
val key = FacadeKey(facadeClassFqName, ktFiles.toSet())
|
||||||
return cache.computeIfAbsent(key) {
|
return cache.getOrPut(key) {
|
||||||
getOrCreateFirLightFacadeNoCache(ktFiles, facadeClassFqName)
|
getOrCreateFirLightFacadeNoCache(ktFiles, facadeClassFqName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -35,9 +42,26 @@ class SymbolLightClassFacadeCache(project: Project) {
|
|||||||
private fun getOrCreateFirLightFacadeNoCache(
|
private fun getOrCreateFirLightFacadeNoCache(
|
||||||
ktFiles: List<KtFile>,
|
ktFiles: List<KtFile>,
|
||||||
facadeClassFqName: FqName,
|
facadeClassFqName: FqName,
|
||||||
): FirLightClassForFacade {
|
): KtLightClassForFacade? {
|
||||||
val firstFile = ktFiles.first()
|
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>)
|
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