Annotation parameter must be constant on vararg and array arguments
This commit is contained in:
@@ -17,6 +17,7 @@
|
||||
package org.jetbrains.jet.lang.resolve;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
@@ -34,7 +35,6 @@ import org.jetbrains.jet.lang.resolve.calls.util.CallMaker;
|
||||
import org.jetbrains.jet.lang.resolve.constants.ArrayValue;
|
||||
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
|
||||
import org.jetbrains.jet.lang.resolve.constants.IntegerValueTypeConstant;
|
||||
import org.jetbrains.jet.lang.resolve.constants.IntegerValueTypeConstructor;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
|
||||
import org.jetbrains.jet.lang.types.ErrorUtils;
|
||||
@@ -43,11 +43,13 @@ import org.jetbrains.jet.lang.types.expressions.ExpressionTypingServices;
|
||||
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.jetbrains.jet.lang.resolve.BindingContext.ANNOTATION_DESCRIPTOR_TO_PSI_ELEMENT;
|
||||
import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE;
|
||||
import static org.jetbrains.jet.lang.types.TypeUtils.getPrimitiveNumberType;
|
||||
|
||||
public class AnnotationResolver {
|
||||
|
||||
@@ -215,9 +217,12 @@ public class AnnotationResolver {
|
||||
ValueParameterDescriptor parameterDescriptor = descriptorToArgument.getKey();
|
||||
|
||||
JetType varargElementType = parameterDescriptor.getVarargElementType();
|
||||
List<CompileTimeConstant<?>> constants = resolveValueArguments(descriptorToArgument.getValue(), parameterDescriptor.getType(), trace);
|
||||
boolean argumentsAsVararg = varargElementType != null && !hasSpread(descriptorToArgument.getValue());
|
||||
List<CompileTimeConstant<?>> constants = resolveValueArguments(descriptorToArgument.getValue(),
|
||||
argumentsAsVararg ? varargElementType : parameterDescriptor.getType(),
|
||||
trace);
|
||||
|
||||
if (varargElementType != null && !hasSpread(descriptorToArgument.getValue())) {
|
||||
if (argumentsAsVararg) {
|
||||
JetType arrayType = KotlinBuiltIns.getInstance().getPrimitiveArrayJetTypeByPrimitiveJetType(varargElementType);
|
||||
if (arrayType == null) {
|
||||
arrayType = KotlinBuiltIns.getInstance().getArrayType(varargElementType);
|
||||
@@ -232,6 +237,71 @@ public class AnnotationResolver {
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkCompileTimeConstant(
|
||||
@NotNull JetExpression argumentExpression,
|
||||
@NotNull JetType expectedType,
|
||||
@NotNull BindingTrace trace
|
||||
) {
|
||||
JetType expressionType = trace.get(BindingContext.EXPRESSION_TYPE, argumentExpression);
|
||||
|
||||
if (expressionType == null || !expressionType.equals(expectedType)) {
|
||||
// TYPE_MISMATCH should be reported otherwise
|
||||
return;
|
||||
}
|
||||
|
||||
// array(1, <!>null<!>, 3) - error should be reported on inner expression
|
||||
if (argumentExpression instanceof JetCallExpression) {
|
||||
Pair<List<JetExpression>, JetType> arrayArgument = getArgumentExpressionsForArrayCall((JetCallExpression) argumentExpression, trace);
|
||||
if (arrayArgument != null) {
|
||||
for (JetExpression expression : arrayArgument.getFirst()) {
|
||||
checkCompileTimeConstant(expression, arrayArgument.getSecond(), trace);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CompileTimeConstant<?> constant = trace.get(BindingContext.COMPILE_TIME_VALUE, argumentExpression);
|
||||
if (constant != null && constant.canBeUsedInAnnotations()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ClassifierDescriptor descriptor = expressionType.getConstructor().getDeclarationDescriptor();
|
||||
if (descriptor != null && DescriptorUtils.isEnumClass(descriptor)) {
|
||||
trace.report(Errors.ANNOTATION_PARAMETER_MUST_BE_ENUM_CONST.on(argumentExpression));
|
||||
}
|
||||
else if (descriptor instanceof ClassDescriptor && AnnotationUtils.isJavaLangClass((ClassDescriptor) descriptor)) {
|
||||
trace.report(Errors.ANNOTATION_PARAMETER_MUST_BE_CLASS_LITERAL.on(argumentExpression));
|
||||
}
|
||||
else {
|
||||
trace.report(Errors.ANNOTATION_PARAMETER_MUST_BE_CONST.on(argumentExpression));
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static Pair<List<JetExpression>, JetType> getArgumentExpressionsForArrayCall(
|
||||
@NotNull JetCallExpression expression,
|
||||
@NotNull BindingTrace trace
|
||||
) {
|
||||
ResolvedCall<?> resolvedCall = trace.get(BindingContext.RESOLVED_CALL, (expression).getCalleeExpression());
|
||||
if (resolvedCall == null || !AnnotationUtils.isArrayMethodCall(resolvedCall)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
assert resolvedCall.getValueArguments().size() == 1 : "Array function should have only one vararg parameter";
|
||||
Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> argumentEntry = resolvedCall.getValueArguments().entrySet().iterator().next();
|
||||
|
||||
List<JetExpression> result = Lists.newArrayList();
|
||||
JetType elementType = argumentEntry.getKey().getVarargElementType();
|
||||
for (ValueArgument valueArgument : argumentEntry.getValue().getArguments()) {
|
||||
JetExpression valueArgumentExpression = valueArgument.getArgumentExpression();
|
||||
if (valueArgumentExpression != null) {
|
||||
if (elementType != null) {
|
||||
result.add(valueArgumentExpression);
|
||||
}
|
||||
}
|
||||
}
|
||||
return new Pair<List<JetExpression>, JetType>(result, elementType);
|
||||
}
|
||||
|
||||
private static boolean hasSpread(@NotNull ResolvedValueArgument argument) {
|
||||
List<ValueArgument> arguments = argument.getArguments();
|
||||
return arguments.size() == 1 && arguments.get(0).getSpreadElement() != null;
|
||||
@@ -252,24 +322,10 @@ public class AnnotationResolver {
|
||||
JetType defaultType = ((IntegerValueTypeConstant) constant).getType(expectedType);
|
||||
ArgumentTypeResolver.updateNumberType(defaultType, argumentExpression, trace);
|
||||
}
|
||||
if (constant != null && constant.canBeUsedInAnnotations()) {
|
||||
if (constant != null) {
|
||||
constants.add(constant);
|
||||
}
|
||||
else {
|
||||
JetType expressionType = trace.get(BindingContext.EXPRESSION_TYPE, argumentExpression);
|
||||
if (expressionType != null && expressionType.equals(expectedType)) {
|
||||
ClassifierDescriptor descriptor = expressionType.getConstructor().getDeclarationDescriptor();
|
||||
if (descriptor != null && DescriptorUtils.isEnumClass(descriptor)) {
|
||||
trace.report(Errors.ANNOTATION_PARAMETER_MUST_BE_ENUM_CONST.on(argumentExpression));
|
||||
}
|
||||
else if (descriptor instanceof ClassDescriptor && AnnotationUtils.isJavaLangClass((ClassDescriptor) descriptor)) {
|
||||
trace.report(Errors.ANNOTATION_PARAMETER_MUST_BE_CLASS_LITERAL.on(argumentExpression));
|
||||
}
|
||||
else {
|
||||
trace.report(Errors.ANNOTATION_PARAMETER_MUST_BE_CONST.on(argumentExpression));
|
||||
}
|
||||
}
|
||||
}
|
||||
checkCompileTimeConstant(argumentExpression, expectedType, trace);
|
||||
}
|
||||
}
|
||||
return constants;
|
||||
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
annotation class Ann(val i: IntArray)
|
||||
|
||||
Ann(intArray(<!ANNOTATION_PARAMETER_MUST_BE_CONST!>i<!>))
|
||||
Ann(intArray(i2))
|
||||
Ann(intArray(<!ANNOTATION_PARAMETER_MUST_BE_CONST!>i3<!>))
|
||||
Ann(intArray(<!ANNOTATION_PARAMETER_MUST_BE_CONST!>i<!>, i2, <!ANNOTATION_PARAMETER_MUST_BE_CONST!>i3<!>))
|
||||
Ann(intArray(<!TYPE_MISMATCH!>intArray(i, i2, i3)<!>))
|
||||
class Test
|
||||
|
||||
var i = 1
|
||||
val i2 = 1
|
||||
val i3 = foo()
|
||||
|
||||
fun foo(): Int = 1
|
||||
|
||||
annotation class AnnJC(val i: Array<Class<*>>)
|
||||
AnnJC(array(javaClass<Test>()))
|
||||
AnnJC(array(iJC))
|
||||
class TestJC
|
||||
val iJC = javaClass<Test>()
|
||||
|
||||
annotation class AnnAnn(val i: Array<Ann>)
|
||||
AnnAnn(array(Ann(intArray(1))))
|
||||
AnnAnn(array(<!ANNOTATION_PARAMETER_MUST_BE_CONST!>iAnn<!>))
|
||||
class TestAnn
|
||||
val iAnn = <!ANNOTATION_CLASS_CONSTRUCTOR_CALL!>Ann(intArray(1))<!>
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
annotation class Ann(vararg val i: Int)
|
||||
|
||||
Ann(<!ANNOTATION_PARAMETER_MUST_BE_CONST!>i<!>)
|
||||
Ann(i2)
|
||||
Ann(<!ANNOTATION_PARAMETER_MUST_BE_CONST!>i3<!>)
|
||||
Ann(<!ANNOTATION_PARAMETER_MUST_BE_CONST!>i<!>, i2, <!ANNOTATION_PARAMETER_MUST_BE_CONST!>i3<!>)
|
||||
Ann(*intArray(<!ANNOTATION_PARAMETER_MUST_BE_CONST!>i<!>))
|
||||
Ann(*intArray(i2))
|
||||
Ann(*intArray(<!ANNOTATION_PARAMETER_MUST_BE_CONST!>i3<!>))
|
||||
Ann(*intArray(<!ANNOTATION_PARAMETER_MUST_BE_CONST!>i<!>, i2, <!ANNOTATION_PARAMETER_MUST_BE_CONST!>i3<!>))
|
||||
class Test
|
||||
|
||||
var i = 1
|
||||
val i2 = 1
|
||||
val i3 = foo()
|
||||
|
||||
fun foo(): Int = 1
|
||||
|
||||
annotation class AnnJC(vararg val i: Class<*>)
|
||||
AnnJC(*array(javaClass<Test>()))
|
||||
AnnJC(*array(iJC))
|
||||
class TestJC
|
||||
val iJC = javaClass<Test>()
|
||||
|
||||
annotation class AnnAnn(vararg val i: Ann)
|
||||
AnnAnn(*array(Ann(1)))
|
||||
AnnAnn(*array(<!ANNOTATION_PARAMETER_MUST_BE_CONST!>iAnn<!>))
|
||||
class TestAnn
|
||||
val iAnn = <!ANNOTATION_CLASS_CONSTRUCTOR_CALL!>Ann(1)<!>
|
||||
@@ -510,6 +510,7 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/annotations")
|
||||
@InnerTestClasses({Annotations.AnnotationParameterMustBeConstant.class})
|
||||
public static class Annotations extends AbstractJetDiagnosticsTest {
|
||||
public void testAllFilesPresentInAnnotations() throws Exception {
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/diagnostics/tests/annotations"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
@@ -560,6 +561,11 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
|
||||
doTest("compiler/testData/diagnostics/tests/annotations/annotationParameterMustBeConstant.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("annotationParameterMustBeConstantVararg.kt")
|
||||
public void testAnnotationParameterMustBeConstantVararg() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/annotations/annotationParameterMustBeConstantVararg.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("annotationParameterMustBeEnumConst.kt")
|
||||
public void testAnnotationParameterMustBeEnumConst() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/annotations/annotationParameterMustBeEnumConst.kt");
|
||||
@@ -645,6 +651,25 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
|
||||
doTest("compiler/testData/diagnostics/tests/annotations/onMultiDeclaration.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/annotations/annotationParameterMustBeConstant")
|
||||
public static class AnnotationParameterMustBeConstant extends AbstractJetDiagnosticsTest {
|
||||
public void testAllFilesPresentInAnnotationParameterMustBeConstant() throws Exception {
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/diagnostics/tests/annotations/annotationParameterMustBeConstant"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("array.kt")
|
||||
public void testArray() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/annotations/annotationParameterMustBeConstant/array.kt");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static Test innerSuite() {
|
||||
TestSuite suite = new TestSuite("Annotations");
|
||||
suite.addTestSuite(Annotations.class);
|
||||
suite.addTestSuite(AnnotationParameterMustBeConstant.class);
|
||||
return suite;
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/backingField")
|
||||
@@ -6796,7 +6821,7 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
|
||||
public static Test innerSuite() {
|
||||
TestSuite suite = new TestSuite("Tests");
|
||||
suite.addTestSuite(Tests.class);
|
||||
suite.addTestSuite(Annotations.class);
|
||||
suite.addTest(Annotations.innerSuite());
|
||||
suite.addTestSuite(BackingField.class);
|
||||
suite.addTestSuite(CallableReference.class);
|
||||
suite.addTest(Cast.innerSuite());
|
||||
|
||||
+4
-2
@@ -1,4 +1,6 @@
|
||||
// "class com.intellij.codeInspection.SuppressIntentionAction" "false"
|
||||
|
||||
[suppress("FOO"<caret>!!)]
|
||||
fun foo() {}
|
||||
[Ann(Integer.MAX_VALUE<caret> + 1)]
|
||||
fun foo() {}
|
||||
|
||||
annotation class Ann(val b: Int)
|
||||
Reference in New Issue
Block a user