mirror of
https://github.com/openjdk/jdk.git
synced 2026-03-16 10:53:31 +00:00
8038263: Refactor annotation handling after actualEnterAnnotations
Move all repeating annotations code into Annotate, rework annotations pipeline into a more completer-like design, eliminate a cast from enterAnnotations/enterTypeAnnotations Reviewed-by: jjg, jfranck
This commit is contained in:
parent
16c2ee6450
commit
b343919526
@ -34,7 +34,6 @@ import javax.lang.model.element.*;
|
||||
import javax.tools.JavaFileObject;
|
||||
|
||||
import com.sun.tools.javac.code.Type.*;
|
||||
import com.sun.tools.javac.comp.Annotate;
|
||||
import com.sun.tools.javac.comp.Attr;
|
||||
import com.sun.tools.javac.comp.AttrContext;
|
||||
import com.sun.tools.javac.comp.Env;
|
||||
@ -153,10 +152,6 @@ public abstract class Symbol extends AnnoConstruct implements Element {
|
||||
}
|
||||
}
|
||||
|
||||
public void appendTypeAttributesWithCompletion(final Annotate.AnnotateRepeatedContext<Attribute.TypeCompound> ctx) {
|
||||
initedMetadata().appendTypeAttributesWithCompletion(ctx);
|
||||
}
|
||||
|
||||
public void appendUniqueTypeAttributes(List<Attribute.TypeCompound> l) {
|
||||
if (l.nonEmpty()) {
|
||||
initedMetadata().appendUniqueTypes(l);
|
||||
@ -211,10 +206,6 @@ public abstract class Symbol extends AnnoConstruct implements Element {
|
||||
}
|
||||
}
|
||||
|
||||
public void setDeclarationAttributesWithCompletion(final Annotate.AnnotateRepeatedContext<Attribute.Compound> ctx) {
|
||||
initedMetadata().setDeclarationAttributesWithCompletion(ctx);
|
||||
}
|
||||
|
||||
public void setTypeAttributes(List<Attribute.TypeCompound> a) {
|
||||
if (metadata != null || a.nonEmpty()) {
|
||||
if (metadata == null)
|
||||
|
||||
@ -25,19 +25,9 @@
|
||||
|
||||
package com.sun.tools.javac.code;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import javax.tools.JavaFileObject;
|
||||
|
||||
import com.sun.tools.javac.comp.Annotate;
|
||||
import com.sun.tools.javac.comp.AttrContext;
|
||||
import com.sun.tools.javac.comp.Env;
|
||||
import com.sun.tools.javac.util.*;
|
||||
import com.sun.tools.javac.util.Assert;
|
||||
import com.sun.tools.javac.util.List;
|
||||
import com.sun.tools.javac.util.Log;
|
||||
import com.sun.tools.javac.util.Pair;
|
||||
import static com.sun.tools.javac.code.Kinds.PCK;
|
||||
|
||||
/**
|
||||
* Container for all annotations (attributes in javac) on a Symbol.
|
||||
@ -157,70 +147,6 @@ public class SymbolMetadata {
|
||||
setClassInitTypeAttributes(other.getClassInitTypeAttributes());
|
||||
}
|
||||
|
||||
public void setDeclarationAttributesWithCompletion(final Annotate.AnnotateRepeatedContext<Attribute.Compound> ctx) {
|
||||
Assert.check(pendingCompletion() || (!isStarted() && sym.kind == PCK));
|
||||
this.setDeclarationAttributes(getAttributesForCompletion(ctx));
|
||||
}
|
||||
|
||||
public void appendTypeAttributesWithCompletion(final Annotate.AnnotateRepeatedContext<Attribute.TypeCompound> ctx) {
|
||||
this.appendUniqueTypes(getAttributesForCompletion(ctx));
|
||||
}
|
||||
|
||||
private <T extends Attribute.Compound> List<T> getAttributesForCompletion(
|
||||
final Annotate.AnnotateRepeatedContext<T> ctx) {
|
||||
|
||||
Map<Symbol.TypeSymbol, ListBuffer<T>> annotated = ctx.annotated;
|
||||
boolean atLeastOneRepeated = false;
|
||||
List<T> buf = List.<T>nil();
|
||||
for (ListBuffer<T> lb : annotated.values()) {
|
||||
if (lb.size() == 1) {
|
||||
buf = buf.prepend(lb.first());
|
||||
} else { // repeated
|
||||
// This will break when other subtypes of Attributs.Compound
|
||||
// are introduced, because PlaceHolder is a subtype of TypeCompound.
|
||||
T res;
|
||||
@SuppressWarnings("unchecked")
|
||||
T ph = (T) new Placeholder<>(ctx, lb.toList(), sym);
|
||||
res = ph;
|
||||
buf = buf.prepend(res);
|
||||
atLeastOneRepeated = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (atLeastOneRepeated) {
|
||||
// The Symbol s is now annotated with a combination of
|
||||
// finished non-repeating annotations and placeholders for
|
||||
// repeating annotations.
|
||||
//
|
||||
// We need to do this in two passes because when creating
|
||||
// a container for a repeating annotation we must
|
||||
// guarantee that the @Repeatable on the
|
||||
// contained annotation is fully annotated
|
||||
//
|
||||
// The way we force this order is to do all repeating
|
||||
// annotations in a pass after all non-repeating are
|
||||
// finished. This will work because @Repeatable
|
||||
// is non-repeating and therefore will be annotated in the
|
||||
// fist pass.
|
||||
|
||||
// Queue a pass that will replace Attribute.Placeholders
|
||||
// with Attribute.Compound (made from synthesized containers).
|
||||
ctx.annotateRepeated(new Annotate.Worker() {
|
||||
@Override
|
||||
public String toString() {
|
||||
return "repeated annotation pass of: " + sym + " in: " + sym.owner;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
complete(ctx);
|
||||
}
|
||||
});
|
||||
}
|
||||
// Add non-repeating attributes
|
||||
return buf.reverse();
|
||||
}
|
||||
|
||||
public SymbolMetadata reset() {
|
||||
attributes = DECL_IN_PROGRESS;
|
||||
return this;
|
||||
@ -313,143 +239,4 @@ public class SymbolMetadata {
|
||||
private boolean isStarted() {
|
||||
return attributes != DECL_NOT_STARTED;
|
||||
}
|
||||
|
||||
private List<Attribute.Compound> getPlaceholders() {
|
||||
List<Attribute.Compound> res = List.<Attribute.Compound>nil();
|
||||
for (Attribute.Compound a : filterDeclSentinels(attributes)) {
|
||||
if (a instanceof Placeholder) {
|
||||
res = res.prepend(a);
|
||||
}
|
||||
}
|
||||
return res.reverse();
|
||||
}
|
||||
|
||||
private List<Attribute.TypeCompound> getTypePlaceholders() {
|
||||
List<Attribute.TypeCompound> res = List.<Attribute.TypeCompound>nil();
|
||||
for (Attribute.TypeCompound a : type_attributes) {
|
||||
if (a instanceof Placeholder) {
|
||||
res = res.prepend(a);
|
||||
}
|
||||
}
|
||||
return res.reverse();
|
||||
}
|
||||
|
||||
/*
|
||||
* Replace Placeholders for repeating annotations with their containers
|
||||
*/
|
||||
private <T extends Attribute.Compound> void complete(Annotate.AnnotateRepeatedContext<T> ctx) {
|
||||
Log log = ctx.log;
|
||||
Env<AttrContext> env = ctx.env;
|
||||
JavaFileObject oldSource = log.useSource(env.toplevel.sourcefile);
|
||||
try {
|
||||
// TODO: can we reduce duplication in the following branches?
|
||||
if (ctx.isTypeCompound) {
|
||||
Assert.check(!isTypesEmpty());
|
||||
|
||||
if (isTypesEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<Attribute.TypeCompound> result = List.nil();
|
||||
for (Attribute.TypeCompound a : getTypeAttributes()) {
|
||||
if (a instanceof Placeholder) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Placeholder<Attribute.TypeCompound> ph = (Placeholder<Attribute.TypeCompound>) a;
|
||||
Attribute.TypeCompound replacement = replaceOne(ph, ph.getRepeatedContext());
|
||||
|
||||
if (null != replacement) {
|
||||
result = result.prepend(replacement);
|
||||
}
|
||||
} else {
|
||||
result = result.prepend(a);
|
||||
}
|
||||
}
|
||||
|
||||
type_attributes = result.reverse();
|
||||
|
||||
Assert.check(SymbolMetadata.this.getTypePlaceholders().isEmpty());
|
||||
} else {
|
||||
Assert.check(!pendingCompletion());
|
||||
|
||||
if (isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<Attribute.Compound> result = List.nil();
|
||||
for (Attribute.Compound a : getDeclarationAttributes()) {
|
||||
if (a instanceof Placeholder) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Attribute.Compound replacement = replaceOne((Placeholder<T>) a, ctx);
|
||||
|
||||
if (null != replacement) {
|
||||
result = result.prepend(replacement);
|
||||
}
|
||||
} else {
|
||||
result = result.prepend(a);
|
||||
}
|
||||
}
|
||||
|
||||
attributes = result.reverse();
|
||||
|
||||
Assert.check(SymbolMetadata.this.getPlaceholders().isEmpty());
|
||||
}
|
||||
} finally {
|
||||
log.useSource(oldSource);
|
||||
}
|
||||
}
|
||||
|
||||
private <T extends Attribute.Compound> T replaceOne(Placeholder<T> placeholder, Annotate.AnnotateRepeatedContext<T> ctx) {
|
||||
Log log = ctx.log;
|
||||
|
||||
// Process repeated annotations
|
||||
T validRepeated = ctx.processRepeatedAnnotations(placeholder.getPlaceholderFor(), 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",
|
||||
manualContainer.first().type.tsym);
|
||||
}
|
||||
}
|
||||
|
||||
// A null return will delete the Placeholder
|
||||
return validRepeated;
|
||||
}
|
||||
|
||||
private static class Placeholder<T extends Attribute.Compound> extends Attribute.TypeCompound {
|
||||
|
||||
private final Annotate.AnnotateRepeatedContext<T> ctx;
|
||||
private final List<T> placeholderFor;
|
||||
private final Symbol on;
|
||||
|
||||
public Placeholder(Annotate.AnnotateRepeatedContext<T> ctx,
|
||||
List<T> placeholderFor, Symbol on) {
|
||||
super(on.type, List.<Pair<Symbol.MethodSymbol, Attribute>>nil(),
|
||||
ctx.isTypeCompound ?
|
||||
((Attribute.TypeCompound)placeholderFor.head).position :
|
||||
// TODO: Eventually, we will need to get rid of this
|
||||
// use of unknown, either by using null, or by
|
||||
// throwing an assertion failure here.
|
||||
TypeAnnotationPosition.unknown);
|
||||
this.ctx = ctx;
|
||||
this.placeholderFor = placeholderFor;
|
||||
this.on = on;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "<placeholder: " + placeholderFor + " on: " + on + ">";
|
||||
}
|
||||
|
||||
public List<T> getPlaceholderFor() {
|
||||
return placeholderFor;
|
||||
}
|
||||
|
||||
public Annotate.AnnotateRepeatedContext<T> getRepeatedContext() {
|
||||
return ctx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -189,53 +189,72 @@ public class Annotate {
|
||||
* This context contains all the information needed to synthesize new
|
||||
* annotations trees by the completer for repeating annotations.
|
||||
*/
|
||||
public class AnnotateRepeatedContext<T extends Attribute.Compound> {
|
||||
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 Log log;
|
||||
public final boolean isTypeCompound;
|
||||
|
||||
public AnnotateRepeatedContext(Env<AttrContext> env,
|
||||
Map<Symbol.TypeSymbol, ListBuffer<T>> annotated,
|
||||
Map<T, JCDiagnostic.DiagnosticPosition> pos,
|
||||
Log log,
|
||||
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);
|
||||
Assert.checkNonNull(log);
|
||||
|
||||
this.env = env;
|
||||
this.annotated = annotated;
|
||||
this.pos = pos;
|
||||
this.log = log;
|
||||
this.isTypeCompound = isTypeCompound;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a list of repeating annotations returning a new
|
||||
* Attribute.Compound that is the attribute for the synthesized tree
|
||||
* for the container.
|
||||
*
|
||||
* @param repeatingAnnotations a List of repeating annotations
|
||||
* @return a new Attribute.Compound that is the container for the repeatingAnnotations
|
||||
*/
|
||||
public T processRepeatedAnnotations(List<T> repeatingAnnotations, Symbol sym) {
|
||||
return Annotate.this.processRepeatedAnnotations(repeatingAnnotations, this, sym);
|
||||
}
|
||||
|
||||
/**
|
||||
* Queue the Worker a on the repeating annotations queue of the
|
||||
* Annotate instance this context belongs to.
|
||||
*
|
||||
* @param a the Worker to enqueue for repeating annotation annotating
|
||||
*/
|
||||
public void annotateRepeated(Worker a) {
|
||||
Annotate.this.repeated(a);
|
||||
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(" }");
|
||||
}
|
||||
sb.append(" ]");
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "<placeholder: " + placeholderFor + " on: " + on + ">";
|
||||
}
|
||||
|
||||
public List<T> getPlaceholderFor() {
|
||||
return placeholderFor;
|
||||
}
|
||||
|
||||
public Annotate.AnnotationContext<T> getRepeatedContext() {
|
||||
return ctx;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ********************************************************************
|
||||
* Compute an attribute from its annotation.
|
||||
*********************************************************************/
|
||||
@ -247,24 +266,44 @@ public class Annotate {
|
||||
Attribute.Compound enterAnnotation(JCAnnotation a,
|
||||
Type expected,
|
||||
Env<AttrContext> env) {
|
||||
return enterAnnotation(a, expected, env, false);
|
||||
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) {
|
||||
return (Attribute.TypeCompound) enterAnnotation(a, expected, env, true);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
// boolean typeAnnotation determines whether the method returns
|
||||
// a Compound (false) or TypeCompound (true).
|
||||
Attribute.Compound enterAnnotation(JCAnnotation a,
|
||||
Type expected,
|
||||
Env<AttrContext> env,
|
||||
boolean typeAnnotation) {
|
||||
// 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.
|
||||
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));
|
||||
a.type = chk.checkType(a.annotationType.pos(), at, expected);
|
||||
@ -312,27 +351,7 @@ public class Annotate {
|
||||
buf.append(new Pair<>((MethodSymbol)method, value));
|
||||
t.type = result;
|
||||
}
|
||||
if (typeAnnotation) {
|
||||
if (a.attribute == null || !(a.attribute instanceof Attribute.TypeCompound)) {
|
||||
// Create a new TypeCompound
|
||||
|
||||
Attribute.TypeCompound tc =
|
||||
new Attribute.TypeCompound(a.type, buf.toList(),
|
||||
// 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 a.attribute;
|
||||
}
|
||||
} else {
|
||||
Attribute.Compound ac = new Attribute.Compound(a.type, buf.toList());
|
||||
a.attribute = ac;
|
||||
return ac;
|
||||
}
|
||||
return buf.toList();
|
||||
}
|
||||
|
||||
Attribute enterAttributeValue(Type expected,
|
||||
@ -459,7 +478,7 @@ public class Annotate {
|
||||
* annotation are invalid. This method reports errors/warnings.
|
||||
*/
|
||||
private <T extends Attribute.Compound> T processRepeatedAnnotations(List<T> annotations,
|
||||
AnnotateRepeatedContext<T> ctx,
|
||||
AnnotationContext<T> ctx,
|
||||
Symbol on) {
|
||||
T firstOccurrence = annotations.head;
|
||||
List<Attribute> repeated = List.nil();
|
||||
@ -686,6 +705,172 @@ public class Annotate {
|
||||
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) {
|
||||
// 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.
|
||||
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",
|
||||
manualContainer.first().type.tsym);
|
||||
}
|
||||
}
|
||||
|
||||
// A null return will delete the Placeholder
|
||||
return validRepeated;
|
||||
}
|
||||
|
||||
/* ********************************************************************
|
||||
* Annotation processing
|
||||
*********************************************************************/
|
||||
@ -745,44 +930,39 @@ public class Annotate {
|
||||
});
|
||||
}
|
||||
|
||||
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) {
|
||||
Map<TypeSymbol, ListBuffer<Attribute.Compound>> annotated = new LinkedHashMap<>();
|
||||
Map<Attribute.Compound, DiagnosticPosition> pos = new HashMap<>();
|
||||
|
||||
for (List<JCAnnotation> al = annotations; !al.isEmpty(); al = al.tail) {
|
||||
JCAnnotation a = al.head;
|
||||
Attribute.Compound c = enterAnnotation(a, syms.annotationType, env);
|
||||
if (c == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (annotated.containsKey(a.type.tsym)) {
|
||||
if (!allowRepeatedAnnos) {
|
||||
log.error(a.pos(), "repeatable.annotations.not.supported.in.source");
|
||||
allowRepeatedAnnos = true;
|
||||
}
|
||||
ListBuffer<Attribute.Compound> 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()
|
||||
&& s.owner.kind != MTH
|
||||
&& types.isSameType(c.type, syms.deprecatedType)) {
|
||||
s.flags_field |= Flags.DEPRECATED;
|
||||
}
|
||||
}
|
||||
|
||||
s.setDeclarationAttributesWithCompletion(
|
||||
new AnnotateRepeatedContext<>(env, annotated, pos, log, false));
|
||||
Assert.checkNonNull(s, "Symbol argument to actualEnterAnnotations is null");
|
||||
attachAttributesLater(annotations, env, s, false,
|
||||
enterAnnotationsCreator,
|
||||
declAnnotationsAttacher);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -792,9 +972,7 @@ public class Annotate {
|
||||
final Env<AttrContext> env,
|
||||
final Symbol s,
|
||||
final DiagnosticPosition deferPos) {
|
||||
Map<TypeSymbol, ListBuffer<Attribute.TypeCompound>> annotated = new LinkedHashMap<>();
|
||||
Map<Attribute.TypeCompound, DiagnosticPosition> pos = new HashMap<>();
|
||||
|
||||
Assert.checkNonNull(s, "Symbol argument to actualEnterTypeAnnotations is nul/");
|
||||
JavaFileObject prev = log.useSource(env.toplevel.sourcefile);
|
||||
DiagnosticPosition prevLintPos = null;
|
||||
|
||||
@ -802,32 +980,9 @@ public class Annotate {
|
||||
prevLintPos = deferredLintHandler.setPos(deferPos);
|
||||
}
|
||||
try {
|
||||
|
||||
for (List<JCAnnotation> al = annotations; !al.isEmpty(); al = al.tail) {
|
||||
JCAnnotation a = al.head;
|
||||
Attribute.TypeCompound tc =
|
||||
enterTypeAnnotation(a, syms.annotationType, env);
|
||||
|
||||
Assert.checkNonNull(tc, "Failed to create type annotation");
|
||||
|
||||
if (annotated.containsKey(a.type.tsym)) {
|
||||
if (!allowRepeatedAnnos) {
|
||||
log.error(a.pos(), "repeatable.annotations.not.supported.in.source");
|
||||
allowRepeatedAnnos = true;
|
||||
}
|
||||
ListBuffer<Attribute.TypeCompound> l = annotated.get(a.type.tsym);
|
||||
l = l.append(tc);
|
||||
annotated.put(a.type.tsym, l);
|
||||
pos.put(tc, a.pos());
|
||||
} else {
|
||||
annotated.put(a.type.tsym, ListBuffer.of(tc));
|
||||
pos.put(tc, a.pos());
|
||||
}
|
||||
}
|
||||
|
||||
Assert.checkNonNull(s, "Symbol argument to actualEnterTypeAnnotations is null");
|
||||
s.appendTypeAttributesWithCompletion(
|
||||
new AnnotateRepeatedContext<>(env, annotated, pos, log, true));
|
||||
attachAttributesLater(annotations, env, s, true,
|
||||
enterTypeAnnotationsCreator,
|
||||
typeAnnotationsAttacher);
|
||||
} finally {
|
||||
if (prevLintPos != null)
|
||||
deferredLintHandler.setPos(prevLintPos);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user