8044196: Incorrect applying of repeatable annotations with incompatible target to type parameter
Summary: Additional applicability checks added.
Reviewed-by: jlahoda
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotations.java Wed Apr 29 15:05:33 2015 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotations.java Thu Apr 30 12:21:50 2015 +0200
@@ -28,11 +28,11 @@
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.type.TypeKind;
-
import javax.tools.JavaFileObject;
import com.sun.tools.javac.code.Attribute.Array;
import com.sun.tools.javac.code.Attribute.TypeCompound;
+import com.sun.tools.javac.code.Symbol.TypeSymbol;
import com.sun.tools.javac.code.Type.ArrayType;
import com.sun.tools.javac.code.Type.CapturedType;
import com.sun.tools.javac.code.Type.ClassType;
@@ -153,8 +153,8 @@
public enum AnnotationType { DECLARATION, TYPE, NONE, BOTH }
- public List<Attribute> annotationTargets(Attribute.Compound anno) {
- Attribute.Compound atTarget = anno.type.tsym.getAnnotationTypeMetadata().getTarget();
+ public List<Attribute> annotationTargets(TypeSymbol tsym) {
+ Attribute.Compound atTarget = tsym.getAnnotationTypeMetadata().getTarget();
if (atTarget == null) {
return null;
}
@@ -177,7 +177,7 @@
* a type annotation, or both.
*/
public AnnotationType annotationTargetType(Attribute.Compound a, Symbol s) {
- List<Attribute> targets = annotationTargets(a);
+ List<Attribute> targets = annotationTargets(a.type.tsym);
return (targets == null) ?
AnnotationType.DECLARATION :
targets.stream()
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java Wed Apr 29 15:05:33 2015 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java Thu Apr 30 12:21:50 2015 +0200
@@ -243,7 +243,10 @@
log.error(annotations.head.pos, "already.annotated", Kinds.kindName(s), s);
Assert.checkNonNull(s, "Symbol argument to actualEnterAnnotations is null");
- annotateNow(s, annotations, localEnv, false);
+
+ // false is passed as fifth parameter since annotateLater is
+ // never called for a type parameter
+ annotateNow(s, annotations, localEnv, false, false);
} finally {
if (prevLint != null)
chk.setLint(prevLint);
@@ -327,7 +330,8 @@
* then continue on with repeating annotations processing.
*/
private <T extends Attribute.Compound> void annotateNow(Symbol toAnnotate,
- List<JCAnnotation> withAnnotations, Env<AttrContext> env, boolean typeAnnotations)
+ List<JCAnnotation> withAnnotations, Env<AttrContext> env, boolean typeAnnotations,
+ boolean isTypeParam)
{
Map<TypeSymbol, ListBuffer<T>> annotated = new LinkedHashMap<>();
Map<T, DiagnosticPosition> pos = new HashMap<>();
@@ -377,7 +381,7 @@
buf = buf.prepend(lb.first());
} else {
AnnotationContext<T> ctx = new AnnotationContext<>(env, annotated, pos, typeAnnotations);
- T res = makeContainerAnnotation(lb.toList(), ctx, toAnnotate);
+ T res = makeContainerAnnotation(lb.toList(), ctx, toAnnotate, isTypeParam);
if (res != null)
buf = buf.prepend(res);
}
@@ -698,7 +702,7 @@
* annotation are invalid. This method reports errors/warnings.
*/
private <T extends Attribute.Compound> T processRepeatedAnnotations(List<T> annotations,
- AnnotationContext<T> ctx, Symbol on)
+ AnnotationContext<T> ctx, Symbol on, boolean isTypeParam)
{
T firstOccurrence = annotations.head;
List<Attribute> repeated = List.nil();
@@ -752,7 +756,8 @@
if (!repeated.isEmpty()) {
repeated = repeated.reverse();
- TreeMaker m = make.at(ctx.pos.get(firstOccurrence));
+ DiagnosticPosition pos = ctx.pos.get(firstOccurrence);
+ TreeMaker m = make.at(pos);
Pair<MethodSymbol, Attribute> p =
new Pair<MethodSymbol, Attribute>(containerValueSymbol,
new Attribute.Array(arrayOfOrigAnnoType, repeated));
@@ -768,7 +773,14 @@
Attribute.TypeCompound at = new Attribute.TypeCompound(targetContainerType, List.of(p),
((Attribute.TypeCompound)annotations.head).position);
- // TODO: annotation applicability checks from below?
+ JCAnnotation annoTree = m.TypeAnnotation(at);
+ if (!chk.validateAnnotationDeferErrors(annoTree))
+ log.error(annoTree.pos(), Errors.DuplicateAnnotationInvalidRepeated(origAnnoType));
+
+ if (!chk.isTypeAnnotation(annoTree, isTypeParam)) {
+ log.error(pos, isTypeParam ? Errors.InvalidRepeatableAnnotationNotApplicable(targetContainerType, on)
+ : Errors.InvalidRepeatableAnnotationNotApplicableInContext(targetContainerType));
+ }
at.setSynthesized(true);
@@ -925,11 +937,11 @@
}
private <T extends Attribute.Compound> T makeContainerAnnotation(List<T> toBeReplaced,
- AnnotationContext<T> ctx, Symbol sym)
+ AnnotationContext<T> ctx, Symbol sym, boolean isTypeParam)
{
// Process repeated annotations
T validRepeated =
- processRepeatedAnnotations(toBeReplaced, ctx, sym);
+ processRepeatedAnnotations(toBeReplaced, ctx, sym, isTypeParam);
if (validRepeated != null) {
// Check that the container isn't manually
@@ -955,7 +967,7 @@
* Attribute the list of annotations and enter them onto s.
*/
public void enterTypeAnnotations(List<JCAnnotation> annotations, Env<AttrContext> env,
- Symbol s, DiagnosticPosition deferPos)
+ Symbol s, DiagnosticPosition deferPos, boolean isTypeParam)
{
Assert.checkNonNull(s, "Symbol argument to actualEnterTypeAnnotations is nul/");
JavaFileObject prev = log.useSource(env.toplevel.sourcefile);
@@ -965,7 +977,7 @@
prevLintPos = deferredLintHandler.setPos(deferPos);
}
try {
- annotateNow(s, annotations, env, true);
+ annotateNow(s, annotations, env, true, isTypeParam);
} finally {
if (prevLintPos != null)
deferredLintHandler.setPos(prevLintPos);
@@ -1048,21 +1060,21 @@
@Override
public void visitAnnotatedType(JCAnnotatedType tree) {
- enterTypeAnnotations(tree.annotations, env, sym, deferPos);
+ enterTypeAnnotations(tree.annotations, env, sym, deferPos, false);
scan(tree.underlyingType);
}
@Override
public void visitTypeParameter(JCTypeParameter tree) {
- enterTypeAnnotations(tree.annotations, env, sym, deferPos);
+ enterTypeAnnotations(tree.annotations, env, sym, deferPos, true);
scan(tree.bounds);
}
@Override
public void visitNewArray(JCNewArray tree) {
- enterTypeAnnotations(tree.annotations, env, sym, deferPos);
+ enterTypeAnnotations(tree.annotations, env, sym, deferPos, false);
for (List<JCAnnotation> dimAnnos : tree.dimAnnotations)
- enterTypeAnnotations(dimAnnos, env, sym, deferPos);
+ enterTypeAnnotations(dimAnnos, env, sym, deferPos, false);
scan(tree.elemtype);
scan(tree.elems);
}
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java Wed Apr 29 15:05:33 2015 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java Thu Apr 30 12:21:50 2015 +0200
@@ -2999,7 +2999,7 @@
/** Is the annotation applicable to types? */
protected boolean isTypeAnnotation(JCAnnotation a, boolean isTypeParameter) {
- List<Attribute> targets = typeAnnotations.annotationTargets(a.attribute);
+ List<Attribute> targets = typeAnnotations.annotationTargets(a.annotationType.type.tsym);
return (targets == null) ?
false :
targets.stream()
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties Wed Apr 29 15:05:33 2015 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties Thu Apr 30 12:21:50 2015 +0200
@@ -414,6 +414,10 @@
compiler.err.invalid.repeatable.annotation.not.applicable=\
container {0} is not applicable to element {1}
+# 0: type
+compiler.err.invalid.repeatable.annotation.not.applicable.in.context=\
+ container {0} is not applicable in this type context
+
# 0: name
compiler.err.duplicate.class=\
duplicate class: {0}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/annotations/repeatingAnnotations/InvalidClsTypeParamTarget.java Thu Apr 30 12:21:50 2015 +0200
@@ -0,0 +1,21 @@
+/**
+ * @test /nodynamiccopyright/
+ * @bug 8044196
+ * @summary Ensure that containers with target FIELD can't be applied to type parameters.
+ * @compile/fail/ref=InvalidClsTypeParamTarget.out -XDrawDiagnostics InvalidClsTypeParamTarget.java
+ */
+
+import java.lang.annotation.*;
+
+class InvalidClsTypeParamTarget {
+
+ @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE, ElementType.FIELD})
+ @Repeatable(TC.class)
+ @interface T { int value(); }
+
+ @Target(ElementType.FIELD)
+ @interface TC { T[] value(); }
+
+ class Test<@T(1) @T(2) N> {
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/annotations/repeatingAnnotations/InvalidClsTypeParamTarget.out Thu Apr 30 12:21:50 2015 +0200
@@ -0,0 +1,2 @@
+InvalidClsTypeParamTarget.java:19:16: compiler.err.invalid.repeatable.annotation.not.applicable: InvalidClsTypeParamTarget.TC, InvalidClsTypeParamTarget.Test
+1 error
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/annotations/repeatingAnnotations/InvalidMethodTypeParamTarget.java Thu Apr 30 12:21:50 2015 +0200
@@ -0,0 +1,20 @@
+/**
+ * @test /nodynamiccopyright/
+ * @bug 8044196
+ * @summary Ensure that containers with target METHOD can't be applied to type parameters.
+ * @compile/fail/ref=InvalidMethodTypeParamTarget.out -XDrawDiagnostics InvalidMethodTypeParamTarget.java
+ */
+
+import java.lang.annotation.*;
+
+class InvalidMethodTypeParamTarget {
+
+ @Target({ElementType.TYPE_PARAMETER, ElementType.METHOD})
+ @Repeatable(TC.class)
+ @interface T { int value(); }
+
+ @Target(ElementType.METHOD)
+ @interface TC { T[] value(); }
+
+ public <@T(1) @T(2) N> void method() { }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/annotations/repeatingAnnotations/InvalidMethodTypeParamTarget.out Thu Apr 30 12:21:50 2015 +0200
@@ -0,0 +1,2 @@
+InvalidMethodTypeParamTarget.java:19:13: compiler.err.invalid.repeatable.annotation.not.applicable: InvalidMethodTypeParamTarget.TC, <N>method()
+1 error
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/annotations/repeatingAnnotations/InvalidMethodTypeUse.java Thu Apr 30 12:21:50 2015 +0200
@@ -0,0 +1,24 @@
+/**
+ * @test /nodynamiccopyright/
+ * @bug 8044196
+ * @summary Make sure repeatable annotations can't be erroneously applied to type arguments.
+ * @compile/fail/ref=InvalidMethodTypeUse.out -XDrawDiagnostics InvalidMethodTypeUse.java
+ */
+
+import java.lang.annotation.*;
+
+class InvalidMethodTypeUse {
+
+ @Target({ElementType.TYPE_USE, ElementType.METHOD, ElementType.TYPE_PARAMETER})
+ @Repeatable(TC.class)
+ @interface T { int value(); }
+
+ @Target({ElementType.METHOD, ElementType.TYPE_PARAMETER})
+ @interface TC { T[] value(); }
+
+ void method() {
+ this.<@T(1) @T(2) String>method2();
+ }
+
+ <@T(3) S> void method2() { }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/annotations/repeatingAnnotations/InvalidMethodTypeUse.out Thu Apr 30 12:21:50 2015 +0200
@@ -0,0 +1,2 @@
+InvalidMethodTypeUse.java:20:15: compiler.err.invalid.repeatable.annotation.not.applicable.in.context: InvalidMethodTypeUse.TC
+1 error
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/annotations/repeatingAnnotations/InvalidRepAnnoOnCast.java Thu Apr 30 12:21:50 2015 +0200
@@ -0,0 +1,20 @@
+/**
+ * @test /nodynamiccopyright/
+ * @bug 8044196
+ * @summary Make sure repeatable annotations can't be erroneously applied to a cast type
+ * @compile/fail/ref=InvalidRepAnnoOnCast.out -XDrawDiagnostics InvalidRepAnnoOnCast.java
+ */
+
+import java.lang.annotation.*;
+
+class InvalidRepAnnoOnCast {
+
+ @Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+ @Repeatable(TC.class)
+ @interface T { int value(); }
+
+ @Target(ElementType.TYPE_PARAMETER)
+ @interface TC { T[] value(); }
+
+ String s = (@T(1) @T(2) String) new Object();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/annotations/repeatingAnnotations/InvalidRepAnnoOnCast.out Thu Apr 30 12:21:50 2015 +0200
@@ -0,0 +1,2 @@
+InvalidRepAnnoOnCast.java:19:17: compiler.err.invalid.repeatable.annotation.not.applicable.in.context: InvalidRepAnnoOnCast.TC
+1 error
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/annotations/repeatingAnnotations/brokenTypeAnnoContainer/BrokenTypeAnnoContainer.java Thu Apr 30 12:21:50 2015 +0200
@@ -0,0 +1,14 @@
+/**
+ * @test /nodynamiccopyright/
+ * @bug 8044196
+ * @summary Ensure that a broken type annotation container generates a correct error message.
+ * @compile T.java TC.java
+ * @compile TCBroken.java
+ * @compile/fail/ref=BrokenTypeAnnoContainer.out -XDrawDiagnostics BrokenTypeAnnoContainer.java
+ */
+
+class BrokenTypeAnnoContainer {
+ void method() {
+ int ll2 = (@T(1) @T(2) int) 0;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/annotations/repeatingAnnotations/brokenTypeAnnoContainer/BrokenTypeAnnoContainer.out Thu Apr 30 12:21:50 2015 +0200
@@ -0,0 +1,2 @@
+BrokenTypeAnnoContainer.java:12:20: compiler.err.duplicate.annotation.invalid.repeated: T
+1 error
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/annotations/repeatingAnnotations/brokenTypeAnnoContainer/T.java Thu Apr 30 12:21:50 2015 +0200
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.lang.annotation.*;
+
+@Target(ElementType.TYPE_USE)
+@Repeatable(TC.class)
+@interface T { int value(); }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/annotations/repeatingAnnotations/brokenTypeAnnoContainer/TC.java Thu Apr 30 12:21:50 2015 +0200
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.lang.annotation.*;
+
+@Target(ElementType.TYPE_USE)
+@interface TC {
+ T[] value();
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/annotations/repeatingAnnotations/brokenTypeAnnoContainer/TCBroken.java Thu Apr 30 12:21:50 2015 +0200
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.lang.annotation.*;
+
+@Target(ElementType.TYPE_USE)
+@interface TC {
+ T[] value();
+ int foo();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/InvalidTypeContextRepeatableAnnotation.java Thu Apr 30 12:21:50 2015 +0200
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// key: compiler.err.invalid.repeatable.annotation.not.applicable.in.context
+
+
+import java.lang.annotation.*;
+
+@Target({ElementType.TYPE_USE, ElementType.METHOD, ElementType.TYPE_PARAMETER})
+@Repeatable(TC.class)
+@interface T { int value(); }
+
+@Target({ElementType.METHOD, ElementType.TYPE_PARAMETER})
+@interface TC { T[] value(); }
+
+public class InvalidTypeContextRepeatableAnnotation {
+ void method() {
+ this.<@T(1) @T(2) String>method2();
+ }
+
+ <@T(3) S> void method2() {
+ }
+}