[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.FqName
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
|
import org.jetbrains.kotlin.psi.psiUtil.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.isPrivate
|
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.isTopLevelKtOrJavaMember
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Can be null in scripts and for elements from non-jvm modules.
|
* 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 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
|
// Returns original declaration if given PsiElement is a Kotlin light element, and element itself otherwise
|
||||||
val PsiElement.unwrapped: PsiElement?
|
val PsiElement.unwrapped: PsiElement?
|
||||||
get() = when (this) {
|
get() = when (this) {
|
||||||
@@ -60,11 +134,10 @@ val PsiElement.unwrapped: PsiElement?
|
|||||||
val PsiElement.namedUnwrappedElement: PsiNamedElement?
|
val PsiElement.namedUnwrappedElement: PsiNamedElement?
|
||||||
get() = unwrapped?.getNonStrictParentOfType()
|
get() = unwrapped?.getNonStrictParentOfType()
|
||||||
|
|
||||||
|
|
||||||
val KtClassOrObject.hasInterfaceDefaultImpls: Boolean
|
val KtClassOrObject.hasInterfaceDefaultImpls: Boolean
|
||||||
get() = this is KtClass && isInterface() && hasNonAbstractMembers(this)
|
get() = this is KtClass && isInterface() && hasNonAbstractMembers(this)
|
||||||
|
|
||||||
private fun hasNonAbstractMembers(ktInterface: KtClass): Boolean = ktInterface.declarations.any(::isNonAbstractMember)
|
|
||||||
|
|
||||||
val KtClassOrObject.hasRepeatableAnnotationContainer: Boolean
|
val KtClassOrObject.hasRepeatableAnnotationContainer: Boolean
|
||||||
get() = this is KtClass &&
|
get() = this is KtClass &&
|
||||||
isAnnotation() &&
|
isAnnotation() &&
|
||||||
@@ -81,6 +154,8 @@ val KtClassOrObject.hasRepeatableAnnotationContainer: Boolean
|
|||||||
return hasRepeatableAnnotation
|
return hasRepeatableAnnotation
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun hasNonAbstractMembers(ktInterface: KtClass): Boolean = ktInterface.declarations.any(::isNonAbstractMember)
|
||||||
|
|
||||||
private fun isNonAbstractMember(member: KtDeclaration?): Boolean =
|
private fun isNonAbstractMember(member: KtDeclaration?): Boolean =
|
||||||
(member is KtNamedFunction && member.hasBody()) ||
|
(member is KtNamedFunction && member.hasBody()) ||
|
||||||
(member is KtProperty && (member.hasDelegateExpressionOrInitializer() || member.getter?.hasBody() ?: false || member.setter?.hasBody() ?: false))
|
(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)
|
private val REPEATABLE_ANNOTATION_CONTAINER_NAME = Name.identifier(JvmAbi.REPEATABLE_ANNOTATION_CONTAINER_NAME)
|
||||||
fun FqName.repeatableAnnotationContainerChild() = child(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? {
|
fun propertyNameByAccessor(name: String, accessor: KtLightMethod): String? {
|
||||||
val toRename = accessor.kotlinOrigin ?: return null
|
val toRename = accessor.kotlinOrigin ?: return null
|
||||||
if (toRename !is KtProperty && toRename !is KtParameter) return null
|
if (toRename !is KtProperty && toRename !is KtParameter) return null
|
||||||
@@ -148,6 +248,7 @@ fun fastCheckIsNullabilityApplied(lightElement: KtLightElement<*, PsiModifierLis
|
|||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
private val PsiMethod.canBeGetter: Boolean
|
private val PsiMethod.canBeGetter: Boolean
|
||||||
get() = JvmAbi.isGetterName(name) && parameters.isEmpty() && returnTypeElement?.textMatches("void") != true
|
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