Allow to use emptyArray in annotation as argument

#KT-14236 Fixed
This commit is contained in:
Mikhail Zarechenskiy
2017-02-06 20:17:03 +03:00
parent 9f0403f72c
commit d7093db5c5
10 changed files with 62 additions and 20 deletions
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -56,7 +56,8 @@ public class CompileTimeConstantUtils {
"kotlin.charArrayOf",
"kotlin.shortArrayOf",
"kotlin.byteArrayOf",
"kotlin.booleanArrayOf"
"kotlin.booleanArrayOf",
"kotlin.emptyArray"
);
public static void checkConstructorParametersType(@NotNull List<KtParameter> parameters, @NotNull BindingTrace trace) {
@@ -110,7 +111,7 @@ public class CompileTimeConstantUtils {
return false;
}
public static boolean isArrayMethodCall(@NotNull ResolvedCall<?> resolvedCall) {
public static boolean isArrayFunctionCall(@NotNull ResolvedCall<?> resolvedCall) {
return ARRAY_CALL_NAMES.contains(DescriptorUtils.getFqName(resolvedCall.getCandidateDescriptor()).asString());
}
@@ -166,23 +166,24 @@ class ConstantExpressionEvaluator(
trace: BindingTrace
): Pair<List<KtExpression>, KotlinType?>? {
val resolvedCall = expression.getResolvedCall(trace.bindingContext)
if (resolvedCall == null || !CompileTimeConstantUtils.isArrayMethodCall(resolvedCall)) {
if (resolvedCall == null || !CompileTimeConstantUtils.isArrayFunctionCall(resolvedCall)) {
return null
}
val argumentEntry = resolvedCall.valueArguments.entries.single()
val elementType = argumentEntry.key.varargElementType ?: return null
val returnType = resolvedCall.resultingDescriptor.returnType ?: return null
val componentType = builtIns.getArrayElementType(returnType)
val result = arrayListOf<KtExpression>()
for (valueArgument in argumentEntry.value.arguments) {
val valueArgumentExpression = valueArgument.getArgumentExpression()
if (valueArgumentExpression != null) {
result.add(valueArgumentExpression)
for ((_, resolvedValueArgument) in resolvedCall.valueArguments) {
for (valueArgument in resolvedValueArgument.arguments) {
val valueArgumentExpression = valueArgument.getArgumentExpression()
if (valueArgumentExpression != null) {
result.add(valueArgumentExpression)
}
}
}
return Pair<List<KtExpression>, KotlinType>(result, elementType)
return Pair<List<KtExpression>, KotlinType>(result, componentType)
}
private fun hasSpread(argument: ResolvedValueArgument): Boolean {
@@ -646,13 +647,14 @@ private class ConstantExpressionEvaluatorVisitor(
val resultingDescriptor = call.resultingDescriptor
// arrayOf()
if (CompileTimeConstantUtils.isArrayMethodCall(call)) {
val varargType = resultingDescriptor.valueParameters.first().varargElementType!!
// arrayOf() or emptyArray()
if (CompileTimeConstantUtils.isArrayFunctionCall(call)) {
val returnType = resultingDescriptor.returnType ?: return null
val componentType = constantExpressionEvaluator.builtIns.getArrayElementType(returnType)
val arguments = call.valueArguments.values.flatMap { resolveArguments(it.arguments, varargType) }
val arguments = call.valueArguments.values.flatMap { resolveArguments(it.arguments, componentType) }
return factory.createArrayValue(arguments.map { it.toConstantValue(varargType) }, resultingDescriptor.returnType!!).
return factory.createArrayValue(arguments.map { it.toConstantValue(componentType) }, resultingDescriptor.returnType!!).
wrap(
usesVariableAsConstant = arguments.any { it.usesVariableAsConstant },
usesNonConstValAsConstant = arguments.any { it.usesNonConstValAsConstant }
@@ -0,0 +1,8 @@
annotation class Anno(val x: Array<String> = emptyArray())
@Anno fun test1() = 1
@Anno(arrayOf("K")) fun test2() = 2
fun box(): String {
return if (test1() + test2() == 3) "OK" else "Fail"
}
@@ -0,0 +1,12 @@
@java.lang.annotation.Retention
@kotlin.Metadata
public annotation class Anno {
public abstract method x(): java.lang.String[]
}
@kotlin.Metadata
public final class AnnotationWithEmptyArrayKt {
public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String
public final static @Anno method test1(): int
public final static @Anno method test2(): int
}
@@ -19,6 +19,7 @@ val i2 = foo()
fun foo(): Int = 1
@AnnSA(emptyArray())
class MyClass {
val i = 1
}
@@ -37,7 +37,7 @@ public final annotation class AnnSA : kotlin.Annotation {
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public final class MyClass {
@AnnSA(sa = {}) public final class MyClass {
public constructor MyClass()
public final val i: kotlin.Int = 1
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
@@ -5845,6 +5845,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
doTest(fileName);
}
@TestMetadata("annotationWithEmptyArray.kt")
public void testAnnotationWithEmptyArray() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/defaultArguments/constructor/annotationWithEmptyArray.kt");
doTest(fileName);
}
@TestMetadata("checkIfConstructorIsSynthetic.kt")
public void testCheckIfConstructorIsSynthetic() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/defaultArguments/constructor/checkIfConstructorIsSynthetic.kt");
@@ -5845,6 +5845,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
doTest(fileName);
}
@TestMetadata("annotationWithEmptyArray.kt")
public void testAnnotationWithEmptyArray() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/defaultArguments/constructor/annotationWithEmptyArray.kt");
doTest(fileName);
}
@TestMetadata("checkIfConstructorIsSynthetic.kt")
public void testCheckIfConstructorIsSynthetic() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/defaultArguments/constructor/checkIfConstructorIsSynthetic.kt");
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -500,7 +500,7 @@ class CodeInliner<TCallElement : KtElement>(
val argumentExpression = argument.getArgumentExpression() ?: return@forEachDescendantOfType
val resolvedCall = argumentExpression.getResolvedCall(argumentExpression.analyze(BodyResolveMode.PARTIAL)) ?: return@forEachDescendantOfType
val callExpression = resolvedCall.call.callElement as? KtCallExpression ?: return@forEachDescendantOfType
if (CompileTimeConstantUtils.isArrayMethodCall(resolvedCall)) {
if (CompileTimeConstantUtils.isArrayFunctionCall(resolvedCall)) {
argumentsToExpand.add(argument to callExpression.valueArguments)
}
}
@@ -6614,6 +6614,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
doTest(fileName);
}
@TestMetadata("annotationWithEmptyArray.kt")
public void testAnnotationWithEmptyArray() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/defaultArguments/constructor/annotationWithEmptyArray.kt");
doTest(fileName);
}
@TestMetadata("checkIfConstructorIsSynthetic.kt")
public void testCheckIfConstructorIsSynthetic() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/defaultArguments/constructor/checkIfConstructorIsSynthetic.kt");