Mercurial > hg > jdk9-shenandoah > langtools
changeset 2900:732890c00534
8044196: Incorrect applying of repeatable annotations with incompatible target to type parameter
Summary: Additional applicability checks added.
Reviewed-by: jlahoda
line wrap: on
line diff
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotations.java Wed Apr 29 15:05:33 2015 -0700 +++ b/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/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java Wed Apr 29 15:05:33 2015 -0700 +++ b/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/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java Wed Apr 29 15:05:33 2015 -0700 +++ b/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/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties Wed Apr 29 15:05:33 2015 -0700 +++ b/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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() { + } +}