src/share/classes/com/sun/tools/javac/comp/Annotate.java

Print this page

        

*** 27,42 **** --- 27,44 ---- import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; + import javax.lang.model.type.TypeKind; import javax.tools.JavaFileObject; import com.sun.tools.javac.util.*; import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; import com.sun.tools.javac.code.*; import com.sun.tools.javac.code.Symbol.*; + import com.sun.tools.javac.code.TypeAnnotationPosition.*; import com.sun.tools.javac.tree.*; import com.sun.tools.javac.tree.JCTree.*; import static com.sun.tools.javac.code.Kinds.*; import static com.sun.tools.javac.code.TypeTag.ARRAY;
*** 263,296 **** * Attribute. Used from MemberEnter for attaching the attributes * to the annotated symbol. */ Attribute.Compound enterAnnotation(JCAnnotation a, Type expected, ! Env<AttrContext> env) { ! List<Pair<MethodSymbol,Attribute>> elems = ! enterAttributeValues(a, expected, env); ! Attribute.Compound ac = new Attribute.Compound(a.type, elems); a.attribute = ac; return ac; } Attribute.TypeCompound enterTypeAnnotation(JCAnnotation a, Type expected, ! Env<AttrContext> env) { ! List<Pair<MethodSymbol,Attribute>> elems = ! enterAttributeValues(a, expected, env); if (a.attribute == null || !(a.attribute instanceof Attribute.TypeCompound)) { // Create a new TypeCompound - Attribute.TypeCompound tc = ! new Attribute.TypeCompound(a.type, elems, ! // TODO: Eventually, we will get rid of this use of ! // unknown, because we'll get a position from ! // MemberEnter (task 8027262). ! TypeAnnotationPosition.unknown); a.attribute = tc; return tc; } else { // Use an existing TypeCompound return (Attribute.TypeCompound)a.attribute; --- 265,296 ---- * Attribute. Used from MemberEnter for attaching the attributes * to the annotated symbol. */ Attribute.Compound enterAnnotation(JCAnnotation a, Type expected, ! Env<AttrContext> env, ! TypeAnnotationPosition position) { ! List<Pair<MethodSymbol,Attribute>> buf = ! enterAttributeValues(a, expected, env, position); ! Attribute.Compound ac = ! new Attribute.Compound(a.type, buf, position); a.attribute = ac; return ac; } Attribute.TypeCompound enterTypeAnnotation(JCAnnotation a, Type expected, ! Env<AttrContext> env, ! TypeAnnotationPosition position) { ! List<Pair<MethodSymbol,Attribute>> buf = ! enterAttributeValues(a, expected, env, position); if (a.attribute == null || !(a.attribute instanceof Attribute.TypeCompound)) { // Create a new TypeCompound Attribute.TypeCompound tc = ! new Attribute.TypeCompound(a.type, buf, position); a.attribute = tc; return tc; } else { // Use an existing TypeCompound return (Attribute.TypeCompound)a.attribute;
*** 298,308 **** } private List<Pair<MethodSymbol,Attribute>> enterAttributeValues(JCAnnotation a, Type expected, ! Env<AttrContext> env) { // The annotation might have had its type attributed (but not // checked) by attr.attribAnnotationTypes during MemberEnter, // in which case we do not need to do it again. Type at = (a.annotationType.type != null ? a.annotationType.type : attr.attribType(a.annotationType, env)); --- 298,309 ---- } private List<Pair<MethodSymbol,Attribute>> enterAttributeValues(JCAnnotation a, Type expected, ! Env<AttrContext> env, ! TypeAnnotationPosition position) { // The annotation might have had its type attributed (but not // checked) by attr.attribAnnotationTypes during MemberEnter, // in which case we do not need to do it again. Type at = (a.annotationType.type != null ? a.annotationType.type : attr.attribType(a.annotationType, env));
*** 323,339 **** new ListBuffer<>(); for (List<JCExpression> tl = args; tl.nonEmpty(); tl = tl.tail) { JCExpression t = tl.head; if (!t.hasTag(ASSIGN)) { log.error(t.pos(), "annotation.value.must.be.name.value"); ! enterAttributeValue(t.type = syms.errType, t, env); continue; } JCAssign assign = (JCAssign)t; if (!assign.lhs.hasTag(IDENT)) { log.error(t.pos(), "annotation.value.must.be.name.value"); ! enterAttributeValue(t.type = syms.errType, t, env); continue; } JCIdent left = (JCIdent)assign.lhs; Symbol method = rs.resolveQualifiedMethod(assign.rhs.pos(), env, --- 324,340 ---- new ListBuffer<>(); for (List<JCExpression> tl = args; tl.nonEmpty(); tl = tl.tail) { JCExpression t = tl.head; if (!t.hasTag(ASSIGN)) { log.error(t.pos(), "annotation.value.must.be.name.value"); ! enterAttributeValue(t.type = syms.errType, t, env, position); continue; } JCAssign assign = (JCAssign)t; if (!assign.lhs.hasTag(IDENT)) { log.error(t.pos(), "annotation.value.must.be.name.value"); ! enterAttributeValue(t.type = syms.errType, t, env, position); continue; } JCIdent left = (JCIdent)assign.lhs; Symbol method = rs.resolveQualifiedMethod(assign.rhs.pos(), env,
*** 344,364 **** left.sym = method; left.type = method.type; if (method.owner != a.type.tsym && !isError) log.error(left.pos(), "no.annotation.member", left.name, a.type); Type result = method.type.getReturnType(); ! Attribute value = enterAttributeValue(result, assign.rhs, env); if (!method.type.isErroneous()) buf.append(new Pair<>((MethodSymbol)method, value)); t.type = result; } return buf.toList(); } Attribute enterAttributeValue(Type expected, JCExpression tree, ! Env<AttrContext> env) { //first, try completing the attribution value sym - if a completion //error is thrown, we should recover gracefully, and display an //ordinary resolution diagnostic. try { expected.tsym.complete(); --- 345,366 ---- left.sym = method; left.type = method.type; if (method.owner != a.type.tsym && !isError) log.error(left.pos(), "no.annotation.member", left.name, a.type); Type result = method.type.getReturnType(); ! Attribute value = enterAttributeValue(result, assign.rhs, env, position); if (!method.type.isErroneous()) buf.append(new Pair<>((MethodSymbol)method, value)); t.type = result; } return buf.toList(); } Attribute enterAttributeValue(Type expected, JCExpression tree, ! Env<AttrContext> env, ! TypeAnnotationPosition position) { //first, try completing the attribution value sym - if a completion //error is thrown, we should recover gracefully, and display an //ordinary resolution diagnostic. try { expected.tsym.complete();
*** 376,387 **** log.error(na.elemtype.pos(), "new.not.allowed.in.annotation"); } ListBuffer<Attribute> buf = new ListBuffer<>(); for (List<JCExpression> l = na.elems; l.nonEmpty(); l=l.tail) { buf.append(enterAttributeValue(types.elemtype(expected), ! l.head, ! env)); } na.type = expected; return new Attribute. Array(expected, buf.toArray(new Attribute[buf.length()])); } --- 378,388 ---- log.error(na.elemtype.pos(), "new.not.allowed.in.annotation"); } ListBuffer<Attribute> buf = new ListBuffer<>(); for (List<JCExpression> l = na.elems; l.nonEmpty(); l=l.tail) { buf.append(enterAttributeValue(types.elemtype(expected), ! l.head, env, position)); } na.type = expected; return new Attribute. Array(expected, buf.toArray(new Attribute[buf.length()])); }
*** 391,418 **** JCNewArray na = (JCNewArray)tree; if (na.elemtype != null) { log.error(na.elemtype.pos(), "new.not.allowed.in.annotation"); } for (List<JCExpression> l = na.elems; l.nonEmpty(); l=l.tail) { ! enterAttributeValue(syms.errType, ! l.head, ! env); } return new Attribute.Error(syms.errType); } if ((expected.tsym.flags() & Flags.ANNOTATION) != 0) { if (tree.hasTag(ANNOTATION)) { ! return enterAnnotation((JCAnnotation)tree, expected, env); } else { log.error(tree.pos(), "annotation.value.must.be.annotation"); expected = syms.errType; } } if (tree.hasTag(ANNOTATION)) { //error recovery if (!expected.isErroneous()) log.error(tree.pos(), "annotation.not.valid.for.type", expected); ! enterAnnotation((JCAnnotation)tree, syms.errType, env); return new Attribute.Error(((JCAnnotation)tree).annotationType.type); } if (expected.isPrimitive() || (types.isSameType(expected, syms.stringType) && !expected.hasTag(TypeTag.ERROR))) { Type result = attr.attribExpr(tree, env, expected); --- 392,417 ---- JCNewArray na = (JCNewArray)tree; if (na.elemtype != null) { log.error(na.elemtype.pos(), "new.not.allowed.in.annotation"); } for (List<JCExpression> l = na.elems; l.nonEmpty(); l=l.tail) { ! enterAttributeValue(syms.errType, l.head, env, position); } return new Attribute.Error(syms.errType); } if ((expected.tsym.flags() & Flags.ANNOTATION) != 0) { if (tree.hasTag(ANNOTATION)) { ! return enterAnnotation((JCAnnotation)tree, expected, env, position); } else { log.error(tree.pos(), "annotation.value.must.be.annotation"); expected = syms.errType; } } if (tree.hasTag(ANNOTATION)) { //error recovery if (!expected.isErroneous()) log.error(tree.pos(), "annotation.not.valid.for.type", expected); ! enterAnnotation((JCAnnotation)tree, syms.errType, env, position); return new Attribute.Error(((JCAnnotation)tree).annotationType.type); } if (expected.isPrimitive() || (types.isSameType(expected, syms.stringType) && !expected.hasTag(TypeTag.ERROR))) { Type result = attr.attribExpr(tree, env, expected);
*** 477,487 **** * synthesized container annotation or null IFF all repeating * annotation are invalid. This method reports errors/warnings. */ private <T extends Attribute.Compound> T processRepeatedAnnotations(List<T> annotations, AnnotationContext<T> ctx, ! Symbol on) { T firstOccurrence = annotations.head; List<Attribute> repeated = List.nil(); Type origAnnoType = null; Type arrayOfOrigAnnoType = null; Type targetContainerType = null; --- 476,487 ---- * synthesized container annotation or null IFF all repeating * annotation are invalid. This method reports errors/warnings. */ private <T extends Attribute.Compound> T processRepeatedAnnotations(List<T> annotations, AnnotationContext<T> ctx, ! Symbol on, ! TypeAnnotationPosition position) { T firstOccurrence = annotations.head; List<Attribute> repeated = List.nil(); Type origAnnoType = null; Type arrayOfOrigAnnoType = null; Type targetContainerType = null;
*** 489,504 **** Assert.check(!annotations.isEmpty() && !annotations.tail.isEmpty()); // i.e. size() > 1 int count = 0; ! for (List<T> al = annotations; ! !al.isEmpty(); ! al = al.tail) ! { count++; - // There must be more than a single anno in the annotation list Assert.check(count > 1 || !al.tail.isEmpty()); T currentAnno = al.head; --- 489,500 ---- Assert.check(!annotations.isEmpty() && !annotations.tail.isEmpty()); // i.e. size() > 1 int count = 0; ! for (List<T> al = annotations; !al.isEmpty(); al = al.tail) { count++; // There must be more than a single anno in the annotation list Assert.check(count > 1 || !al.tail.isEmpty()); T currentAnno = al.head;
*** 534,572 **** TreeMaker m = make.at(ctx.pos.get(firstOccurrence)); Pair<MethodSymbol, Attribute> p = new Pair<MethodSymbol, Attribute>(containerValueSymbol, new Attribute.Array(arrayOfOrigAnnoType, repeated)); if (ctx.isTypeCompound) { ! /* TODO: the following code would be cleaner: ! Attribute.TypeCompound at = new Attribute.TypeCompound(targetContainerType, List.of(p), ! ((Attribute.TypeCompound)annotations.head).position); ! JCTypeAnnotation annoTree = m.TypeAnnotation(at); ! at = enterTypeAnnotation(annoTree, targetContainerType, ctx.env); ! */ ! // However, we directly construct the TypeCompound to keep the ! // direct relation to the contained TypeCompounds. ! Attribute.TypeCompound at = new Attribute.TypeCompound(targetContainerType, List.of(p), ! ((Attribute.TypeCompound)annotations.head).position); ! ! // TODO: annotation applicability checks from below? ! at.setSynthesized(true); @SuppressWarnings("unchecked") T x = (T) at; return x; } else { ! Attribute.Compound c = new Attribute.Compound(targetContainerType, List.of(p)); JCAnnotation annoTree = m.Annotation(c); if (!chk.annotationApplicable(annoTree, on)) log.error(annoTree.pos(), "invalid.repeatable.annotation.incompatible.target", targetContainerType, origAnnoType); if (!chk.validateAnnotationDeferErrors(annoTree)) log.error(annoTree.pos(), "duplicate.annotation.invalid.repeated", origAnnoType); ! c = enterAnnotation(annoTree, targetContainerType, ctx.env); c.setSynthesized(true); @SuppressWarnings("unchecked") T x = (T) c; return x; --- 530,558 ---- TreeMaker m = make.at(ctx.pos.get(firstOccurrence)); Pair<MethodSymbol, Attribute> p = new Pair<MethodSymbol, Attribute>(containerValueSymbol, new Attribute.Array(arrayOfOrigAnnoType, repeated)); if (ctx.isTypeCompound) { ! Attribute.TypeCompound at = new Attribute.TypeCompound(targetContainerType, List.of(p), position); at.setSynthesized(true); @SuppressWarnings("unchecked") T x = (T) at; return x; } else { ! Attribute.Compound c = new Attribute.Compound(targetContainerType, ! List.of(p), ! position); JCAnnotation annoTree = m.Annotation(c); if (!chk.annotationApplicable(annoTree, on)) log.error(annoTree.pos(), "invalid.repeatable.annotation.incompatible.target", targetContainerType, origAnnoType); if (!chk.validateAnnotationDeferErrors(annoTree)) log.error(annoTree.pos(), "duplicate.annotation.invalid.repeated", origAnnoType); ! c = enterAnnotation(annoTree, targetContainerType, ctx.env, position); c.setSynthesized(true); @SuppressWarnings("unchecked") T x = (T) c; return x;
*** 574,583 **** --- 560,570 ---- } else { return null; // errors should have been reported elsewhere } } + /** Fetches the actual Type that should be the containing annotation. */ private Type getContainingType(Attribute.Compound currentAnno, DiagnosticPosition pos, boolean reportError) {
*** 708,724 **** private <T extends Attribute.Compound> AnnotationContext<T> prepareEnterAnnotations(List<JCAnnotation> annotations, Env<AttrContext> env, Symbol sym, AttributeCreator<T> creator, ! boolean isTypeCompound) { Map<TypeSymbol, ListBuffer<T>> annotated = new LinkedHashMap<>(); Map<T, DiagnosticPosition> pos = new HashMap<>(); for (List<JCAnnotation> al = annotations; !al.isEmpty(); al = al.tail) { JCAnnotation a = al.head; ! T c = creator.create(a, syms.annotationType, env); Assert.checkNonNull(c, "Failed to create annotation"); if (annotated.containsKey(a.type.tsym)) { if (!allowRepeatedAnnos) { --- 695,712 ---- private <T extends Attribute.Compound> AnnotationContext<T> prepareEnterAnnotations(List<JCAnnotation> annotations, Env<AttrContext> env, Symbol sym, AttributeCreator<T> creator, ! boolean isTypeCompound, ! TypeAnnotationPosition position) { Map<TypeSymbol, ListBuffer<T>> annotated = new LinkedHashMap<>(); Map<T, DiagnosticPosition> pos = new HashMap<>(); for (List<JCAnnotation> al = annotations; !al.isEmpty(); al = al.tail) { JCAnnotation a = al.head; ! T c = creator.create(a, syms.annotationType, env, position); Assert.checkNonNull(c, "Failed to create annotation"); if (annotated.containsKey(a.type.tsym)) { if (!allowRepeatedAnnos) {
*** 752,765 **** private <T extends Attribute.Compound> void attachAttributesLater(final List<JCAnnotation> annotations, final Env<AttrContext> env, final Symbol sym, final boolean isTypeCompound, final AttributeCreator<T> creator, final AttributeAttacher<T> attacher) { final AnnotationContext<T> ctx = ! prepareEnterAnnotations(annotations, env, sym, creator, isTypeCompound); final Map<Symbol.TypeSymbol, ListBuffer<T>> annotated = ctx.annotated; boolean hasRepeated = false; List<T> buf = List.<T>nil(); --- 740,755 ---- private <T extends Attribute.Compound> void attachAttributesLater(final List<JCAnnotation> annotations, final Env<AttrContext> env, final Symbol sym, final boolean isTypeCompound, + final TypeAnnotationPosition position, final AttributeCreator<T> creator, final AttributeAttacher<T> attacher) { final AnnotationContext<T> ctx = ! prepareEnterAnnotations(annotations, env, sym, creator, ! isTypeCompound, position); final Map<Symbol.TypeSymbol, ListBuffer<T>> annotated = ctx.annotated; boolean hasRepeated = false; List<T> buf = List.<T>nil();
*** 779,791 **** if (!isTypeCompound) { // Attach declaration attributes early, so // that @Repeatable and other annotations get attached. // Since the attacher uses setDeclarationAttributes, this // will be overwritten later. ! attacher.attach(sym, attrs); } if (hasRepeated) { repeated(new Annotate.Worker() { @Override public String toString() { return "repeated annotation pass of: " + sym + " in: " + sym.owner; } --- 769,796 ---- if (!isTypeCompound) { // Attach declaration attributes early, so // that @Repeatable and other annotations get attached. // Since the attacher uses setDeclarationAttributes, this // will be overwritten later. ! @SuppressWarnings("unchecked") ! List<Attribute.Compound> tempattrs = (List<Attribute.Compound>) attrs; ! sym.setDeclarationAttributes(tempattrs); } + if (hasRepeated) { + replacePlaceholdersAndAttach(attrs, ctx, env, sym, attacher); + } else { + attachAttributesAfterRepeated(attrs, env, attacher); + } + } + + private <T extends Attribute.Compound> + void replacePlaceholdersAndAttach(final List<T> attrs, + final AnnotationContext<T> ctx, + final Env<AttrContext> env, + final Symbol sym, + final AttributeAttacher<T> attacher) { repeated(new Annotate.Worker() { @Override public String toString() { return "repeated annotation pass of: " + sym + " in: " + sym.owner; }
*** 793,833 **** @Override public void run() { JavaFileObject oldSource = log.useSource(env.toplevel.sourcefile); try { ! attacher.attach(sym, replacePlaceholders(attrs, ctx, sym)); } finally { log.useSource(oldSource); } } }); } else { ! attacher.attach(sym, attrs); } } ! private interface AttributeAttacher<T extends Attribute.Compound> { ! public void attach(Symbol sym, List<T> attrs); } ! private final AttributeAttacher<Attribute.Compound> declAnnotationsAttacher = ! new AttributeAttacher<Attribute.Compound>() { @Override ! public void attach(Symbol sym, List<Attribute.Compound> attrs) { sym.resetAnnotations(); sym.setDeclarationAttributes(attrs); } }; ! private final AttributeAttacher<Attribute.TypeCompound> typeAnnotationsAttacher = ! new AttributeAttacher<Attribute.TypeCompound>() { @Override ! public void attach(Symbol sym, List<Attribute.TypeCompound> attrs) { ! sym.appendUniqueTypeAttributes(attrs); } }; private <T extends Attribute.Compound> List<T> replacePlaceholders(List<T> buf, Annotate.AnnotationContext<T> ctx, Symbol sym) { --- 798,1075 ---- @Override public void run() { JavaFileObject oldSource = log.useSource(env.toplevel.sourcefile); try { ! final List<T> replaced = ! replacePlaceholders(attrs, ctx, sym); ! attachAttributesAfterRepeated(replaced, env, attacher); } finally { log.useSource(oldSource); } } }); + } + + private <T extends Attribute.Compound> + void attachAttributesAfterRepeated(final List<T> attrs, + final Env<AttrContext> env, + final AttributeAttacher<T> attacher) { + afterRepeated(new Worker() { + @Override + public String toString() { + return "attach pass for: " + attrs; + } + + @Override + public void run() { + JavaFileObject oldSource = + log.useSource(env.toplevel.sourcefile); + try { + attacher.attach(attrs); + } finally { + log.useSource(oldSource); + } + } + }); + } + + public interface AttributeAttacher<T extends Attribute.Compound> { + public void attach(List<T> attrs); + } + + public interface Reporter<T extends Attribute.Compound> { + public void report(List<T> attrs); + } + + public enum AnnotationType { DECLARATION, TYPE, BOTH } + + /** + * Determine whether an annotation is a declaration annotation, + * a type annotation, or both. + */ + public AnnotationType annotationType(Attribute.Compound a, Symbol s) { + Attribute.Compound atTarget = + a.type.tsym.attribute(syms.annotationTargetType.tsym); + if (atTarget == null) { + return inferTargetMetaInfo(a, s); + } + Attribute atValue = atTarget.member(names.value); + if (!(atValue instanceof Attribute.Array)) { + Assert.error("annotationType(): bad @Target argument " + atValue + + " (" + atValue.getClass() + ")"); + return AnnotationType.DECLARATION; // error recovery + } + Attribute.Array arr = (Attribute.Array) atValue; + boolean isDecl = false, isType = false; + for (Attribute app : arr.values) { + if (!(app instanceof Attribute.Enum)) { + Assert.error("annotationType(): unrecognized Attribute kind " + app + + " (" + app.getClass() + ")"); + isDecl = true; + continue; + } + Attribute.Enum e = (Attribute.Enum) app; + if (e.value.name == names.TYPE) { + if (s.kind == Kinds.TYP) + isDecl = true; + } else if (e.value.name == names.FIELD) { + if (s.kind == Kinds.VAR && + s.owner.kind != Kinds.MTH) + isDecl = true; + } else if (e.value.name == names.METHOD) { + if (s.kind == Kinds.MTH && + !s.isConstructor()) + isDecl = true; + } else if (e.value.name == names.PARAMETER) { + if (s.kind == Kinds.VAR && + s.owner.kind == Kinds.MTH && + (s.flags() & Flags.PARAMETER) != 0) + isDecl = true; + } else if (e.value.name == names.CONSTRUCTOR) { + if (s.kind == Kinds.MTH && + s.isConstructor()) + isDecl = true; + } else if (e.value.name == names.LOCAL_VARIABLE) { + if (s.kind == Kinds.VAR && + s.owner.kind == Kinds.MTH && + (s.flags() & Flags.PARAMETER) == 0) + isDecl = true; + } else if (e.value.name == names.ANNOTATION_TYPE) { + if (s.kind == Kinds.TYP && + (s.flags() & Flags.ANNOTATION) != 0) + isDecl = true; + } else if (e.value.name == names.PACKAGE) { + if (s.kind == Kinds.PCK) + isDecl = true; + } else if (e.value.name == names.TYPE_USE) { + if (s.kind == Kinds.TYP || + s.kind == Kinds.VAR || + (s.kind == Kinds.MTH && !s.isConstructor() && + !s.type.getReturnType().hasTag(TypeTag.VOID)) || + (s.kind == Kinds.MTH && s.isConstructor())) + isType = true; + } else if (e.value.name == names.TYPE_PARAMETER) { + /* Irrelevant in this case */ + // TYPE_PARAMETER doesn't aid in distinguishing between + // Type annotations and declaration annotations on an + // Element + } else { + Assert.error("annotationType(): unrecognized Attribute name " + e.value.name + + " (" + e.value.name.getClass() + ")"); + isDecl = true; + } + } + if (isDecl && isType) { + return AnnotationType.BOTH; + } else if (isType) { + return AnnotationType.TYPE; } else { ! return AnnotationType.DECLARATION; } } ! private Attribute.TypeCompound toTypeCompound(Attribute.Compound a) { ! // It is safe to alias the position. ! return new Attribute.TypeCompound(a, a.position); } ! /** Infer the target annotation kind, if none is given. ! * We only infer declaration annotations. ! */ ! private static AnnotationType inferTargetMetaInfo(Attribute.Compound a, Symbol s) { ! return AnnotationType.DECLARATION; ! } ! ! private AttributeAttacher<Attribute.Compound> ! declAnnotationsAttacher(final Symbol sym) { ! return new AttributeAttacher<Attribute.Compound>() { @Override ! public void attach(List<Attribute.Compound> attrs) { sym.resetAnnotations(); sym.setDeclarationAttributes(attrs); } }; + } ! private AttributeAttacher<Attribute.TypeCompound> ! typeAnnotationsAttacher(final Symbol sym) { ! return new AttributeAttacher<Attribute.TypeCompound>() { @Override ! public void attach(List<Attribute.TypeCompound> attrs) { ! if (!attrs.isEmpty()) { ! attachTypeAnnotations(sym, attrs); ! } } }; + } + + private void reportIllegalScoping(List<Attribute.TypeCompound> attrs, + int pos) { + switch (attrs.size()) { + case 0: + // Don't issue an error if all type annotations are + // also declaration annotations. + // If the annotations are also declaration annotations, they are + // illegal as type annotations but might be legal as declaration annotations. + // The normal declaration annotation checks make sure that the use is valid. + break; + case 1: + //System.err.println("Reporting illegal scoping"); + log.error(pos, "cant.type.annotate.scoping.1", attrs); + break; + default: + //System.err.println("Reporting illegal scoping"); + log.error(pos, "cant.type.annotate.scoping", attrs); + } + } + + private Reporter<Attribute.TypeCompound> + illegalScopingReporter(final int pos) { + return new Reporter<Attribute.TypeCompound>() { + @Override + public void report(List<Attribute.TypeCompound> attrs) { + reportIllegalScoping(attrs, pos); + } + }; + } + + private AttributeAttacher<Attribute.Compound> + classifyingAttacher(final Symbol sym) { + return classifyingAttacher(sym, declAnnotationsAttacher(sym), + typeAnnotationsAttacher(sym), + null); + } + + + private AttributeAttacher<Attribute.Compound> + classifyingAttacher(final Symbol sym, + final AttributeAttacher<Attribute.Compound> declAttacher, + final AttributeAttacher<Attribute.TypeCompound> typeAttacher, + final Reporter<Attribute.TypeCompound> reporter) { + return new AttributeAttacher<Attribute.Compound>() { + @Override + public void attach(List<Attribute.Compound> attrs) { + ListBuffer<Attribute.Compound> declAnnos = new ListBuffer<>(); + ListBuffer<Attribute.TypeCompound> typeAnnos = new ListBuffer<>(); + ListBuffer<Attribute.TypeCompound> onlyTypeAnnos = new ListBuffer<>(); + + for (Attribute.Compound a : attrs) { + Assert.check(!(a instanceof Placeholder), + "Placeholders found in annotations being attached!"); + switch (annotationType(a, sym)) { + case DECLARATION: + declAnnos.append(a); + break; + case BOTH: { + declAnnos.append(a); + Attribute.TypeCompound ta = toTypeCompound(a); + Assert.checkNonNull(ta.position); + typeAnnos.append(ta); + break; + } + case TYPE: { + Attribute.TypeCompound ta = toTypeCompound(a); + Assert.checkNonNull(ta.position); + typeAnnos.append(ta); + // Also keep track which annotations are only type annotations + onlyTypeAnnos.append(ta); + break; + } + default: + throw new AssertionError("Unknown annotation type"); + } + } + + if (declAttacher != null) + declAttacher.attach(declAnnos.toList()); + + if (typeAttacher != null) + typeAttacher.attach(typeAnnos.toList()); + + if (reporter != null) + reporter.report(onlyTypeAnnos.toList()); + } + }; + } + + public void attachTypeAnnotations(Symbol sym, List<Attribute.TypeCompound> attrs) { + sym.appendUniqueTypeAttributes(attrs); + + // For type annotations on variables in methods, make + // sure they are attached to the owner too. + switch(sym.getKind()) { + case PARAMETER: + case LOCAL_VARIABLE: + case RESOURCE_VARIABLE: + case EXCEPTION_PARAMETER: + // Make sure all type annotations from the symbol are also + // on the owner. + sym.owner.appendUniqueTypeAttributes(attrs); + break; + } + } private <T extends Attribute.Compound> List<T> replacePlaceholders(List<T> buf, Annotate.AnnotationContext<T> ctx, Symbol sym) {
*** 852,862 **** Annotate.AnnotationContext<T> ctx, Symbol sym) { // Process repeated annotations T validRepeated = processRepeatedAnnotations(placeholder.getPlaceholderFor(), ! ctx, sym); if (validRepeated != null) { // Check that the container isn't manually // present along with repeated instances of // its contained annotation. --- 1094,1104 ---- Annotate.AnnotationContext<T> ctx, Symbol sym) { // Process repeated annotations T validRepeated = processRepeatedAnnotations(placeholder.getPlaceholderFor(), ! ctx, sym, placeholder.position); if (validRepeated != null) { // Check that the container isn't manually // present along with repeated instances of // its contained annotation.
*** 873,887 **** /* ******************************************************************** * Annotation processing *********************************************************************/ ! /** Queue annotations for later processing. */ void annotateLater(final List<JCAnnotation> annotations, final Env<AttrContext> localEnv, final Symbol s, final DiagnosticPosition deferPos) { if (annotations.isEmpty()) { return; } if (s.kind != PCK) { s.resetAnnotations(); // mark Annotations as incomplete for now --- 1115,1153 ---- /* ******************************************************************** * Annotation processing *********************************************************************/ ! void annotateLater(final List<JCAnnotation> annotations, ! final Env<AttrContext> localEnv, ! final Symbol s) { ! annotateLater(annotations, localEnv, s, null); ! } ! void annotateLater(final List<JCAnnotation> annotations, final Env<AttrContext> localEnv, final Symbol s, final DiagnosticPosition deferPos) { + annotateLater(annotations, localEnv, s, deferPos, null, + declAnnotationsAttacher(s)); + } + + void annotateLater(final List<JCAnnotation> annotations, + final Env<AttrContext> localEnv, + final Symbol s, + final DiagnosticPosition deferPos, + final TypeAnnotationPosition tapos) { + annotateLater(annotations, localEnv, s, deferPos, tapos, + classifyingAttacher(s)); + } + + void annotateLater(final List<JCAnnotation> annotations, + final Env<AttrContext> localEnv, + final Symbol s, + final DiagnosticPosition deferPos, + final TypeAnnotationPosition tapos, + final AttributeAttacher<Attribute.Compound> attacher) { if (annotations.isEmpty()) { return; } if (s.kind != PCK) { s.resetAnnotations(); // mark Annotations as incomplete for now
*** 892,1080 **** return "annotate " + annotations + " onto " + s + " in " + s.owner; } @Override public void run() { Assert.check(s.kind == PCK || s.annotationsPendingCompletion()); JavaFileObject prev = log.useSource(localEnv.toplevel.sourcefile); ! DiagnosticPosition prevLintPos = ! deferPos != null ! ? deferredLintHandler.setPos(deferPos) ! : deferredLintHandler.immediate(); Lint prevLint = deferPos != null ? null : chk.setLint(lint); try { if (s.hasAnnotations() && annotations.nonEmpty()) log.error(annotations.head.pos, "already.annotated", kindName(s), s); ! actualEnterAnnotations(annotations, localEnv, s); } finally { if (prevLint != null) chk.setLint(prevLint); deferredLintHandler.setPos(prevLintPos); log.useSource(prev); } } - }); ! validate(new Annotate.Worker() { //validate annotations @Override public void run() { JavaFileObject prev = log.useSource(localEnv.toplevel.sourcefile); try { chk.validateAnnotations(annotations, s); } finally { log.useSource(prev); } } ! }); } private interface AttributeCreator<T extends Attribute.Compound> { ! public T create(JCAnnotation a, Type expected, Env<AttrContext> env); } // TODO: When SE8 features can be used, these can go away and be // replaced by method refs. private final AttributeCreator<Attribute.Compound> enterAnnotationsCreator = new AttributeCreator<Attribute.Compound>() { @Override public Attribute.Compound create(JCAnnotation a, Type expected, ! Env<AttrContext> env) { ! return enterAnnotation(a, syms.annotationType, env); } }; private final AttributeCreator<Attribute.TypeCompound> enterTypeAnnotationsCreator = new AttributeCreator<Attribute.TypeCompound>() { @Override public Attribute.TypeCompound create(JCAnnotation a, Type expected, ! Env<AttrContext> env) { ! return enterTypeAnnotation(a, syms.annotationType, env); } }; /** Enter a set of annotations. */ private void actualEnterAnnotations(List<JCAnnotation> annotations, Env<AttrContext> env, ! Symbol s) { ! Assert.checkNonNull(s, "Symbol argument to actualEnterAnnotations is null"); ! attachAttributesLater(annotations, env, s, false, ! enterAnnotationsCreator, ! declAnnotationsAttacher); } /* * If the symbol is non-null, attach the type annotation to it. */ private void actualEnterTypeAnnotations(final List<JCAnnotation> annotations, final Env<AttrContext> env, final Symbol s, ! final DiagnosticPosition deferPos) { ! Assert.checkNonNull(s, "Symbol argument to actualEnterTypeAnnotations is nul/"); JavaFileObject prev = log.useSource(env.toplevel.sourcefile); DiagnosticPosition prevLintPos = null; if (deferPos != null) { prevLintPos = deferredLintHandler.setPos(deferPos); } try { ! attachAttributesLater(annotations, env, s, true, ! enterTypeAnnotationsCreator, ! typeAnnotationsAttacher); } finally { if (prevLintPos != null) deferredLintHandler.setPos(prevLintPos); log.useSource(prev); } } public void annotateTypeLater(final JCTree tree, final Env<AttrContext> env, final Symbol sym, ! final DiagnosticPosition deferPos) { Assert.checkNonNull(sym); normal(new Annotate.Worker() { @Override public String toString() { return "type annotate " + tree + " onto " + sym + " in " + sym.owner; } @Override public void run() { ! tree.accept(new TypeAnnotate(env, sym, deferPos)); } }); } /** ! * We need to use a TreeScanner, because it is not enough to visit the top-level ! * annotations. We also need to visit type arguments, etc. */ private class TypeAnnotate extends TreeScanner { ! private final Env<AttrContext> env; private final Symbol sym; ! private DiagnosticPosition deferPos; ! public TypeAnnotate(final Env<AttrContext> env, final Symbol sym, ! final DiagnosticPosition deferPos) { ! ! this.env = env; this.sym = sym; this.deferPos = deferPos; } @Override ! public void visitAnnotatedType(final JCAnnotatedType tree) { ! actualEnterTypeAnnotations(tree.annotations, env, sym, deferPos); ! super.visitAnnotatedType(tree); } @Override ! public void visitTypeParameter(final JCTypeParameter tree) { ! actualEnterTypeAnnotations(tree.annotations, env, sym, deferPos); ! super.visitTypeParameter(tree); } @Override ! public void visitNewArray(final JCNewArray tree) { ! actualEnterTypeAnnotations(tree.annotations, env, sym, deferPos); ! for (List<JCAnnotation> dimAnnos : tree.dimAnnotations) ! actualEnterTypeAnnotations(dimAnnos, env, sym, deferPos); ! super.visitNewArray(tree); } @Override ! public void visitMethodDef(final JCMethodDecl tree) { ! scan(tree.mods); ! scan(tree.restype); ! scan(tree.typarams); ! scan(tree.recvparam); scan(tree.params); ! scan(tree.thrown); ! scan(tree.defaultValue); ! // Do not annotate the body, just the signature. ! // scan(tree.body); } @Override ! public void visitVarDef(final JCVariableDecl tree) { ! DiagnosticPosition prevPos = deferPos; ! deferPos = tree.pos(); ! try { ! if (sym != null && sym.kind == Kinds.VAR) { ! // Don't visit a parameter once when the sym is the method ! // and once when the sym is the parameter. ! scan(tree.mods); ! scan(tree.vartype); } ! scan(tree.init); ! } finally { ! deferPos = prevPos; } } @Override public void visitClassDef(JCClassDecl tree) { // We can only hit a classdef if it is declared within --- 1158,1949 ---- return "annotate " + annotations + " onto " + s + " in " + s.owner; } @Override public void run() { + annotateNow(annotations, localEnv, s, deferPos, + tapos, attacher); + } + }); + + validate(annotationValidator(annotations, localEnv, s)); + } + + private void annotateNow(final List<JCAnnotation> annotations, + final Env<AttrContext> localEnv, + final Symbol s, + final DiagnosticPosition deferPos, + final TypeAnnotationPosition position, + final AttributeAttacher<Attribute.Compound> attacher) { + if (annotations.isEmpty()) { + return; + } Assert.check(s.kind == PCK || s.annotationsPendingCompletion()); JavaFileObject prev = log.useSource(localEnv.toplevel.sourcefile); ! DiagnosticPosition prevLintPos = deferPos != null ? ! deferredLintHandler.setPos(deferPos) : ! deferredLintHandler.immediate(); Lint prevLint = deferPos != null ? null : chk.setLint(lint); try { if (s.hasAnnotations() && annotations.nonEmpty()) log.error(annotations.head.pos, "already.annotated", kindName(s), s); ! actualEnterAnnotations(annotations, localEnv, s, position, attacher); } finally { if (prevLint != null) chk.setLint(prevLint); deferredLintHandler.setPos(prevLintPos); log.useSource(prev); } } ! private Annotate.Worker annotationValidator(final List<JCAnnotation> annotations, ! final Env<AttrContext> localEnv, ! final Symbol s) { ! return new Annotate.Worker() { //validate annotations @Override public void run() { JavaFileObject prev = log.useSource(localEnv.toplevel.sourcefile); try { chk.validateAnnotations(annotations, s); } finally { log.useSource(prev); } } ! }; ! } ! ! private Annotate.Worker typeAnnotationValidator(final List<JCAnnotation> annotations, ! final Env<AttrContext> localEnv, ! final boolean isTypeParameter) { ! return new Annotate.Worker() { //validate annotations ! @Override ! public void run() { ! JavaFileObject prev = log.useSource(localEnv.toplevel.sourcefile); ! try { ! chk.validateTypeAnnotations(annotations, isTypeParameter); ! } finally { ! log.useSource(prev); ! } ! } ! }; } private interface AttributeCreator<T extends Attribute.Compound> { ! public T create(JCAnnotation a, ! Type expected, ! Env<AttrContext> env, ! TypeAnnotationPosition position); } // TODO: When SE8 features can be used, these can go away and be // replaced by method refs. private final AttributeCreator<Attribute.Compound> enterAnnotationsCreator = new AttributeCreator<Attribute.Compound>() { @Override public Attribute.Compound create(JCAnnotation a, Type expected, ! Env<AttrContext> env, ! TypeAnnotationPosition position) { ! return enterAnnotation(a, syms.annotationType, env, position); } }; private final AttributeCreator<Attribute.TypeCompound> enterTypeAnnotationsCreator = new AttributeCreator<Attribute.TypeCompound>() { @Override public Attribute.TypeCompound create(JCAnnotation a, Type expected, ! Env<AttrContext> env, ! TypeAnnotationPosition position) { ! return enterTypeAnnotation(a, syms.annotationType, env, position); } }; /** Enter a set of annotations. */ private void actualEnterAnnotations(List<JCAnnotation> annotations, Env<AttrContext> env, ! Symbol s, ! TypeAnnotationPosition position, ! AttributeAttacher<Attribute.Compound> attacher) { ! Assert.checkNonNull(s); ! attachAttributesLater(annotations, env, s, false, position, ! enterAnnotationsCreator, attacher); } /* * If the symbol is non-null, attach the type annotation to it. */ private void actualEnterTypeAnnotations(final List<JCAnnotation> annotations, final Env<AttrContext> env, final Symbol s, ! final DiagnosticPosition deferPos, ! final TypeAnnotationPosition position, ! final AttributeAttacher<Attribute.TypeCompound> attacher) { ! Assert.checkNonNull(s); JavaFileObject prev = log.useSource(env.toplevel.sourcefile); DiagnosticPosition prevLintPos = null; if (deferPos != null) { prevLintPos = deferredLintHandler.setPos(deferPos); } try { ! attachAttributesLater(annotations, env, s, true, position, ! enterTypeAnnotationsCreator, attacher); } finally { if (prevLintPos != null) deferredLintHandler.setPos(prevLintPos); log.useSource(prev); } } public void annotateTypeLater(final JCTree tree, final Env<AttrContext> env, final Symbol sym, ! final DiagnosticPosition deferPos, ! final JCLambda currentLambda, ! final PositionCreator creator, ! final boolean speculative) { ! annotateTypeLater(tree, List.<JCAnnotation>nil(), env, sym, ! deferPos, currentLambda, creator, speculative); ! } ! ! public void annotateTypeLater(final JCTree tree, ! final List<JCAnnotation> declAnnos, ! final Env<AttrContext> env, ! final Symbol sym, ! final DiagnosticPosition deferPos, ! final JCLambda currentLambda, ! final PositionCreator creator, ! final boolean speculative) { Assert.checkNonNull(sym); + Assert.checkNonNull(declAnnos); + Assert.checkNonNull(creator); + normal(new Annotate.Worker() { @Override public String toString() { return "type annotate " + tree + " onto " + sym + " in " + sym.owner; } @Override public void run() { ! if (!declAnnos.isEmpty()) { ! sym.resetAnnotations(); // mark Annotations as incomplete for now ! } ! ! tree.accept(typeAnnotater(declAnnos, sym, env, deferPos, ! currentLambda, creator, speculative)); } }); } /** ! * A client passed into various visitors that takes a type path as ! * an argument and performs an action (typically creating a ! * TypeAnnotationPosition and then creating a {@code Worker} and ! * adding it to a queue. */ + public abstract class PositionCreator { + public TypeAnnotationPosition create() { + return create(List.<TypePathEntry>nil(), null, 0); + } + + public TypeAnnotationPosition createNonNull(List<TypePathEntry> path, + JCLambda lambda, + int typeIndex) { + final TypeAnnotationPosition out = create(path, lambda, typeIndex); + + if (out != null) + return out; + else + throw new AssertionError("No annotation creator registered"); + } + + public abstract TypeAnnotationPosition create(List<TypePathEntry> path, + JCLambda lambda, + int typeIndex); + } + + // For when we don't have a creator. Creates null. + public final PositionCreator noCreator = + new PositionCreator() { + @Override + public TypeAnnotationPosition create(List<TypePathEntry> path, + JCLambda lambda, + int typeIndex) { + return null; + } + }; + + // Create class extension positions + public final PositionCreator extendsCreator = + new PositionCreator() { + @Override + public TypeAnnotationPosition create(List<TypePathEntry> path, + JCLambda lambda, + int typeIndex) { + return TypeAnnotationPosition.classExtends(path, lambda, -1); + } + }; + + // Create interface implementation positions + public PositionCreator implementsCreator(final int idx) { + return new PositionCreator() { + @Override + public TypeAnnotationPosition create(List<TypePathEntry> path, + JCLambda lambda, + int typeIndex) { + return TypeAnnotationPosition.classExtends(path, lambda, idx, -1); + } + }; + } + + // Create method parameter positions + public final PositionCreator paramCreator(final int idx) { + return new PositionCreator() { + @Override + public TypeAnnotationPosition create(List<TypePathEntry> path, + JCLambda lambda, + int typeIndex) { + return TypeAnnotationPosition.methodParameter(path, lambda, idx, -1); + } + }; + } + + // Create class type parameter positions + public PositionCreator typeParamCreator(final int idx) { + return new PositionCreator() { + @Override + public TypeAnnotationPosition create(List<TypePathEntry> path, + JCLambda lambda, + int typeIndex) { + return TypeAnnotationPosition.typeParameter(path, lambda, idx, -1); + } + }; + } + + public PositionCreator typeParamBoundCreator(final JCTypeParameter typaram, + final int param_idx, + final int bound_idx) { + return new PositionCreator() { + @Override + public TypeAnnotationPosition create(List<TypePathEntry> path, + JCLambda lambda, + int typeIndex) { + final int real_bound_idx = + typaram.bounds.head.type.isInterface() ? bound_idx + 1 : bound_idx; + return TypeAnnotationPosition + .typeParameterBound(path, lambda, param_idx, real_bound_idx, -1); + } + }; + } + + // Create field positions + public final PositionCreator fieldCreator = + new PositionCreator() { + @Override + public TypeAnnotationPosition create(List<TypePathEntry> path, + JCLambda lambda, + int typeIndex) { + return TypeAnnotationPosition.field(path, lambda, -1); + } + }; + + // Create local variable positions + public PositionCreator localVarCreator(final int pos) { + return new PositionCreator() { + @Override + public TypeAnnotationPosition create(List<TypePathEntry> path, + JCLambda lambda, + int typeIndex) { + return TypeAnnotationPosition.localVariable(path, lambda, pos); + } + }; + } + + public PositionCreator resourceVarCreator(final int pos) { + return new PositionCreator() { + @Override + public TypeAnnotationPosition create(List<TypePathEntry> path, + JCLambda lambda, + int typeIndex) { + return TypeAnnotationPosition.resourceVariable(path, lambda, pos); + } + }; + } + + public PositionCreator exceptionParamCreator(final int pos) { + return new PositionCreator() { + @Override + public TypeAnnotationPosition create(List<TypePathEntry> path, + JCLambda lambda, + int typeIndex) { + return TypeAnnotationPosition.exceptionParameter(path, lambda, + typeIndex, pos); + } + }; + } + + public PositionCreator methodTypeParamCreator(final int idx) { + return new PositionCreator() { + @Override + public TypeAnnotationPosition create(List<TypePathEntry> path, + JCLambda lambda, + int typeIndex) { + return TypeAnnotationPosition.methodTypeParameter(path, lambda, idx, -1); + } + }; + } + + public PositionCreator methodRefTypeArgCreator(final int idx, + final int pos) { + return new PositionCreator() { + @Override + public TypeAnnotationPosition create(List<TypePathEntry> path, + JCLambda lambda, + int typeIndex) { + return TypeAnnotationPosition.methodRefTypeArg(path, lambda, idx, pos); + } + }; + } + + public PositionCreator constructorRefTypeArgCreator(final int idx, + final int pos) { + return new PositionCreator() { + @Override + public TypeAnnotationPosition create(List<TypePathEntry> path, + JCLambda lambda, + int typeIndex) { + return TypeAnnotationPosition + .constructorRefTypeArg(path, lambda, idx, pos); + } + }; + } + + public PositionCreator methodInvokeTypeArgCreator(final int idx, + final int pos) { + return new PositionCreator() { + @Override + public TypeAnnotationPosition create(List<TypePathEntry> path, + JCLambda lambda, + int typeIndex) { + return TypeAnnotationPosition.methodInvocationTypeArg(path, lambda, idx, pos); + } + }; + } + + public PositionCreator constructorInvokeTypeArgCreator(final int idx, + final int pos) { + return new PositionCreator() { + @Override + public TypeAnnotationPosition create(List<TypePathEntry> path, + JCLambda lambda, + int typeIndex) { + return TypeAnnotationPosition.constructorInvocationTypeArg(path, lambda, idx, pos); + } + }; + } + + public PositionCreator methodTypeParamBoundCreator(final JCTypeParameter typaram, + final int param_idx, + final int bound_idx) { + return new PositionCreator() { + @Override + public TypeAnnotationPosition create(List<TypePathEntry> path, + JCLambda lambda, + int typeIndex) { + final int real_bound_idx = + typaram.bounds.head.type.isInterface() ? bound_idx + 1 : bound_idx; + return TypeAnnotationPosition + .methodTypeParameterBound(path, lambda, param_idx, real_bound_idx, -1); + } + }; + } + + public PositionCreator throwCreator(final int idx) { + return new PositionCreator() { + @Override + public TypeAnnotationPosition create(List<TypePathEntry> path, + JCLambda lambda, + int typeIndex) { + return TypeAnnotationPosition.methodThrows(path, lambda, idx, -1); + } + }; + } + + public final PositionCreator returnCreator = + new PositionCreator() { + @Override + public TypeAnnotationPosition create(List<TypePathEntry> path, + JCLambda lambda, + int typeIndex) { + return TypeAnnotationPosition.methodReturn(path, lambda, -1); + } + }; + + public PositionCreator receiverCreator = + new PositionCreator() { + @Override + public TypeAnnotationPosition create(List<TypePathEntry> path, + JCLambda lambda, + int typeIndex) { + return TypeAnnotationPosition.methodReceiver(path, lambda, -1); + } + }; + + public PositionCreator methodRefCreator(final int pos) { + return new PositionCreator() { + @Override + public TypeAnnotationPosition create(List<TypePathEntry> path, + JCLambda lambda, + int typeIndex) { + return TypeAnnotationPosition.methodRef(path, lambda, pos); + } + }; + } + + public PositionCreator constructorRefCreator(final int pos) { + return new PositionCreator() { + @Override + public TypeAnnotationPosition create(List<TypePathEntry> path, + JCLambda lambda, + int typeIndex) { + return TypeAnnotationPosition.constructorRef(path, lambda, pos); + } + }; + } + + public PositionCreator instanceOfCreator(final int pos) { + return new PositionCreator() { + @Override + public TypeAnnotationPosition create(List<TypePathEntry> path, + JCLambda lambda, + int typeIndex) { + return TypeAnnotationPosition.instanceOf(path, lambda, pos); + } + }; + } + + public PositionCreator newObjCreator(final int pos) { + return new PositionCreator() { + @Override + public TypeAnnotationPosition create(List<TypePathEntry> path, + JCLambda lambda, + int typeIndex) { + return TypeAnnotationPosition.newObj(path, lambda, pos); + } + }; + } + + public PositionCreator castCreator(final int pos) { + return new PositionCreator() { + @Override + public TypeAnnotationPosition create(List<TypePathEntry> path, + JCLambda lambda, + int typeIndex) { + return TypeAnnotationPosition.typeCast(path, lambda, typeIndex, pos); + } + }; + } + + private static List<TypePathEntry> addInners(Type type, + List<TypePathEntry> typepath) { + Type encl = type.getEnclosingType(); + while (encl != null && encl.getKind() != TypeKind.NONE && + encl.getKind() != TypeKind.ERROR) { + typepath = typepath.append(TypePathEntry.INNER_TYPE); + encl = encl.getEnclosingType(); + } + return typepath; + } + + public TypeAnnotate typeAnnotater(final List<JCAnnotation> declAnnos, + final Symbol sym, + final Env<AttrContext> env, + final DiagnosticPosition deferPos, + final JCLambda currentLambda, + final PositionCreator creator, + final boolean speculative) { + if (!speculative) { + return new TypeAnnotate(declAnnos, sym, env, deferPos, + currentLambda, creator, + declAnnotationsAttacher(sym), + typeAnnotationsAttacher(sym)); + } else { + return new TypeAnnotate(declAnnos, sym, env, deferPos, + currentLambda, creator, null, null); + } + } + private class TypeAnnotate extends TreeScanner { ! protected PositionCreator creator; ! private List<TypePathEntry> typepath = List.nil(); ! private JCLambda currentLambda; ! private int type_index = 0; ! private boolean innermost; ! // These attachers are for declaration annotations ! private AttributeAttacher<Attribute.Compound> declAttacher; ! private AttributeAttacher<Attribute.TypeCompound> typeAttacher; ! private Reporter<Attribute.TypeCompound> reporter; private final Symbol sym; ! private final DiagnosticPosition deferPos; ! private final Env<AttrContext> env; ! private final List<JCAnnotation> declAnnos; ! public TypeAnnotate(final List<JCAnnotation> declAnnos, final Symbol sym, ! final Env<AttrContext> env, ! final DiagnosticPosition deferPos, ! final JCLambda currentLambda, ! final PositionCreator creator, ! final AttributeAttacher<Attribute.Compound> declAttacher, ! final AttributeAttacher<Attribute.TypeCompound> typeAttacher) { ! this.declAnnos = declAnnos; this.sym = sym; + this.env = env; this.deferPos = deferPos; + this.currentLambda = currentLambda; + this.creator = creator; + this.innermost = true; + this.declAttacher = declAttacher; + this.typeAttacher = typeAttacher; + this.reporter = null; + } + + private void doDeclAnnos() { + if (!declAnnos.isEmpty()) { + final TypeAnnotationPosition tapos = + creator.createNonNull(typepath, currentLambda, type_index); + annotateNow(declAnnos, env, sym, deferPos, tapos, + classifyingAttacher(sym, declAttacher, + typeAttacher, reporter)); + validate(annotationValidator(declAnnos, env, sym)); + } + } + + private void doTypeAnnos(List<JCAnnotation> annos, + boolean isTypeParameter) { + if (!annos.isEmpty()) { + final AttributeAttacher<Attribute.TypeCompound> currTypeAttacher = typeAttacher; + final Reporter<Attribute.TypeCompound> currReporter = reporter; + final AttributeAttacher<Attribute.TypeCompound> attacher = + new AttributeAttacher<Attribute.TypeCompound>() { + @Override + public void attach(List<Attribute.TypeCompound> attrs) { + if (currTypeAttacher != null) + currTypeAttacher.attach(attrs); + if (currReporter != null) + currReporter.report(attrs); + } + }; + final TypeAnnotationPosition tapos = + creator.createNonNull(typepath, currentLambda, type_index); + actualEnterTypeAnnotations(annos, env, sym, deferPos, tapos, + attacher); + validate(typeAnnotationValidator(annos, env, isTypeParameter)); + } + } + + @Override + public void visitTypeIdent(final JCPrimitiveTypeTree tree) { + if (innermost) { + final AttributeAttacher<Attribute.TypeCompound> oldTypeAttacher = typeAttacher; + typeAttacher = + new AttributeAttacher<Attribute.TypeCompound>() { + @Override + public void attach(List<Attribute.TypeCompound> attrs) { + if (null != oldTypeAttacher) + oldTypeAttacher.attach(attrs); + + if (!attrs.isEmpty()) { + tree.type = tree.type.annotatedType(attrs); + } + } + }; + doDeclAnnos(); + typeAttacher = oldTypeAttacher; + } + } + + @Override + public void visitIdent(final JCIdent tree) { + if (innermost) { + final AttributeAttacher<Attribute.TypeCompound> oldTypeAttacher = typeAttacher; + final Reporter<Attribute.TypeCompound> oldReporter = reporter; + typeAttacher = + new AttributeAttacher<Attribute.TypeCompound>() { + @Override + public void attach(List<Attribute.TypeCompound> attrs) { + if (null != oldTypeAttacher) + oldTypeAttacher.attach(attrs); + + if (!attrs.isEmpty() && + !tree.type.hasTag(TypeTag.PACKAGE)) { + tree.type = tree.type.annotatedType(attrs); + } + } + }; + if (tree.type != null) { + final List<TypePathEntry> oldpath = typepath; + typepath = addInners(tree.type, typepath); + doDeclAnnos(); + typepath = oldpath; + } else { + doDeclAnnos(); + } + reporter = oldReporter; + typeAttacher = oldTypeAttacher; + } + } + + @Override + public void visitAnnotatedType(JCAnnotatedType tree) { + Assert.checkNonNull(tree.getUnderlyingType().type); + final boolean oldinnermost = innermost; + innermost = false; + scan(tree.annotations); + innermost = oldinnermost; + scan(tree.underlyingType); + final Reporter<Attribute.TypeCompound> oldReporter = reporter; + final List<TypePathEntry> oldpath = typepath; + typepath = addInners(tree.getUnderlyingType().type, typepath); + doTypeAnnos(tree.annotations, false); + typepath = oldpath; + reporter = oldReporter; } @Override ! public void visitTypeArray(JCArrayTypeTree tree) { ! final List<TypePathEntry> oldpath = typepath; ! typepath = typepath.append(TypePathEntry.ARRAY); ! super.visitTypeArray(tree); ! typepath = oldpath; } @Override ! public void visitTypeApply(JCTypeApply tree) { ! Assert.checkNonNull(tree.getType().type); ! final List<TypePathEntry> oldpath = typepath; ! scan(tree.clazz); ! ! ! if (tree.getType() != null && tree.getType().type != null) { ! typepath = addInners(tree.getType().type, typepath); ! } ! final boolean oldinnermost = innermost; ! innermost = false; ! int i = 0; ! for (List<JCExpression> l = tree.arguments; l.nonEmpty(); ! l = l.tail, i++) { ! final JCExpression arg = l.head; ! final List<TypePathEntry> noargpath = typepath; ! typepath = typepath.append(new TypePathEntry(TypePathEntryKind.TYPE_ARGUMENT, i)); ! scan(arg); ! typepath = noargpath; ! } ! typepath = oldpath; ! innermost = oldinnermost; ! } ! ! @Override ! public void visitNewArray(JCNewArray tree) { ! final List<TypePathEntry> oldpath = typepath; ! final PositionCreator oldcreator = creator; ! creator = newObjCreator(tree.pos); ! doTypeAnnos(tree.annotations, false); ! ! for (int i = 0; i < tree.dimAnnotations.size(); i++) { ! final List<JCAnnotation> dimAnnos = tree.dimAnnotations.get(i); ! doTypeAnnos(dimAnnos, false); ! // This is right. As per the type annotations spec, ! // the first array dimension has no arrays in the type ! // path, the second has one, and so on, and the ! // element type has n for n dimensions. ! typepath = typepath.append(TypePathEntry.ARRAY); ! } ! ! // The element type is sometimes null, in the case of ! // array literals. ! scan(tree.elemtype); ! typepath = oldpath; ! creator = oldcreator; ! } ! ! @Override ! public void visitWildcard(JCWildcard tree) { ! final List<TypePathEntry> oldpath = typepath; ! typepath = typepath.append(TypePathEntry.WILDCARD); ! super.visitWildcard(tree); ! typepath = oldpath; } @Override ! public void visitTypeParameter(JCTypeParameter tree) { ! scan(tree.annotations); ! Assert.checkNonNull(tree.type); ! doTypeAnnos(tree.annotations, true); } @Override ! public void visitLambda(JCLambda tree) { ! final JCLambda oldLambda = currentLambda; ! currentLambda = tree; ! scan(tree.body); scan(tree.params); ! currentLambda = oldLambda; ! } @Override ! public void visitTypeIntersection(JCTypeIntersection tree) { ! final boolean oldinnermost = innermost; ! for (List<JCExpression> l = tree.bounds; l.nonEmpty(); ! l = l.tail, type_index++) { ! scan(l.head); ! // Set innermost to false after the first element ! innermost = false; } ! innermost = oldinnermost; } + + @Override + public void visitTypeUnion(JCTypeUnion tree) { + final boolean oldinnermost = innermost; + for (List<JCExpression> l = tree.alternatives; l.nonEmpty(); + l = l.tail, type_index++) { + scan(l.head); + // Set innermost to false after the first element + innermost = false; + } + innermost = oldinnermost; + } + + @Override + public void visitSelect(JCFieldAccess tree) { + Symbol sym = tree.sym; + //System.err.println("visitSelect " + tree); + final AttributeAttacher<Attribute.TypeCompound> oldTypeAttacher = typeAttacher; + final Reporter<Attribute.TypeCompound> oldReporter = reporter; + // If we're selecting from an interface or a static class, + // set up attachers that will only attach declaration + // annotations and will report type annotations as errors. + Type selectedTy = tree.selected.type; + if (sym != null && (sym.isStatic() || sym.isInterface() || + selectedTy.hasTag(TypeTag.PACKAGE))) { + typeAttacher = null; + reporter = illegalScopingReporter(tree.pos); + } + super.visitSelect(tree); + typeAttacher = oldTypeAttacher; + reporter = oldReporter; + } + + // These methods stop the visitor from continuing on when it + // sees a definition. + @Override + public void visitVarDef(final JCVariableDecl tree) { } @Override public void visitClassDef(JCClassDecl tree) { // We can only hit a classdef if it is declared within
*** 1082,1094 **** // separately later. } @Override public void visitNewClass(JCNewClass tree) { ! if (tree.def == null) { ! // For an anonymous class instantiation the class ! // will be visited separately. ! super.visitNewClass(tree); } } } } --- 1951,2009 ---- // separately later. } @Override public void visitNewClass(JCNewClass tree) { ! // This will be visited by Attr later, so don't do ! // anything. } } + + private class TypeAnnotateExpr extends TypeAnnotate { + public TypeAnnotateExpr(final Symbol sym, + final Env<AttrContext> env, + final DiagnosticPosition deferPos, + final JCLambda currentLambda, + final PositionCreator creator) { + super(List.<JCAnnotation>nil(), sym, env, deferPos, + currentLambda, creator, null, null); + } + + @Override + public void visitTypeCast(final JCTypeCast tree) { + final PositionCreator oldcreator = creator; + creator = castCreator(tree.pos); + super.visitTypeCast(tree); + creator = oldcreator; + } + + @Override + public void visitTypeTest(JCInstanceOf tree) { + final PositionCreator oldcreator = creator; + creator = instanceOfCreator(tree.pos); + super.visitTypeTest(tree); + creator = oldcreator; + } + } + + public void typeAnnotateExprLater(final JCTree tree, + final Env<AttrContext> env, + final Symbol sym, + final DiagnosticPosition deferPos, + final JCLambda currentLambda, + final PositionCreator creator) { + Assert.checkNonNull(sym); + Assert.checkNonNull(creator); + + normal(new Annotate.Worker() { + @Override + public String toString() { + return "type annotate " + tree + " onto " + sym + " in " + sym.owner; + } + @Override + public void run() { + tree.accept(new TypeAnnotateExpr(sym, env, deferPos, + currentLambda, creator)); + } + }); } }