[psi] don't load text for compiled code
use stubs when possible, when stub doesn't contain anything, decompiled text won't contain it either, no sense to load
This commit is contained in:
-8
@@ -31,12 +31,4 @@ open class KtDecompiledFile(
|
||||
decompiledText.drop()
|
||||
}
|
||||
|
||||
fun <T : Any> getDeclaration(indexer: DecompiledTextIndexer<T>, key: T): KtDeclaration? {
|
||||
val range = decompiledText.get().index.getRange(indexer, key) ?: return null
|
||||
return PsiTreeUtil.findElementOfClassAtRange(this@KtDecompiledFile, range.startOffset, range.endOffset, KtDeclaration::class.java)
|
||||
}
|
||||
|
||||
fun <T : Any> hasDeclarationWithKey(indexer: DecompiledTextIndexer<T>, key: T): Boolean {
|
||||
return decompiledText.get().index.getRange(indexer, key) != null
|
||||
}
|
||||
}
|
||||
|
||||
+141
-41
@@ -6,22 +6,26 @@
|
||||
package org.jetbrains.kotlin.analysis.decompiler.psi.text
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.util.containers.ContainerUtil
|
||||
import org.jetbrains.kotlin.analysis.decompiler.psi.file.KtDecompiledFile
|
||||
import org.jetbrains.kotlin.analysis.decompiler.stub.COMPILED_DEFAULT_INITIALIZER
|
||||
import org.jetbrains.kotlin.analysis.decompiler.stub.COMPILED_DEFAULT_PARAMETER_VALUE
|
||||
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
|
||||
import org.jetbrains.kotlin.builtins.jvm.JvmBuiltInsSignatures
|
||||
import org.jetbrains.kotlin.builtins.StandardNames
|
||||
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.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.hasSuspendModifier
|
||||
import org.jetbrains.kotlin.psi.psiUtil.unwrapNullability
|
||||
import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes
|
||||
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
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
import org.jetbrains.kotlin.types.AbbreviatedType
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.typeUtil.isNullableAny
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
|
||||
|
||||
object ByDescriptorIndexer : DecompiledTextIndexer<String> {
|
||||
@@ -60,47 +64,117 @@ object ByDescriptorIndexer : DecompiledTextIndexer<String> {
|
||||
return getDeclarationForDescriptor(original.containingDeclaration, file)
|
||||
}
|
||||
|
||||
val descriptorKey = original.toStringKey()
|
||||
if (original is MemberDescriptor) {
|
||||
val declarationContainer: KtDeclarationContainer? = when {
|
||||
DescriptorUtils.isTopLevelDeclaration(original) -> file
|
||||
original.containingDeclaration is ClassDescriptor ->
|
||||
getDeclarationForDescriptor(original.containingDeclaration as ClassDescriptor, file) as? KtClassOrObject
|
||||
else -> null
|
||||
}
|
||||
|
||||
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 declarations = when {
|
||||
original is ConstructorDescriptor && declarationContainer is KtClass -> declarationContainer.allConstructors
|
||||
else -> declarationContainer.declarations.filter { it.name == descriptorName }
|
||||
}
|
||||
|
||||
if (declarationContainer != null) {
|
||||
val descriptorName = original.name.asString()
|
||||
val singleOrNull = declarationContainer.declarations.singleOrNull { it.name == descriptorName }
|
||||
if (singleOrNull != null) {
|
||||
return singleOrNull
|
||||
return declarations
|
||||
.firstOrNull { declaration ->
|
||||
if (original is CallableDescriptor) {
|
||||
declaration is KtCallableDeclaration && isSameCallable(declaration, original)
|
||||
} else declaration !is KtCallableDeclaration
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return file.getDeclaration(this, descriptorKey) ?: run {
|
||||
return getBuiltinsDescriptorKey(descriptor)?.let { file.getDeclaration(this, it) }
|
||||
}
|
||||
error("Should not be reachable")
|
||||
}
|
||||
|
||||
fun getBuiltinsDescriptorKey(descriptor: DeclarationDescriptor): String? {
|
||||
if (descriptor !is ClassDescriptor) return null
|
||||
fun isSameCallable(
|
||||
declaration: KtCallableDeclaration,
|
||||
original: CallableDescriptor
|
||||
): Boolean {
|
||||
if (!receiverTypesMatch(declaration.receiverTypeReference, original.extensionReceiverParameter)) return false
|
||||
|
||||
val classFqName = descriptor.fqNameUnsafe
|
||||
if (!JvmBuiltInsSignatures.isSerializableInJava(classFqName)) return null
|
||||
if (!returnTypesMatch(declaration, original)) return false
|
||||
if (!typeParametersMatch(declaration, original)) return false
|
||||
|
||||
val builtInDescriptor =
|
||||
DefaultBuiltIns.Instance.builtInsModule.resolveTopLevelClass(classFqName.toSafe(), NoLookupLocation.FROM_IDE)
|
||||
return builtInDescriptor?.toStringKey()
|
||||
if (!parametersMatch(declaration, original)) return false
|
||||
return true
|
||||
}
|
||||
|
||||
private fun returnTypesMatch(declaration: KtCallableDeclaration, descriptor: CallableDescriptor): Boolean {
|
||||
if (declaration is KtConstructor<*>) return true
|
||||
return areTypesTheSame(descriptor.returnType!!, declaration.typeReference!!)
|
||||
}
|
||||
|
||||
private fun typeParametersMatch(declaration: KtCallableDeclaration, descriptor: CallableDescriptor): Boolean {
|
||||
if (declaration.typeParameters.size != declaration.typeParameters.size) return false
|
||||
val boundsByName = declaration.typeConstraints.groupBy { it.subjectTypeParameterName?.getReferencedName() }
|
||||
descriptor.typeParameters.zip(declaration.typeParameters) { descriptorTypeParam, psiTypeParameter ->
|
||||
if (descriptorTypeParam.name.toString() != psiTypeParameter.name) return false
|
||||
val psiBounds = mutableListOf<KtTypeReference>()
|
||||
psiBounds.addIfNotNull(psiTypeParameter.extendsBound)
|
||||
boundsByName[psiTypeParameter.name]?.forEach {
|
||||
psiBounds.addIfNotNull(it.boundTypeReference)
|
||||
}
|
||||
val expectedBounds = descriptorTypeParam.upperBounds.filter { !it.isNullableAny() }
|
||||
if (psiBounds.size != expectedBounds.size) return false
|
||||
expectedBounds.zip(psiBounds) { expectedBound, candidateBound ->
|
||||
if (!areTypesTheSame(expectedBound, candidateBound)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
private fun parametersMatch(
|
||||
declaration: KtCallableDeclaration,
|
||||
original: CallableDescriptor
|
||||
): Boolean {
|
||||
if (declaration.valueParameters.size != original.valueParameters.size) {
|
||||
return false
|
||||
}
|
||||
declaration.valueParameters.zip(original.valueParameters).forEach { (ktParam, paramDesc) ->
|
||||
val isVarargs = ktParam.isVarArg
|
||||
if (isVarargs != (paramDesc.varargElementType != null)) {
|
||||
return false
|
||||
}
|
||||
if (!areTypesTheSame(if (isVarargs) paramDesc.varargElementType!! else paramDesc.type, ktParam.typeReference!!)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
private fun receiverTypesMatch(
|
||||
ktTypeReference: KtTypeReference?,
|
||||
receiverParameter: ReceiverParameterDescriptor?,
|
||||
): Boolean {
|
||||
if (ktTypeReference != null) {
|
||||
if (receiverParameter == null) return false
|
||||
val receiverType = receiverParameter.type
|
||||
if (!areTypesTheSame(receiverType, ktTypeReference)) {
|
||||
return false
|
||||
}
|
||||
} else if (receiverParameter != null) return false
|
||||
return true
|
||||
}
|
||||
|
||||
private fun areTypesTheSame(
|
||||
kotlinType: KotlinType,
|
||||
ktTypeReference: KtTypeReference
|
||||
): Boolean {
|
||||
val qualifiedName = getQualifiedName(
|
||||
ktTypeReference.typeElement,
|
||||
ktTypeReference.getAllModifierLists().any { it.hasSuspendModifier() }) ?: return false
|
||||
val declarationDescriptor =
|
||||
((kotlinType as? AbbreviatedType)?.abbreviation ?: kotlinType).constructor.declarationDescriptor ?: return false
|
||||
if (declarationDescriptor is TypeParameterDescriptor) {
|
||||
return declarationDescriptor.name.asString() == qualifiedName
|
||||
}
|
||||
return declarationDescriptor.fqNameSafe.asString() == qualifiedName
|
||||
}
|
||||
|
||||
private fun DeclarationDescriptor.toStringKey(): String {
|
||||
@@ -118,3 +192,29 @@ object ByDescriptorIndexer : DecompiledTextIndexer<String> {
|
||||
|
||||
private val LOG = Logger.getInstance(this::class.java)
|
||||
}
|
||||
|
||||
fun getQualifiedName(typeElement: KtTypeElement?, isSuspend: Boolean): String? {
|
||||
val referencedName = when (typeElement) {
|
||||
is KtUserType -> getQualifiedName(typeElement)
|
||||
is KtFunctionType -> {
|
||||
var parametersCount = typeElement.parameters.size
|
||||
typeElement.receiverTypeReference?.let { parametersCount++ }
|
||||
if (isSuspend) {
|
||||
StandardNames.getSuspendFunctionClassId(parametersCount).asFqNameString()
|
||||
} else {
|
||||
StandardNames.getFunctionClassId(parametersCount).asFqNameString()
|
||||
}
|
||||
}
|
||||
is KtNullableType -> getQualifiedName(typeElement.unwrapNullability(), isSuspend)
|
||||
else -> null
|
||||
}
|
||||
return referencedName
|
||||
}
|
||||
|
||||
private fun getQualifiedName(userType: KtUserType): String? {
|
||||
val qualifier = userType.qualifier ?: return userType.referencedName
|
||||
return getQualifiedName(qualifier) + "." + userType.referencedName
|
||||
}
|
||||
|
||||
fun KtElementImplStub<*>.getAllModifierLists(): Array<out KtDeclarationModifierList> =
|
||||
getStubOrPsiChildren(KtStubElementTypes.MODIFIER_LIST, KtStubElementTypes.MODIFIER_LIST.arrayFactory)
|
||||
|
||||
+2
-12
@@ -19,18 +19,8 @@ import org.jetbrains.kotlin.psi.KtDeclaration
|
||||
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)) {
|
||||
findByStubs(file, relativeClassName, member, memberName)?.let { return it }
|
||||
}
|
||||
|
||||
val declaration = file.getDeclaration(BySignatureIndexer, key) ?: return null
|
||||
return if (member is PsiMethod && member.isConstructor && declaration is KtClassOrObject) {
|
||||
declaration.primaryConstructor ?: declaration
|
||||
} else {
|
||||
declaration
|
||||
}
|
||||
val memberName = member.name ?: return null
|
||||
return findByStubs(file, relativeClassName, member, memberName)
|
||||
}
|
||||
}
|
||||
|
||||
+150
-9
@@ -6,15 +6,25 @@
|
||||
package org.jetbrains.kotlin.analysis.decompiled.light.classes.origin
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.psi.PsiField
|
||||
import com.intellij.psi.PsiMember
|
||||
import com.intellij.psi.PsiMethod
|
||||
import com.intellij.psi.*
|
||||
import org.jetbrains.kotlin.analysis.decompiler.psi.file.KtClsFile
|
||||
import org.jetbrains.kotlin.asJava.syntheticAccessors
|
||||
import org.jetbrains.kotlin.analysis.decompiler.psi.text.getAllModifierLists
|
||||
import org.jetbrains.kotlin.analysis.decompiler.psi.text.getQualifiedName
|
||||
import org.jetbrains.kotlin.asJava.elements.psiType
|
||||
import org.jetbrains.kotlin.builtins.StandardNames
|
||||
import org.jetbrains.kotlin.constant.StringValue
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||
import org.jetbrains.kotlin.load.java.propertyNameByGetMethodName
|
||||
import org.jetbrains.kotlin.load.java.propertyNamesBySetMethodName
|
||||
import org.jetbrains.kotlin.load.kotlin.MemberSignature
|
||||
import org.jetbrains.kotlin.name.JvmNames
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.hasSuspendModifier
|
||||
import org.jetbrains.kotlin.psi.stubs.impl.KotlinAnnotationEntryStubImpl
|
||||
import org.jetbrains.kotlin.type.MapPsiToAsmDesc
|
||||
import org.jetbrains.kotlin.utils.SmartList
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
abstract class KotlinDeclarationInCompiledFileSearcher {
|
||||
@@ -49,26 +59,157 @@ abstract class KotlinDeclarationInCompiledFileSearcher {
|
||||
classOrFile
|
||||
else {
|
||||
relativeClassName.fold(classOrFile) { declaration: KtDeclarationContainer?, name: Name ->
|
||||
declaration?.declarations?.singleOrNull() { it is KtClassOrObject && it.name == name.asString() } as? KtClassOrObject
|
||||
declaration?.declarations?.singleOrNull { it is KtClassOrObject && it.name == name.asString() } as? KtClassOrObject
|
||||
}
|
||||
} ?: return null
|
||||
|
||||
if (member is PsiMethod && member.isConstructor) {
|
||||
return container.safeAs<KtClassOrObject>()?.takeIf { it.name == memberName }?.allConstructors?.singleOrNull()
|
||||
return container.safeAs<KtClassOrObject>()
|
||||
?.takeIf { it.name == memberName }
|
||||
?.allConstructors
|
||||
?.firstOrNull { doParametersMatch(member, it) }
|
||||
}
|
||||
|
||||
val declarations = container.declarations
|
||||
return when (member) {
|
||||
is PsiMethod -> {
|
||||
val names = member.syntheticAccessors(withoutOverrideCheck = true).map(Name::asString) + memberName
|
||||
declarations.singleOrNull { it.name in names }
|
||||
val names = SmartList(memberName)
|
||||
val setter = if (JvmAbi.isGetterName(memberName) && !PsiType.VOID.equals(member.returnType)) {
|
||||
propertyNameByGetMethodName(Name.identifier(memberName))?.let { names.add(it.identifier) }
|
||||
false
|
||||
} else if (JvmAbi.isSetterName(memberName) && PsiType.VOID.equals(member.returnType)) {
|
||||
propertyNamesBySetMethodName(Name.identifier(memberName)).forEach { names.add(it.identifier) }
|
||||
true
|
||||
} else true
|
||||
declarations
|
||||
.firstOrNull { declaration ->
|
||||
nameMatches(declaration, names) &&
|
||||
(declaration is KtNamedFunction && doParametersMatch(member, declaration) ||
|
||||
declaration is KtProperty && doPropertyMatch(member, declaration, setter))
|
||||
}
|
||||
}
|
||||
|
||||
is PsiField -> declarations.singleOrNull { it !is KtNamedFunction && it.name == memberName }
|
||||
is PsiField -> {
|
||||
if (container is KtObjectDeclaration && memberName == "INSTANCE") {
|
||||
return container
|
||||
}
|
||||
declarations.singleOrNull { it !is KtNamedFunction && it.name == memberName }
|
||||
}
|
||||
else -> declarations.singleOrNull { it.name == memberName }
|
||||
}
|
||||
}
|
||||
|
||||
private fun nameMatches(declaration: KtDeclaration?, names: MutableList<String>): Boolean {
|
||||
if (getJvmName(declaration) in names) return true
|
||||
return declaration is KtProperty && (getJvmName(declaration.getter) in names || getJvmName(declaration.setter) in names)
|
||||
}
|
||||
|
||||
private fun getJvmName(declaration: KtDeclaration?): String? {
|
||||
if (declaration == null) return null
|
||||
val annotationEntry = declaration.annotationEntries.firstOrNull {
|
||||
it.calleeExpression?.constructorReferenceExpression?.getReferencedName() == JvmNames.JVM_NAME_SHORT
|
||||
}
|
||||
if (annotationEntry != null) {
|
||||
val constantValue = (annotationEntry.stub as? KotlinAnnotationEntryStubImpl)?.valueArguments?.get(Name.identifier("name"))
|
||||
if (constantValue is StringValue) {
|
||||
return constantValue.value
|
||||
}
|
||||
}
|
||||
return declaration.name
|
||||
}
|
||||
|
||||
private fun doPropertyMatch(member: PsiMethod, property: KtProperty, setter: Boolean): Boolean {
|
||||
val ktTypes = mutableListOf<KtTypeReference>()
|
||||
property.contextReceivers.forEach { ktTypes.add(it.typeReference()!!) }
|
||||
property.receiverTypeReference?.let { ktTypes.add(it) }
|
||||
property.typeReference?.let { ktTypes.add(it) }
|
||||
|
||||
val psiTypes = mutableListOf<PsiType>()
|
||||
member.parameterList.parameters.forEach { psiTypes.add(it.type) }
|
||||
if (!setter) {
|
||||
val returnType = member.returnType ?: return false
|
||||
psiTypes.add(returnType)
|
||||
}
|
||||
|
||||
if (ktTypes.size != psiTypes.size) return false
|
||||
ktTypes.zip(psiTypes).forEach { (ktType, psiType) ->
|
||||
if (!areTypesTheSame(ktType, psiType, false)) return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
private fun doParametersMatch(member: PsiMethod, ktNamedFunction: KtFunction): Boolean {
|
||||
if (!doTypeParameters(member, ktNamedFunction)) {
|
||||
return false
|
||||
}
|
||||
val ktTypes = mutableListOf<KtTypeReference>()
|
||||
ktNamedFunction.contextReceivers.forEach { ktTypes.add(it.typeReference()!!) }
|
||||
ktNamedFunction.receiverTypeReference?.let { ktTypes.add(it) }
|
||||
val parametersCount = member.parameterList.parametersCount
|
||||
val isJvmOverloads = ktNamedFunction.annotationEntries.any {
|
||||
it.calleeExpression?.constructorReferenceExpression?.getReferencedName() ==
|
||||
JvmNames.JVM_OVERLOADS_FQ_NAME.shortName().asString()
|
||||
}
|
||||
val firstDefaultParametersToPass = if (isJvmOverloads) {
|
||||
val totalNumberOfParametersWithDefaultValues = ktNamedFunction.valueParameters.filter { it.hasDefaultValue() }.size
|
||||
val numberOfSkippedParameters = ktNamedFunction.valueParameters.size + ktTypes.size - parametersCount
|
||||
totalNumberOfParametersWithDefaultValues - numberOfSkippedParameters
|
||||
} else 0
|
||||
var defaultParamIdx = 0
|
||||
for (valueParameter in ktNamedFunction.valueParameters) {
|
||||
if (isJvmOverloads && valueParameter.hasDefaultValue()) {
|
||||
if (defaultParamIdx >= firstDefaultParametersToPass) {
|
||||
continue
|
||||
}
|
||||
defaultParamIdx++
|
||||
}
|
||||
|
||||
ktTypes.add(valueParameter.typeReference!!)
|
||||
}
|
||||
if (parametersCount != ktTypes.size) return false
|
||||
member.parameterList.parameters.map { it.type }
|
||||
.zip(ktTypes)
|
||||
.forEach { (psiType, ktTypeRef) ->
|
||||
if (!areTypesTheSame(ktTypeRef, psiType, (ktTypeRef.parent as? KtParameter)?.isVarArg == true)) return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
private fun doTypeParameters(member: PsiMethod, ktNamedFunction: KtFunction): Boolean {
|
||||
if (member.typeParameters.size != ktNamedFunction.typeParameters.size) return false
|
||||
val boundsByName = ktNamedFunction.typeConstraints.groupBy { it.subjectTypeParameterName?.getReferencedName() }
|
||||
member.typeParameters.zip(ktNamedFunction.typeParameters) { psiTypeParam, ktTypeParameter ->
|
||||
if (psiTypeParam.name.toString() != ktTypeParameter.name) return false
|
||||
val psiBounds = mutableListOf<KtTypeReference>()
|
||||
psiBounds.addIfNotNull(ktTypeParameter.extendsBound)
|
||||
boundsByName[ktTypeParameter.name]?.forEach {
|
||||
psiBounds.addIfNotNull(it.boundTypeReference)
|
||||
}
|
||||
val expectedBounds = psiTypeParam.extendsListTypes
|
||||
if (psiBounds.size != expectedBounds.size) return false
|
||||
expectedBounds.zip(psiBounds) { expectedBound, candidateBound ->
|
||||
if (!areTypesTheSame(candidateBound, expectedBound, false)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare erased types
|
||||
*/
|
||||
private fun areTypesTheSame(ktTypeRef: KtTypeReference, psiType: PsiType, varArgs: Boolean): Boolean {
|
||||
val qualifiedName =
|
||||
getQualifiedName(ktTypeRef.typeElement, ktTypeRef.getAllModifierLists().any { it.hasSuspendModifier() }) ?: return false
|
||||
if (psiType is PsiArrayType && psiType.componentType !is PsiPrimitiveType) {
|
||||
return qualifiedName == StandardNames.FqNames.array.asString() ||
|
||||
varArgs && areTypesTheSame(ktTypeRef, psiType.componentType, false)
|
||||
}
|
||||
//currently functional types are unresolved and thus type comparison doesn't work
|
||||
return psiType.canonicalText.takeWhile { it != '<' } == psiType(qualifiedName, ktTypeRef).canonicalText
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun getInstance(): KotlinDeclarationInCompiledFileSearcher =
|
||||
ApplicationManager.getApplication().getService(KotlinDeclarationInCompiledFileSearcher::class.java)
|
||||
|
||||
+23
-3
@@ -12,7 +12,9 @@ import com.intellij.psi.search.GlobalSearchScope
|
||||
import org.jetbrains.kotlin.analysis.test.framework.test.configurators.AnalysisApiTestConfigurator
|
||||
import org.jetbrains.kotlin.analysis.utils.printer.PrettyPrinter
|
||||
import org.jetbrains.kotlin.asJava.toLightClass
|
||||
import org.jetbrains.kotlin.psi.KtClass
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
import org.jetbrains.kotlin.psi.KtEnumEntry
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi.psiUtil.forEachDescendantOfType
|
||||
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
||||
@@ -101,9 +103,27 @@ open class AbstractSymbolLightClassesStructureTestBase(
|
||||
private fun wrongInheritorStructure(line: String): Nothing = error("Can't parse '$line' line correctly")
|
||||
protected fun PrettyPrinter.handleFile(ktFile: KtFile) {
|
||||
val text = ktFile.text
|
||||
ktFile.forEachDescendantOfType<KtClassOrObject> { classOrObject ->
|
||||
handleClassDeclaration(classOrObject, text)
|
||||
appendLine()
|
||||
if (ktFile.isCompiled) {
|
||||
ktFile.declarations.forEach { classOrObject ->
|
||||
if (classOrObject is KtClassOrObject) {
|
||||
if (classOrObject is KtClass && classOrObject.isEnum()) {
|
||||
classOrObject.declarations.forEach { declaration ->
|
||||
if (declaration is KtEnumEntry) {
|
||||
handleClassDeclaration(declaration, text)
|
||||
appendLine()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
handleClassDeclaration(classOrObject, text)
|
||||
appendLine()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ktFile.forEachDescendantOfType<KtClassOrObject> { classOrObject ->
|
||||
handleClassDeclaration(classOrObject, text)
|
||||
appendLine()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -125,13 +125,17 @@ public class KtNamedFunction extends KtTypeParameterListOwnerStub<KotlinFunction
|
||||
@Nullable
|
||||
public KtExpression getBodyExpression() {
|
||||
KotlinFunctionStub stub = getStub();
|
||||
if (stub != null && !stub.hasBody()) {
|
||||
return null;
|
||||
if (stub != null) {
|
||||
if (!stub.hasBody()) {
|
||||
return null;
|
||||
}
|
||||
if (getContainingKtFile().isCompiled()) {
|
||||
//don't load ast
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return AstLoadingFilter.forceAllowTreeLoading(this.getContainingFile(), () ->
|
||||
findChildByClass(KtExpression.class)
|
||||
);
|
||||
return findChildByClass(KtExpression.class);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
@@ -279,9 +279,7 @@ public class KtProperty extends KtTypeParameterListOwnerStub<KotlinPropertyStub>
|
||||
}
|
||||
}
|
||||
|
||||
return AstLoadingFilter.forceAllowTreeLoading(this.getContainingFile(), () ->
|
||||
PsiTreeUtil.getNextSiblingOfType(findChildByType(EQ), KtExpression.class)
|
||||
);
|
||||
return PsiTreeUtil.getNextSiblingOfType(findChildByType(EQ), KtExpression.class);
|
||||
}
|
||||
|
||||
public boolean hasDelegateExpressionOrInitializer() {
|
||||
|
||||
@@ -89,13 +89,17 @@ public class KtPropertyAccessor extends KtDeclarationStub<KotlinPropertyAccessor
|
||||
@Override
|
||||
public KtExpression getBodyExpression() {
|
||||
KotlinPropertyAccessorStub stub = getStub();
|
||||
if (stub != null && !stub.hasBody()) {
|
||||
return null;
|
||||
if (stub != null) {
|
||||
if (!stub.hasBody()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (getContainingKtFile().isCompiled()) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return AstLoadingFilter.forceAllowTreeLoading(this.getContainingFile(), () ->
|
||||
findChildByClass(KtExpression.class)
|
||||
);
|
||||
return findChildByClass(KtExpression.class);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
@@ -225,6 +225,7 @@ inline fun <reified T : PsiElement> PsiElement.forEachDescendantOfType(
|
||||
crossinline canGoInside: (PsiElement) -> Boolean,
|
||||
noinline action: (T) -> Unit
|
||||
) {
|
||||
checkDecompiledText()
|
||||
this.accept(object : PsiRecursiveElementVisitor() {
|
||||
override fun visitElement(element: PsiElement) {
|
||||
if (canGoInside(element)) {
|
||||
@@ -257,6 +258,7 @@ inline fun <reified T : PsiElement> PsiElement.findDescendantOfType(
|
||||
crossinline canGoInside: (PsiElement) -> Boolean,
|
||||
noinline predicate: (T) -> Boolean = { true }
|
||||
): T? {
|
||||
checkDecompiledText()
|
||||
var result: T? = null
|
||||
this.accept(object : PsiRecursiveElementWalkingVisitor() {
|
||||
override fun visitElement(element: PsiElement) {
|
||||
@@ -274,6 +276,13 @@ inline fun <reified T : PsiElement> PsiElement.findDescendantOfType(
|
||||
return result
|
||||
}
|
||||
|
||||
fun PsiElement.checkDecompiledText() {
|
||||
val file = containingFile
|
||||
if (file is KtFile && file.isCompiled) {
|
||||
error("Attempt to load decompiled text, please use stubs instead. Decompile process might be slow and should be avoided")
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <reified T : PsiElement> PsiElement.collectDescendantsOfType(noinline predicate: (T) -> Boolean = { true }): List<T> {
|
||||
return collectDescendantsOfType({ true }, predicate)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user