Mon, 03 Dec 2012 11:16:32 +0100
8001114: Container annotation is not checked for semantic correctness
Reviewed-by: jjg
1.1 --- a/src/share/classes/com/sun/tools/javac/code/Annotations.java Wed Dec 12 20:26:56 2012 +0100 1.2 +++ b/src/share/classes/com/sun/tools/javac/code/Annotations.java Mon Dec 03 11:16:32 2012 +0100 1.3 @@ -74,12 +74,12 @@ 1.4 */ 1.5 private List<Attribute.Compound> attributes = NOT_STARTED; 1.6 /* 1.7 - * The Symbol this Annotatios belong to 1.8 + * The Symbol this Annotations belong to 1.9 */ 1.10 - private final Symbol s; 1.11 + private final Symbol sym; 1.12 1.13 - public Annotations(Symbol s) { 1.14 - this.s = s; 1.15 + public Annotations(Symbol sym) { 1.16 + this.sym = sym; 1.17 } 1.18 1.19 public List<Attribute.Compound> getAttributes() { 1.20 @@ -102,7 +102,7 @@ 1.21 } 1.22 1.23 public void setAttributesWithCompletion(final Annotate.AnnotateRepeatedContext ctx) { 1.24 - Assert.check(pendingCompletion() || (!isStarted() && s.kind == PCK)); 1.25 + Assert.check(pendingCompletion() || (!isStarted() && sym.kind == PCK)); 1.26 1.27 Map<Symbol.TypeSymbol, ListBuffer<Attribute.Compound>> annotated = ctx.annotated; 1.28 boolean atLeastOneRepeated = false; 1.29 @@ -111,7 +111,7 @@ 1.30 if (lb.size() == 1) { 1.31 buf = buf.prepend(lb.first()); 1.32 } else { // repeated 1.33 - buf = buf.prepend(new Placeholder(lb.toList(), s)); 1.34 + buf = buf.prepend(new Placeholder(lb.toList(), sym)); 1.35 atLeastOneRepeated = true; 1.36 } 1.37 } 1.38 @@ -141,7 +141,7 @@ 1.39 1.40 @Override 1.41 public String toString() { 1.42 - return "repeated annotation pass of: " + s + " in: " + s.owner; 1.43 + return "repeated annotation pass of: " + sym + " in: " + sym.owner; 1.44 } 1.45 1.46 @Override 1.47 @@ -253,7 +253,7 @@ 1.48 1.49 // Process repeated annotations 1.50 Attribute.Compound validRepeated = 1.51 - ctx.processRepeatedAnnotations(placeholder.getPlaceholderFor()); 1.52 + ctx.processRepeatedAnnotations(placeholder.getPlaceholderFor(), sym); 1.53 1.54 if (validRepeated != null) { 1.55 // Check that the container isn't manually
2.1 --- a/src/share/classes/com/sun/tools/javac/comp/Annotate.java Wed Dec 12 20:26:56 2012 +0100 2.2 +++ b/src/share/classes/com/sun/tools/javac/comp/Annotate.java Mon Dec 03 11:16:32 2012 +0100 2.3 @@ -26,7 +26,6 @@ 2.4 package com.sun.tools.javac.comp; 2.5 2.6 import java.util.Map; 2.7 - 2.8 import com.sun.tools.javac.util.*; 2.9 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; 2.10 import com.sun.tools.javac.code.*; 2.11 @@ -171,8 +170,8 @@ 2.12 * @param repeatingAnnotations a List of repeating annotations 2.13 * @return a new Attribute.Compound that is the container for the repeatingAnnotations 2.14 */ 2.15 - public Attribute.Compound processRepeatedAnnotations(List<Attribute.Compound> repeatingAnnotations) { 2.16 - return Annotate.this.processRepeatedAnnotations(repeatingAnnotations, this); 2.17 + public Attribute.Compound processRepeatedAnnotations(List<Attribute.Compound> repeatingAnnotations, Symbol sym) { 2.18 + return Annotate.this.processRepeatedAnnotations(repeatingAnnotations, this, sym); 2.19 } 2.20 2.21 /** 2.22 @@ -339,10 +338,11 @@ 2.23 * annotation are invalid. This method reports errors/warnings. 2.24 */ 2.25 private Attribute.Compound processRepeatedAnnotations(List<Attribute.Compound> annotations, 2.26 - AnnotateRepeatedContext ctx) { 2.27 + AnnotateRepeatedContext ctx, 2.28 + Symbol on) { 2.29 Attribute.Compound firstOccurrence = annotations.head; 2.30 List<Attribute> repeated = List.nil(); 2.31 - Type origAnnoType; 2.32 + Type origAnnoType = null; 2.33 Type arrayOfOrigAnnoType = null; 2.34 Type targetContainerType = null; 2.35 MethodSymbol containerValueSymbol = null; 2.36 @@ -390,6 +390,13 @@ 2.37 new Attribute.Array(arrayOfOrigAnnoType, repeated)); 2.38 annoTree = m.Annotation(new Attribute.Compound(targetContainerType, 2.39 List.of(p))); 2.40 + 2.41 + if (!chk.annotationApplicable(annoTree, on)) 2.42 + log.error(annoTree.pos(), "invalid.containedby.annotation.incompatible.target", targetContainerType, origAnnoType); 2.43 + 2.44 + if (!chk.validateAnnotationDeferErrors(annoTree)) 2.45 + log.error(annoTree.pos(), "duplicate.annotation.invalid.repeated", origAnnoType); 2.46 + 2.47 Attribute.Compound c = enterAnnotation(annoTree, 2.48 targetContainerType, 2.49 ctx.env); 2.50 @@ -410,7 +417,7 @@ 2.51 // annotation's declaration, or null if it has none 2.52 Attribute.Compound ca = origAnnoDecl.attribute(syms.containedByType.tsym); 2.53 if (ca == null) { // has no ContainedBy annotation 2.54 - log.error(pos, "duplicate.annotation.missing.container", origAnnoType); 2.55 + log.error(pos, "duplicate.annotation.missing.container", origAnnoType, syms.containedByType); 2.56 return null; 2.57 } 2.58
3.1 --- a/src/share/classes/com/sun/tools/javac/comp/Check.java Wed Dec 12 20:26:56 2012 +0100 3.2 +++ b/src/share/classes/com/sun/tools/javac/comp/Check.java Mon Dec 03 11:16:32 2012 +0100 3.3 @@ -2892,39 +2892,54 @@ 3.4 } 3.5 3.6 /** Check an annotation value. 3.7 + * 3.8 + * @param a The annotation tree to check 3.9 + * @return true if this annotation tree is valid, otherwise false 3.10 */ 3.11 - public void validateAnnotation(JCAnnotation a) { 3.12 - // collect an inventory of the members (sorted alphabetically) 3.13 - Set<MethodSymbol> members = new TreeSet<MethodSymbol>(new Comparator<Symbol>() { 3.14 - public int compare(Symbol t, Symbol t1) { 3.15 - return t.name.compareTo(t1.name); 3.16 - } 3.17 - }); 3.18 + public boolean validateAnnotationDeferErrors(JCAnnotation a) { 3.19 + boolean res = false; 3.20 + final Log.DiagnosticHandler diagHandler = new Log.DiscardDiagnosticHandler(log); 3.21 + try { 3.22 + res = validateAnnotation(a); 3.23 + } finally { 3.24 + log.popDiagnosticHandler(diagHandler); 3.25 + } 3.26 + return res; 3.27 + } 3.28 + 3.29 + private boolean validateAnnotation(JCAnnotation a) { 3.30 + boolean isValid = true; 3.31 + // collect an inventory of the annotation elements 3.32 + Set<MethodSymbol> members = new LinkedHashSet<MethodSymbol>(); 3.33 for (Scope.Entry e = a.annotationType.type.tsym.members().elems; 3.34 e != null; 3.35 e = e.sibling) 3.36 if (e.sym.kind == MTH) 3.37 members.add((MethodSymbol) e.sym); 3.38 3.39 - // count them off as they're annotated 3.40 + // remove the ones that are assigned values 3.41 for (JCTree arg : a.args) { 3.42 if (!arg.hasTag(ASSIGN)) continue; // recovery 3.43 JCAssign assign = (JCAssign) arg; 3.44 Symbol m = TreeInfo.symbol(assign.lhs); 3.45 if (m == null || m.type.isErroneous()) continue; 3.46 - if (!members.remove(m)) 3.47 + if (!members.remove(m)) { 3.48 + isValid = false; 3.49 log.error(assign.lhs.pos(), "duplicate.annotation.member.value", 3.50 m.name, a.type); 3.51 + } 3.52 } 3.53 3.54 // all the remaining ones better have default values 3.55 - ListBuffer<Name> missingDefaults = ListBuffer.lb(); 3.56 + List<Name> missingDefaults = List.nil(); 3.57 for (MethodSymbol m : members) { 3.58 if (m.defaultValue == null && !m.type.isErroneous()) { 3.59 - missingDefaults.append(m.name); 3.60 + missingDefaults = missingDefaults.append(m.name); 3.61 } 3.62 } 3.63 + missingDefaults = missingDefaults.reverse(); 3.64 if (missingDefaults.nonEmpty()) { 3.65 + isValid = false; 3.66 String key = (missingDefaults.size() > 1) 3.67 ? "annotation.missing.default.value.1" 3.68 : "annotation.missing.default.value"; 3.69 @@ -2935,21 +2950,23 @@ 3.70 // repeated values in its value member 3.71 if (a.annotationType.type.tsym != syms.annotationTargetType.tsym || 3.72 a.args.tail == null) 3.73 - return; 3.74 + return isValid; 3.75 3.76 - if (!a.args.head.hasTag(ASSIGN)) return; // error recovery 3.77 + if (!a.args.head.hasTag(ASSIGN)) return false; // error recovery 3.78 JCAssign assign = (JCAssign) a.args.head; 3.79 Symbol m = TreeInfo.symbol(assign.lhs); 3.80 - if (m.name != names.value) return; 3.81 + if (m.name != names.value) return false; 3.82 JCTree rhs = assign.rhs; 3.83 - if (!rhs.hasTag(NEWARRAY)) return; 3.84 + if (!rhs.hasTag(NEWARRAY)) return false; 3.85 JCNewArray na = (JCNewArray) rhs; 3.86 Set<Symbol> targets = new HashSet<Symbol>(); 3.87 for (JCTree elem : na.elems) { 3.88 if (!targets.add(TreeInfo.symbol(elem))) { 3.89 + isValid = false; 3.90 log.error(elem.pos(), "repeated.annotation.target"); 3.91 } 3.92 } 3.93 + return isValid; 3.94 } 3.95 3.96 void checkDeprecatedAnnotation(DiagnosticPosition pos, Symbol s) {
4.1 --- a/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java Wed Dec 12 20:26:56 2012 +0100 4.2 +++ b/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java Mon Dec 03 11:16:32 2012 +0100 4.3 @@ -1360,6 +1360,16 @@ 4.4 void attachAnnotationDefault(final Symbol sym) { 4.5 final MethodSymbol meth = (MethodSymbol)sym; // only on methods 4.6 final Attribute value = readAttributeValue(); 4.7 + 4.8 + // The default value is set later during annotation. It might 4.9 + // be the case that the Symbol sym is annotated _after_ the 4.10 + // repeating instances that depend on this default value, 4.11 + // because of this we set an interim value that tells us this 4.12 + // element (most likely) has a default. 4.13 + // 4.14 + // Set interim value for now, reset just before we do this 4.15 + // properly at annotate time. 4.16 + meth.defaultValue = value; 4.17 annotate.normal(new AnnotationDefaultCompleter(meth, value)); 4.18 } 4.19 4.20 @@ -1680,6 +1690,9 @@ 4.21 public void enterAnnotation() { 4.22 JavaFileObject previousClassFile = currentClassFile; 4.23 try { 4.24 + // Reset the interim value set earlier in 4.25 + // attachAnnotationDefault(). 4.26 + sym.defaultValue = null; 4.27 currentClassFile = classFile; 4.28 sym.defaultValue = deproxy(sym.type.getReturnType(), value); 4.29 } finally {
5.1 --- a/src/share/classes/com/sun/tools/javac/resources/compiler.properties Wed Dec 12 20:26:56 2012 +0100 5.2 +++ b/src/share/classes/com/sun/tools/javac/resources/compiler.properties Mon Dec 03 11:16:32 2012 +0100 5.3 @@ -307,13 +307,17 @@ 5.4 compiler.err.duplicate.annotation=\ 5.5 duplicate annotation 5.6 5.7 +# 0: type 5.8 +compiler.err.duplicate.annotation.invalid.repeated=\ 5.9 + annotation {0} cannot be repeated\nIt does not define a valid containing annotation. 5.10 + 5.11 # 0: name, 1: type 5.12 compiler.err.duplicate.annotation.member.value=\ 5.13 duplicate annotation member value {0} in {1} 5.14 5.15 -# 0: type 5.16 +# 0: type, 1: type 5.17 compiler.err.duplicate.annotation.missing.container=\ 5.18 - duplicate annotation, the declaration of {0} does not have a ContainedBy annotation 5.19 + duplicate annotation, the declaration of {0} does not have a valid {1} annotation 5.20 5.21 # 0: type, 1: type 5.22 compiler.err.invalid.container.no.containedby=\
6.1 --- a/test/tools/javac/annotations/repeatingAnnotations/MissingDefaultCase1.java Wed Dec 12 20:26:56 2012 +0100 6.2 +++ b/test/tools/javac/annotations/repeatingAnnotations/MissingDefaultCase1.java Mon Dec 03 11:16:32 2012 +0100 6.3 @@ -20,4 +20,3 @@ 6.4 6.5 @Foo @Foo 6.6 public class MissingDefaultCase1 {} 6.7 -
7.1 --- a/test/tools/javac/annotations/repeatingAnnotations/MissingDefaultCase1.out Wed Dec 12 20:26:56 2012 +0100 7.2 +++ b/test/tools/javac/annotations/repeatingAnnotations/MissingDefaultCase1.out Mon Dec 03 11:16:32 2012 +0100 7.3 @@ -1,2 +1,3 @@ 7.4 +MissingDefaultCase1.java:21:1: compiler.err.duplicate.annotation.invalid.repeated: Foo 7.5 MissingDefaultCase1.java:12:1: compiler.err.invalid.containedby.annotation.elem.nondefault: FooContainer, other() 7.6 -1 error 7.7 +2 errors
8.1 --- a/test/tools/javac/annotations/repeatingAnnotations/MissingDefaultCase2.java Wed Dec 12 20:26:56 2012 +0100 8.2 +++ b/test/tools/javac/annotations/repeatingAnnotations/MissingDefaultCase2.java Mon Dec 03 11:16:32 2012 +0100 8.3 @@ -20,4 +20,3 @@ 8.4 8.5 @Foo @Foo 8.6 public class MissingDefaultCase2 {} 8.7 -
9.1 --- a/test/tools/javac/annotations/repeatingAnnotations/MissingDefaultCase2.out Wed Dec 12 20:26:56 2012 +0100 9.2 +++ b/test/tools/javac/annotations/repeatingAnnotations/MissingDefaultCase2.out Mon Dec 03 11:16:32 2012 +0100 9.3 @@ -1,2 +1,3 @@ 9.4 +MissingDefaultCase2.java:21:1: compiler.err.duplicate.annotation.invalid.repeated: Foo 9.5 MissingDefaultCase2.java:12:1: compiler.err.invalid.containedby.annotation.elem.nondefault: FooContainer, other() 9.6 -1 error 9.7 +2 errors
10.1 --- a/test/tools/javac/annotations/repeatingAnnotations/NoRepeatableAnno.out Wed Dec 12 20:26:56 2012 +0100 10.2 +++ b/test/tools/javac/annotations/repeatingAnnotations/NoRepeatableAnno.out Mon Dec 03 11:16:32 2012 +0100 10.3 @@ -1,3 +1,3 @@ 10.4 -NoRepeatableAnno.java:11:1: compiler.err.duplicate.annotation.missing.container: Foo 10.5 -NoRepeatableAnno.java:11:6: compiler.err.duplicate.annotation.missing.container: Foo 10.6 +NoRepeatableAnno.java:11:1: compiler.err.duplicate.annotation.missing.container: Foo, java.lang.annotation.ContainedBy 10.7 +NoRepeatableAnno.java:11:6: compiler.err.duplicate.annotation.missing.container: Foo, java.lang.annotation.ContainedBy 10.8 2 errors
11.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 11.2 +++ b/test/tools/javac/annotations/repeatingAnnotations/RepeatingTargetNotAllowed.java Mon Dec 03 11:16:32 2012 +0100 11.3 @@ -0,0 +1,45 @@ 11.4 +/* 11.5 + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. 11.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 11.7 + * 11.8 + * This code is free software; you can redistribute it and/or modify it 11.9 + * under the terms of the GNU General Public License version 2 only, as 11.10 + * published by the Free Software Foundation. 11.11 + * 11.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 11.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 11.15 + * version 2 for more details (a copy is included in the LICENSE file that 11.16 + * accompanied this code). 11.17 + * 11.18 + * You should have received a copy of the GNU General Public License version 11.19 + * 2 along with this work; if not, write to the Free Software Foundation, 11.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 11.21 + * 11.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 11.23 + * or visit www.oracle.com if you need additional information or have any 11.24 + * questions. 11.25 + */ 11.26 + 11.27 +/** 11.28 + * @test 11.29 + * @summary Container annotation is not checked for semantic correctness 11.30 + * @bug 8001114 11.31 + * 11.32 + * @compile/fail/ref=RepeatingTargetNotAllowed.out -XDrawDiagnostics RepeatingTargetNotAllowed.java 11.33 + */ 11.34 + 11.35 +import java.lang.annotation.*; 11.36 + 11.37 +@ContainedBy(Foos.class) 11.38 +@interface Foo {} 11.39 + 11.40 +@ContainerFor(Foo.class) 11.41 +@Target(ElementType.ANNOTATION_TYPE) 11.42 +@interface Foos { 11.43 + Foo[] value(); 11.44 +} 11.45 + 11.46 +public class RepeatingTargetNotAllowed { 11.47 + @Foo @Foo int f = 0; 11.48 +}
12.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 12.2 +++ b/test/tools/javac/annotations/repeatingAnnotations/RepeatingTargetNotAllowed.out Mon Dec 03 11:16:32 2012 +0100 12.3 @@ -0,0 +1,2 @@ 12.4 +RepeatingTargetNotAllowed.java:44:5: compiler.err.invalid.containedby.annotation.incompatible.target: Foos, Foo 12.5 +1 error
13.1 --- a/test/tools/javac/diags/examples/ContainedByNonDefault.java Wed Dec 12 20:26:56 2012 +0100 13.2 +++ b/test/tools/javac/diags/examples/ContainedByNonDefault.java Mon Dec 03 11:16:32 2012 +0100 13.3 @@ -31,6 +31,4 @@ 13.4 @ContainerFor(Anno.class) 13.5 @interface Annos { Anno[] value(); String foo(); } 13.6 13.7 -@Anno 13.8 -@Anno 13.9 class ContainedByNonDefault { }
14.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 14.2 +++ b/test/tools/javac/diags/examples/InvalidDuplicateAnnotation.java Mon Dec 03 11:16:32 2012 +0100 14.3 @@ -0,0 +1,40 @@ 14.4 +/* 14.5 + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. 14.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 14.7 + * 14.8 + * This code is free software; you can redistribute it and/or modify it 14.9 + * under the terms of the GNU General Public License version 2 only, as 14.10 + * published by the Free Software Foundation. 14.11 + * 14.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 14.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14.15 + * version 2 for more details (a copy is included in the LICENSE file that 14.16 + * accompanied this code). 14.17 + * 14.18 + * You should have received a copy of the GNU General Public License version 14.19 + * 2 along with this work; if not, write to the Free Software Foundation, 14.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 14.21 + * 14.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 14.23 + * or visit www.oracle.com if you need additional information or have any 14.24 + * questions. 14.25 + */ 14.26 + 14.27 +// key: compiler.err.duplicate.annotation.invalid.repeated 14.28 +// key: compiler.err.invalid.containedby.annotation.elem.nondefault 14.29 +// 14.30 +// We need an almost valid containing annotation. The easiest way to get 14.31 +// one close enough to valid is by forgetting a default. 14.32 + 14.33 +import java.lang.annotation.*; 14.34 + 14.35 +@ContainedBy(Annos.class) 14.36 +@interface Anno { } 14.37 + 14.38 +@ContainerFor(Anno.class) 14.39 +@interface Annos { Anno[] value(); String foo(); } 14.40 + 14.41 +@Anno 14.42 +@Anno 14.43 +class InvalidDuplicateAnnotation { }