Add UL support for const fields initializers

Fixed #KT-34081
This commit is contained in:
Igor Yakovlev
2019-11-22 21:34:44 +03:00
parent 775eb67219
commit 0ff77bd3c5
6 changed files with 82 additions and 37 deletions
@@ -10,16 +10,17 @@ import com.intellij.psi.*
import com.intellij.psi.impl.PsiImplUtil
import com.intellij.psi.impl.light.LightIdentifier
import com.intellij.psi.meta.PsiMetaData
import com.intellij.psi.util.TypeConversionUtil
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.psi.KtCallElement
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.resolve.constants.*
import org.jetbrains.kotlin.resolve.constants.AnnotationValue
import org.jetbrains.kotlin.resolve.constants.ArrayValue
import org.jetbrains.kotlin.resolve.constants.ConstantValue
import org.jetbrains.kotlin.resolve.constants.ErrorValue
class KtUltraLightNullabilityAnnotation(
member: KtUltraLightElementWithNullabilityAnnotation<*, *>,
@@ -120,31 +121,6 @@ private fun ConstantValue<*>.toAnnotationMemberValue(
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 value = (value as KClassValue.Value.NormalClass).value
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>
@@ -135,12 +135,22 @@ internal open class KtUltraLightFieldImpl protected constructor(
override fun getContainingClass() = containingClass
override fun getContainingFile(): PsiFile? = containingClass.containingFile
override fun computeConstantValue(): Any? =
if (hasModifierProperty(PsiModifier.FINAL) &&
(TypeConversionUtil.isPrimitiveAndNotNull(_type) || _type.equalsToText(CommonClassNames.JAVA_LANG_STRING))
)
(declaration.resolve() as? VariableDescriptor)?.compileTimeInitializer?.value
else null
private val _initializer by lazyPub {
_constantInitializer?.createPsiLiteral(declaration)
}
override fun getInitializer(): PsiExpression? = _initializer
override fun hasInitializer(): Boolean = initializer !== null
private val _constantInitializer by lazyPub {
if ((declaration as? KtProperty)?.hasInitializer() != true) return@lazyPub null
if (!hasModifierProperty(PsiModifier.FINAL)) return@lazyPub null
if (!TypeConversionUtil.isPrimitiveAndNotNull(_type) && !_type.equalsToText(CommonClassNames.JAVA_LANG_STRING)) return@lazyPub null
propertyDescriptor?.compileTimeInitializer
}
override fun computeConstantValue(): Any? = _constantInitializer?.value
override fun computeConstantValue(visitedVars: MutableSet<PsiVariable>?): Any? = computeConstantValue()
@@ -16,6 +16,7 @@ import com.intellij.psi.impl.compiled.ClsTypeElementImpl
import com.intellij.psi.impl.compiled.SignatureParsing
import com.intellij.psi.impl.compiled.StubBuildingVisitor
import com.intellij.psi.impl.light.*
import com.intellij.psi.util.TypeConversionUtil
import com.intellij.util.BitUtil.isSet
import com.intellij.util.containers.ContainerUtil
import org.jetbrains.kotlin.asJava.LightClassGenerationSupport
@@ -23,6 +24,7 @@ import org.jetbrains.kotlin.asJava.UltraLightClassModifierExtension
import org.jetbrains.kotlin.asJava.builder.LightMemberOriginForDeclaration
import org.jetbrains.kotlin.asJava.elements.KotlinLightTypeParameterListBuilder
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
import org.jetbrains.kotlin.asJava.elements.psiType
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap
import org.jetbrains.kotlin.codegen.AsmUtil
@@ -41,7 +43,7 @@ import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.annotations.JVM_STATIC_ANNOTATION_FQ_NAME
import org.jetbrains.kotlin.resolve.annotations.argumentValue
import org.jetbrains.kotlin.resolve.constants.EnumValue
import org.jetbrains.kotlin.resolve.constants.*
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKind
@@ -355,6 +357,35 @@ private fun toQualifiedName(userType: KtUserType): FqName? {
return FqName.fromSegments(ContainerUtil.reverse(reversedNames))
}
internal 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 value = (value as KClassValue.Value.NormalClass).value
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 -> when (value) {
is Long -> "${value}L"
is Float -> "${value}f"
else -> value.toString()
}
}
/***
* @see org.jetbrains.kotlin.codegen.ImplementationBodyCodegen
*/
@@ -45,7 +45,7 @@ final class null /* null*/ {
@null()
public static final java.lang.Object INSTANCE;
private static final java.lang.String fy /* constant value text */;
private static final java.lang.String fy = "text" /* initializer type: java.lang.String */ /* constant value text */;
@org.jetbrains.annotations.NotNull()
public final java.lang.String getFy();
@@ -104,7 +104,7 @@ final class null /* null*/ {
@null()
public static final java.lang.Object INSTANCE;
private static final java.lang.String fy /* constant value text */;
private static final java.lang.String fy = "text" /* initializer type: java.lang.String */ /* constant value text */;
@org.jetbrains.annotations.NotNull()
public final java.lang.String getFy();
+22
View File
@@ -29,3 +29,25 @@ object Obj : java.lang.Runnable {
override fun run() {}
@JvmStatic fun zoo(): Int = 2
}
object ConstContainer {
const val str = "one" // String
const val one = 1 // Int
const val oneLong = 1L // Long
const val complexLong = 1L + 1 // Long
const val e = 2.7182818284 // Double
const val eFloat = 2.7182818284f // Float
const val complexFloat = 2.7182818284f + 2.4 // Float
}
class ClassWithConstContainer {
companion object {
const val str = "one" // String
const val one = 1 // Int
const val oneLong = 1L // Long
const val complexLong = 1L + 1 // Long
const val e = 2.7182818284 // Double
const val eFloat = 2.7182818284f // Float
const val complexFloat = 2.7182818284f + 2.4 // Float
}
}
@@ -170,7 +170,13 @@ object UltraLightChecker {
if (this is PsiParameter && this.isVarArgs) {
result += " /* vararg */"
}
if (hasInitializer()) {
result += " = ${initializer?.text} /* initializer type: ${initializer?.type?.renderType()} */"
}
computeConstantValue()?.let { result += " /* constant value $it */" }
return result
}