Check annotation constructor parameter types
This commit is contained in:
@@ -114,6 +114,7 @@ public interface Errors {
|
|||||||
|
|
||||||
DiagnosticFactory1<JetAnnotationEntry, String> NOT_AN_ANNOTATION_CLASS = DiagnosticFactory1.create(ERROR);
|
DiagnosticFactory1<JetAnnotationEntry, String> NOT_AN_ANNOTATION_CLASS = DiagnosticFactory1.create(ERROR);
|
||||||
DiagnosticFactory0<PsiElement> ANNOTATION_CLASS_WITH_BODY = DiagnosticFactory0.create(ERROR);
|
DiagnosticFactory0<PsiElement> ANNOTATION_CLASS_WITH_BODY = DiagnosticFactory0.create(ERROR);
|
||||||
|
DiagnosticFactory0<JetTypeReference> INVALID_TYPE_OF_ANNOTATION_MEMBER = DiagnosticFactory0.create(ERROR);
|
||||||
|
|
||||||
// Classes and traits
|
// Classes and traits
|
||||||
|
|
||||||
|
|||||||
+1
@@ -434,6 +434,7 @@ public class DefaultErrorMessages {
|
|||||||
|
|
||||||
MAP.put(NOT_AN_ANNOTATION_CLASS, "''{0}'' is not an annotation class", TO_STRING);
|
MAP.put(NOT_AN_ANNOTATION_CLASS, "''{0}'' is not an annotation class", TO_STRING);
|
||||||
MAP.put(ANNOTATION_CLASS_WITH_BODY, "Body is not allowed for annotation class");
|
MAP.put(ANNOTATION_CLASS_WITH_BODY, "Body is not allowed for annotation class");
|
||||||
|
MAP.put(INVALID_TYPE_OF_ANNOTATION_MEMBER, "Invalid type of annotation member");
|
||||||
|
|
||||||
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");
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,96 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2013 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.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.jet.lang.resolve;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
|
||||||
|
import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
|
||||||
|
import org.jetbrains.jet.lang.psi.JetParameter;
|
||||||
|
import org.jetbrains.jet.lang.psi.JetTypeReference;
|
||||||
|
import org.jetbrains.jet.lang.types.JetType;
|
||||||
|
import org.jetbrains.jet.lang.types.TypeProjection;
|
||||||
|
import org.jetbrains.jet.lang.types.TypeUtils;
|
||||||
|
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.jetbrains.jet.lang.diagnostics.Errors.INVALID_TYPE_OF_ANNOTATION_MEMBER;
|
||||||
|
import static org.jetbrains.jet.lang.resolve.BindingContext.VALUE_PARAMETER;
|
||||||
|
import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isAnnotationClass;
|
||||||
|
import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isEnumClass;
|
||||||
|
|
||||||
|
public class AnnotationUtils {
|
||||||
|
|
||||||
|
public static void checkConstructorParametersType(@NotNull List<JetParameter> parameters, @NotNull BindingTrace trace) {
|
||||||
|
for (JetParameter parameter : parameters) {
|
||||||
|
VariableDescriptor parameterDescriptor = trace.getBindingContext().get(VALUE_PARAMETER, parameter);
|
||||||
|
if (parameterDescriptor == null) continue;
|
||||||
|
JetType parameterType = parameterDescriptor.getType();
|
||||||
|
if (!isAcceptableTypeForAnnotationParameter(parameterType)) {
|
||||||
|
JetTypeReference typeReference = parameter.getTypeReference();
|
||||||
|
if (typeReference != null) {
|
||||||
|
trace.report(INVALID_TYPE_OF_ANNOTATION_MEMBER.on(typeReference));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isAcceptableTypeForAnnotationParameter(@NotNull JetType parameterType) {
|
||||||
|
if (parameterType.isNullable()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ClassDescriptor typeDescriptor = TypeUtils.getClassDescriptor(parameterType);
|
||||||
|
if (typeDescriptor == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
KotlinBuiltIns builtIns = KotlinBuiltIns.getInstance();
|
||||||
|
if (isEnumClass(typeDescriptor) ||
|
||||||
|
isAnnotationClass(typeDescriptor) ||
|
||||||
|
isJavaLangClass(typeDescriptor) ||
|
||||||
|
builtIns.isPrimitiveArray(parameterType) ||
|
||||||
|
builtIns.isPrimitiveType(parameterType) ||
|
||||||
|
builtIns.getStringType().equals(parameterType)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (builtIns.isArray(parameterType)) {
|
||||||
|
List<TypeProjection> arguments = parameterType.getArguments();
|
||||||
|
if (arguments.size() == 1) {
|
||||||
|
JetType arrayType = arguments.get(0).getType();
|
||||||
|
if (arrayType.isNullable()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ClassDescriptor arrayTypeDescriptor = TypeUtils.getClassDescriptor(arrayType);
|
||||||
|
if (arrayTypeDescriptor != null) {
|
||||||
|
return isEnumClass(arrayTypeDescriptor) ||
|
||||||
|
isAnnotationClass(arrayTypeDescriptor) ||
|
||||||
|
isJavaLangClass(arrayTypeDescriptor) ||
|
||||||
|
builtIns.getStringType().equals(arrayType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isJavaLangClass(ClassDescriptor descriptor) {
|
||||||
|
return "java.lang.Class".equals(DescriptorUtils.getFQName(descriptor).asString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private AnnotationUtils() {
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1264,7 +1264,7 @@ public class DescriptorResolver {
|
|||||||
WritableScopeImpl parameterScope = new WritableScopeImpl(
|
WritableScopeImpl parameterScope = new WritableScopeImpl(
|
||||||
scope, constructorDescriptor, new TraceBasedRedeclarationHandler(trace), "Scope with value parameters of a constructor");
|
scope, constructorDescriptor, new TraceBasedRedeclarationHandler(trace), "Scope with value parameters of a constructor");
|
||||||
parameterScope.changeLockLevel(WritableScope.LockLevel.BOTH);
|
parameterScope.changeLockLevel(WritableScope.LockLevel.BOTH);
|
||||||
return constructorDescriptor.initialize(
|
ConstructorDescriptorImpl constructor = constructorDescriptor.initialize(
|
||||||
typeParameters,
|
typeParameters,
|
||||||
resolveValueParameters(
|
resolveValueParameters(
|
||||||
constructorDescriptor,
|
constructorDescriptor,
|
||||||
@@ -1272,6 +1272,10 @@ public class DescriptorResolver {
|
|||||||
valueParameters, trace),
|
valueParameters, trace),
|
||||||
resolveVisibilityFromModifiers(modifierList, getDefaultConstructorVisibility(classDescriptor)),
|
resolveVisibilityFromModifiers(modifierList, getDefaultConstructorVisibility(classDescriptor)),
|
||||||
DescriptorUtils.isConstructorOfStaticNestedClass(constructorDescriptor));
|
DescriptorUtils.isConstructorOfStaticNestedClass(constructorDescriptor));
|
||||||
|
if (isAnnotationClass(classDescriptor)) {
|
||||||
|
AnnotationUtils.checkConstructorParametersType(valueParameters, trace);
|
||||||
|
}
|
||||||
|
return constructor;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
|
|||||||
@@ -289,6 +289,10 @@ public class DescriptorUtils {
|
|||||||
return isKindOf(descriptor, ClassKind.ENUM_CLASS);
|
return isKindOf(descriptor, ClassKind.ENUM_CLASS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isAnnotationClass(@NotNull DeclarationDescriptor descriptor) {
|
||||||
|
return isKindOf(descriptor, ClassKind.ANNOTATION_CLASS);
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean isClass(@NotNull DeclarationDescriptor descriptor) {
|
public static boolean isClass(@NotNull DeclarationDescriptor descriptor) {
|
||||||
return isKindOf(descriptor, ClassKind.CLASS);
|
return isKindOf(descriptor, ClassKind.CLASS);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -883,6 +883,10 @@ public class KotlinBuiltIns {
|
|||||||
return jetArrayTypeToPrimitiveJetType.containsKey(TypeUtils.makeNotNullable(type));
|
return jetArrayTypeToPrimitiveJetType.containsKey(TypeUtils.makeNotNullable(type));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isPrimitiveType(@NotNull JetType type) {
|
||||||
|
return primitiveJetTypeToJetArrayType.containsKey(type);
|
||||||
|
}
|
||||||
|
|
||||||
// Functions
|
// Functions
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
@AString(value = Test.vstring)
|
@AString(value = Test.vstring)
|
||||||
@AStringNullable(value = Test.vstringNullable)
|
|
||||||
@AChar(value = Test.vchar)
|
@AChar(value = Test.vchar)
|
||||||
@AInt(value = Test.vint)
|
@AInt(value = Test.vint)
|
||||||
@AByte(value = Test.vbyte)
|
@AByte(value = Test.vbyte)
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
annotation class AString(val value: String)
|
annotation class AString(val value: String)
|
||||||
annotation class AStringNullable(val value: String?)
|
|
||||||
annotation class AChar(val value: Char)
|
annotation class AChar(val value: Char)
|
||||||
annotation class AInt(val value: Int)
|
annotation class AInt(val value: Int)
|
||||||
annotation class AByte(val value: Byte)
|
annotation class AByte(val value: Byte)
|
||||||
@@ -11,7 +10,6 @@ class Test {
|
|||||||
|
|
||||||
class object {
|
class object {
|
||||||
val vstring: String = "Test"
|
val vstring: String = "Test"
|
||||||
val vstringNullable: String? = "Test"
|
|
||||||
val vchar: Char = 'c'
|
val vchar: Char = 'c'
|
||||||
val vint: Int = 10
|
val vint: Int = 10
|
||||||
val vbyte: Byte = 11
|
val vbyte: Byte = 11
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
@AString(value = Test.vstring)
|
@AString(value = Test.vstring)
|
||||||
@AStringNullable(value = Test.vstringNullable)
|
|
||||||
@AChar(value = Test.vchar)
|
@AChar(value = Test.vchar)
|
||||||
@AInt(value = Test.vint)
|
@AInt(value = Test.vint)
|
||||||
@AByte(value = Test.vbyte)
|
@AByte(value = Test.vbyte)
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
annotation class AString(val value: String)
|
annotation class AString(val value: String)
|
||||||
annotation class AStringNullable(val value: String?)
|
|
||||||
annotation class AChar(val value: Char)
|
annotation class AChar(val value: Char)
|
||||||
annotation class AInt(val value: Int)
|
annotation class AInt(val value: Int)
|
||||||
annotation class AByte(val value: Byte)
|
annotation class AByte(val value: Byte)
|
||||||
@@ -11,7 +10,6 @@ trait Test {
|
|||||||
|
|
||||||
class object {
|
class object {
|
||||||
val vstring: String = "Test"
|
val vstring: String = "Test"
|
||||||
val vstringNullable: String? = "Test"
|
|
||||||
val vchar: Char = 'c'
|
val vchar: Char = 'c'
|
||||||
val vint: Int = 10
|
val vint: Int = 10
|
||||||
val vbyte: Byte = 11
|
val vbyte: Byte = 11
|
||||||
|
|||||||
+72
@@ -0,0 +1,72 @@
|
|||||||
|
package test
|
||||||
|
|
||||||
|
import java.lang.annotation.RetentionPolicy
|
||||||
|
|
||||||
|
// CORRECT
|
||||||
|
annotation class Ann1(val p1: Int,
|
||||||
|
val p2: Byte,
|
||||||
|
val p3: Short,
|
||||||
|
val p4: Long,
|
||||||
|
val p5: Double,
|
||||||
|
val p6: Float,
|
||||||
|
val p7: Char,
|
||||||
|
val p8: Boolean)
|
||||||
|
|
||||||
|
annotation class Ann2(val p1: String)
|
||||||
|
annotation class Ann3(val p1: Ann1)
|
||||||
|
annotation class Ann4(val p1: IntArray,
|
||||||
|
val p2: ByteArray,
|
||||||
|
val p3: ShortArray,
|
||||||
|
val p4: LongArray,
|
||||||
|
val p5: DoubleArray,
|
||||||
|
val p6: FloatArray,
|
||||||
|
val p7: CharArray,
|
||||||
|
val p8: BooleanArray)
|
||||||
|
|
||||||
|
annotation class Ann5(val p1: MyEnum)
|
||||||
|
|
||||||
|
annotation class Ann6(val p: Class<*>)
|
||||||
|
annotation class Ann7(val p: RetentionPolicy)
|
||||||
|
|
||||||
|
annotation class Ann8(val p1: Array<String>,
|
||||||
|
val p2: Array<Class<*>>,
|
||||||
|
val p3: Array<MyEnum>,
|
||||||
|
val p4: Array<Ann1>)
|
||||||
|
|
||||||
|
annotation class Ann9(vararg val p1: String,
|
||||||
|
vararg val p2: Class<*>,
|
||||||
|
vararg val p3: MyEnum,
|
||||||
|
vararg val p4: Ann1,
|
||||||
|
vararg val p5: Int)
|
||||||
|
|
||||||
|
// INCORRECT
|
||||||
|
annotation class InAnn1(val p1: <!INVALID_TYPE_OF_ANNOTATION_MEMBER!>Int?<!>,
|
||||||
|
val p3: <!INVALID_TYPE_OF_ANNOTATION_MEMBER!>Short?<!>,
|
||||||
|
val p4: <!INVALID_TYPE_OF_ANNOTATION_MEMBER!>Long?<!>,
|
||||||
|
val p5: <!INVALID_TYPE_OF_ANNOTATION_MEMBER!>Double?<!>,
|
||||||
|
val p6: <!INVALID_TYPE_OF_ANNOTATION_MEMBER!>Float?<!>,
|
||||||
|
val p7: <!INVALID_TYPE_OF_ANNOTATION_MEMBER!>Char?<!>,
|
||||||
|
val p8: <!INVALID_TYPE_OF_ANNOTATION_MEMBER!>Boolean?<!>)
|
||||||
|
|
||||||
|
annotation class InAnn4(val p1: <!INVALID_TYPE_OF_ANNOTATION_MEMBER!>Array<Int><!>,
|
||||||
|
val p2: <!INVALID_TYPE_OF_ANNOTATION_MEMBER!>Array<Int>?<!>)
|
||||||
|
|
||||||
|
annotation class InAnn6(val p: <!INVALID_TYPE_OF_ANNOTATION_MEMBER!>Class<*>?<!>)
|
||||||
|
annotation class InAnn7(val p: <!INVALID_TYPE_OF_ANNOTATION_MEMBER!>RetentionPolicy?<!>)
|
||||||
|
annotation class InAnn8(val p1: <!INVALID_TYPE_OF_ANNOTATION_MEMBER!>Array<Int><!>,
|
||||||
|
val p2: <!INVALID_TYPE_OF_ANNOTATION_MEMBER!>Array<Int?><!>,
|
||||||
|
val p3: <!INVALID_TYPE_OF_ANNOTATION_MEMBER!>Array<MyClass><!>,
|
||||||
|
val p4: <!INVALID_TYPE_OF_ANNOTATION_MEMBER!>Array<IntArray><!>)
|
||||||
|
|
||||||
|
annotation class InAnn9(val p: <!INVALID_TYPE_OF_ANNOTATION_MEMBER!>MyClass<!>)
|
||||||
|
|
||||||
|
annotation class InAnn10(val p1: <!INVALID_TYPE_OF_ANNOTATION_MEMBER!>String?<!>)
|
||||||
|
annotation class InAnn11(val p1: <!INVALID_TYPE_OF_ANNOTATION_MEMBER!>Ann1?<!>)
|
||||||
|
annotation class InAnn12(val p1: <!INVALID_TYPE_OF_ANNOTATION_MEMBER!>MyEnum?<!>)
|
||||||
|
|
||||||
|
|
||||||
|
enum class MyEnum {
|
||||||
|
A
|
||||||
|
}
|
||||||
|
|
||||||
|
class MyClass
|
||||||
@@ -565,6 +565,11 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage
|
|||||||
doTest("compiler/testData/diagnostics/tests/annotations/Deprecated.kt");
|
doTest("compiler/testData/diagnostics/tests/annotations/Deprecated.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("invalidTypesInAnnotationConstructor.kt")
|
||||||
|
public void testInvalidTypesInAnnotationConstructor() throws Exception {
|
||||||
|
doTest("compiler/testData/diagnostics/tests/annotations/invalidTypesInAnnotationConstructor.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("JavaAnnotationConstructors.kt")
|
@TestMetadata("JavaAnnotationConstructors.kt")
|
||||||
public void testJavaAnnotationConstructors() throws Exception {
|
public void testJavaAnnotationConstructors() throws Exception {
|
||||||
doTest("compiler/testData/diagnostics/tests/annotations/JavaAnnotationConstructors.kt");
|
doTest("compiler/testData/diagnostics/tests/annotations/JavaAnnotationConstructors.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user