Prohibit instantiation of annotation classes

#KT-3465 Fixed
This commit is contained in:
Natalia Ukhorskaya
2013-12-18 17:26:42 +04:00
parent 9fad61352b
commit 359f2ddbda
8 changed files with 85 additions and 0 deletions
@@ -111,6 +111,7 @@ public interface Errors {
// Annotations
DiagnosticFactory0<JetCallExpression> ANNOTATION_CLASS_CONSTRUCTOR_CALL = DiagnosticFactory0.create(ERROR);
DiagnosticFactory1<JetAnnotationEntry, String> NOT_AN_ANNOTATION_CLASS = DiagnosticFactory1.create(ERROR);
DiagnosticFactory0<PsiElement> ANNOTATION_CLASS_WITH_BODY = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<JetTypeReference> INVALID_TYPE_OF_ANNOTATION_MEMBER = DiagnosticFactory0.create(ERROR);
@@ -451,6 +451,7 @@ public class DefaultErrorMessages {
MAP.put(TYPE_PARAMETER_AS_REIFIED, "Cannot use ''{0}'' as reified type parameter. Use a class instead.", NAME);
MAP.put(ANNOTATION_CLASS_CONSTRUCTOR_CALL, "Annotation class cannot be instantiated");
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(INVALID_TYPE_OF_ANNOTATION_MEMBER, "Invalid type of annotation member");
@@ -17,6 +17,8 @@
package org.jetbrains.jet.lang.resolve.calls;
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.*;
@@ -24,6 +26,7 @@ import org.jetbrains.jet.lang.evaluate.ConstantExpressionEvaluator;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.BindingTrace;
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
import org.jetbrains.jet.lang.resolve.TemporaryBindingTrace;
import org.jetbrains.jet.lang.resolve.calls.context.BasicCallResolutionContext;
import org.jetbrains.jet.lang.resolve.calls.context.CheckValueArgumentsMode;
@@ -349,6 +352,12 @@ public class CallExpressionResolver {
if (functionDescriptor == null) {
return JetTypeInfo.create(null, context.dataFlowInfo);
}
if (functionDescriptor instanceof ConstructorDescriptor && DescriptorUtils.isAnnotationClass(functionDescriptor.getContainingDeclaration())) {
if (!canInstantiateAnnotationClass(callExpression)) {
context.trace.report(ANNOTATION_CLASS_CONSTRUCTOR_CALL.on(callExpression));
}
}
JetType type = functionDescriptor.getReturnType();
return JetTypeInfo.create(type, resolvedCall.getDataFlowInfoForArguments().getResultInfo());
@@ -371,6 +380,20 @@ public class CallExpressionResolver {
return JetTypeInfo.create(null, context.dataFlowInfo);
}
private static boolean canInstantiateAnnotationClass(@NotNull JetCallExpression expression) {
PsiElement parent = expression.getParent();
if (parent instanceof JetValueArgument) {
return PsiTreeUtil.getParentOfType(parent, JetAnnotationEntry.class) != null;
}
else if (parent instanceof JetParameter) {
JetClass jetClass = PsiTreeUtil.getParentOfType(parent, JetClass.class);
if (jetClass != null) {
return jetClass.hasModifier(JetTokens.ANNOTATION_KEYWORD);
}
}
return false;
}
private void checkSuper(@NotNull ReceiverValue receiverValue, @NotNull OverloadResolutionResults<? extends CallableDescriptor> results,
@NotNull BindingTrace trace, @NotNull JetExpression expression) {
if (!results.isSingleResult()) return;
@@ -0,0 +1,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
@interface JavaAnn {
String value();
}
@@ -0,0 +1,8 @@
JavaAnn("value") class MyClass
fun box(): String {
val ann = javaClass<MyClass>().getAnnotation(javaClass<JavaAnn>())
if (ann == null) return "fail: cannot find Ann on MyClass}"
if (ann.value() != "value") return "fail: annotation parameter i should be 'value', but was ${ann.value()}"
return "OK"
}
@@ -0,0 +1,35 @@
annotation class Ann
annotation class Ann1(val a: Int)
annotation class Ann2(val a: Ann1)
annotation class Ann3(val a: Ann1 = Ann1(1))
annotation class Ann4(val value: String)
Ann2(Ann1(1)) val a = 1
Ann2(a = Ann1(1)) val c = 2
Ann4("a") class MyClass
fun foo() {
<!ANNOTATION_CLASS_CONSTRUCTOR_CALL!>Ann()<!>
val <!UNUSED_VARIABLE!>a<!> = <!ANNOTATION_CLASS_CONSTRUCTOR_CALL!>Ann()<!>
<!ANNOTATION_CLASS_CONSTRUCTOR_CALL!>Ann1(<!NO_VALUE_FOR_PARAMETER!>)<!><!>
<!ANNOTATION_CLASS_CONSTRUCTOR_CALL!>Ann1(1)<!>
bar(<!ANNOTATION_CLASS_CONSTRUCTOR_CALL!>Ann()<!>)
bar(a = <!ANNOTATION_CLASS_CONSTRUCTOR_CALL!>Ann()<!>)
val ann = javaClass<MyClass>().getAnnotation(javaClass<Ann4>())
ann!!.value()
}
fun bar(a: Ann = <!ANNOTATION_CLASS_CONSTRUCTOR_CALL!>Ann()<!>) {
if (a is Ann) {}
}
fun String.invoke() {}
// from stdlib
fun <T> javaClass() : Class<T> = null <!CAST_NEVER_SUCCEEDS!>as<!> Class<T>
@@ -575,6 +575,11 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
doTest("compiler/testData/diagnostics/tests/annotations/BasicAnnotations.kt");
}
@TestMetadata("ConstructorCall.kt")
public void testConstructorCall() throws Exception {
doTest("compiler/testData/diagnostics/tests/annotations/ConstructorCall.kt");
}
@TestMetadata("Deprecated.kt")
public void testDeprecated() throws Exception {
doTest("compiler/testData/diagnostics/tests/annotations/Deprecated.kt");
@@ -43,6 +43,11 @@ public class BlackBoxWithJavaCodegenTestGenerated extends AbstractBlackBoxCodege
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/codegen/boxWithJava/annotations"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("javaAnnotationCall.kt")
public void testJavaAnnotationCall() throws Exception {
doTestWithJava("compiler/testData/codegen/boxWithJava/annotations/javaAnnotationCall.kt");
}
@TestMetadata("javaNegativePropertyAsAnnotationParameter.kt")
public void testJavaNegativePropertyAsAnnotationParameter() throws Exception {
doTestWithJava("compiler/testData/codegen/boxWithJava/annotations/javaNegativePropertyAsAnnotationParameter.kt");