[light classes] move lightClassUtils to light-classes-base module
^KT-53097
This commit is contained in:
+107
-6
@@ -21,10 +21,7 @@ import org.jetbrains.kotlin.load.java.propertyNamesBySetMethodName
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
||||
import org.jetbrains.kotlin.psi.psiUtil.isPrivate
|
||||
import org.jetbrains.kotlin.psi.psiUtil.isTopLevelKtOrJavaMember
|
||||
import org.jetbrains.kotlin.psi.psiUtil.*
|
||||
|
||||
/**
|
||||
* Can be null in scripts and for elements from non-jvm modules.
|
||||
@@ -48,6 +45,83 @@ fun KtFile.findFacadeClass(): KtLightClass? = KotlinAsJavaSupport.getInstance(pr
|
||||
|
||||
fun KtScript.toLightClass(): KtLightClass? = KotlinAsJavaSupport.getInstance(project).getLightClassForScript(this)
|
||||
|
||||
fun KtElement.toLightElements(): List<PsiNamedElement> = when (this) {
|
||||
is KtClassOrObject -> listOfNotNull(toLightClass())
|
||||
is KtNamedFunction,
|
||||
is KtConstructor<*> -> LightClassUtil.getLightClassMethods(this as KtFunction)
|
||||
is KtProperty -> LightClassUtil.getLightClassPropertyMethods(this).allDeclarations
|
||||
is KtPropertyAccessor -> listOfNotNull(LightClassUtil.getLightClassAccessorMethod(this))
|
||||
is KtParameter -> mutableListOf<PsiNamedElement>().also { elements ->
|
||||
toPsiParameters().toCollection(elements)
|
||||
LightClassUtil.getLightClassPropertyMethods(this).toCollection(elements)
|
||||
toAnnotationLightMethod()?.let(elements::add)
|
||||
}
|
||||
|
||||
is KtTypeParameter -> toPsiTypeParameters()
|
||||
is KtFile -> listOfNotNull(findFacadeClass())
|
||||
else -> listOf()
|
||||
}
|
||||
|
||||
fun PsiElement.toLightMethods(): List<PsiMethod> = when (this) {
|
||||
is KtFunction -> LightClassUtil.getLightClassMethods(this)
|
||||
is KtProperty -> LightClassUtil.getLightClassPropertyMethods(this).toList()
|
||||
is KtParameter -> LightClassUtil.getLightClassPropertyMethods(this).toList()
|
||||
is KtPropertyAccessor -> LightClassUtil.getLightClassAccessorMethods(this)
|
||||
is KtClass -> listOfNotNull(toLightClass()?.constructors?.firstOrNull())
|
||||
is PsiMethod -> listOf(this)
|
||||
else -> listOf()
|
||||
}
|
||||
|
||||
fun PsiElement.getRepresentativeLightMethod(): PsiMethod? = when (this) {
|
||||
is KtFunction -> LightClassUtil.getLightClassMethod(this)
|
||||
is KtProperty -> LightClassUtil.getLightClassPropertyMethods(this).getter
|
||||
is KtParameter -> LightClassUtil.getLightClassPropertyMethods(this).getter
|
||||
is KtPropertyAccessor -> LightClassUtil.getLightClassAccessorMethod(this)
|
||||
is PsiMethod -> this
|
||||
else -> null
|
||||
}
|
||||
|
||||
fun KtParameter.toPsiParameters(): Collection<PsiParameter> {
|
||||
val paramList = getNonStrictParentOfType<KtParameterList>() ?: return emptyList()
|
||||
|
||||
val paramIndex = paramList.parameters.indexOf(this)
|
||||
if (paramIndex < 0) return emptyList()
|
||||
val owner = paramList.parent
|
||||
val lightParamIndex = if (owner is KtDeclaration && owner.isExtensionDeclaration()) paramIndex + 1 else paramIndex
|
||||
|
||||
val methods: Collection<PsiMethod> = when (owner) {
|
||||
is KtFunction -> LightClassUtil.getLightClassMethods(owner)
|
||||
is KtPropertyAccessor -> LightClassUtil.getLightClassAccessorMethods(owner)
|
||||
else -> null
|
||||
} ?: return emptyList()
|
||||
|
||||
return methods.mapNotNull { it.parameterList.parameters.getOrNull(lightParamIndex) }
|
||||
}
|
||||
|
||||
private fun KtParameter.toAnnotationLightMethod(): PsiMethod? {
|
||||
val parent = ownerFunction as? KtPrimaryConstructor ?: return null
|
||||
val containingClass = parent.getContainingClassOrObject()
|
||||
if (!containingClass.isAnnotation()) return null
|
||||
|
||||
return LightClassUtil.getLightClassMethod(this)
|
||||
}
|
||||
|
||||
fun KtParameter.toLightGetter(): PsiMethod? = LightClassUtil.getLightClassPropertyMethods(this).getter
|
||||
|
||||
fun KtParameter.toLightSetter(): PsiMethod? = LightClassUtil.getLightClassPropertyMethods(this).setter
|
||||
|
||||
fun KtTypeParameter.toPsiTypeParameters(): List<PsiTypeParameter> {
|
||||
val paramList = getNonStrictParentOfType<KtTypeParameterList>() ?: return listOf()
|
||||
|
||||
val paramIndex = paramList.parameters.indexOf(this)
|
||||
val ktDeclaration = paramList.getNonStrictParentOfType<KtDeclaration>() ?: return listOf()
|
||||
val lightOwners = ktDeclaration.toLightElements()
|
||||
|
||||
return lightOwners.mapNotNull { lightOwner ->
|
||||
(lightOwner as? PsiTypeParameterListOwner)?.typeParameters?.getOrNull(paramIndex)
|
||||
}
|
||||
}
|
||||
|
||||
// Returns original declaration if given PsiElement is a Kotlin light element, and element itself otherwise
|
||||
val PsiElement.unwrapped: PsiElement?
|
||||
get() = when (this) {
|
||||
@@ -60,11 +134,10 @@ val PsiElement.unwrapped: PsiElement?
|
||||
val PsiElement.namedUnwrappedElement: PsiNamedElement?
|
||||
get() = unwrapped?.getNonStrictParentOfType()
|
||||
|
||||
|
||||
val KtClassOrObject.hasInterfaceDefaultImpls: Boolean
|
||||
get() = this is KtClass && isInterface() && hasNonAbstractMembers(this)
|
||||
|
||||
private fun hasNonAbstractMembers(ktInterface: KtClass): Boolean = ktInterface.declarations.any(::isNonAbstractMember)
|
||||
|
||||
val KtClassOrObject.hasRepeatableAnnotationContainer: Boolean
|
||||
get() = this is KtClass &&
|
||||
isAnnotation() &&
|
||||
@@ -81,6 +154,8 @@ val KtClassOrObject.hasRepeatableAnnotationContainer: Boolean
|
||||
return hasRepeatableAnnotation
|
||||
}
|
||||
|
||||
private fun hasNonAbstractMembers(ktInterface: KtClass): Boolean = ktInterface.declarations.any(::isNonAbstractMember)
|
||||
|
||||
private fun isNonAbstractMember(member: KtDeclaration?): Boolean =
|
||||
(member is KtNamedFunction && member.hasBody()) ||
|
||||
(member is KtProperty && (member.hasDelegateExpressionOrInitializer() || member.getter?.hasBody() ?: false || member.setter?.hasBody() ?: false))
|
||||
@@ -91,6 +166,31 @@ fun FqName.defaultImplsChild() = child(DEFAULT_IMPLS_CLASS_NAME)
|
||||
private val REPEATABLE_ANNOTATION_CONTAINER_NAME = Name.identifier(JvmAbi.REPEATABLE_ANNOTATION_CONTAINER_NAME)
|
||||
fun FqName.repeatableAnnotationContainerChild() = child(REPEATABLE_ANNOTATION_CONTAINER_NAME)
|
||||
|
||||
@Suppress("unused")
|
||||
fun KtElement.toLightAnnotation(): PsiAnnotation? {
|
||||
val ktDeclaration = getStrictParentOfType<KtModifierList>()?.parent as? KtDeclaration ?: return null
|
||||
for (lightElement in ktDeclaration.toLightElements()) {
|
||||
if (lightElement !is PsiModifierListOwner) continue
|
||||
for (rootAnnotation in lightElement.modifierList?.annotations ?: continue) {
|
||||
for (annotation in rootAnnotation.withNestedAnnotations()) {
|
||||
if (annotation is KtLightElement<*, *> && annotation.kotlinOrigin == this)
|
||||
return annotation
|
||||
}
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private fun PsiAnnotation.withNestedAnnotations(): Sequence<PsiAnnotation> {
|
||||
fun handleValue(memberValue: PsiAnnotationMemberValue?): Sequence<PsiAnnotation> = when (memberValue) {
|
||||
is PsiArrayInitializerMemberValue -> memberValue.initializers.asSequence().flatMap { handleValue(it) }
|
||||
is PsiAnnotation -> memberValue.withNestedAnnotations()
|
||||
else -> emptySequence()
|
||||
}
|
||||
|
||||
return sequenceOf(this) + parameterList.attributes.asSequence().flatMap { handleValue(it.value) }
|
||||
}
|
||||
|
||||
fun propertyNameByAccessor(name: String, accessor: KtLightMethod): String? {
|
||||
val toRename = accessor.kotlinOrigin ?: return null
|
||||
if (toRename !is KtProperty && toRename !is KtParameter) return null
|
||||
@@ -148,6 +248,7 @@ fun fastCheckIsNullabilityApplied(lightElement: KtLightElement<*, PsiModifierLis
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
private val PsiMethod.canBeGetter: Boolean
|
||||
get() = JvmAbi.isGetterName(name) && parameters.isEmpty() && returnTypeElement?.textMatches("void") != true
|
||||
|
||||
@@ -1,151 +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.asJava
|
||||
|
||||
import com.intellij.psi.*
|
||||
import org.jetbrains.kotlin.asJava.classes.runReadAction
|
||||
import org.jetbrains.kotlin.asJava.elements.*
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.*
|
||||
import org.jetbrains.kotlin.resolve.DelegatingBindingTrace
|
||||
import org.jetbrains.kotlin.resolve.constants.ArrayValue
|
||||
import org.jetbrains.kotlin.resolve.constants.ConstantValue
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
|
||||
fun KtElement.toLightElements(): List<PsiNamedElement> = when (this) {
|
||||
is KtClassOrObject -> listOfNotNull(toLightClass())
|
||||
is KtNamedFunction,
|
||||
is KtConstructor<*> -> LightClassUtil.getLightClassMethods(this as KtFunction)
|
||||
is KtProperty -> LightClassUtil.getLightClassPropertyMethods(this).allDeclarations
|
||||
is KtPropertyAccessor -> listOfNotNull(LightClassUtil.getLightClassAccessorMethod(this))
|
||||
is KtParameter -> mutableListOf<PsiNamedElement>().also { elements ->
|
||||
toPsiParameters().toCollection(elements)
|
||||
LightClassUtil.getLightClassPropertyMethods(this).toCollection(elements)
|
||||
toAnnotationLightMethod()?.let(elements::add)
|
||||
}
|
||||
|
||||
is KtTypeParameter -> toPsiTypeParameters()
|
||||
is KtFile -> listOfNotNull(findFacadeClass())
|
||||
else -> listOf()
|
||||
}
|
||||
|
||||
fun PsiElement.toLightMethods(): List<PsiMethod> = when (this) {
|
||||
is KtFunction -> LightClassUtil.getLightClassMethods(this)
|
||||
is KtProperty -> LightClassUtil.getLightClassPropertyMethods(this).toList()
|
||||
is KtParameter -> LightClassUtil.getLightClassPropertyMethods(this).toList()
|
||||
is KtPropertyAccessor -> LightClassUtil.getLightClassAccessorMethods(this)
|
||||
is KtClass -> listOfNotNull(toLightClass()?.constructors?.firstOrNull())
|
||||
is PsiMethod -> listOf(this)
|
||||
else -> listOf()
|
||||
}
|
||||
|
||||
fun PsiElement.getRepresentativeLightMethod(): PsiMethod? = when (this) {
|
||||
is KtFunction -> LightClassUtil.getLightClassMethod(this)
|
||||
is KtProperty -> LightClassUtil.getLightClassPropertyMethods(this).getter
|
||||
is KtParameter -> LightClassUtil.getLightClassPropertyMethods(this).getter
|
||||
is KtPropertyAccessor -> LightClassUtil.getLightClassAccessorMethod(this)
|
||||
is PsiMethod -> this
|
||||
else -> null
|
||||
}
|
||||
|
||||
fun KtParameter.toPsiParameters(): Collection<PsiParameter> {
|
||||
val paramList = getNonStrictParentOfType<KtParameterList>() ?: return emptyList()
|
||||
|
||||
val paramIndex = paramList.parameters.indexOf(this)
|
||||
if (paramIndex < 0) return emptyList()
|
||||
val owner = paramList.parent
|
||||
val lightParamIndex = if (owner is KtDeclaration && owner.isExtensionDeclaration()) paramIndex + 1 else paramIndex
|
||||
|
||||
val methods: Collection<PsiMethod> = when (owner) {
|
||||
is KtFunction -> LightClassUtil.getLightClassMethods(owner)
|
||||
is KtPropertyAccessor -> LightClassUtil.getLightClassAccessorMethods(owner)
|
||||
else -> null
|
||||
} ?: return emptyList()
|
||||
|
||||
return methods.mapNotNull { it.parameterList.parameters.getOrNull(lightParamIndex) }
|
||||
}
|
||||
|
||||
private fun KtParameter.toAnnotationLightMethod(): PsiMethod? {
|
||||
val parent = ownerFunction as? KtPrimaryConstructor ?: return null
|
||||
val containingClass = parent.getContainingClassOrObject()
|
||||
if (!containingClass.isAnnotation()) return null
|
||||
|
||||
return LightClassUtil.getLightClassMethod(this)
|
||||
}
|
||||
|
||||
fun KtParameter.toLightGetter(): PsiMethod? = LightClassUtil.getLightClassPropertyMethods(this).getter
|
||||
|
||||
fun KtParameter.toLightSetter(): PsiMethod? = LightClassUtil.getLightClassPropertyMethods(this).setter
|
||||
|
||||
fun KtTypeParameter.toPsiTypeParameters(): List<PsiTypeParameter> {
|
||||
val paramList = getNonStrictParentOfType<KtTypeParameterList>() ?: return listOf()
|
||||
|
||||
val paramIndex = paramList.parameters.indexOf(this)
|
||||
val ktDeclaration = paramList.getNonStrictParentOfType<KtDeclaration>() ?: return listOf()
|
||||
val lightOwners = ktDeclaration.toLightElements()
|
||||
|
||||
return lightOwners.mapNotNull { lightOwner ->
|
||||
(lightOwner as? PsiTypeParameterListOwner)?.typeParameters?.getOrNull(paramIndex)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
fun KtElement.toLightAnnotation(): PsiAnnotation? {
|
||||
val ktDeclaration = getStrictParentOfType<KtModifierList>()?.parent as? KtDeclaration ?: return null
|
||||
for (lightElement in ktDeclaration.toLightElements()) {
|
||||
if (lightElement !is PsiModifierListOwner) continue
|
||||
for (rootAnnotation in lightElement.modifierList?.annotations ?: continue) {
|
||||
for (annotation in rootAnnotation.withNestedAnnotations()) {
|
||||
if (annotation is KtLightElement<*, *> && annotation.kotlinOrigin == this)
|
||||
return annotation
|
||||
}
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private fun PsiAnnotation.withNestedAnnotations(): Sequence<PsiAnnotation> {
|
||||
fun handleValue(memberValue: PsiAnnotationMemberValue?): Sequence<PsiAnnotation> = when (memberValue) {
|
||||
is PsiArrayInitializerMemberValue -> memberValue.initializers.asSequence().flatMap { handleValue(it) }
|
||||
is PsiAnnotation -> memberValue.withNestedAnnotations()
|
||||
else -> emptySequence()
|
||||
}
|
||||
|
||||
return sequenceOf(this) + parameterList.attributes.asSequence().flatMap { handleValue(it.value) }
|
||||
}
|
||||
|
||||
fun KtLightMethod.checkIsMangled(): Boolean {
|
||||
val demangledName = KotlinTypeMapper.InternalNameMapper.demangleInternalName(name) ?: return false
|
||||
val originalName = propertyNameByAccessor(demangledName, this) ?: demangledName
|
||||
return originalName == kotlinOrigin?.name
|
||||
}
|
||||
|
||||
fun computeExpression(expression: PsiElement): Any? {
|
||||
fun evalConstantValue(constantValue: ConstantValue<*>): Any? =
|
||||
if (constantValue is ArrayValue) {
|
||||
val items = constantValue.value.map { evalConstantValue(it) }
|
||||
items.singleOrNull() ?: items
|
||||
} else {
|
||||
constantValue.value
|
||||
}
|
||||
|
||||
val expressionToCompute = when (expression) {
|
||||
is KtLightElementBase -> expression.kotlinOrigin as? KtExpression ?: return null
|
||||
else -> return null
|
||||
}
|
||||
|
||||
val generationSupport = LightClassGenerationSupport.getInstance(expressionToCompute.project)
|
||||
val evaluator = generationSupport.createConstantEvaluator(expressionToCompute)
|
||||
|
||||
val constant = runReadAction {
|
||||
val evaluatorTrace = DelegatingBindingTrace(generationSupport.analyze(expressionToCompute), "Evaluating annotation argument")
|
||||
evaluator.evaluateExpression(expressionToCompute, evaluatorTrace)
|
||||
} ?: return null
|
||||
|
||||
if (constant.isError) return null
|
||||
return evalConstantValue(constant.toConstantValue(TypeUtils.NO_EXPECTED_TYPE))
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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.asJava
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.asJava.classes.runReadAction
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightElementBase
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
import org.jetbrains.kotlin.resolve.DelegatingBindingTrace
|
||||
import org.jetbrains.kotlin.resolve.constants.ArrayValue
|
||||
import org.jetbrains.kotlin.resolve.constants.ConstantValue
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
|
||||
fun KtLightMethod.checkIsMangled(): Boolean {
|
||||
val demangledName = KotlinTypeMapper.InternalNameMapper.demangleInternalName(name) ?: return false
|
||||
val originalName = propertyNameByAccessor(demangledName, this) ?: demangledName
|
||||
return originalName == kotlinOrigin?.name
|
||||
}
|
||||
|
||||
fun computeExpression(expression: PsiElement): Any? {
|
||||
fun evalConstantValue(constantValue: ConstantValue<*>): Any? =
|
||||
if (constantValue is ArrayValue) {
|
||||
val items = constantValue.value.map { evalConstantValue(it) }
|
||||
items.singleOrNull() ?: items
|
||||
} else {
|
||||
constantValue.value
|
||||
}
|
||||
|
||||
val expressionToCompute = when (expression) {
|
||||
is KtLightElementBase -> expression.kotlinOrigin as? KtExpression ?: return null
|
||||
else -> return null
|
||||
}
|
||||
|
||||
val generationSupport = LightClassGenerationSupport.getInstance(expressionToCompute.project)
|
||||
val evaluator = generationSupport.createConstantEvaluator(expressionToCompute)
|
||||
|
||||
val constant = runReadAction {
|
||||
val evaluatorTrace = DelegatingBindingTrace(generationSupport.analyze(expressionToCompute), "Evaluating annotation argument")
|
||||
evaluator.evaluateExpression(expressionToCompute, evaluatorTrace)
|
||||
} ?: return null
|
||||
|
||||
if (constant.isError) return null
|
||||
return evalConstantValue(constant.toConstantValue(TypeUtils.NO_EXPECTED_TYPE))
|
||||
}
|
||||
Reference in New Issue
Block a user