[KAPT] Keep constant references in annotations with array values
#KT-29929 Fixed
This commit is contained in:
committed by
TeamCityServer
parent
9e9450caa2
commit
8071a1e246
@@ -55,4 +55,6 @@ fun pairedListToMap(valuePairs: List<Any>?): Map<String, Any?> {
|
||||
|
||||
operator fun <T : Any> JavacList<T>.plus(other: JavacList<T>): JavacList<T> {
|
||||
return this.appendList(other)
|
||||
}
|
||||
}
|
||||
|
||||
fun <T : Any> Iterable<T>.toJavacList(): JavacList<T> = JavacList.from(this)
|
||||
|
||||
+42
-22
@@ -34,12 +34,9 @@ import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.kapt3.KaptContextForStubGeneration
|
||||
import org.jetbrains.kotlin.kapt3.base.*
|
||||
import org.jetbrains.kotlin.kapt3.base.javac.kaptError
|
||||
import org.jetbrains.kotlin.kapt3.base.javac.reportKaptError
|
||||
import org.jetbrains.kotlin.kapt3.base.mapJList
|
||||
import org.jetbrains.kotlin.kapt3.base.mapJListIndexed
|
||||
import org.jetbrains.kotlin.kapt3.base.pairedListToMap
|
||||
import org.jetbrains.kotlin.kapt3.base.plus
|
||||
import org.jetbrains.kotlin.kapt3.base.stubs.KaptStubLineInformation
|
||||
import org.jetbrains.kotlin.kapt3.base.stubs.KotlinPosition
|
||||
import org.jetbrains.kotlin.kapt3.base.util.TopLevelJava9Aware
|
||||
@@ -53,6 +50,7 @@ import org.jetbrains.kotlin.load.kotlin.TypeMappingMode
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.isOneSegmentFQN
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.ArrayFqNames
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.DelegatingBindingTrace
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||
@@ -111,6 +109,10 @@ class ClassFileToSourceStubConverter(val kaptContext: KaptContextForStubGenerati
|
||||
private val JAVA_KEYWORDS = Tokens.TokenKind.values()
|
||||
.filter { JAVA_KEYWORD_FILTER_REGEX.matches(it.toString().orEmpty()) }
|
||||
.mapTo(hashSetOf(), Any::toString)
|
||||
|
||||
private val KOTLIN_PACKAGE = FqName("kotlin")
|
||||
|
||||
private val ARRAY_OF_FUNCTIONS = (ArrayFqNames.PRIMITIVE_TYPE_TO_ARRAY.values + ArrayFqNames.ARRAY_OF_FUNCTION).toSet()
|
||||
}
|
||||
|
||||
private val correctErrorTypes = kaptContext.options[KaptFlag.CORRECT_ERROR_TYPES]
|
||||
@@ -1240,11 +1242,6 @@ class ClassFileToSourceStubConverter(val kaptContext: KaptContextForStubGenerati
|
||||
private fun convertConstantValueArguments(containingClass: ClassNode, constantValue: Any?, args: List<KtExpression>): JCExpression? {
|
||||
val singleArg = args.singleOrNull()
|
||||
|
||||
if (constantValue.isOfPrimitiveType()) {
|
||||
// Do not inline primitive constants
|
||||
tryParseReferenceToIntConstant(singleArg)?.let { return it }
|
||||
}
|
||||
|
||||
fun tryParseTypeExpression(expression: KtExpression?): JCExpression? {
|
||||
if (expression is KtReferenceExpression) {
|
||||
val descriptor = kaptContext.bindingContext[BindingContext.REFERENCE_TARGET, expression]
|
||||
@@ -1272,6 +1269,37 @@ class ClassFileToSourceStubConverter(val kaptContext: KaptContextForStubGenerati
|
||||
return treeMaker.Select(typeExpression, treeMaker.name("class"))
|
||||
}
|
||||
|
||||
fun unwrapArgumentExpression(): List<KtExpression?>? =
|
||||
when (singleArg) {
|
||||
is KtCallExpression -> {
|
||||
val resultingDescriptor = singleArg.getResolvedCall(kaptContext.bindingContext)?.resultingDescriptor
|
||||
|
||||
if (resultingDescriptor is FunctionDescriptor && isArrayOfFunction(resultingDescriptor))
|
||||
singleArg.valueArguments.map { it.getArgumentExpression() }
|
||||
else
|
||||
null
|
||||
}
|
||||
is KtCollectionLiteralExpression -> singleArg.getInnerExpressions()
|
||||
else -> null
|
||||
}
|
||||
|
||||
|
||||
if (constantValue.isOfPrimitiveType()) {
|
||||
// Do not inline primitive constants
|
||||
tryParseReferenceToIntConstant(singleArg)?.let { return it }
|
||||
} else if (constantValue is List<*> &&
|
||||
constantValue.isNotEmpty() &&
|
||||
args.isNotEmpty() &&
|
||||
constantValue.all { it.isOfPrimitiveType() }
|
||||
) {
|
||||
unwrapArgumentExpression()?.let { argumentExpressions ->
|
||||
val parsed = argumentExpressions.mapNotNull(::tryParseReferenceToIntConstant).toJavacList()
|
||||
if (parsed.size == argumentExpressions.size) {
|
||||
return treeMaker.NewArray(null, null, parsed)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Unresolved class literal
|
||||
if (constantValue == null && singleArg is KtClassLiteralExpression) {
|
||||
tryParseTypeLiteralExpression(singleArg)?.let { return it }
|
||||
@@ -1287,19 +1315,7 @@ class ClassFileToSourceStubConverter(val kaptContext: KaptContextForStubGenerati
|
||||
|
||||
// Probably arrayOf(SomeUnresolvedType::class, ...)
|
||||
if (constantValue is List<*>) {
|
||||
val callArgs = when (singleArg) {
|
||||
is KtCallExpression -> {
|
||||
val resultingDescriptor = singleArg.getResolvedCall(kaptContext.bindingContext)?.resultingDescriptor
|
||||
|
||||
if (resultingDescriptor is FunctionDescriptor && resultingDescriptor.fqNameSafe.asString() == "kotlin.arrayOf")
|
||||
singleArg.valueArguments.map { it.getArgumentExpression() }
|
||||
else
|
||||
null
|
||||
}
|
||||
is KtCollectionLiteralExpression -> singleArg.getInnerExpressions()
|
||||
else -> null
|
||||
}
|
||||
|
||||
val callArgs = unwrapArgumentExpression()
|
||||
// So we make sure something is absent in the constant value
|
||||
if (callArgs != null && callArgs.size != constantValue.size) {
|
||||
val literalExpressions = mapJList(callArgs, ::tryParseTypeLiteralExpression)
|
||||
@@ -1498,6 +1514,10 @@ class ClassFileToSourceStubConverter(val kaptContext: KaptContextForStubGenerati
|
||||
file to importsFromRoot.mapTo(mutableSetOf()) { it.asString() }
|
||||
}.toMap()
|
||||
|
||||
private fun isArrayOfFunction(d: FunctionDescriptor): Boolean {
|
||||
val name = d.fqNameSafe
|
||||
return name.parent() == KOTLIN_PACKAGE && ARRAY_OF_FUNCTIONS.contains(name.shortName())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
+5
-5
@@ -64,6 +64,11 @@ public class ClassFileToSourceStubConverterTestGenerated extends AbstractClassFi
|
||||
runTest("plugins/kapt3/kapt3-compiler/testData/converter/annotations3.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("annotationsWithConstants.kt")
|
||||
public void testAnnotationsWithConstants() throws Exception {
|
||||
runTest("plugins/kapt3/kapt3-compiler/testData/converter/annotationsWithConstants.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("annotationsWithTargets.kt")
|
||||
public void testAnnotationsWithTargets() throws Exception {
|
||||
runTest("plugins/kapt3/kapt3-compiler/testData/converter/annotationsWithTargets.kt");
|
||||
@@ -314,11 +319,6 @@ public class ClassFileToSourceStubConverterTestGenerated extends AbstractClassFi
|
||||
runTest("plugins/kapt3/kapt3-compiler/testData/converter/kt18682.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt18791.kt")
|
||||
public void testKt18791() throws Exception {
|
||||
runTest("plugins/kapt3/kapt3-compiler/testData/converter/kt18791.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt19700.kt")
|
||||
public void testKt19700() throws Exception {
|
||||
runTest("plugins/kapt3/kapt3-compiler/testData/converter/kt19700.kt");
|
||||
|
||||
+5
-5
@@ -65,6 +65,11 @@ public class IrClassFileToSourceStubConverterTestGenerated extends AbstractIrCla
|
||||
runTest("plugins/kapt3/kapt3-compiler/testData/converter/annotations3.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("annotationsWithConstants.kt")
|
||||
public void testAnnotationsWithConstants() throws Exception {
|
||||
runTest("plugins/kapt3/kapt3-compiler/testData/converter/annotationsWithConstants.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("annotationsWithTargets.kt")
|
||||
public void testAnnotationsWithTargets() throws Exception {
|
||||
runTest("plugins/kapt3/kapt3-compiler/testData/converter/annotationsWithTargets.kt");
|
||||
@@ -315,11 +320,6 @@ public class IrClassFileToSourceStubConverterTestGenerated extends AbstractIrCla
|
||||
runTest("plugins/kapt3/kapt3-compiler/testData/converter/kt18682.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt18791.kt")
|
||||
public void testKt18791() throws Exception {
|
||||
runTest("plugins/kapt3/kapt3-compiler/testData/converter/kt18791.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt19700.kt")
|
||||
public void testKt19700() throws Exception {
|
||||
runTest("plugins/kapt3/kapt3-compiler/testData/converter/kt19700.kt");
|
||||
|
||||
+23
-1
@@ -52,6 +52,10 @@ import lib.R.id.textView
|
||||
|
||||
annotation class Bind(val id: Int)
|
||||
|
||||
annotation class MultiValue(val ids: IntArray)
|
||||
annotation class MultiValueString(val ids: Array<String>)
|
||||
annotation class MultiValueByte(val ids: ByteArray)
|
||||
|
||||
@Target(AnnotationTarget.FIELD)
|
||||
annotation class BindField(val id: Int)
|
||||
|
||||
@@ -111,6 +115,24 @@ class MyActivity {
|
||||
@Bind(B.id.textView)
|
||||
fun plainIntConstant() {}
|
||||
|
||||
@MultiValue(ids = [])
|
||||
fun multi0() {}
|
||||
|
||||
@MultiValue(ids = [B.id.textView])
|
||||
fun multi1() {}
|
||||
|
||||
@MultiValue(ids = [B.id.textView, B.a3])
|
||||
fun multi2() {}
|
||||
|
||||
@MultiValue(ids = intArrayOf(B.id.textView, B.a3))
|
||||
fun multi3() {}
|
||||
|
||||
@MultiValueString(ids = arrayOf(B.a9))
|
||||
fun multi4() {}
|
||||
|
||||
@MultiValueByte(ids = byteArrayOf(B.a2))
|
||||
fun multi5() {}
|
||||
|
||||
const val propA = B.id.textView
|
||||
val propB = B.id.textView
|
||||
var propC = B.id.textView
|
||||
@@ -129,4 +151,4 @@ object JJ {
|
||||
// EXPECTED_ERROR class B is public, should be declared in a file named B.java
|
||||
// EXPECTED_ERROR class R is public, should be declared in a file named R.java
|
||||
// EXPECTED_ERROR class R is public, should be declared in a file named R.java
|
||||
// EXPECTED_ERROR class R2 is public, should be declared in a file named R2.java
|
||||
// EXPECTED_ERROR class R2 is public, should be declared in a file named R2.java
|
||||
+63
@@ -115,6 +115,45 @@ package app;
|
||||
|
||||
import java.lang.System;
|
||||
|
||||
@kotlin.Metadata()
|
||||
@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME)
|
||||
public abstract @interface MultiValue {
|
||||
|
||||
public abstract int[] ids();
|
||||
}
|
||||
|
||||
////////////////////
|
||||
|
||||
package app;
|
||||
|
||||
import java.lang.System;
|
||||
|
||||
@kotlin.Metadata()
|
||||
@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME)
|
||||
public abstract @interface MultiValueByte {
|
||||
|
||||
public abstract byte[] ids();
|
||||
}
|
||||
|
||||
////////////////////
|
||||
|
||||
package app;
|
||||
|
||||
import java.lang.System;
|
||||
|
||||
@kotlin.Metadata()
|
||||
@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME)
|
||||
public abstract @interface MultiValueString {
|
||||
|
||||
public abstract java.lang.String[] ids();
|
||||
}
|
||||
|
||||
////////////////////
|
||||
|
||||
package app;
|
||||
|
||||
import java.lang.System;
|
||||
|
||||
@kotlin.Metadata()
|
||||
public final class MyActivity {
|
||||
@BindField(id = lib.R.id.textView)
|
||||
@@ -222,6 +261,30 @@ public final class MyActivity {
|
||||
public final void plainIntConstant() {
|
||||
}
|
||||
|
||||
@MultiValue(ids = {})
|
||||
public final void multi0() {
|
||||
}
|
||||
|
||||
@MultiValue(ids = {app.B.id.textView})
|
||||
public final void multi1() {
|
||||
}
|
||||
|
||||
@MultiValue(ids = {app.B.id.textView, app.B.a3})
|
||||
public final void multi2() {
|
||||
}
|
||||
|
||||
@MultiValue(ids = {app.B.id.textView, app.B.a3})
|
||||
public final void multi3() {
|
||||
}
|
||||
|
||||
@MultiValueString(ids = {"A"})
|
||||
public final void multi4() {
|
||||
}
|
||||
|
||||
@MultiValueByte(ids = {app.B.a2})
|
||||
public final void multi5() {
|
||||
}
|
||||
|
||||
public final int getPropB() {
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user