Create annotation arguments in ultra-light classes via PsiElementFactory

This commit is contained in:
Denis Zharkov
2018-12-14 11:02:57 +03:00
parent 5c083d798e
commit e0975df1c0
4 changed files with 33 additions and 46 deletions
@@ -4,17 +4,16 @@ import com.intellij.lang.jvm.JvmModifier
import com.intellij.psi.*
import com.intellij.psi.impl.PsiImplUtil
import com.intellij.psi.impl.light.LightIdentifier
import com.intellij.psi.impl.light.LightTypeElement
import com.intellij.psi.impl.source.PsiClassReferenceType
import com.intellij.psi.meta.PsiMetaData
import com.intellij.psi.util.TypeConversionUtil
import org.jetbrains.annotations.NotNull
import org.jetbrains.annotations.Nullable
import org.jetbrains.kotlin.asJava.elements.KtLightAbstractAnnotation
import org.jetbrains.kotlin.asJava.elements.KtLightElementBase
import org.jetbrains.kotlin.asJava.elements.KtLightNullabilityAnnotation
import org.jetbrains.kotlin.asJava.elements.psiType
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.load.kotlin.TypeMappingMode
import org.jetbrains.kotlin.psi.KtCallElement
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.resolve.constants.*
@@ -127,13 +126,34 @@ private fun ConstantValue<*>.toAnnotationMemberValue(
this.value.mapNotNull { element -> element.toAnnotationMemberValue(arrayLiteralParent, ultraLightSupport) }
}
is KClassValue -> KtUltraLightPsiClassObjectAccessExpression(this, ultraLightSupport, parent)
is ErrorValue -> null
else -> KtUltraLightPsiLiteralForConstantValue(this, ultraLightSupport, parent)
else -> createPsiLiteral(parent)
}
private fun ConstantValue<*>.createPsiLiteral(parent: PsiElement): PsiExpression? {
val asString = asStringForPsiLiteral(parent)
val instance = PsiElementFactory.SERVICE.getInstance(parent.project)
return instance.createExpressionFromText(asString, parent)
}
private fun ConstantValue<*>.asStringForPsiLiteral(parent: PsiElement): String =
when (this) {
is NullValue -> "null"
is StringValue -> "\"$value\""
is KClassValue -> {
val arrayPart = "[]".repeat(value.arrayNestedness)
val fqName = value.classId.asSingleFqName()
val canonicalText = psiType(
fqName.asString(), parent, boxPrimitiveType = value.arrayNestedness > 0
).let(TypeConversionUtil::erasure).getCanonicalText(false)
"$canonicalText$arrayPart.class"
}
is EnumValue -> "${enumClassId.asSingleFqName().asString()}.$enumEntryName"
else -> value.toString()
}
private class KtUltraLightPsiArrayInitializerMemberValue(
val lightParent: PsiElement,
private val arguments: (KtUltraLightPsiArrayInitializerMemberValue) -> List<PsiAnnotationMemberValue>
@@ -149,39 +169,6 @@ private class KtUltraLightPsiArrayInitializerMemberValue(
override fun getText(): String = "{" + initializers.joinToString { it.text } + "}"
}
private open class KtUltraLightPsiLiteralForConstantValue(
private val constantValue: ConstantValue<*>,
private val ultraLightSupport: UltraLightSupport,
lightParent: PsiElement
) : KtLightElementBase(lightParent), PsiLiteralExpression {
override val kotlinOrigin: KtElement? get() = null
override fun getValue(): Any? = constantValue.value
override fun getType() =
constantValue.getType(ultraLightSupport.moduleDescriptor).asPsiType(ultraLightSupport, TypeMappingMode.DEFAULT, this)
override fun getText() = when (constantValue) {
is NullValue -> "<undefined value>"
is StringValue -> "\"${value.toString()}\""
is EnumValue -> constantValue.enumClassId.shortClassName.asString() + "." + constantValue.enumEntryName.asString()
else -> value.toString()
}
}
private class KtUltraLightPsiClassObjectAccessExpression(
kClassValue: KClassValue,
ultraLightSupport: UltraLightSupport,
parent: PsiElement
) : KtUltraLightPsiLiteralForConstantValue(kClassValue, ultraLightSupport, parent), PsiClassObjectAccessExpression {
override fun getOperand(): PsiTypeElement {
val argument = (type as? PsiClassReferenceType)?.parameters?.getOrNull(0)
return LightTypeElement(parent.manager, argument ?: type)
}
override fun getText() = operand.text + ".class"
}
fun PsiModifierListOwner.isPrivateOrParameterInPrivateMethod(): Boolean {
if (hasModifier(JvmModifier.PRIVATE)) return true
if (this !is PsiParameter) return false
@@ -78,7 +78,7 @@ class KtLightPsiClassObjectAccessExpression(override val kotlinOrigin: KtClassLi
override fun getOperand(): PsiTypeElement = LightTypeElement(kotlinOrigin.manager, type)
}
private fun psiType(kotlinFqName: String, context: PsiElement, boxPrimitiveType: Boolean = false): PsiType? {
internal fun psiType(kotlinFqName: String, context: PsiElement, boxPrimitiveType: Boolean = false): PsiType {
if (!boxPrimitiveType) {
when (kotlinFqName) {
"kotlin.Int" -> return PsiType.INT
@@ -132,4 +132,4 @@ class KtLightPsiNameValuePair private constructor(
override fun getLiteralValue(): String? = (getValue() as? PsiLiteralExpression)?.value?.toString()
}
}
@@ -78,7 +78,7 @@ class KtLightPsiClassObjectAccessExpression(override val kotlinOrigin: KtClassLi
override fun getOperand(): PsiTypeElement = LightTypeElement(kotlinOrigin.manager, type)
}
private fun psiType(kotlinFqName: String, context: PsiElement, boxPrimitiveType: Boolean = false): PsiType? {
internal fun psiType(kotlinFqName: String, context: PsiElement, boxPrimitiveType: Boolean = false): PsiType {
if (!boxPrimitiveType) {
when (kotlinFqName) {
"kotlin.Int" -> return PsiType.INT
@@ -132,4 +132,4 @@ class KtLightPsiNameValuePair private constructor(
override fun getLiteralValue(): String? = (getValue() as? PsiLiteralExpression)?.value?.toString()
}
}
@@ -33,8 +33,8 @@ public abstract interface Base /* Base*/ {
}
public final class Derived /* Derived*/ implements Base {
@Ann(x=1, y="134", z=String.class, e={Integer.class, Double.class}, depr=DeprecationLevel.WARNING, t={@SimpleAnn(value="243"), @SimpleAnn(value="4324")})
public void foo(@Ann(x=2, y="324", z=Ann.class, e={Byte.class, Base.class}, depr=DeprecationLevel.WARNING, t={@SimpleAnn(value="687"), @SimpleAnn(value="78")}) @org.jetbrains.annotations.NotNull() java.lang.String);
@Ann(x=1, y="134", z=java.lang.String.class, e={int.class, double.class}, depr=kotlin.DeprecationLevel.WARNING, t={@SimpleAnn(value="243"), @SimpleAnn(value="4324")})
public void foo(@Ann(x=2, y="324", z=Ann.class, e={byte.class, Base.class}, depr=kotlin.DeprecationLevel.WARNING, t={@SimpleAnn(value="687"), @SimpleAnn(value="78")}) @org.jetbrains.annotations.NotNull() java.lang.String);
@null()
public Derived(@org.jetbrains.annotations.NotNull() Base);