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));
+ }
+ });
}
}