< prev index next >
src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java
Print this page
@@ -23,32 +23,43 @@
* questions.
*/
package com.sun.tools.javac.comp;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.Map;
-
-import javax.tools.JavaFileObject;
-
-import com.sun.tools.javac.util.*;
-import com.sun.tools.javac.util.DefinedBy.Api;
-import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
import com.sun.tools.javac.code.*;
+import com.sun.tools.javac.code.Attribute.Compound;
+import com.sun.tools.javac.code.Attribute.TypeCompound;
+import com.sun.tools.javac.code.Scope.WriteableScope;
import com.sun.tools.javac.code.Symbol.*;
-import com.sun.tools.javac.tree.*;
+import com.sun.tools.javac.code.TypeMetadata.Entry.Kind;
+import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.JCTree.*;
+import com.sun.tools.javac.tree.TreeInfo;
+import com.sun.tools.javac.tree.TreeMaker;
+import com.sun.tools.javac.tree.TreeScanner;
+import com.sun.tools.javac.util.*;
+import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
+import com.sun.tools.javac.util.List;
+
+import javax.tools.JavaFileObject;
+import java.util.*;
-import static com.sun.tools.javac.code.Kinds.Kind.*;
+import static com.sun.tools.javac.code.Flags.SYNTHETIC;
+import static com.sun.tools.javac.code.Kinds.Kind.MTH;
+import static com.sun.tools.javac.code.Kinds.Kind.VAR;
+import static com.sun.tools.javac.code.Scope.LookupKind.NON_RECURSIVE;
import static com.sun.tools.javac.code.TypeTag.ARRAY;
import static com.sun.tools.javac.code.TypeTag.CLASS;
-import static com.sun.tools.javac.tree.JCTree.Tag.*;
+import static com.sun.tools.javac.tree.JCTree.Tag.ANNOTATION;
+import static com.sun.tools.javac.tree.JCTree.Tag.ASSIGN;
+import static com.sun.tools.javac.tree.JCTree.Tag.IDENT;
+import static com.sun.tools.javac.tree.JCTree.Tag.NEWARRAY;
-/** Enter annotations on symbols. Annotations accumulate in a queue,
- * which is processed at the top level of any set of recursive calls
- * requesting it be processed.
+/** Enter annotations onto symbols and types (and trees).
+ *
+ * This is also a pseudo stage in the compiler taking care of scheduling when annotations are
+ * entered.
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own risk.
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
@@ -62,383 +73,524 @@
instance = new Annotate(context);
return instance;
}
private final Attr attr;
- private final TreeMaker make;
+ private final Check chk;
+ private final ConstFold cfolder;
+ private final DeferredLintHandler deferredLintHandler;
+ private final Enter enter;
+ private final Lint lint;
private final Log log;
- private final Symtab syms;
private final Names names;
- private final Resolve rs;
+ private final Resolve resolve;
+ private final TreeMaker make;
+ private final Symtab syms;
+ private final TypeEnvs typeEnvs;
private final Types types;
- private final ConstFold cfolder;
- private final Check chk;
- private final Lint lint;
- private final DeferredLintHandler deferredLintHandler;
- private final Source source;
- private boolean allowTypeAnnos;
- private boolean allowRepeatedAnnos;
+ private final Attribute theUnfinishedDefaultValue;
+ private final boolean allowRepeatedAnnos;
protected Annotate(Context context) {
context.put(annotateKey, this);
+
attr = Attr.instance(context);
- make = TreeMaker.instance(context);
+ chk = Check.instance(context);
+ cfolder = ConstFold.instance(context);
+ deferredLintHandler = DeferredLintHandler.instance(context);
+ enter = Enter.instance(context);
log = Log.instance(context);
- syms = Symtab.instance(context);
+ lint = Lint.instance(context);
+ make = TreeMaker.instance(context);
names = Names.instance(context);
- rs = Resolve.instance(context);
+ resolve = Resolve.instance(context);
+ syms = Symtab.instance(context);
+ typeEnvs = TypeEnvs.instance(context);
types = Types.instance(context);
- cfolder = ConstFold.instance(context);
- chk = Check.instance(context);
- source = Source.instance(context);
- lint = Lint.instance(context);
- deferredLintHandler = DeferredLintHandler.instance(context);
- allowRepeatedAnnos = source.allowRepeatedAnnotations();
- allowTypeAnnos = source.allowTypeAnnotations();
- }
-
-/* ********************************************************************
- * Queue maintenance
- *********************************************************************/
- private int enterCount = 0;
+ theUnfinishedDefaultValue = new Attribute.Error(syms.errType);
- ListBuffer<Worker> q = new ListBuffer<>();
- ListBuffer<Worker> typesQ = new ListBuffer<>();
- ListBuffer<Worker> repeatedQ = new ListBuffer<>();
- ListBuffer<Worker> afterRepeatedQ = new ListBuffer<>();
- ListBuffer<Worker> validateQ = new ListBuffer<>();
-
- public void earlier(Worker a) {
- q.prepend(a);
+ Source source = Source.instance(context);
+ allowRepeatedAnnos = source.allowRepeatedAnnotations();
}
- public void normal(Worker a) {
- q.append(a);
+ public List<TypeCompound> fromAnnotations(List<JCAnnotation> annotations) {
+ if (annotations.isEmpty()) {
+ return List.nil();
}
- public void typeAnnotation(Worker a) {
- typesQ.append(a);
+ ListBuffer<TypeCompound> buf = new ListBuffer<>();
+ for (JCAnnotation anno : annotations) {
+ Assert.checkNonNull(anno.attribute);
+ buf.append((TypeCompound) anno.attribute);
}
-
- public void repeated(Worker a) {
- repeatedQ.append(a);
+ return buf.toList();
}
- public void afterRepeated(Worker a) {
- afterRepeatedQ.append(a);
+ /** Annotate (used for everything else) */
+ public void normal(Runnable r) {
+ q.append(r);
}
- public void validate(Worker a) {
+ /** Validate, triggers after 'normal' */
+ public void validate(Runnable a) {
validateQ.append(a);
}
- /** Called when the Enter phase starts. */
- public void enterStart() {
- enterCount++;
- }
-
- /** Called after the Enter phase completes. */
- public void enterDone() {
- enterCount--;
- flush();
- }
-
- /** Variant which allows for a delayed flush of annotations.
- * Needed by ClassReader */
- public void enterDoneWithoutFlush() {
- enterCount--;
- }
-
+ /** Flush all annotation queues */
public void flush() {
- if (enterCount != 0) return;
- enterCount++;
+ if (enter.isEntering()) return;
+ if (isFlushing()) return;
+
+ startFlushing();
try {
while (q.nonEmpty()) {
q.next().run();
}
while (typesQ.nonEmpty()) {
typesQ.next().run();
}
- while (repeatedQ.nonEmpty()) {
- repeatedQ.next().run();
- }
- while (afterRepeatedQ.nonEmpty()) {
- afterRepeatedQ.next().run();
+ while (afterTypesQ.nonEmpty()) {
+ afterTypesQ.next().run();
}
while (validateQ.nonEmpty()) {
validateQ.next().run();
}
} finally {
- enterCount--;
+ doneFlushing();
}
}
- /** A client that needs to run during {@link #flush()} registers an worker
- * into one of the queues defined in this class. The queues are: {@link #earlier(Worker)},
- * {@link #normal(Worker)}, {@link #typeAnnotation(Worker)}, {@link #repeated(Worker)},
- * {@link #afterRepeated(Worker)}, {@link #validate(Worker)}.
- * The {@link Worker#run()} method will called inside the {@link #flush()}
- * call. Queues are empties in the abovementioned order.
- */
- public interface Worker {
- void run();
- String toString();
+ private ListBuffer<Runnable> q = new ListBuffer<>();
+ private ListBuffer<Runnable> validateQ = new ListBuffer<>();
+
+ private int flushCount = 0;
+ private boolean isFlushing() { return flushCount > 0; }
+ private void startFlushing() { flushCount++; }
+ private void doneFlushing() { flushCount--; }
+
+ ListBuffer<Runnable> typesQ = new ListBuffer<>();
+ ListBuffer<Runnable> afterTypesQ = new ListBuffer<>();
+
+
+ public void typeAnnotation(Runnable a) {
+ typesQ.append(a);
+ }
+
+ public void afterTypes(Runnable a) {
+ afterTypesQ.append(a);
}
/**
- * This context contains all the information needed to synthesize new
- * annotations trees by the completer for repeating annotations.
+ * Queue annotations for later attribution and entering. This is probably the method you are looking for.
+ *
+ * @param annotations the list of JCAnnotations to attribute and enter
+ * @param localEnv the enclosing env
+ * @param s ths Symbol on which to enter the annotations
+ * @param deferPos report errors here
*/
- private class AnnotationContext<T extends Attribute.Compound> {
- public final Env<AttrContext> env;
- public final Map<Symbol.TypeSymbol, ListBuffer<T>> annotated;
- public final Map<T, JCDiagnostic.DiagnosticPosition> pos;
- public final boolean isTypeCompound;
+ public void annotateLater(List<JCAnnotation> annotations, Env<AttrContext> localEnv,
+ Symbol s, DiagnosticPosition deferPos)
+ {
+ if (annotations.isEmpty()) {
+ return;
+ }
- public AnnotationContext(Env<AttrContext> env,
- Map<Symbol.TypeSymbol, ListBuffer<T>> annotated,
- Map<T, JCDiagnostic.DiagnosticPosition> pos,
- boolean isTypeCompound) {
- Assert.checkNonNull(env);
- Assert.checkNonNull(annotated);
- Assert.checkNonNull(pos);
+ s.resetAnnotations(); // mark Annotations as incomplete for now
- this.env = env;
- this.annotated = annotated;
- this.pos = pos;
- this.isTypeCompound = isTypeCompound;
+ normal(new Runnable() {
+ @Override
+ public String toString() {
+ return "Annotate " + annotations + " onto " + s + " in " + s.owner;
}
- public String toString() {
- StringBuilder sb = new StringBuilder();
- sb.append("RepeatedContext[");
- for (Map.Entry<Symbol.TypeSymbol, ListBuffer<T>> entry :
- annotated.entrySet()) {
- sb.append(" ");
- sb.append(entry.getKey());
- sb.append(" = { ");
- sb.append(entry.getValue());
- sb.append(" }");
+ @Override
+ public void run() {
+ Assert.check(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", Kinds.kindName(s), s);
+
+ Assert.checkNonNull(s, "Symbol argument to actualEnterAnnotations is null");
+ annotateNow(s, annotations, localEnv, false);
+ } finally {
+ if (prevLint != null)
+ chk.setLint(prevLint);
+ deferredLintHandler.setPos(prevLintPos);
+ log.useSource(prev);
+ }
+ }
+ });
+
+ validate(new Runnable() { //validate annotations
+ @Override
+ public void run() {
+ JavaFileObject prev = log.useSource(localEnv.toplevel.sourcefile);
+ try {
+ chk.validateAnnotations(annotations, s);
+ } finally {
+ log.useSource(prev);
+ }
}
- sb.append(" ]");
- return sb.toString();
+
+ @Override
+ public String toString() {
+ return "validate annotations: " + annotations + " on " + s;
}
+ });
}
- private static class Placeholder<T extends Attribute.Compound> extends Attribute.Compound {
- private final Annotate.AnnotationContext<T> ctx;
- private final List<T> placeholderFor;
- private final Symbol on;
+ /** Queue processing of an attribute default value. */
+ public void annotateDefaultValueLater(JCExpression defaultValue, Env<AttrContext> localEnv,
+ MethodSymbol m, DiagnosticPosition deferPos)
+ {
+ normal(new Runnable() {
+ @Override
+ public void run() {
+ JavaFileObject prev = log.useSource(localEnv.toplevel.sourcefile);
+ DiagnosticPosition prevLintPos = deferredLintHandler.setPos(deferPos);
+ try {
+ enterDefaultValue(defaultValue, localEnv, m);
+ } finally {
+ deferredLintHandler.setPos(prevLintPos);
+ log.useSource(prev);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "Annotate " + m.owner + "." +
+ m + " default " + defaultValue;
+ }
+ });
- public Placeholder(Annotate.AnnotationContext<T> ctx,
- List<T> placeholderFor, Symbol on) {
- super(on.type, List.<Pair<Symbol.MethodSymbol, Attribute>>nil(),
- placeholderFor.head.position);
- this.ctx = ctx;
- this.placeholderFor = placeholderFor;
- this.on = on;
+ validate(new Runnable() { //validate annotations
+ @Override
+ public void run() {
+ JavaFileObject prev = log.useSource(localEnv.toplevel.sourcefile);
+ try {
+ // if default value is an annotation, check it is a well-formed
+ // annotation value (e.g. no duplicate values, no missing values, etc.)
+ chk.validateAnnotationTree(defaultValue);
+ } finally {
+ log.useSource(prev);
+ }
}
- @Override @DefinedBy(Api.LANGUAGE_MODEL)
+ @Override
public String toString() {
- return "<placeholder: " + placeholderFor + " on: " + on + ">";
+ return "Validate default value " + m.owner + "." + m + " default " + defaultValue;
+ }
+ });
+ }
+
+ /** Enter a default value for an annotation element. */
+ private void enterDefaultValue(JCExpression defaultValue,
+ Env<AttrContext> localEnv, MethodSymbol m) {
+ m.defaultValue = attributeAnnotationValue(m.type.getReturnType(), defaultValue, localEnv);
+ }
+
+ /**
+ * Gather up annotations into a map from type symbols to lists of Compound attributes,
+ * then continue on with repeating annotations processing.
+ */
+ private <T extends Attribute.Compound> void annotateNow(Symbol toAnnotate,
+ List<JCAnnotation> withAnnotations, Env<AttrContext> env, boolean typeAnnotations)
+ {
+ Map<TypeSymbol, ListBuffer<T>> annotated = new LinkedHashMap<>();
+ Map<T, DiagnosticPosition> pos = new HashMap<>();
+ boolean allowRepeatedAnnos = this.allowRepeatedAnnos;
+
+ for (List<JCAnnotation> al = withAnnotations; !al.isEmpty(); al = al.tail) {
+ JCAnnotation a = al.head;
+
+ T c;
+ if (typeAnnotations) {
+ @SuppressWarnings("unchecked")
+ T tmp = (T)attributeTypeAnnotation(a, syms.annotationType, env);
+ c = tmp;
+ } else {
+ @SuppressWarnings("unchecked")
+ T tmp = (T)attributeAnnotation(a, syms.annotationType, env);
+ c = tmp;
}
- public List<T> getPlaceholderFor() {
- return placeholderFor;
+ Assert.checkNonNull(c, "Failed to create annotation");
+
+ if (annotated.containsKey(a.type.tsym)) {
+ if (!allowRepeatedAnnos) {
+ log.error(a.pos(), "repeatable.annotations.not.supported.in.source");
+ allowRepeatedAnnos = true;
+ }
+ ListBuffer<T> l = annotated.get(a.type.tsym);
+ l = l.append(c);
+ annotated.put(a.type.tsym, l);
+ pos.put(c, a.pos());
+ } else {
+ annotated.put(a.type.tsym, ListBuffer.of(c));
+ pos.put(c, a.pos());
}
- public Annotate.AnnotationContext<T> getRepeatedContext() {
- return ctx;
+ // Note: @Deprecated has no effect on local variables and parameters
+ if (!c.type.isErroneous()
+ && toAnnotate.owner.kind != MTH
+ && types.isSameType(c.type, syms.deprecatedType)) {
+ toAnnotate.flags_field |= Flags.DEPRECATED;
}
}
+ List<T> buf = List.nil();
+ for (ListBuffer<T> lb : annotated.values()) {
+ if (lb.size() == 1) {
+ buf = buf.prepend(lb.first());
+ } else {
+ AnnotationContext<T> ctx = new AnnotationContext<>(env, annotated, pos, typeAnnotations);
+ T res = makeContainerAnnotation(lb.toList(), ctx, toAnnotate);
+ if (res != null)
+ buf = buf.prepend(res);
+ }
+ }
-/* ********************************************************************
- * Compute an attribute from its annotation.
- *********************************************************************/
+ if (typeAnnotations) {
+ @SuppressWarnings("unchecked")
+ List<TypeCompound> attrs = (List<TypeCompound>)buf.reverse();
+ toAnnotate.appendUniqueTypeAttributes(attrs);
+ } else {
+ @SuppressWarnings("unchecked")
+ List<Attribute.Compound> attrs = (List<Attribute.Compound>)buf.reverse();
+ toAnnotate.resetAnnotations();
+ toAnnotate.setDeclarationAttributes(attrs);
+ }
+ }
- /** Process a single compound annotation, returning its
- * Attribute. Used from MemberEnter for attaching the attributes
- * to the annotated symbol.
+ /**
+ * Attribute and store a semantic representation of the annotation tree {@code tree} into the
+ * tree.attribute field.
+ *
+ * @param tree the tree representing an annotation
+ * @param expectedAnnotationType the expected (super)type of the annotation
+ * @param env the current env in where the annotation instance is found
*/
- 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;
+ public Attribute.Compound attributeAnnotation(JCAnnotation tree, Type expectedAnnotationType,
+ Env<AttrContext> env)
+ {
+ // The attribute might have been entered if if is Target or Repetable
+ // Because TreeCopier does not copy type, redo this if type is null
+ if (tree.attribute != null && tree.type != null)
+ return tree.attribute;
- return ac;
- }
+ List<Pair<MethodSymbol, Attribute>> elems = attributeAnnotationValues(tree, expectedAnnotationType, env);
+ Attribute.Compound ac = new Attribute.Compound(tree.type, elems);
- Attribute.TypeCompound enterTypeAnnotation(JCAnnotation a,
- Type expected,
- Env<AttrContext> env) {
- List<Pair<MethodSymbol,Attribute>> elems =
- enterAttributeValues(a, expected, env);
+ return tree.attribute = ac;
+ }
- if (a.attribute == null || !(a.attribute instanceof Attribute.TypeCompound)) {
+ /** Attribute and store a semantic representation of the type annotation tree {@code tree} into
+ * the tree.attribute field.
+ *
+ * @param a the tree representing an annotation
+ * @param expectedAnnotationType the expected (super)type of the annotation
+ * @param env the the current env in where the annotation instance is found
+ */
+ public Attribute.TypeCompound attributeTypeAnnotation(JCAnnotation a, Type expectedAnnotationType,
+ Env<AttrContext> env)
+ {
+ // The attribute might have been entered if if is Target or Repetable
+ // Because TreeCopier does not copy type, redo this if type is null
+ if (a.attribute == null || a.type == null || !(a.attribute instanceof Attribute.TypeCompound)) {
// Create a new TypeCompound
+ List<Pair<MethodSymbol,Attribute>> elems =
+ attributeAnnotationValues(a, expectedAnnotationType, env);
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);
+ new Attribute.TypeCompound(a.type, elems, TypeAnnotationPosition.unknown);
a.attribute = tc;
return tc;
} else {
// Use an existing TypeCompound
return (Attribute.TypeCompound)a.attribute;
}
}
- private List<Pair<MethodSymbol,Attribute>>
- enterAttributeValues(JCAnnotation a,
- Type expected,
- Env<AttrContext> env) {
+ /**
+ * Attribute annotation elements creating a list of pairs of the Symbol representing that
+ * element and the value of that element as an Attribute. */
+ private List<Pair<MethodSymbol, Attribute>> attributeAnnotationValues(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));
+ Type at = (a.annotationType.type != null ?
+ a.annotationType.type : attr.attribType(a.annotationType, env));
a.type = chk.checkType(a.annotationType.pos(), at, expected);
+
boolean isError = a.type.isErroneous();
- if ((a.type.tsym.flags() & Flags.ANNOTATION) == 0 && !isError) {
+ if (!a.type.tsym.isAnnotationType() && !isError) {
log.error(a.annotationType.pos(),
"not.annotation.type", a.type.toString());
isError = true;
}
+
+ // List of name=value pairs (or implicit "value=" if size 1)
List<JCExpression> args = a.args;
+
boolean elidedValue = false;
- if (args.length() == 1 && !args.head.hasTag(ASSIGN)) {
// special case: elided "value=" assumed
- elidedValue = true;
+ if (args.length() == 1 && !args.head.hasTag(ASSIGN)) {
args.head = make.at(args.head.pos).
Assign(make.Ident(names.value), args.head);
+ elidedValue = true;
}
- ListBuffer<Pair<MethodSymbol,Attribute>> buf =
- new ListBuffer<>();
+
+ ListBuffer<Pair<MethodSymbol,Attribute>> buf = 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;
+ Pair<MethodSymbol, Attribute> p = attributeAnnotationNameValuePair(tl.head, a.type, isError, env, elidedValue);
+ if (p != null && !p.fst.type.isErroneous())
+ buf.append(p);
+ }
+ return buf.toList();
+ }
+
+ // where
+ private Pair<MethodSymbol, Attribute> attributeAnnotationNameValuePair(JCExpression nameValuePair,
+ Type thisAnnotationType, boolean badAnnotation, Env<AttrContext> env, boolean elidedValue)
+ {
+ if (!nameValuePair.hasTag(ASSIGN)) {
+ log.error(nameValuePair.pos(), "annotation.value.must.be.name.value");
+ attributeAnnotationValue(nameValuePair.type = syms.errType, nameValuePair, env);
+ return null;
}
- JCAssign assign = (JCAssign)t;
+ JCAssign assign = (JCAssign)nameValuePair;
if (!assign.lhs.hasTag(IDENT)) {
- log.error(t.pos(), "annotation.value.must.be.name.value");
- enterAttributeValue(t.type = syms.errType, t, env);
- continue;
+ log.error(nameValuePair.pos(), "annotation.value.must.be.name.value");
+ attributeAnnotationValue(nameValuePair.type = syms.errType, nameValuePair, env);
+ return null;
}
+
+ // Resolve element to MethodSym
JCIdent left = (JCIdent)assign.lhs;
- Symbol method = rs.resolveQualifiedMethod(elidedValue ? assign.rhs.pos() : left.pos(),
- env,
- a.type,
- left.name,
- List.<Type>nil(),
- null);
+ Symbol method = resolve.resolveQualifiedMethod(elidedValue ? assign.rhs.pos() : left.pos(),
+ env, thisAnnotationType,
+ left.name, List.<Type>nil(), null);
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();
+ if (method.owner != thisAnnotationType.tsym && !badAnnotation)
+ log.error(left.pos(), "no.annotation.member", left.name, thisAnnotationType);
+ Type resultType = method.type.getReturnType();
+
+ // Compute value part
+ Attribute value = attributeAnnotationValue(resultType, assign.rhs, env);
+ nameValuePair.type = resultType;
+
+ return method.type.isErroneous() ? null : new Pair<>((MethodSymbol)method, value);
+
}
- Attribute enterAttributeValue(Type expected,
- JCExpression tree,
- Env<AttrContext> env) {
- //first, try completing the attribution value sym - if a completion
+ /** Attribute an annotation element value */
+ private Attribute attributeAnnotationValue(Type expectedElementType, JCExpression tree,
+ Env<AttrContext> env)
+ {
+ //first, try completing the symbol for the annotation value - if acompletion
//error is thrown, we should recover gracefully, and display an
//ordinary resolution diagnostic.
try {
- expected.tsym.complete();
+ expectedElementType.tsym.complete();
} catch(CompletionFailure e) {
log.error(tree.pos(), "cant.resolve", Kinds.kindName(e.sym), e.sym);
- expected = syms.errType;
+ expectedElementType = syms.errType;
}
- if (expected.hasTag(ARRAY)) {
- if (!tree.hasTag(NEWARRAY)) {
- tree = make.at(tree.pos).
- NewArray(null, List.<JCExpression>nil(), List.of(tree));
- }
- JCNewArray na = (JCNewArray)tree;
- if (na.elemtype != null) {
- 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()]));
+
+ if (expectedElementType.hasTag(ARRAY)) {
+ return getAnnotationArrayValue(expectedElementType, tree, env);
+
}
- if (tree.hasTag(NEWARRAY)) { //error recovery
- if (!expected.isErroneous())
+
+ //error recovery
+ if (tree.hasTag(NEWARRAY)) {
+ if (!expectedElementType.isErroneous())
log.error(tree.pos(), "annotation.value.not.allowable.type");
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,
+ attributeAnnotationValue(syms.errType,
l.head,
env);
}
return new Attribute.Error(syms.errType);
}
- if ((expected.tsym.flags() & Flags.ANNOTATION) != 0) {
+
+ if (expectedElementType.tsym.isAnnotationType()) {
if (tree.hasTag(ANNOTATION)) {
- return enterAnnotation((JCAnnotation)tree, expected, env);
+ return attributeAnnotation((JCAnnotation)tree, expectedElementType, env);
} else {
log.error(tree.pos(), "annotation.value.must.be.annotation");
- expected = syms.errType;
+ expectedElementType = 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);
+
+ //error recovery
+ if (tree.hasTag(ANNOTATION)) {
+ if (!expectedElementType.isErroneous())
+ log.error(tree.pos(), "annotation.not.valid.for.type", expectedElementType);
+ attributeAnnotation((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);
- if (result.isErroneous())
- return new Attribute.Error(result.getOriginalType());
- if (result.constValue() == null) {
- log.error(tree.pos(), "attribute.value.must.be.constant");
- return new Attribute.Error(expected);
+
+ if (expectedElementType.isPrimitive() ||
+ (types.isSameType(expectedElementType, syms.stringType) && !expectedElementType.hasTag(TypeTag.ERROR))) {
+ return getAnnotationPrimitiveValue(expectedElementType, tree, env);
}
- result = cfolder.coerce(result, expected);
- return new Attribute.Constant(expected, result.constValue());
+
+ if (expectedElementType.tsym == syms.classType.tsym) {
+ return getAnnotationClassValue(expectedElementType, tree, env);
}
- if (expected.tsym == syms.classType.tsym) {
- Type result = attr.attribExpr(tree, env, expected);
- if (result.isErroneous()) {
- // Does it look like an unresolved class literal?
- if (TreeInfo.name(tree) == names._class &&
- ((JCFieldAccess) tree).selected.type.isErroneous()) {
- Name n = (((JCFieldAccess) tree).selected).type.tsym.flatName();
- return new Attribute.UnresolvedClass(expected,
- types.createErrorType(n,
+
+ if (expectedElementType.hasTag(CLASS) &&
+ (expectedElementType.tsym.flags() & Flags.ENUM) != 0) {
+ return getAnnotationEnumValue(expectedElementType, tree, env);
+ }
+
+ //error recovery:
+ if (!expectedElementType.isErroneous())
+ log.error(tree.pos(), "annotation.value.not.allowable.type");
+ return new Attribute.Error(attr.attribExpr(tree, env, expectedElementType));
+ }
+
+ private Attribute getAnnotationEnumValue(Type expectedElementType, JCExpression tree, Env<AttrContext> env) {
+ Type result = attr.attribExpr(tree, env, expectedElementType);
+ Symbol sym = TreeInfo.symbol(tree);
+ if (sym == null ||
+ TreeInfo.nonstaticSelect(tree) ||
+ sym.kind != VAR ||
+ (sym.flags() & Flags.ENUM) == 0) {
+ log.error(tree.pos(), "enum.annotation.must.be.enum.constant");
+ return new Attribute.Error(result.getOriginalType());
+ }
+ VarSymbol enumerator = (VarSymbol) sym;
+ return new Attribute.Enum(expectedElementType, enumerator);
+ }
+
+ private Attribute getAnnotationClassValue(Type expectedElementType, JCExpression tree, Env<AttrContext> env) {
+ Type result = attr.attribExpr(tree, env, expectedElementType);
+ if (result.isErroneous()) {
+ // Does it look like an unresolved class literal?
+ if (TreeInfo.name(tree) == names._class &&
+ ((JCFieldAccess) tree).selected.type.isErroneous()) {
+ Name n = (((JCFieldAccess) tree).selected).type.tsym.flatName();
+ return new Attribute.UnresolvedClass(expectedElementType,
+ types.createErrorType(n,
syms.unknownSymbol, syms.classType));
} else {
return new Attribute.Error(result.getOriginalType());
}
}
@@ -450,56 +602,92 @@
return new Attribute.Error(syms.errType);
}
return new Attribute.Class(types,
(((JCFieldAccess) tree).selected).type);
}
- if (expected.hasTag(CLASS) &&
- (expected.tsym.flags() & Flags.ENUM) != 0) {
- Type result = attr.attribExpr(tree, env, expected);
- Symbol sym = TreeInfo.symbol(tree);
- if (sym == null ||
- TreeInfo.nonstaticSelect(tree) ||
- sym.kind != VAR ||
- (sym.flags() & Flags.ENUM) == 0) {
- log.error(tree.pos(), "enum.annotation.must.be.enum.constant");
+
+ private Attribute getAnnotationPrimitiveValue(Type expectedElementType, JCExpression tree, Env<AttrContext> env) {
+ Type result = attr.attribExpr(tree, env, expectedElementType);
+ if (result.isErroneous())
return new Attribute.Error(result.getOriginalType());
+ if (result.constValue() == null) {
+ log.error(tree.pos(), "attribute.value.must.be.constant");
+ return new Attribute.Error(expectedElementType);
}
- VarSymbol enumerator = (VarSymbol) sym;
- return new Attribute.Enum(expected, enumerator);
+ result = cfolder.coerce(result, expectedElementType);
+ return new Attribute.Constant(expectedElementType, result.constValue());
}
- //error recovery:
- if (!expected.isErroneous())
- log.error(tree.pos(), "annotation.value.not.allowable.type");
- return new Attribute.Error(attr.attribExpr(tree, env, expected));
+
+ private Attribute getAnnotationArrayValue(Type expectedElementType, JCExpression tree, Env<AttrContext> env) {
+ // Special case, implicit array
+ if (!tree.hasTag(NEWARRAY)) {
+ tree = make.at(tree.pos).
+ NewArray(null, List.<JCExpression>nil(), List.of(tree));
+ }
+
+ JCNewArray na = (JCNewArray)tree;
+ if (na.elemtype != null) {
+ 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(attributeAnnotationValue(types.elemtype(expectedElementType),
+ l.head,
+ env));
+ }
+ na.type = expectedElementType;
+ return new Attribute.
+ Array(expectedElementType, buf.toArray(new Attribute[buf.length()]));
}
/* *********************************
* Support for repeating annotations
***********************************/
+ /**
+ * This context contains all the information needed to synthesize new
+ * annotations trees for repeating annotations.
+ */
+ private class AnnotationContext<T extends Attribute.Compound> {
+ public final Env<AttrContext> env;
+ public final Map<Symbol.TypeSymbol, ListBuffer<T>> annotated;
+ public final Map<T, JCDiagnostic.DiagnosticPosition> pos;
+ public final boolean isTypeCompound;
+
+ public AnnotationContext(Env<AttrContext> env,
+ Map<Symbol.TypeSymbol, ListBuffer<T>> annotated,
+ Map<T, JCDiagnostic.DiagnosticPosition> pos,
+ boolean isTypeCompound) {
+ Assert.checkNonNull(env);
+ Assert.checkNonNull(annotated);
+ Assert.checkNonNull(pos);
+
+ this.env = env;
+ this.annotated = annotated;
+ this.pos = pos;
+ this.isTypeCompound = isTypeCompound;
+ }
+ }
+
/* Process repeated annotations. This method returns the
* 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) {
+ AnnotationContext<T> ctx, Symbol on)
+ {
T firstOccurrence = annotations.head;
List<Attribute> repeated = List.nil();
Type origAnnoType = null;
Type arrayOfOrigAnnoType = null;
Type targetContainerType = null;
MethodSymbol containerValueSymbol = null;
- Assert.check(!annotations.isEmpty() &&
- !annotations.tail.isEmpty()); // i.e. size() > 1
+ Assert.check(!annotations.isEmpty() && !annotations.tail.isEmpty()); // i.e. size() > 1
int count = 0;
- for (List<T> al = annotations;
- !al.isEmpty();
- al = al.tail)
- {
+ 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());
@@ -530,10 +718,15 @@
}
repeated = repeated.prepend(currentAnno);
}
+ if (!repeated.isEmpty() && targetContainerType == null) {
+ log.error(ctx.pos.get(annotations.head), "duplicate.annotation.invalid.repeated", origAnnoType);
+ return null;
+ }
+
if (!repeated.isEmpty()) {
repeated = repeated.reverse();
TreeMaker m = make.at(ctx.pos.get(firstOccurrence));
Pair<MethodSymbol, Attribute> p =
new Pair<MethodSymbol, Attribute>(containerValueSymbol,
@@ -541,11 +734,11 @@
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);
+ at = attributeTypeAnnotation(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);
@@ -560,16 +753,17 @@
} 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);
+ 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 = attributeAnnotation(annoTree, targetContainerType, ctx.env);
c.setSynthesized(true);
@SuppressWarnings("unchecked")
T x = (T) c;
return x;
@@ -577,21 +771,23 @@
} else {
return null; // errors should have been reported elsewhere
}
}
- /** Fetches the actual Type that should be the containing annotation. */
+ /**
+ * Fetches the actual Type that should be the containing annotation.
+ */
private Type getContainingType(Attribute.Compound currentAnno,
DiagnosticPosition pos,
boolean reportError)
{
Type origAnnoType = currentAnno.type;
TypeSymbol origAnnoDecl = origAnnoType.tsym;
// Fetch the Repeatable annotation from the current
// annotation's declaration, or null if it has none
- Attribute.Compound ca = origAnnoDecl.attribute(syms.repeatableType.tsym);
+ Attribute.Compound ca = origAnnoDecl.getAnnotationTypeMetadata().getRepeatable();
if (ca == null) { // has no Repeatable annotation
if (reportError)
log.error(pos, "duplicate.annotation.missing.container", origAnnoType, syms.repeatableType);
return null;
}
@@ -696,318 +892,116 @@
targetContainerType,
valueRetType,
expectedType);
fatalError = true;
}
- if (error) {
- fatalError = true;
- }
-
- // The conditions for a valid containing annotation are made
- // in Check.validateRepeatedAnnotaton();
return fatalError ? null : containerValueSymbol;
}
- 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) {
- log.error(a.pos(), "repeatable.annotations.not.supported.in.source");
- allowRepeatedAnnos = true;
- }
- ListBuffer<T> l = annotated.get(a.type.tsym);
- l = l.append(c);
- annotated.put(a.type.tsym, l);
- pos.put(c, a.pos());
- } else {
- annotated.put(a.type.tsym, ListBuffer.of(c));
- pos.put(c, a.pos());
- }
-
- // Note: @Deprecated has no effect on local variables and parameters
- if (!c.type.isErroneous()
- && sym.owner.kind != MTH
- && types.isSameType(c.type, syms.deprecatedType)) {
- sym.flags_field |= Flags.DEPRECATED;
- }
- }
-
- return new AnnotationContext<>(env, annotated, pos,
- isTypeCompound);
- }
-
- // Gather up annotations into a map from type symbols to lists of
- // Compound attributes, then continue on with repeating
- // annotations processing
- 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();
- for (ListBuffer<T> lb : annotated.values()) {
- if (lb.size() == 1) {
- buf = buf.prepend(lb.first());
- } else {
- @SuppressWarnings("unchecked")
- T res = (T) new Placeholder<>(ctx, lb.toList(), sym);
- buf = buf.prepend(res);
- hasRepeated = true;
- }
- }
-
- final List<T> attrs = buf.reverse();
-
- 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;
- }
-
- @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) {
- List<T> result = List.nil();
- for (T a : buf) {
- if (a instanceof Placeholder) {
- @SuppressWarnings("unchecked")
- T replacement = replaceOne((Placeholder<T>) a, ctx, sym);
-
- if (null != replacement) {
- result = result.prepend(replacement);
- }
- } else {
- result = result.prepend(a);
- }
- }
-
- return result.reverse();
- }
-
- private <T extends Attribute.Compound> T replaceOne(Placeholder<T> placeholder,
- Annotate.AnnotationContext<T> ctx,
- Symbol sym) {
+ private <T extends Attribute.Compound> T makeContainerAnnotation(List<T> toBeReplaced,
+ AnnotationContext<T> ctx, Symbol sym)
+ {
// Process repeated annotations
T validRepeated =
- processRepeatedAnnotations(placeholder.getPlaceholderFor(),
- ctx, sym);
+ processRepeatedAnnotations(toBeReplaced, ctx, sym);
if (validRepeated != null) {
// Check that the container isn't manually
// present along with repeated instances of
// its contained annotation.
ListBuffer<T> manualContainer = ctx.annotated.get(validRepeated.type.tsym);
if (manualContainer != null) {
- log.error(ctx.pos.get(manualContainer.first()), "invalid.repeatable.annotation.repeated.and.container.present",
+ log.error(ctx.pos.get(manualContainer.first()),
+ "invalid.repeatable.annotation.repeated.and.container.present",
manualContainer.first().type.tsym);
}
}
// A null return will delete the Placeholder
return validRepeated;
}
-/* ********************************************************************
- * 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
- }
- normal(new Annotate.Worker() {
- @Override
- public String toString() {
- return "annotate " + annotations + " onto " + s + " in " + s.owner;
- }
+ /********************
+ * Type annotations *
+ ********************/
- @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);
+ /**
+ * Attribute the list of annotations and enter them onto s.
+ */
+ public void enterTypeAnnotations(List<JCAnnotation> annotations, Env<AttrContext> env,
+ Symbol s, 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 {
- if (s.hasAnnotations() &&
- annotations.nonEmpty())
- log.error(annotations.head.pos,
- "already.annotated",
- Kinds.kindName(s), s);
- actualEnterAnnotations(annotations, localEnv, s);
+ annotateNow(s, annotations, env, true);
} finally {
- if (prevLint != null)
- chk.setLint(prevLint);
+ if (prevLintPos != null)
deferredLintHandler.setPos(prevLintPos);
log.useSource(prev);
}
}
- });
- validate(new Annotate.Worker() { //validate annotations
+ /**
+ * Enqueue tree for scanning of type annotations, attaching to the Symbol sym.
+ */
+ public void queueScanTreeAndTypeAnnotate(JCTree tree, Env<AttrContext> env, Symbol sym,
+ DiagnosticPosition deferPos)
+ {
+ Assert.checkNonNull(sym);
+ normal(new Runnable() {
+ @Override
+ public String toString() {
+ return "type annotate " + tree + " onto " + sym + " in " + sym.owner;
+ }
+
@Override
public void run() {
- JavaFileObject prev = log.useSource(localEnv.toplevel.sourcefile);
- try {
- chk.validateAnnotations(annotations, s);
- } finally {
- log.useSource(prev);
- }
+ tree.accept(new TypeAnnotate(env, sym, deferPos));
}
});
}
- private interface AttributeCreator<T extends Attribute.Compound> {
- public T create(JCAnnotation a, Type expected, Env<AttrContext> env);
+ /**
+ * Apply the annotations to the particular type.
+ */
+ public void annotateTypeSecondStage(JCTree tree, List<JCAnnotation> annotations, Type storeAt) {
+ typeAnnotation(new Runnable() {
+ @Override
+ public String toString() {
+ return "Type annotate 2:nd stage " + annotations + " onto " + tree;
}
- // 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);
+ public void run() {
+ List<Attribute.TypeCompound> compounds = fromAnnotations(annotations);
+ Assert.check(annotations.size() == compounds.size());
+ storeAt.getMetadataOfKind(Kind.ANNOTATIONS).combine(new TypeMetadata.Annotations(compounds));
}
- };
-
- /** 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.
+ /**
+ * Apply the annotations to the particular type.
*/
- 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() {
+ public void annotateTypeParameterSecondStage(JCTree tree, List<JCAnnotation> annotations) {
+ typeAnnotation(new Runnable() {
@Override
public String toString() {
- return "type annotate " + tree + " onto " + sym + " in " + sym.owner;
+ return "Type annotate 2:nd stage " + annotations + " onto " + tree;
}
+
@Override
public void run() {
- tree.accept(new TypeAnnotate(env, sym, deferPos));
+ List<Attribute.TypeCompound> compounds = fromAnnotations(annotations);
+ Assert.check(annotations.size() == compounds.size());
}
});
}
/**
@@ -1017,54 +1011,52 @@
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) {
+ public TypeAnnotate(Env<AttrContext> env, Symbol sym, 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);
+ public void visitAnnotatedType(JCAnnotatedType tree) {
+ enterTypeAnnotations(tree.annotations, env, sym, deferPos);
+ scan(tree.underlyingType);
}
@Override
- public void visitTypeParameter(final JCTypeParameter tree) {
- actualEnterTypeAnnotations(tree.annotations, env, sym, deferPos);
- super.visitTypeParameter(tree);
+ public void visitTypeParameter(JCTypeParameter tree) {
+ enterTypeAnnotations(tree.annotations, env, sym, deferPos);
+ scan(tree.bounds);
}
@Override
- public void visitNewArray(final JCNewArray tree) {
- actualEnterTypeAnnotations(tree.annotations, env, sym, deferPos);
+ public void visitNewArray(JCNewArray tree) {
+ enterTypeAnnotations(tree.annotations, env, sym, deferPos);
for (List<JCAnnotation> dimAnnos : tree.dimAnnotations)
- actualEnterTypeAnnotations(dimAnnos, env, sym, deferPos);
- super.visitNewArray(tree);
+ enterTypeAnnotations(dimAnnos, env, sym, deferPos);
+ scan(tree.elemtype);
+ scan(tree.elems);
}
@Override
- public void visitMethodDef(final JCMethodDecl tree) {
+ public void visitMethodDef(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) {
+ public void visitVarDef(JCVariableDecl tree) {
DiagnosticPosition prevPos = deferPos;
deferPos = tree.pos();
try {
if (sym != null && sym.kind == VAR) {
// Don't visit a parameter once when the sym is the method
@@ -1092,6 +1084,240 @@
// will be visited separately.
super.visitNewClass(tree);
}
}
}
+
+ /*********************
+ * Completer support *
+ *********************/
+
+ private AnnotationTypeCompleter theSourceCompleter = new AnnotationTypeCompleter() {
+ @Override
+ public void complete(ClassSymbol sym) throws CompletionFailure {
+ Env<AttrContext> context = typeEnvs.get(sym);
+ Annotate.this.attributeAnnotationType(context);
+ }
+ };
+
+ /* Last stage completer to enter just enough annotations to have a prototype annotation type.
+ * This currently means entering @Target and @Repetable.
+ */
+ public AnnotationTypeCompleter annotationTypeSourceCompleter() {
+ return theSourceCompleter;
+ }
+
+ private void attributeAnnotationType(Env<AttrContext> env) {
+ Assert.check(((JCClassDecl)env.tree).sym.isAnnotationType(),
+ "Trying to annotation type complete a non-annotation type");
+
+ JavaFileObject prev = log.useSource(env.toplevel.sourcefile);
+ try {
+ JCClassDecl tree = (JCClassDecl)env.tree;
+ AnnotationTypeVisitor v = new AnnotationTypeVisitor(attr, chk, syms, typeEnvs);
+ v.scanAnnotationType(tree);
+ tree.sym.getAnnotationTypeMetadata().setRepeatable(v.repeatable);
+ tree.sym.getAnnotationTypeMetadata().setTarget(v.target);
+ } finally {
+ log.useSource(prev);
+ }
+ }
+
+ public Attribute unfinishedDefaultValue() {
+ return theUnfinishedDefaultValue;
+ }
+
+ public static interface AnnotationTypeCompleter {
+ void complete(ClassSymbol sym) throws CompletionFailure;
+ }
+
+ /** Visitor to determine a prototype annotation type for a class declaring an annotation type.
+ *
+ * <p><b>This is NOT part of any supported API.
+ * If you write code that depends on this, you do so at your own risk.
+ * This code and its internal interfaces are subject to change or
+ * deletion without notice.</b>
+ */
+ public class AnnotationTypeVisitor extends TreeScanner {
+ private Env<AttrContext> env;
+
+ private final Attr attr;
+ private final Check check;
+ private final Symtab tab;
+ private final TypeEnvs typeEnvs;
+
+ private Compound target;
+ private Compound repeatable;
+
+ public AnnotationTypeVisitor(Attr attr, Check check, Symtab tab, TypeEnvs typeEnvs) {
+ this.attr = attr;
+ this.check = check;
+ this.tab = tab;
+ this.typeEnvs = typeEnvs;
+ }
+
+ public Compound getRepeatable() {
+ return repeatable;
+ }
+
+ public Compound getTarget() {
+ return target;
+ }
+
+ public void scanAnnotationType(JCClassDecl decl) {
+ visitClassDef(decl);
+ }
+
+ @Override
+ public void visitClassDef(JCClassDecl tree) {
+ Env<AttrContext> prevEnv = env;
+ env = typeEnvs.get(tree.sym);
+ try {
+ scan(tree.mods); // look for repeatable and target
+ // don't descend into body
+ } finally {
+ env = prevEnv;
+ }
+ }
+
+ @Override
+ public void visitAnnotation(JCAnnotation tree) {
+ Type t = tree.annotationType.type;
+ if (t == null) {
+ t = attr.attribType(tree.annotationType, env);
+ tree.annotationType.type = t = check.checkType(tree.annotationType.pos(), t, tab.annotationType);
+ }
+
+ if (t == tab.annotationTargetType) {
+ target = Annotate.this.attributeAnnotation(tree, tab.annotationTargetType, env);
+ } else if (t == tab.repeatableType) {
+ repeatable = Annotate.this.attributeAnnotation(tree, tab.repeatableType, env);
+ }
+ }
+ }
+
+ /** Represents the semantics of an Annotation Type.
+ *
+ * <p><b>This is NOT part of any supported API.
+ * If you write code that depends on this, you do so at your own risk.
+ * This code and its internal interfaces are subject to change or
+ * deletion without notice.</b>
+ */
+ public static class AnnotationTypeMetadata {
+ final ClassSymbol metaDataFor;
+ private Compound target;
+ private Compound repeatable;
+ private AnnotationTypeCompleter annotationTypeCompleter;
+
+ public AnnotationTypeMetadata(ClassSymbol metaDataFor, AnnotationTypeCompleter annotationTypeCompleter) {
+ this.metaDataFor = metaDataFor;
+ this.annotationTypeCompleter = annotationTypeCompleter;
+ }
+
+ private void init() {
+ // Make sure metaDataFor is member entered
+ while (metaDataFor.completer != null)
+ metaDataFor.complete();
+
+ if (annotationTypeCompleter != null) {
+ AnnotationTypeCompleter c = annotationTypeCompleter;
+ annotationTypeCompleter = null;
+ c.complete(metaDataFor);
+ }
+ }
+
+ public void complete() {
+ init();
+ }
+
+ public Compound getRepeatable() {
+ init();
+ return repeatable;
+ }
+
+ public void setRepeatable(Compound repeatable) {
+ Assert.checkNull(this.repeatable);
+ this.repeatable = repeatable;
+ }
+
+ public Compound getTarget() {
+ init();
+ return target;
+ }
+
+ public void setTarget(Compound target) {
+ Assert.checkNull(this.target);
+ this.target = target;
+ }
+
+ public Set<MethodSymbol> getAnnotationElements() {
+ init();
+ Set<MethodSymbol> members = new LinkedHashSet<>();
+ WriteableScope s = metaDataFor.members();
+ Iterable<Symbol> ss = s.getSymbols(NON_RECURSIVE);
+ for (Symbol sym : ss)
+ if (sym.kind == MTH &&
+ sym.name != sym.name.table.names.clinit &&
+ (sym.flags() & SYNTHETIC) == 0)
+ members.add((MethodSymbol)sym);
+ return members;
+ }
+
+ public Set<MethodSymbol> getAnnotationElementsWithDefault() {
+ init();
+ Set<MethodSymbol> members = getAnnotationElements();
+ Set<MethodSymbol> res = new LinkedHashSet<>();
+ for (MethodSymbol m : members)
+ if (m.defaultValue != null)
+ res.add(m);
+ return res;
+ }
+
+ @Override
+ public String toString() {
+ return "Annotation type for: " + metaDataFor;
+ }
+
+ public boolean isMetadataForAnnotationType() { return true; }
+
+ public static AnnotationTypeMetadata notAnAnnotationType() {
+ return NOT_AN_ANNOTATION_TYPE;
+ }
+
+ private static final AnnotationTypeMetadata NOT_AN_ANNOTATION_TYPE =
+ new AnnotationTypeMetadata(null, null) {
+ @Override
+ public void complete() {
+ } // do nothing
+
+ @Override
+ public String toString() {
+ return "Not an annotation type";
+ }
+
+ @Override
+ public Set<MethodSymbol> getAnnotationElements() {
+ return new LinkedHashSet<>(0);
+ }
+
+ @Override
+ public Set<MethodSymbol> getAnnotationElementsWithDefault() {
+ return new LinkedHashSet<>(0);
+ }
+
+ @Override
+ public boolean isMetadataForAnnotationType() {
+ return false;
+ }
+
+ @Override
+ public Compound getTarget() {
+ return null;
+ }
+
+ @Override
+ public Compound getRepeatable() {
+ return null;
+ }
+ };
+ }
}
< prev index next >