Prohibit non-constant default values for annotation parameter
#KT-7449 Fixed
This commit is contained in:
@@ -131,6 +131,7 @@ public interface Errors {
|
|||||||
DiagnosticFactory0<JetExpression> ANNOTATION_PARAMETER_MUST_BE_KCLASS_LITERAL = DiagnosticFactory0.create(ERROR);
|
DiagnosticFactory0<JetExpression> ANNOTATION_PARAMETER_MUST_BE_KCLASS_LITERAL = DiagnosticFactory0.create(ERROR);
|
||||||
DiagnosticFactory0<JetExpression> ANNOTATION_PARAMETER_MUST_BE_ENUM_CONST = DiagnosticFactory0.create(ERROR);
|
DiagnosticFactory0<JetExpression> ANNOTATION_PARAMETER_MUST_BE_ENUM_CONST = DiagnosticFactory0.create(ERROR);
|
||||||
DiagnosticFactory0<JetAnnotation> DEPRECATED_ANNOTATION_SYNTAX = DiagnosticFactory0.create(WARNING);
|
DiagnosticFactory0<JetAnnotation> DEPRECATED_ANNOTATION_SYNTAX = DiagnosticFactory0.create(WARNING);
|
||||||
|
DiagnosticFactory0<JetExpression> ANNOTATION_PARAMETER_DEFAULT_VALUE_MUST_BE_CONSTANT = DiagnosticFactory0.create(ERROR);
|
||||||
|
|
||||||
// Classes and traits
|
// Classes and traits
|
||||||
|
|
||||||
|
|||||||
+1
@@ -567,6 +567,7 @@ public class DefaultErrorMessages {
|
|||||||
MAP.put(ANNOTATION_PARAMETER_MUST_BE_CLASS_LITERAL, "An annotation parameter must be a `javaClass<T>()` call");
|
MAP.put(ANNOTATION_PARAMETER_MUST_BE_CLASS_LITERAL, "An annotation parameter must be a `javaClass<T>()` call");
|
||||||
MAP.put(ANNOTATION_PARAMETER_MUST_BE_KCLASS_LITERAL, "An annotation parameter must be a class literal (T::class)");
|
MAP.put(ANNOTATION_PARAMETER_MUST_BE_KCLASS_LITERAL, "An annotation parameter must be a class literal (T::class)");
|
||||||
MAP.put(DEPRECATED_ANNOTATION_SYNTAX, "This syntax for annotations is deprecated. Use '@' before annotation identifier instead");
|
MAP.put(DEPRECATED_ANNOTATION_SYNTAX, "This syntax for annotations is deprecated. Use '@' before annotation identifier instead");
|
||||||
|
MAP.put(ANNOTATION_PARAMETER_DEFAULT_VALUE_MUST_BE_CONSTANT, "Default value of annotation parameter must be a compile-time constant");
|
||||||
|
|
||||||
MAP.put(DEFAULT_VALUE_NOT_ALLOWED_IN_OVERRIDE, "An overriding function is not allowed to specify default values for its parameters");
|
MAP.put(DEFAULT_VALUE_NOT_ALLOWED_IN_OVERRIDE, "An overriding function is not allowed to specify default values for its parameters");
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
package org.jetbrains.kotlin.types.expressions
|
package org.jetbrains.kotlin.types.expressions
|
||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||||
|
import org.jetbrains.kotlin.diagnostics.Errors
|
||||||
import org.jetbrains.kotlin.psi.JetParameter
|
import org.jetbrains.kotlin.psi.JetParameter
|
||||||
import org.jetbrains.kotlin.resolve.*
|
import org.jetbrains.kotlin.resolve.*
|
||||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
|
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
|
||||||
@@ -65,6 +66,7 @@ public class ValueParameterResolver(
|
|||||||
expressionTypingServices.getTypeInfo(defaultValue, context.replaceExpectedType(valueParameterDescriptor.getType()))
|
expressionTypingServices.getTypeInfo(defaultValue, context.replaceExpectedType(valueParameterDescriptor.getType()))
|
||||||
if (DescriptorUtils.isAnnotationClass(DescriptorResolver.getContainingClass(context.scope))) {
|
if (DescriptorUtils.isAnnotationClass(DescriptorResolver.getContainingClass(context.scope))) {
|
||||||
ConstantExpressionEvaluator.evaluate(defaultValue, context.trace, valueParameterDescriptor.getType())
|
ConstantExpressionEvaluator.evaluate(defaultValue, context.trace, valueParameterDescriptor.getType())
|
||||||
|
?: context.trace.report(Errors.ANNOTATION_PARAMETER_DEFAULT_VALUE_MUST_BE_CONSTANT.on(defaultValue))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+22
@@ -0,0 +1,22 @@
|
|||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
val CONST = 1
|
||||||
|
fun foo() = 1
|
||||||
|
val nonConst = foo()
|
||||||
|
|
||||||
|
annotation class ValidAnn(
|
||||||
|
val p1: Int = 1 + CONST,
|
||||||
|
val p2: String = "",
|
||||||
|
val p3: KClass<*> = String::class,
|
||||||
|
val p4: IntArray = intArrayOf(1, 2, 3),
|
||||||
|
val p5: Array<String> = arrayOf("abc"),
|
||||||
|
val p6: Array<KClass<*>> = arrayOf(Int::class)
|
||||||
|
)
|
||||||
|
|
||||||
|
val nonConstKClass = String::class
|
||||||
|
|
||||||
|
annotation class InvalidAnn(
|
||||||
|
val p1: Int = <!ANNOTATION_PARAMETER_DEFAULT_VALUE_MUST_BE_CONSTANT!>foo()<!>,
|
||||||
|
val p2: Int = <!ANNOTATION_PARAMETER_DEFAULT_VALUE_MUST_BE_CONSTANT!>nonConst<!>,
|
||||||
|
val p3: KClass<*> = <!ANNOTATION_PARAMETER_DEFAULT_VALUE_MUST_BE_CONSTANT!>nonConstKClass<!>
|
||||||
|
)
|
||||||
+29
@@ -0,0 +1,29 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
internal val CONST: kotlin.Int = 1
|
||||||
|
internal val nonConst: kotlin.Int
|
||||||
|
internal val nonConstKClass: kotlin.reflect.KClass<kotlin.String>
|
||||||
|
internal fun foo(): kotlin.Int
|
||||||
|
|
||||||
|
internal final annotation class InvalidAnn : kotlin.Annotation {
|
||||||
|
public constructor InvalidAnn(/*0*/ p1: kotlin.Int = ..., /*1*/ p2: kotlin.Int = ..., /*2*/ p3: kotlin.reflect.KClass<*> = ...)
|
||||||
|
internal final val p1: kotlin.Int
|
||||||
|
internal final val p2: kotlin.Int
|
||||||
|
internal final val p3: kotlin.reflect.KClass<*>
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
|
|
||||||
|
internal final annotation class ValidAnn : kotlin.Annotation {
|
||||||
|
public constructor ValidAnn(/*0*/ p1: kotlin.Int = ..., /*1*/ p2: kotlin.String = ..., /*2*/ p3: kotlin.reflect.KClass<*> = ..., /*3*/ p4: kotlin.IntArray = ..., /*4*/ p5: kotlin.Array<kotlin.String> = ..., /*5*/ p6: kotlin.Array<kotlin.reflect.KClass<*>> = ...)
|
||||||
|
internal final val p1: kotlin.Int
|
||||||
|
internal final val p2: kotlin.String
|
||||||
|
internal final val p3: kotlin.reflect.KClass<*>
|
||||||
|
internal final val p4: kotlin.IntArray
|
||||||
|
internal final val p5: kotlin.Array<kotlin.String>
|
||||||
|
internal final val p6: kotlin.Array<kotlin.reflect.KClass<*>>
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
+6
@@ -61,6 +61,12 @@ public class JetDiagnosticsTestWithStdLibGenerated extends AbstractJetDiagnostic
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("defaultValueMustBeConstant.kt")
|
||||||
|
public void testDefaultValueMustBeConstant() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/annotations/defaultValueMustBeConstant.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("qualifiedCallValue.kt")
|
@TestMetadata("qualifiedCallValue.kt")
|
||||||
public void testQualifiedCallValue() throws Exception {
|
public void testQualifiedCallValue() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/annotations/qualifiedCallValue.kt");
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/annotations/qualifiedCallValue.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user