Kapt: Generate constant value initializers for mutable properties (KT-30164)

This commit is contained in:
Yan Zhulanow
2019-03-14 15:58:16 +03:00
parent ce13982cfc
commit cce2b472bf
7 changed files with 168 additions and 5 deletions
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.base.kapt3.KaptFlag
import org.jetbrains.kotlin.codegen.coroutines.CONTINUATION_PARAMETER_NAME
import org.jetbrains.kotlin.codegen.needsExperimentalCoroutinesWrapper
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.descriptors.annotations.Annotations
@@ -49,11 +50,13 @@ import org.jetbrains.kotlin.load.java.sources.JavaSourceElement
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DelegatingBindingTrace
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.calls.model.DefaultValueArgument
import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument
import org.jetbrains.kotlin.resolve.constants.*
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameOrNull
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
@@ -644,8 +647,10 @@ class ClassFileToSourceStubConverter(val kaptContext: KaptContextForStubGenerati
private fun convertPropertyInitializer(field: FieldNode): JCExpression? {
val value = field.value
val origin = kaptContext.origins[field]
val propertyInitializer = (origin?.element as? KtProperty)?.initializer
if (value != null) {
val propertyInitializer = (kaptContext.origins[field]?.element as? KtProperty)?.initializer
if (propertyInitializer != null) {
return convertConstantValueArguments(value, listOf(propertyInitializer))
}
@@ -653,6 +658,17 @@ class ClassFileToSourceStubConverter(val kaptContext: KaptContextForStubGenerati
return convertValueOfPrimitiveTypeOrString(value)
}
val propertyType = (origin?.descriptor as? PropertyDescriptor)?.returnType
if (propertyInitializer != null && propertyType != null) {
val moduleDescriptor = kaptContext.generationState.module
val evaluator = ConstantExpressionEvaluator(moduleDescriptor, LanguageVersionSettingsImpl.DEFAULT, kaptContext.project)
val trace = DelegatingBindingTrace(kaptContext.bindingContext, "Kapt")
val const = evaluator.evaluateExpression(propertyInitializer, trace, propertyType)
if (const != null && !const.isError && const.canBeUsedInAnnotations && !const.usesNonConstValAsConstant) {
return convertConstantValueArguments(const.getValue(propertyType), listOf(propertyInitializer))
}
}
if (isFinal(field.access)) {
val type = Type.getType(field.desc)
return convertLiteralExpression(getDefaultValue(type))
@@ -408,4 +408,9 @@ public class ClassFileToSourceStubConverterTestGenerated extends AbstractClassFi
public void testTopLevel() throws Exception {
runTest("plugins/kapt3/kapt3-compiler/testData/converter/topLevel.kt");
}
@TestMetadata("unsafePropertyInitializers.kt")
public void testUnsafePropertyInitializers() throws Exception {
runTest("plugins/kapt3/kapt3-compiler/testData/converter/unsafePropertyInitializers.kt");
}
}
@@ -101,7 +101,7 @@ import java.lang.System;
public final class TestAnno2 {
@org.jetbrains.annotations.NotNull()
@Anno3(value = "field")
private java.lang.String b;
private java.lang.String b = "property initializer";
@Anno1()
public final void a(@org.jetbrains.annotations.NotNull()
@@ -130,9 +130,9 @@ public final class MyActivity {
private final int f = 0;
public final int propA = app.B.id.textView;
private final int propB = app.B.id.textView;
private int propC;
private int propC = app.B.id.textView;
public final int propD = app.B.id.textView;
public int propE;
public int propE = app.B.id.textView;
private final int propF = 0;
@Bind(id = lib.R.id.textView)
@@ -31,7 +31,7 @@ public final class Modifiers {
@org.jetbrains.annotations.NotNull()
private final transient java.lang.String transientField = "";
@org.jetbrains.annotations.NotNull()
private volatile java.lang.String volatileField;
private volatile java.lang.String volatileField = "";
@org.jetbrains.annotations.NotNull()
public final java.lang.String getTransientField() {
@@ -0,0 +1,24 @@
object Foo {
const val aString: String = "foo"
const val aInt: Int = 3
val bString: String = "bar"
val bInt: Int = 5
var cString: String = "baz"
var cInt: Int = 7
val d = Boo.z
val e = Boo.z.length
val f = 5 + 3
val g = "a" + "b"
val h = -4
val i = Int.MAX_VALUE
val j = "$e$g"
val k = g + j
}
object Boo {
val z = foo()
fun foo() = "abc"
}
@@ -0,0 +1,118 @@
import java.lang.System;
@kotlin.Metadata()
public final class Boo {
@org.jetbrains.annotations.NotNull()
private static final java.lang.String z = null;
public static final Boo INSTANCE = null;
@org.jetbrains.annotations.NotNull()
public final java.lang.String getZ() {
return null;
}
@org.jetbrains.annotations.NotNull()
public final java.lang.String foo() {
return null;
}
private Boo() {
super();
}
}
////////////////////
import java.lang.System;
@kotlin.Metadata()
public final class Foo {
@org.jetbrains.annotations.NotNull()
public static final java.lang.String aString = "foo";
public static final int aInt = 3;
@org.jetbrains.annotations.NotNull()
private static final java.lang.String bString = "bar";
private static final int bInt = 5;
@org.jetbrains.annotations.NotNull()
private static java.lang.String cString = "baz";
private static int cInt = 7;
@org.jetbrains.annotations.NotNull()
private static final java.lang.String d = null;
private static final int e = 0;
private static final int f = 8;
@org.jetbrains.annotations.NotNull()
private static final java.lang.String g = "ab";
private static final int h = -4;
private static final int i = 2147483647;
@org.jetbrains.annotations.NotNull()
private static final java.lang.String j = null;
@org.jetbrains.annotations.NotNull()
private static final java.lang.String k = null;
public static final Foo INSTANCE = null;
@org.jetbrains.annotations.NotNull()
public final java.lang.String getBString() {
return null;
}
public final int getBInt() {
return 0;
}
@org.jetbrains.annotations.NotNull()
public final java.lang.String getCString() {
return null;
}
public final void setCString(@org.jetbrains.annotations.NotNull()
java.lang.String p0) {
}
public final int getCInt() {
return 0;
}
public final void setCInt(int p0) {
}
@org.jetbrains.annotations.NotNull()
public final java.lang.String getD() {
return null;
}
public final int getE() {
return 0;
}
public final int getF() {
return 0;
}
@org.jetbrains.annotations.NotNull()
public final java.lang.String getG() {
return null;
}
public final int getH() {
return 0;
}
public final int getI() {
return 0;
}
@org.jetbrains.annotations.NotNull()
public final java.lang.String getJ() {
return null;
}
@org.jetbrains.annotations.NotNull()
public final java.lang.String getK() {
return null;
}
private Foo() {
super();
}
}