From 0ff77bd3c569f8bfcb28c1f711afa53e8fbea744 Mon Sep 17 00:00:00 2001 From: Igor Yakovlev Date: Fri, 22 Nov 2019 21:34:44 +0300 Subject: [PATCH] Add UL support for const fields initializers Fixed #KT-34081 --- .../asJava/classes/ultraLightAnnotations.kt | 32 +++--------------- .../kotlin/asJava/classes/ultraLightField.kt | 22 +++++++++---- .../kotlin/asJava/classes/ultraLightUtils.kt | 33 ++++++++++++++++++- .../inferringAnonymousObjectTypes.java | 4 +-- .../asJava/ultraLightClasses/objects.kt | 22 +++++++++++++ .../kotlin/idea/perf/UltraLightChecker.kt | 6 ++++ 6 files changed, 82 insertions(+), 37 deletions(-) diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightAnnotations.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightAnnotations.kt index 9bbdc0e7a89..2745bf06579 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightAnnotations.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightAnnotations.kt @@ -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 diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightField.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightField.kt index cb257b80098..3506ce7df30 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightField.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightField.kt @@ -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?): Any? = computeConstantValue() diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightUtils.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightUtils.kt index d253f93e77a..3253b70738c 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightUtils.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightUtils.kt @@ -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 */ diff --git a/compiler/testData/asJava/ultraLightClasses/inferringAnonymousObjectTypes.java b/compiler/testData/asJava/ultraLightClasses/inferringAnonymousObjectTypes.java index fbdfdb5553e..003b00a5162 100644 --- a/compiler/testData/asJava/ultraLightClasses/inferringAnonymousObjectTypes.java +++ b/compiler/testData/asJava/ultraLightClasses/inferringAnonymousObjectTypes.java @@ -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(); diff --git a/compiler/testData/asJava/ultraLightClasses/objects.kt b/compiler/testData/asJava/ultraLightClasses/objects.kt index 0f3fdf9b840..60ba1e2d1ff 100644 --- a/compiler/testData/asJava/ultraLightClasses/objects.kt +++ b/compiler/testData/asJava/ultraLightClasses/objects.kt @@ -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 + } +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/perf/UltraLightChecker.kt b/idea/tests/org/jetbrains/kotlin/idea/perf/UltraLightChecker.kt index f6dcb3eafab..2473348483f 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/perf/UltraLightChecker.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/perf/UltraLightChecker.kt @@ -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 }