Migrate LightMemberOriginForCompiledElement from IJ repository
This commit is contained in:
@@ -8,10 +8,6 @@ dependencies {
|
||||
implementation(project(":compiler:frontend.java"))
|
||||
implementation(project(":core:compiler.common"))
|
||||
implementation(project(":compiler:light-classes"))
|
||||
implementation(project(":analysis:analysis-api-providers"))
|
||||
implementation(project(":analysis:analysis-api"))
|
||||
implementation(project(":analysis:analysis-internal-utils"))
|
||||
implementation(project(":analysis:project-structure"))
|
||||
implementation(project(":compiler:psi:cls-psi-stub-builder"))
|
||||
implementation(project(":compiler:psi:cls-psi-file-stub-builder"))
|
||||
implementation(intellijCore())
|
||||
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* 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.analysis.decompiler.psi.text
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import org.jetbrains.kotlin.analysis.decompiler.psi.file.KtDecompiledFile
|
||||
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
|
||||
import org.jetbrains.kotlin.builtins.jvm.JvmBuiltInsSignatures
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.psi.KtCallableDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtDeclarationContainer
|
||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.resolveTopLevelClass
|
||||
|
||||
|
||||
object ByDescriptorIndexer : DecompiledTextIndexer<String> {
|
||||
override fun indexDescriptor(descriptor: DeclarationDescriptor): Collection<String> {
|
||||
return listOf(descriptor.toStringKey())
|
||||
}
|
||||
|
||||
internal fun getDeclarationForDescriptor(descriptor: DeclarationDescriptor, file: KtDecompiledFile): KtDeclaration? {
|
||||
val original = descriptor.original
|
||||
|
||||
if (original is TypeAliasConstructorDescriptor) {
|
||||
return getDeclarationForDescriptor(original.typeAliasDescriptor, file)
|
||||
}
|
||||
|
||||
if (original is ValueParameterDescriptor) {
|
||||
val callable = original.containingDeclaration
|
||||
val callableDeclaration = getDeclarationForDescriptor(callable, file) as? KtCallableDeclaration ?: return null
|
||||
if (original.index >= callableDeclaration.valueParameters.size) {
|
||||
LOG.error(
|
||||
"Parameter count mismatch for ${DescriptorRenderer.DEBUG_TEXT.render(callable)}[${original.index}] vs " +
|
||||
callableDeclaration.valueParameterList?.text
|
||||
)
|
||||
return null
|
||||
}
|
||||
return callableDeclaration.valueParameters[original.index]
|
||||
}
|
||||
|
||||
if (original is ConstructorDescriptor && original.isPrimary) {
|
||||
val classOrObject = getDeclarationForDescriptor(original.containingDeclaration, file) as? KtClassOrObject
|
||||
return classOrObject?.primaryConstructor ?: classOrObject
|
||||
}
|
||||
|
||||
val descriptorKey = original.toStringKey()
|
||||
|
||||
if (!file.isContentsLoaded && original is MemberDescriptor) {
|
||||
val hasDeclarationByKey = file.hasDeclarationWithKey(this, descriptorKey) || (getBuiltinsDescriptorKey(descriptor)?.let {
|
||||
file.hasDeclarationWithKey(
|
||||
this,
|
||||
it
|
||||
)
|
||||
} ?: false)
|
||||
if (hasDeclarationByKey) {
|
||||
val declarationContainer: KtDeclarationContainer? = when {
|
||||
DescriptorUtils.isTopLevelDeclaration(original) -> file
|
||||
original.containingDeclaration is ClassDescriptor ->
|
||||
getDeclarationForDescriptor(original.containingDeclaration as ClassDescriptor, file) as? KtClassOrObject
|
||||
else -> null
|
||||
}
|
||||
|
||||
if (declarationContainer != null) {
|
||||
val descriptorName = original.name.asString()
|
||||
val singleOrNull = declarationContainer.declarations.singleOrNull { it.name == descriptorName }
|
||||
if (singleOrNull != null) {
|
||||
return singleOrNull
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return file.getDeclaration(this, descriptorKey) ?: run {
|
||||
return getBuiltinsDescriptorKey(descriptor)?.let { file.getDeclaration(this, it) }
|
||||
}
|
||||
}
|
||||
|
||||
fun getBuiltinsDescriptorKey(descriptor: DeclarationDescriptor): String? {
|
||||
if (descriptor !is ClassDescriptor) return null
|
||||
|
||||
val classFqName = descriptor.fqNameUnsafe
|
||||
if (!JvmBuiltInsSignatures.isSerializableInJava(classFqName)) return null
|
||||
|
||||
val builtInDescriptor =
|
||||
DefaultBuiltIns.Instance.builtInsModule.resolveTopLevelClass(classFqName.toSafe(), NoLookupLocation.FROM_IDE)
|
||||
return builtInDescriptor?.toStringKey()
|
||||
}
|
||||
|
||||
private fun DeclarationDescriptor.toStringKey(): String {
|
||||
return descriptorRendererForKeys.render(this)
|
||||
}
|
||||
|
||||
private val descriptorRendererForKeys = DescriptorRenderer.withOptions {
|
||||
defaultDecompilerRendererOptions()
|
||||
withDefinedIn = true
|
||||
renderUnabbreviatedType = false
|
||||
}
|
||||
|
||||
private val LOG = Logger.getInstance(this::class.java)
|
||||
}
|
||||
+184
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
* 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.analysis.decompiler.psi.text
|
||||
|
||||
import com.intellij.psi.PsiMember
|
||||
import com.intellij.psi.impl.compiled.SignatureParsing
|
||||
import com.intellij.util.cls.ClsFormatException
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||
import org.jetbrains.kotlin.load.kotlin.MemberSignature
|
||||
import org.jetbrains.kotlin.metadata.deserialization.getExtensionOrNull
|
||||
import org.jetbrains.kotlin.metadata.jvm.JvmProtoBuf
|
||||
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.calls.components.hasDefaultValue
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
|
||||
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
|
||||
import org.jetbrains.kotlin.resolve.jvm.annotations.findJvmOverloadsAnnotation
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassConstructorDescriptor
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPropertyDescriptor
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedSimpleFunctionDescriptor
|
||||
import java.text.CharacterIterator
|
||||
import java.text.StringCharacterIterator
|
||||
|
||||
private object ByJvmSignatureIndexer : DecompiledTextIndexer<ClassNameAndSignature> {
|
||||
override fun indexDescriptor(descriptor: DeclarationDescriptor): Collection<ClassNameAndSignature> {
|
||||
val signatures = arrayListOf<ClassNameAndSignature>()
|
||||
fun save(id: List<Name>, signature: MemberSignature) {
|
||||
signatures.add(ClassNameAndSignature(id, signature))
|
||||
}
|
||||
|
||||
fun ClassDescriptor.apply() {
|
||||
when (kind) {
|
||||
ClassKind.ENUM_ENTRY -> {
|
||||
val enumClass = containingDeclaration as ClassDescriptor
|
||||
val signature = MemberSignature.fromFieldNameAndDesc(name.asString(), enumClass.desc())
|
||||
save(enumClass.relativeClassName(), signature)
|
||||
}
|
||||
ClassKind.OBJECT -> {
|
||||
val instanceFieldSignature = MemberSignature.fromFieldNameAndDesc(JvmAbi.INSTANCE_FIELD, desc())
|
||||
save(relativeClassName(), instanceFieldSignature)
|
||||
if (isCompanionObject) {
|
||||
val signature = MemberSignature.fromFieldNameAndDesc(name.asString(), desc())
|
||||
save((containingDeclaration as? ClassDescriptor)?.relativeClassName().orEmpty(), signature)
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun DeserializedClassConstructorDescriptor.apply() {
|
||||
JvmProtoBufUtil.getJvmConstructorSignature(proto, nameResolver, typeTable)?.let {
|
||||
val id = (containingDeclaration as? ClassDescriptor)?.relativeClassName().orEmpty()
|
||||
val signature = MemberSignature.fromJvmMemberSignature(it)
|
||||
save(id, signature)
|
||||
}
|
||||
}
|
||||
|
||||
fun DeserializedSimpleFunctionDescriptor.apply() {
|
||||
JvmProtoBufUtil.getJvmMethodSignature(proto, nameResolver, typeTable)?.let {
|
||||
val id = (containingDeclaration as? ClassDescriptor)?.relativeClassName().orEmpty()
|
||||
|
||||
val signature = MemberSignature.fromJvmMemberSignature(it)
|
||||
save(id, signature)
|
||||
|
||||
if (findJvmOverloadsAnnotation() == null) return
|
||||
|
||||
val extensionShift = if (isExtension) 1 else 0
|
||||
|
||||
val omittedList = mutableListOf<Int>()
|
||||
valueParameters.asReversed().forEach { parameter ->
|
||||
if (parameter.hasDefaultValue()) {
|
||||
omittedList.add(parameter.index + extensionShift)
|
||||
val newDescriptor = excludeParametersFromDescriptor(it.desc, omittedList)
|
||||
if (newDescriptor != null) {
|
||||
val overloadedSignature = MemberSignature.fromMethodNameAndDesc(it.name, newDescriptor)
|
||||
save(id, overloadedSignature)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun DeserializedPropertyDescriptor.apply() {
|
||||
val className = (containingDeclaration as? ClassDescriptor)?.relativeClassName().orEmpty()
|
||||
val signature = proto.getExtensionOrNull(JvmProtoBuf.propertySignature)
|
||||
if (signature != null) {
|
||||
val fieldSignature = JvmProtoBufUtil.getJvmFieldSignature(proto, nameResolver, typeTable)
|
||||
if (fieldSignature != null) {
|
||||
save(className, MemberSignature.fromJvmMemberSignature(fieldSignature))
|
||||
}
|
||||
if (signature.hasGetter()) {
|
||||
save(className, MemberSignature.fromMethod(nameResolver, signature.getter))
|
||||
}
|
||||
if (signature.hasSetter()) {
|
||||
save(className, MemberSignature.fromMethod(nameResolver, signature.setter))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
when (descriptor) {
|
||||
is ClassDescriptor -> descriptor.apply()
|
||||
is DeserializedClassConstructorDescriptor -> descriptor.apply()
|
||||
is DeserializedSimpleFunctionDescriptor -> descriptor.apply()
|
||||
is DeserializedPropertyDescriptor -> descriptor.apply()
|
||||
}
|
||||
|
||||
return signatures
|
||||
}
|
||||
}
|
||||
|
||||
private fun excludeParametersFromDescriptor(descriptor: String, omittedParameters: List<Int>): String? {
|
||||
|
||||
fun tryParseParametersAndReturnType(): Pair<List<String>, String>? {
|
||||
val iterator = StringCharacterIterator(descriptor)
|
||||
|
||||
fun parseTypeString(): String? {
|
||||
val begin = iterator.index
|
||||
try {
|
||||
SignatureParsing.parseTypeString(iterator) { it }
|
||||
} catch (e: ClsFormatException) {
|
||||
return null
|
||||
}
|
||||
val end = iterator.index
|
||||
return descriptor.substring(begin, end)
|
||||
}
|
||||
|
||||
if (iterator.current() != '(') return null
|
||||
iterator.next()
|
||||
|
||||
if (iterator.current() == ')') {
|
||||
iterator.next()
|
||||
val returnType = parseTypeString() ?: return null
|
||||
return emptyList<String>() to returnType
|
||||
}
|
||||
|
||||
val parameterTypes = mutableListOf<String>()
|
||||
while (iterator.current() != ')' && iterator.current() != CharacterIterator.DONE) {
|
||||
parameterTypes += parseTypeString() ?: return null
|
||||
}
|
||||
|
||||
if (iterator.current() != ')') return null
|
||||
iterator.next()
|
||||
|
||||
val returnType = parseTypeString() ?: return null
|
||||
return parameterTypes to returnType
|
||||
}
|
||||
|
||||
val (parameterTypes, returnType) = tryParseParametersAndReturnType() ?: return null
|
||||
|
||||
val parametersList = parameterTypes
|
||||
.filterIndexed { index, _ -> index !in omittedParameters }
|
||||
.joinToString("")
|
||||
|
||||
return "($parametersList)$returnType"
|
||||
}
|
||||
|
||||
private fun ClassDescriptor.desc(): String = "L" + JvmClassName.byClassId(classId!!).internalName + ";"
|
||||
|
||||
fun PsiMember.relativeClassName(): List<Name> {
|
||||
return generateSequence(this.containingClass) { it.containingClass }.toList().dropLast(1).reversed().map { Name.identifier(it.name!!) }
|
||||
}
|
||||
|
||||
private fun ClassDescriptor.relativeClassName(): List<Name> {
|
||||
return classId!!.relativeClassName.pathSegments().drop(1)
|
||||
}
|
||||
|
||||
// every member is represented by its jvm signature and relative class name (which is easy to obtain from descriptors or cls psi)
|
||||
|
||||
// relative class name is a path containing inner/nested class names from top level class to the class containing this member (excluding top level class name)
|
||||
// Examples: for top level function or function in a top level class relativeClassName is empty
|
||||
// For: class TopLevel { class A { class B { fun f() } } }
|
||||
// relativeClassName for function 'f' will be [A, B]
|
||||
data class ClassNameAndSignature(val relativeClassName: List<Name>, val memberSignature: MemberSignature)
|
||||
|
||||
// expose with different type
|
||||
val BySignatureIndexer: DecompiledTextIndexer<*> = ByJvmSignatureIndexer
|
||||
@@ -0,0 +1,17 @@
|
||||
plugins {
|
||||
kotlin("jvm")
|
||||
id("jps-compatible")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api(project(":compiler:psi"))
|
||||
api(project(":analysis:decompiled:decompiler-to-psi"))
|
||||
api(project(":analysis:decompiled:light-classes-for-decompiled"))
|
||||
api(project(":compiler:light-classes"))
|
||||
implementation(intellijCore())
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
"main" { projectDefault() }
|
||||
"test" { none() }
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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.analysis.decompiled.light.classes.fe10
|
||||
|
||||
import com.intellij.psi.PsiMember
|
||||
import org.jetbrains.kotlin.analysis.decompiled.light.classes.origin.KotlinDeclarationInCompiledFileSearcher
|
||||
import org.jetbrains.kotlin.analysis.decompiler.psi.file.KtClsFile
|
||||
import org.jetbrains.kotlin.analysis.decompiler.psi.text.BySignatureIndexer
|
||||
import org.jetbrains.kotlin.analysis.decompiler.psi.text.ClassNameAndSignature
|
||||
import org.jetbrains.kotlin.analysis.decompiler.psi.text.relativeClassName
|
||||
import org.jetbrains.kotlin.load.kotlin.MemberSignature
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtDeclarationContainer
|
||||
|
||||
class KotlinDeclarationInCompiledFileSearcherFE10Impl: KotlinDeclarationInCompiledFileSearcher() {
|
||||
override fun findDeclarationInCompiledFile(file: KtClsFile, member: PsiMember, signature: MemberSignature): KtDeclaration? {
|
||||
val relativeClassName = member.relativeClassName()
|
||||
val key = ClassNameAndSignature(relativeClassName, signature)
|
||||
|
||||
val memberName = member.name
|
||||
|
||||
if (memberName != null && !file.isContentsLoaded && file.hasDeclarationWithKey(BySignatureIndexer, key)) {
|
||||
val container: KtDeclarationContainer? = if (relativeClassName.isEmpty())
|
||||
file
|
||||
else {
|
||||
val topClassOrObject = file.declarations.singleOrNull() as? KtClassOrObject
|
||||
relativeClassName.fold(topClassOrObject) { classOrObject, name ->
|
||||
classOrObject?.declarations?.singleOrNull { it.name == name.asString() } as? KtClassOrObject
|
||||
}
|
||||
}
|
||||
|
||||
val declaration = container?.declarations?.singleOrNull {
|
||||
it.name == memberName
|
||||
}
|
||||
|
||||
if (declaration != null) {
|
||||
return declaration
|
||||
}
|
||||
}
|
||||
|
||||
return file.getDeclaration(BySignatureIndexer, key)
|
||||
}
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* 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.analysis.decompiled.light.classes.origin
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.psi.PsiMember
|
||||
import org.jetbrains.kotlin.analysis.decompiler.psi.file.KtClsFile
|
||||
import org.jetbrains.kotlin.load.kotlin.MemberSignature
|
||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||
|
||||
abstract class KotlinDeclarationInCompiledFileSearcher {
|
||||
abstract fun findDeclarationInCompiledFile(file: KtClsFile, member: PsiMember, signature: MemberSignature): KtDeclaration?
|
||||
|
||||
companion object {
|
||||
fun getInstance(): KotlinDeclarationInCompiledFileSearcher =
|
||||
ApplicationManager.getApplication().getService(KotlinDeclarationInCompiledFileSearcher::class.java)
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -47,7 +47,7 @@ data class LightMemberOriginForCompiledField(val psiField: PsiField, val file: K
|
||||
override val originalElement: KtDeclaration? by lazyPub {
|
||||
val desc = MapPsiToAsmDesc.typeDesc(psiField.type)
|
||||
val signature = MemberSignature.fromFieldNameAndDesc(psiField.name, desc)
|
||||
findDeclarationInCompiledFile(file, psiField, signature)
|
||||
KotlinDeclarationInCompiledFileSearcher.getInstance().findDeclarationInCompiledFile(file, psiField, signature)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,6 +70,6 @@ data class LightMemberOriginForCompiledMethod(val psiMethod: PsiMethod, val file
|
||||
val desc = MapPsiToAsmDesc.methodDesc(psiMethod)
|
||||
val name = if (psiMethod.isConstructor) "<init>" else psiMethod.name
|
||||
val signature = MemberSignature.fromMethodNameAndDesc(name, desc)
|
||||
findDeclarationInCompiledFile(file, psiMethod, signature)
|
||||
KotlinDeclarationInCompiledFileSearcher.getInstance().findDeclarationInCompiledFile(file, psiMethod, signature)
|
||||
}
|
||||
}
|
||||
+2
-1
@@ -500,7 +500,8 @@ include ":generators:analysis-api-generator",
|
||||
":analysis:project-structure",
|
||||
":analysis:analysis-api-fe10",
|
||||
":analysis:decompiled:decompiler-to-psi",
|
||||
":analysis:decompiled:light-classes-for-decompiled"
|
||||
":analysis:decompiled:light-classes-for-decompiled",
|
||||
":analysis:decompiled:light-classes-for-decompiled-fe10"
|
||||
|
||||
|
||||
if (buildProperties.inJpsBuildIdeaSync) {
|
||||
|
||||
Reference in New Issue
Block a user