diff --git a/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/javacListUtils.kt b/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/javacListUtils.kt index 46701a1de99..fd496cbab0d 100644 --- a/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/javacListUtils.kt +++ b/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/javacListUtils.kt @@ -55,4 +55,6 @@ fun pairedListToMap(valuePairs: List?): Map { operator fun JavacList.plus(other: JavacList): JavacList { return this.appendList(other) -} \ No newline at end of file +} + +fun Iterable.toJavacList(): JavacList = JavacList.from(this) diff --git a/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/stubs/ClassFileToSourceStubConverter.kt b/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/stubs/ClassFileToSourceStubConverter.kt index cb8c559cc57..ac1f92d7345 100644 --- a/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/stubs/ClassFileToSourceStubConverter.kt +++ b/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/stubs/ClassFileToSourceStubConverter.kt @@ -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): 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? = + 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()) + } } diff --git a/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/ClassFileToSourceStubConverterTestGenerated.java b/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/ClassFileToSourceStubConverterTestGenerated.java index d976794a07d..e72dfde7dbb 100644 --- a/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/ClassFileToSourceStubConverterTestGenerated.java +++ b/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/ClassFileToSourceStubConverterTestGenerated.java @@ -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"); diff --git a/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/IrClassFileToSourceStubConverterTestGenerated.java b/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/IrClassFileToSourceStubConverterTestGenerated.java index 0766a041312..425e0e5a795 100644 --- a/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/IrClassFileToSourceStubConverterTestGenerated.java +++ b/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/IrClassFileToSourceStubConverterTestGenerated.java @@ -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"); diff --git a/plugins/kapt3/kapt3-compiler/testData/converter/kt18791.kt b/plugins/kapt3/kapt3-compiler/testData/converter/annotationsWithConstants.kt similarity index 84% rename from plugins/kapt3/kapt3-compiler/testData/converter/kt18791.kt rename to plugins/kapt3/kapt3-compiler/testData/converter/annotationsWithConstants.kt index df97df237ae..2d2712affbc 100644 --- a/plugins/kapt3/kapt3-compiler/testData/converter/kt18791.kt +++ b/plugins/kapt3/kapt3-compiler/testData/converter/annotationsWithConstants.kt @@ -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) +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 \ No newline at end of file +// EXPECTED_ERROR class R2 is public, should be declared in a file named R2.java diff --git a/plugins/kapt3/kapt3-compiler/testData/converter/kt18791.txt b/plugins/kapt3/kapt3-compiler/testData/converter/annotationsWithConstants.txt similarity index 82% rename from plugins/kapt3/kapt3-compiler/testData/converter/kt18791.txt rename to plugins/kapt3/kapt3-compiler/testData/converter/annotationsWithConstants.txt index e0258881d9b..6805a8c3550 100644 --- a/plugins/kapt3/kapt3-compiler/testData/converter/kt18791.txt +++ b/plugins/kapt3/kapt3-compiler/testData/converter/annotationsWithConstants.txt @@ -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; }