--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java Thu Apr 09 06:40:21 2015 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java Thu Apr 09 17:37:46 2015 -0700
@@ -696,7 +696,8 @@
@DefinedBy(Api.COMPILER_TREE)
public TypeMirror getTypeMirror(TreePath path) {
Tree t = path.getLeaf();
- return ((JCTree)t).type;
+ Type ty = ((JCTree)t).type;
+ return ty == null ? null : ty.stripMetadataIfNeeded();
}
@DefinedBy(Api.COMPILER_TREE)
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/ClassFinder.java Thu Apr 09 06:40:21 2015 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/ClassFinder.java Thu Apr 09 17:37:46 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -25,7 +25,8 @@
package com.sun.tools.javac.code;
-import java.io.*;
+import java.io.IOException;
+import java.io.File;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;
@@ -38,16 +39,15 @@
import javax.tools.StandardJavaFileManager;
import com.sun.tools.javac.code.Scope.WriteableScope;
-import com.sun.tools.javac.code.Symbol.*;
import com.sun.tools.javac.code.Symbol.ClassSymbol;
import com.sun.tools.javac.code.Symbol.Completer;
import com.sun.tools.javac.code.Symbol.CompletionFailure;
import com.sun.tools.javac.code.Symbol.PackageSymbol;
import com.sun.tools.javac.code.Symbol.TypeSymbol;
import com.sun.tools.javac.comp.Annotate;
+import com.sun.tools.javac.comp.Enter;
import com.sun.tools.javac.file.JRTIndex;
import com.sun.tools.javac.file.JavacFileManager;
-import com.sun.tools.javac.file.RelativePath.RelativeDirectory;
import com.sun.tools.javac.jvm.ClassReader;
import com.sun.tools.javac.jvm.Profile;
import com.sun.tools.javac.util.*;
@@ -75,7 +75,7 @@
ClassReader reader;
- Annotate annotate;
+ private final Annotate annotate;
/** Switch: verbose output.
*/
@@ -272,18 +272,13 @@
try {
ClassSymbol c = (ClassSymbol) sym;
dependencies.push(c, CompletionCause.CLASS_READER);
+ annotate.blockAnnotations();
c.members_field = new Scope.ErrorScope(c); // make sure it's always defined
- annotate.enterStart();
- try {
- completeOwners(c.owner);
- completeEnclosing(c);
- } finally {
- // The flush needs to happen only after annotations
- // are filled in.
- annotate.enterDoneWithoutFlush();
- }
+ completeOwners(c.owner);
+ completeEnclosing(c);
fillIn(c);
} finally {
+ annotate.unblockAnnotationsNoFlush();
dependencies.pop();
}
} else if (sym.kind == PCK) {
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java Thu Apr 09 06:40:21 2015 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java Thu Apr 09 17:37:46 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -33,6 +33,11 @@
import javax.lang.model.element.*;
import javax.tools.JavaFileObject;
+import com.sun.tools.javac.code.Attribute.Compound;
+import com.sun.tools.javac.code.TypeAnnotations.AnnotationType;
+import com.sun.tools.javac.code.TypeMetadata.Entry;
+import com.sun.tools.javac.comp.Annotate.AnnotationTypeCompleter;
+import com.sun.tools.javac.comp.Annotate.AnnotationTypeMetadata;
import com.sun.tools.javac.code.Scope.WriteableScope;
import com.sun.tools.javac.code.Type.*;
import com.sun.tools.javac.comp.Attr;
@@ -738,6 +743,13 @@
return list;
}
+ public AnnotationTypeMetadata getAnnotationTypeMetadata() {
+ Assert.error("Only on ClassSymbol");
+ return null; //unreachable
+ }
+
+ public boolean isAnnotationType() { return false; }
+
@Override
public <R, P> R accept(Symbol.Visitor<R, P> v, P p) {
return v.visitTypeSymbol(this, p);
@@ -958,6 +970,9 @@
*/
public Pool pool;
+ /** the annotation metadata attached to this class */
+ private AnnotationTypeMetadata annotationTypeMetadata;
+
public ClassSymbol(long flags, Name name, Type type, Symbol owner) {
super(TYP, flags, name, type, owner);
this.members_field = null;
@@ -966,6 +981,7 @@
this.sourcefile = null;
this.classfile = null;
this.pool = null;
+ this.annotationTypeMetadata = AnnotationTypeMetadata.notAnAnnotationType();
}
public ClassSymbol(long flags, Name name, Symbol owner) {
@@ -1202,8 +1218,24 @@
t.all_interfaces_field = null;
}
metadata = null;
+ annotationTypeMetadata = AnnotationTypeMetadata.notAnAnnotationType();
+ }
+
+ @Override
+ public AnnotationTypeMetadata getAnnotationTypeMetadata() {
+ return annotationTypeMetadata;
}
+ @Override
+ public boolean isAnnotationType() {
+ return (flags_field & Flags.ANNOTATION) != 0;
+ }
+
+ public void setAnnotationTypeMetadata(AnnotationTypeMetadata a) {
+ Assert.checkNonNull(a);
+ Assert.check(!annotationTypeMetadata.isMetadataForAnnotationType());
+ this.annotationTypeMetadata = a;
+ }
}
@@ -1360,7 +1392,7 @@
/** The names of the parameters */
public List<Name> savedParameterNames;
- /** For an attribute field accessor, its default value if any.
+ /** For an annotation type element, its default value if any.
* The value is null if none appeared in the method
* declaration.
*/
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java Thu Apr 09 06:40:21 2015 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java Thu Apr 09 17:37:46 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -36,7 +36,7 @@
import javax.lang.model.type.*;
import com.sun.tools.javac.code.Symbol.*;
-import com.sun.tools.javac.code.Types.MapVisitor;
+import com.sun.tools.javac.code.TypeMetadata.Entry;
import com.sun.tools.javac.util.*;
import com.sun.tools.javac.util.DefinedBy.Api;
import static com.sun.tools.javac.code.BoundKind.*;
@@ -87,11 +87,10 @@
return metadata;
}
- public TypeMetadata.Element getMetadataOfKind(final TypeMetadata.Element.Kind kind) {
+ public Entry getMetadataOfKind(final Entry.Kind kind) {
return metadata != null ? metadata.get(kind) : null;
}
-
/** Constant type: no type at all. */
public static final JCNoType noType = new JCNoType() {
@Override @DefinedBy(Api.LANGUAGE_MODEL)
@@ -238,7 +237,12 @@
List<Type> typarams = t.getTypeArguments();
List<Type> typarams1 = visit(typarams, s);
if (outer1 == outer && typarams1 == typarams) return t;
- else return new ClassType(outer1, typarams1, t.tsym, t.metadata);
+ else return new ClassType(outer1, typarams1, t.tsym, t.metadata) {
+ @Override
+ protected boolean needsStripping() {
+ return true;
+ }
+ };
}
@Override
@@ -249,7 +253,12 @@
if (t == wt.type)
return wt;
else
- return new WildcardType(t, wt.kind, wt.tsym, wt.bound, wt.metadata);
+ return new WildcardType(t, wt.kind, wt.tsym, wt.bound, wt.metadata) {
+ @Override
+ protected boolean needsStripping() {
+ return true;
+ }
+ };
}
@Override
@@ -257,7 +266,12 @@
Type elemtype = t.elemtype;
Type elemtype1 = visit(elemtype, s);
if (elemtype1 == elemtype) return t;
- else return new ArrayType(elemtype1, t.tsym, t.metadata);
+ else return new ArrayType(elemtype1, t.tsym, t.metadata) {
+ @Override
+ protected boolean needsStripping() {
+ return true;
+ }
+ };
}
@Override
@@ -271,7 +285,12 @@
if (argtypes1 == argtypes &&
restype1 == restype &&
thrown1 == thrown) return t;
- else return new MethodType(argtypes1, restype1, thrown1, t.tsym);
+ else return new MethodType(argtypes1, restype1, thrown1, t.tsym) {
+ @Override
+ protected boolean needsStripping() {
+ return true;
+ }
+ };
}
@Override
@@ -313,38 +332,78 @@
}
/**
- * Create a new type with exactly the given metadata. The
- * argument is guaranteed to always be non-empty, and should have
- * already been copied/combined with the current type's metadata.
- * This is used internally by other methods.
- *
+ * Returns the original version of this type, before metadata were added. This routine is meant
+ * for internal use only (i.e. {@link Type#equalsIgnoreMetadata(Type)}, {@link Type#stripMetadata});
+ * it should not be used outside this class.
*/
- public abstract Type clone(TypeMetadata md);
+ protected Type typeNoMetadata() {
+ return metadata == TypeMetadata.EMPTY ? this : baseType();
+ }
- public Type combineMetadata(final TypeMetadata.Element md) {
- return clone(metadata.combine(md));
+ /**
+ * Create a new copy of this type but with the specified TypeMetadata.
+ */
+ public abstract Type cloneWithMetadata(TypeMetadata metadata);
+
+ /**
+ * Does this type require annotation stripping for API clients?
+ */
+ protected boolean needsStripping() {
+ return false;
}
+ /**
+ * Strip all metadata associated with this type - this could return a new clone of the type.
+ * This routine is only used to present the correct annotated types back to the users when types
+ * are accessed through compiler APIs; it should not be used anywhere in the compiler internals
+ * as doing so might result in performance penalties.
+ */
+ public Type stripMetadataIfNeeded() {
+ return needsStripping() ?
+ accept(stripMetadata, null) :
+ this;
+ }
+ //where
+ private final static TypeMapping<Void> stripMetadata = new TypeMapping<Void>() {
+ @Override
+ public Type visitClassType(ClassType t, Void aVoid) {
+ return super.visitClassType((ClassType)t.typeNoMetadata(), aVoid);
+ }
+
+ @Override
+ public Type visitArrayType(ArrayType t, Void aVoid) {
+ return super.visitArrayType((ArrayType)t.typeNoMetadata(), aVoid);
+ }
+
+ @Override
+ public Type visitTypeVar(TypeVar t, Void aVoid) {
+ return super.visitTypeVar((TypeVar)t.typeNoMetadata(), aVoid);
+ }
+
+ @Override
+ public Type visitWildcardType(WildcardType wt, Void aVoid) {
+ return super.visitWildcardType((WildcardType)wt.typeNoMetadata(), aVoid);
+ }
+ };
+
public Type annotatedType(final List<Attribute.TypeCompound> annos) {
- final TypeMetadata.Element annoMetadata = new TypeMetadata.Annotations(annos);
- return combineMetadata(annoMetadata);
+ final Entry annoMetadata = new TypeMetadata.Annotations(annos);
+ return cloneWithMetadata(metadata.combine(annoMetadata));
}
public boolean isAnnotated() {
final TypeMetadata.Annotations metadata =
- (TypeMetadata.Annotations)getMetadataOfKind(TypeMetadata.Element.Kind.ANNOTATIONS);
+ (TypeMetadata.Annotations)getMetadataOfKind(Entry.Kind.ANNOTATIONS);
return null != metadata && !metadata.getAnnotations().isEmpty();
}
- private static final List<Attribute.TypeCompound> noAnnotations = List.nil();
-
@Override @DefinedBy(Api.LANGUAGE_MODEL)
public List<Attribute.TypeCompound> getAnnotationMirrors() {
final TypeMetadata.Annotations metadata =
- (TypeMetadata.Annotations)getMetadataOfKind(TypeMetadata.Element.Kind.ANNOTATIONS);
+ (TypeMetadata.Annotations)getMetadataOfKind(Entry.Kind.ANNOTATIONS);
- return metadata == null ? noAnnotations : metadata.getAnnotations();
+ return metadata == null ? List.nil() : metadata.getAnnotations();
}
@@ -431,13 +490,15 @@
}
/**
- * This method is analogous to isSameType, but weaker, since we
- * never complete classes. Where isSameType would complete a
- * class, equals assumes that the two types are different.
+ * Override this method with care. For most Type instances this should behave as ==.
*/
@Override @DefinedBy(Api.LANGUAGE_MODEL)
public boolean equals(Object t) {
- return super.equals(t);
+ return this == t;
+ }
+
+ public boolean equalsIgnoreMetadata(Type t) {
+ return typeNoMetadata().equals(t.typeNoMetadata());
}
@Override @DefinedBy(Api.LANGUAGE_MODEL)
@@ -547,7 +608,7 @@
* Does this type contain occurrences of type t?
*/
public boolean contains(Type t) {
- return t == this;
+ return t.equalsIgnoreMetadata(this);
}
public static boolean contains(List<Type> ts, Type t) {
@@ -615,19 +676,21 @@
TypeTag tag;
public JCPrimitiveType(TypeTag tag, TypeSymbol tsym) {
- this(tag, tsym, TypeMetadata.empty);
+ this(tag, tsym, TypeMetadata.EMPTY);
}
- private JCPrimitiveType(TypeTag tag, TypeSymbol tsym,
- TypeMetadata metadata) {
+ private JCPrimitiveType(TypeTag tag, TypeSymbol tsym, TypeMetadata metadata) {
super(tsym, metadata);
this.tag = tag;
Assert.check(tag.isPrimitive);
}
@Override
- public JCPrimitiveType clone(TypeMetadata md) {
- return new JCPrimitiveType(tag, tsym, md);
+ public JCPrimitiveType cloneWithMetadata(TypeMetadata md) {
+ return new JCPrimitiveType(tag, tsym, md) {
+ @Override
+ public Type baseType() { return JCPrimitiveType.this.baseType(); }
+ };
}
@Override
@@ -740,7 +803,7 @@
}
public WildcardType(Type type, BoundKind kind, TypeSymbol tsym) {
- this(type, kind, tsym, null, TypeMetadata.empty);
+ this(type, kind, tsym, null, TypeMetadata.EMPTY);
}
public WildcardType(Type type, BoundKind kind, TypeSymbol tsym,
@@ -750,7 +813,7 @@
public WildcardType(Type type, BoundKind kind, TypeSymbol tsym,
TypeVar bound) {
- this(type, kind, tsym, bound, TypeMetadata.empty);
+ this(type, kind, tsym, bound, TypeMetadata.EMPTY);
}
public WildcardType(Type type, BoundKind kind, TypeSymbol tsym,
@@ -762,8 +825,11 @@
}
@Override
- public WildcardType clone(TypeMetadata md) {
- return new WildcardType(type, kind, tsym, bound, md);
+ public WildcardType cloneWithMetadata(TypeMetadata md) {
+ return new WildcardType(type, kind, tsym, bound, md) {
+ @Override
+ public Type baseType() { return WildcardType.this.baseType(); }
+ };
}
@Override
@@ -883,7 +949,7 @@
public List<Type> all_interfaces_field;
public ClassType(Type outer, List<Type> typarams, TypeSymbol tsym) {
- this(outer, typarams, tsym, TypeMetadata.empty);
+ this(outer, typarams, tsym, TypeMetadata.EMPTY);
}
public ClassType(Type outer, List<Type> typarams, TypeSymbol tsym,
@@ -897,13 +963,11 @@
}
@Override
- public ClassType clone(TypeMetadata md) {
- final ClassType out =
- new ClassType(outer_field, typarams_field, tsym, md);
- out.allparams_field = allparams_field;
- out.supertype_field = supertype_field;
- out.interfaces_field = interfaces_field;
- return out;
+ public ClassType cloneWithMetadata(TypeMetadata md) {
+ return new ClassType(outer_field, typarams_field, tsym, md) {
+ @Override
+ public Type baseType() { return ClassType.this.baseType(); }
+ };
}
@Override
@@ -935,14 +999,16 @@
@DefinedBy(Api.LANGUAGE_MODEL)
public String toString() {
StringBuilder buf = new StringBuilder();
- appendAnnotationsString(buf);
if (getEnclosingType().hasTag(CLASS) && tsym.owner.kind == TYP) {
buf.append(getEnclosingType().toString());
buf.append(".");
+ appendAnnotationsString(buf);
buf.append(className(tsym, false));
} else {
+ appendAnnotationsString(buf);
buf.append(className(tsym, true));
}
+
if (getTypeArguments().nonEmpty()) {
buf.append('<');
buf.append(getTypeArguments().toString());
@@ -1050,7 +1116,7 @@
public boolean contains(Type elem) {
return
- elem == this
+ elem.equalsIgnoreMetadata(this)
|| (isParameterized()
&& (getEnclosingType().contains(elem) || contains(getTypeArguments(), elem)))
|| (isCompound()
@@ -1073,10 +1139,6 @@
}
public static class ErasedClassType extends ClassType {
- public ErasedClassType(Type outer, TypeSymbol tsym) {
- super(outer, List.<Type>nil(), tsym);
- }
-
public ErasedClassType(Type outer, TypeSymbol tsym,
TypeMetadata metadata) {
super(outer, List.<Type>nil(), tsym, metadata);
@@ -1104,7 +1166,7 @@
}
@Override
- public UnionClassType clone(TypeMetadata md) {
+ public UnionClassType cloneWithMetadata(TypeMetadata md) {
throw new AssertionError("Cannot add metadata to a union type");
}
@@ -1155,7 +1217,7 @@
}
@Override
- public IntersectionClassType clone(TypeMetadata md) {
+ public IntersectionClassType cloneWithMetadata(TypeMetadata md) {
throw new AssertionError("Cannot add metadata to an intersection type");
}
@@ -1196,7 +1258,7 @@
public Type elemtype;
public ArrayType(Type elemtype, TypeSymbol arrayClass) {
- this(elemtype, arrayClass, TypeMetadata.empty);
+ this(elemtype, arrayClass, TypeMetadata.EMPTY);
}
public ArrayType(Type elemtype, TypeSymbol arrayClass,
@@ -1205,9 +1267,18 @@
this.elemtype = elemtype;
}
+ public ArrayType(ArrayType that) {
+ //note: type metadata is deliberately shared here, as we want side-effects from annotation
+ //processing to flow from original array to the cloned array.
+ this(that.elemtype, that.tsym, that.getMetadata());
+ }
+
@Override
- public ArrayType clone(TypeMetadata md) {
- return new ArrayType(elemtype, tsym, md);
+ public ArrayType cloneWithMetadata(TypeMetadata md) {
+ return new ArrayType(elemtype, tsym, md) {
+ @Override
+ public Type baseType() { return ArrayType.this.baseType(); }
+ };
}
@Override
@@ -1228,12 +1299,15 @@
return sb.toString();
}
- @DefinedBy(Api.LANGUAGE_MODEL)
+ @Override @DefinedBy(Api.LANGUAGE_MODEL)
public boolean equals(Object obj) {
- return
- this == obj ||
- (obj instanceof ArrayType &&
- this.elemtype.equals(((ArrayType)obj).elemtype));
+ if (obj instanceof ArrayType) {
+ ArrayType that = (ArrayType)obj;
+ return this == that ||
+ elemtype.equals(that.elemtype);
+ }
+
+ return false;
}
@DefinedBy(Api.LANGUAGE_MODEL)
@@ -1279,7 +1353,7 @@
}
public boolean contains(Type elem) {
- return elem == this || elemtype.contains(elem);
+ return elem.equalsIgnoreMetadata(this) || elemtype.contains(elem);
}
public void complete() {
@@ -1318,14 +1392,14 @@
TypeSymbol methodClass) {
// Presently no way to refer to a method type directly, so
// we cannot put type annotations on it.
- super(methodClass, TypeMetadata.empty);
+ super(methodClass, TypeMetadata.EMPTY);
this.argtypes = argtypes;
this.restype = restype;
this.thrown = thrown;
}
@Override
- public MethodType clone(TypeMetadata md) {
+ public MethodType cloneWithMetadata(TypeMetadata md) {
throw new AssertionError("Cannot add metadata to a method type");
}
@@ -1370,7 +1444,7 @@
}
public boolean contains(Type elem) {
- return elem == this || contains(argtypes, elem) || restype.contains(elem) || contains(thrown, elem);
+ return elem.equalsIgnoreMetadata(this) || contains(argtypes, elem) || restype.contains(elem) || contains(thrown, elem);
}
public MethodType asMethodType() { return this; }
@@ -1408,11 +1482,11 @@
PackageType(TypeSymbol tsym) {
// Package types cannot be annotated
- super(tsym, TypeMetadata.empty);
+ super(tsym, TypeMetadata.EMPTY);
}
@Override
- public PackageType clone(TypeMetadata md) {
+ public PackageType cloneWithMetadata(TypeMetadata md) {
throw new AssertionError("Cannot add metadata to a package type");
}
@@ -1464,14 +1538,14 @@
public Type lower;
public TypeVar(Name name, Symbol owner, Type lower) {
- super(null, TypeMetadata.empty);
+ super(null, TypeMetadata.EMPTY);
tsym = new TypeVariableSymbol(0, name, this, owner);
- this.bound = bound;
+ this.bound = null;
this.lower = lower;
}
public TypeVar(TypeSymbol tsym, Type bound, Type lower) {
- this(tsym, bound, lower, TypeMetadata.empty);
+ this(tsym, bound, lower, TypeMetadata.EMPTY);
}
public TypeVar(TypeSymbol tsym, Type bound, Type lower,
@@ -1482,8 +1556,11 @@
}
@Override
- public TypeVar clone(TypeMetadata md) {
- return new TypeVar(tsym, bound, lower, md);
+ public TypeVar cloneWithMetadata(TypeMetadata md) {
+ return new TypeVar(tsym, bound, lower, md) {
+ @Override
+ public Type baseType() { return TypeVar.this.baseType(); }
+ };
}
@Override
@@ -1566,8 +1643,11 @@
}
@Override
- public CapturedType clone(TypeMetadata md) {
- return new CapturedType(tsym, bound, bound, lower, wildcard, md);
+ public CapturedType cloneWithMetadata(TypeMetadata md) {
+ return new CapturedType(tsym, bound, bound, lower, wildcard, md) {
+ @Override
+ public Type baseType() { return CapturedType.this.baseType(); }
+ };
}
@Override
@@ -1597,7 +1677,7 @@
public TypeTag tag;
public DelegatedType(TypeTag tag, Type qtype) {
- this(tag, qtype, TypeMetadata.empty);
+ this(tag, qtype, TypeMetadata.EMPTY);
}
public DelegatedType(TypeTag tag, Type qtype,
@@ -1635,7 +1715,7 @@
}
@Override
- public ForAll clone(TypeMetadata md) {
+ public ForAll cloneWithMetadata(TypeMetadata md) {
throw new AssertionError("Cannot add metadata to a forall type");
}
@@ -1785,7 +1865,7 @@
}
@Override
- public UndetVar clone(TypeMetadata md) {
+ public UndetVar cloneWithMetadata(TypeMetadata md) {
throw new AssertionError("Cannot add metadata to an UndetVar type");
}
@@ -1940,11 +2020,11 @@
// Need to use List.nil(), because JCNoType constructor
// gets called in static initializers in Type, where
// noAnnotations is also defined.
- super(null, TypeMetadata.empty);
+ super(null, TypeMetadata.EMPTY);
}
@Override
- public JCNoType clone(TypeMetadata md) {
+ public JCNoType cloneWithMetadata(TypeMetadata md) {
throw new AssertionError("Cannot add metadata to a JCNoType");
}
@@ -1973,11 +2053,11 @@
public JCVoidType() {
// Void cannot be annotated
- super(null, TypeMetadata.empty);
+ super(null, TypeMetadata.EMPTY);
}
@Override
- public JCVoidType clone(TypeMetadata md) {
+ public JCVoidType cloneWithMetadata(TypeMetadata md) {
throw new AssertionError("Cannot add metadata to a void type");
}
@@ -2008,11 +2088,11 @@
static class BottomType extends Type implements NullType {
public BottomType() {
// Bottom is a synthesized internal type, so it cannot be annotated
- super(null, TypeMetadata.empty);
+ super(null, TypeMetadata.EMPTY);
}
@Override
- public BottomType clone(TypeMetadata md) {
+ public BottomType cloneWithMetadata(TypeMetadata md) {
throw new AssertionError("Cannot add metadata to a bottom type");
}
@@ -2077,8 +2157,11 @@
}
@Override
- public ErrorType clone(TypeMetadata md) {
- return new ErrorType(originalType, tsym, md);
+ public ErrorType cloneWithMetadata(TypeMetadata md) {
+ return new ErrorType(originalType, tsym, md) {
+ @Override
+ public Type baseType() { return ErrorType.this.baseType(); }
+ };
}
@Override
@@ -2145,11 +2228,11 @@
public UnknownType() {
// Unknown is a synthesized internal type, so it cannot be
// annotated.
- super(null, TypeMetadata.empty);
+ super(null, TypeMetadata.EMPTY);
}
@Override
- public UnknownType clone(TypeMetadata md) {
+ public UnknownType cloneWithMetadata(TypeMetadata md) {
throw new AssertionError("Cannot add metadata to an unknown type");
}
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotationPosition.java Thu Apr 09 06:40:21 2015 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotationPosition.java Thu Apr 09 17:37:46 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -118,14 +118,10 @@
public static final List<TypePathEntry> emptyPath = List.nil();
- // NOTE: All of these will be converted to final fields eventually.
-
public final TargetType type;
// For generic/array types.
- // This field is in the process of being made final. Do not
- // introduce new mutations.
public List<TypePathEntry> location;
// Tree position.
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotations.java Thu Apr 09 06:40:21 2015 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotations.java Thu Apr 09 17:37:46 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -31,6 +31,7 @@
import javax.tools.JavaFileObject;
+import com.sun.tools.javac.code.Attribute.Array;
import com.sun.tools.javac.code.Attribute.TypeCompound;
import com.sun.tools.javac.code.Type.ArrayType;
import com.sun.tools.javac.code.Type.CapturedType;
@@ -47,8 +48,8 @@
import com.sun.tools.javac.code.TypeAnnotationPosition.TypePathEntryKind;
import com.sun.tools.javac.code.Symbol.VarSymbol;
import com.sun.tools.javac.code.Symbol.MethodSymbol;
+import com.sun.tools.javac.code.TypeMetadata.Entry.Kind;
import com.sun.tools.javac.comp.Annotate;
-import com.sun.tools.javac.comp.Annotate.Worker;
import com.sun.tools.javac.comp.Attr;
import com.sun.tools.javac.comp.AttrContext;
import com.sun.tools.javac.comp.Env;
@@ -71,7 +72,6 @@
import com.sun.tools.javac.util.ListBuffer;
import com.sun.tools.javac.util.Log;
import com.sun.tools.javac.util.Names;
-import com.sun.tools.javac.util.Options;
import static com.sun.tools.javac.code.Kinds.Kind.*;
@@ -105,7 +105,6 @@
syms = Symtab.instance(context);
annotate = Annotate.instance(context);
attr = Attr.instance(context);
- Options options = Options.instance(context);
}
/**
@@ -113,12 +112,9 @@
* determine the correct positions for type annotations.
* This version only visits types in signatures and should be
* called from MemberEnter.
- * The method takes the Annotate object as parameter and
- * adds an Annotate.Worker to the correct Annotate queue for
- * later processing.
*/
public void organizeTypeAnnotationsSignatures(final Env<AttrContext> env, final JCClassDecl tree) {
- annotate.afterRepeated( new Worker() {
+ annotate.afterTypes(new Runnable() {
@Override
public void run() {
JavaFileObject oldSource = log.useSource(env.toplevel.sourcefile);
@@ -129,11 +125,11 @@
log.useSource(oldSource);
}
}
- } );
+ });
}
public void validateTypeAnnotationsSignatures(final Env<AttrContext> env, final JCClassDecl tree) {
- annotate.validate(new Worker() { //validate annotations
+ annotate.validate(new Runnable() { //validate annotations
@Override
public void run() {
JavaFileObject oldSource = log.useSource(env.toplevel.sourcefile);
@@ -144,7 +140,7 @@
log.useSource(oldSource);
}
}
- } );
+ });
}
/**
@@ -155,101 +151,106 @@
new TypeAnnotationPositions(false).scan(tree);
}
- public enum AnnotationType { DECLARATION, TYPE, BOTH }
+ public enum AnnotationType { DECLARATION, TYPE, NONE, BOTH }
+
+ public List<Attribute> annotationTargets(Attribute.Compound anno) {
+ Attribute.Compound atTarget = anno.type.tsym.getAnnotationTypeMetadata().getTarget();
+ if (atTarget == null) {
+ return null;
+ }
+
+ Attribute atValue = atTarget.member(names.value);
+ if (!(atValue instanceof Attribute.Array)) {
+ return null;
+ }
+
+ List<Attribute> targets = ((Array)atValue).getValue();
+ if (targets.stream().anyMatch(a -> !(a instanceof Attribute.Enum))) {
+ return null;
+ }
+
+ return targets;
+ }
/**
* 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 == TYP)
- isDecl = true;
- } else if (e.value.name == names.FIELD) {
- if (s.kind == VAR &&
- s.owner.kind != MTH)
- isDecl = true;
- } else if (e.value.name == names.METHOD) {
- if (s.kind == MTH &&
- !s.isConstructor())
- isDecl = true;
- } else if (e.value.name == names.PARAMETER) {
- if (s.kind == VAR &&
- s.owner.kind == MTH &&
- (s.flags() & Flags.PARAMETER) != 0)
- isDecl = true;
- } else if (e.value.name == names.CONSTRUCTOR) {
- if (s.kind == MTH &&
- s.isConstructor())
- isDecl = true;
- } else if (e.value.name == names.LOCAL_VARIABLE) {
- if (s.kind == VAR &&
- s.owner.kind == MTH &&
- (s.flags() & Flags.PARAMETER) == 0)
- isDecl = true;
- } else if (e.value.name == names.ANNOTATION_TYPE) {
- if (s.kind == TYP &&
- (s.flags() & Flags.ANNOTATION) != 0)
- isDecl = true;
- } else if (e.value.name == names.PACKAGE) {
- if (s.kind == PCK)
- isDecl = true;
- } else if (e.value.name == names.TYPE_USE) {
- if (s.kind == TYP ||
- s.kind == VAR ||
- (s.kind == MTH && !s.isConstructor() &&
- !s.type.getReturnType().hasTag(TypeTag.VOID)) ||
- (s.kind == 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) {
+ public AnnotationType annotationTargetType(Attribute.Compound a, Symbol s) {
+ List<Attribute> targets = annotationTargets(a);
+ return (targets == null) ?
+ AnnotationType.DECLARATION :
+ targets.stream()
+ .map(attr -> targetToAnnotationType(attr, s))
+ .reduce(AnnotationType.NONE, this::combineAnnotationType);
+ }
+
+ private AnnotationType combineAnnotationType(AnnotationType at1, AnnotationType at2) {
+ if (at1 == AnnotationType.NONE) {
+ return at2;
+ } else if (at2 == AnnotationType.NONE) {
+ return at1;
+ } else if (at1 != at2) {
return AnnotationType.BOTH;
- } else if (isType) {
- return AnnotationType.TYPE;
} else {
- return AnnotationType.DECLARATION;
+ return at1;
}
}
- /** Infer the target annotation kind, if none is give.
- * We only infer declaration annotations.
- */
- private static AnnotationType inferTargetMetaInfo(Attribute.Compound a, Symbol s) {
- return AnnotationType.DECLARATION;
+ private AnnotationType targetToAnnotationType(Attribute a, Symbol s) {
+ Attribute.Enum e = (Attribute.Enum)a;
+ if (e.value.name == names.TYPE) {
+ if (s.kind == TYP)
+ return AnnotationType.DECLARATION;
+ } else if (e.value.name == names.FIELD) {
+ if (s.kind == VAR &&
+ s.owner.kind != MTH)
+ return AnnotationType.DECLARATION;
+ } else if (e.value.name == names.METHOD) {
+ if (s.kind == MTH &&
+ !s.isConstructor())
+ return AnnotationType.DECLARATION;
+ } else if (e.value.name == names.PARAMETER) {
+ if (s.kind == VAR &&
+ s.owner.kind == MTH &&
+ (s.flags() & Flags.PARAMETER) != 0)
+ return AnnotationType.DECLARATION;
+ } else if (e.value.name == names.CONSTRUCTOR) {
+ if (s.kind == MTH &&
+ s.isConstructor())
+ return AnnotationType.DECLARATION;
+ } else if (e.value.name == names.LOCAL_VARIABLE) {
+ if (s.kind == VAR &&
+ s.owner.kind == MTH &&
+ (s.flags() & Flags.PARAMETER) == 0)
+ return AnnotationType.DECLARATION;
+ } else if (e.value.name == names.ANNOTATION_TYPE) {
+ if (s.kind == TYP &&
+ (s.flags() & Flags.ANNOTATION) != 0)
+ return AnnotationType.DECLARATION;
+ } else if (e.value.name == names.PACKAGE) {
+ if (s.kind == PCK)
+ return AnnotationType.DECLARATION;
+ } else if (e.value.name == names.TYPE_USE) {
+ if (s.kind == TYP ||
+ s.kind == VAR ||
+ (s.kind == MTH && !s.isConstructor() &&
+ !s.type.getReturnType().hasTag(TypeTag.VOID)) ||
+ (s.kind == MTH && s.isConstructor()))
+ return AnnotationType.TYPE;
+ } 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("annotationTargetType(): unrecognized Attribute name " + e.value.name +
+ " (" + e.value.name.getClass() + ")");
+ return AnnotationType.DECLARATION;
+ }
+ return AnnotationType.NONE;
}
-
private class TypeAnnotationPositions extends TreeScanner {
private final boolean sigOnly;
@@ -262,18 +263,29 @@
* When traversing the AST we keep the "frames" of visited
* trees in order to determine the position of annotations.
*/
- private ListBuffer<JCTree> frames = new ListBuffer<>();
+ private List<JCTree> frames = List.nil();
- protected void push(JCTree t) { frames = frames.prepend(t); }
- protected JCTree pop() { return frames.next(); }
+ protected void push(JCTree t) {
+ frames = frames.prepend(t);
+ }
+ protected JCTree pop() {
+ JCTree t = frames.head;
+ frames = frames.tail;
+ return t;
+ }
// could this be frames.elems.tail.head?
- private JCTree peek2() { return frames.toList().tail.head; }
+ private JCTree peek2() {
+ return frames.tail.head;
+ }
@Override
public void scan(JCTree tree) {
push(tree);
- super.scan(tree);
- pop();
+ try {
+ super.scan(tree);
+ } finally {
+ pop();
+ }
}
/**
@@ -283,41 +295,44 @@
* we never build an JCAnnotatedType. This step finds these
* annotations and marks them as if they were part of the type.
*/
- private void separateAnnotationsKinds(JCTree typetree, Type type, Symbol sym,
- TypeAnnotationPosition pos) {
- List<Attribute.Compound> annotations = sym.getRawAttributes();
+ private void separateAnnotationsKinds(JCTree typetree, Type type,
+ Symbol sym, TypeAnnotationPosition pos)
+ {
+ List<Attribute.Compound> allAnnotations = sym.getRawAttributes();
ListBuffer<Attribute.Compound> declAnnos = new ListBuffer<>();
ListBuffer<Attribute.TypeCompound> typeAnnos = new ListBuffer<>();
ListBuffer<Attribute.TypeCompound> onlyTypeAnnos = new ListBuffer<>();
- for (Attribute.Compound a : annotations) {
- switch (annotationType(a, sym)) {
- case DECLARATION:
- declAnnos.append(a);
- break;
- case BOTH: {
- declAnnos.append(a);
- Attribute.TypeCompound ta = toTypeCompound(a, pos);
- typeAnnos.append(ta);
- break;
- }
- case TYPE: {
- Attribute.TypeCompound ta = toTypeCompound(a, pos);
- typeAnnos.append(ta);
- // Also keep track which annotations are only type annotations
- onlyTypeAnnos.append(ta);
- break;
- }
+ for (Attribute.Compound a : allAnnotations) {
+ switch (annotationTargetType(a, sym)) {
+ case DECLARATION:
+ declAnnos.append(a);
+ break;
+ case BOTH: {
+ declAnnos.append(a);
+ Attribute.TypeCompound ta = toTypeCompound(a, pos);
+ typeAnnos.append(ta);
+ break;
+ }
+ case TYPE: {
+ Attribute.TypeCompound ta = toTypeCompound(a, pos);
+ typeAnnos.append(ta);
+ // Also keep track which annotations are only type annotations
+ onlyTypeAnnos.append(ta);
+ break;
+ }
}
}
- sym.resetAnnotations();
- sym.setDeclarationAttributes(declAnnos.toList());
-
+ // If we have no type annotations we are done for this Symbol
if (typeAnnos.isEmpty()) {
return;
}
+ // Reset decl annotations to the set {all - type only}
+ sym.resetAnnotations();
+ sym.setDeclarationAttributes(declAnnos.toList());
+
List<Attribute.TypeCompound> typeAnnotations = typeAnnos.toList();
if (type == null) {
@@ -328,7 +343,7 @@
// Declaration annotations are always allowed on constructor returns.
// Therefore, use typeAnnotations instead of onlyTypeAnnos.
- type = typeWithAnnotations(typetree, type, typeAnnotations, typeAnnotations);
+ typeWithAnnotations(typetree, type, typeAnnotations, typeAnnotations, pos);
// Note that we don't use the result, the call to
// typeWithAnnotations side-effects the type annotation positions.
// This is important for constructors of nested classes.
@@ -336,8 +351,8 @@
return;
}
- // type is non-null and annotations are added to that type
- type = typeWithAnnotations(typetree, type, typeAnnotations, onlyTypeAnnos.toList());
+ // type is non-null, add type annotations from declaration context to the type
+ type = typeWithAnnotations(typetree, type, typeAnnotations, onlyTypeAnnos.toList(), pos);
if (sym.getKind() == ElementKind.METHOD) {
sym.type.asMethodType().restype = type;
@@ -390,59 +405,23 @@
// Note that it is assumed that all annotations share the same position.
private Type typeWithAnnotations(final JCTree typetree, final Type type,
final List<Attribute.TypeCompound> annotations,
- final List<Attribute.TypeCompound> onlyTypeAnnotations) {
- //System.err.printf("typeWithAnnotations(typetree: %s, type: %s, annotations: %s, onlyTypeAnnotations: %s)%n",
- // typetree, type, annotations, onlyTypeAnnotations);
+ final List<Attribute.TypeCompound> onlyTypeAnnotations,
+ final TypeAnnotationPosition pos)
+ {
if (annotations.isEmpty()) {
return type;
}
- if (type.hasTag(TypeTag.ARRAY)) {
- Type.ArrayType arType = (Type.ArrayType) type;
- Type.ArrayType tomodify = new Type.ArrayType(null, arType.tsym);
- Type toreturn;
- if (type.isAnnotated()) {
- toreturn = tomodify.annotatedType(type.getAnnotationMirrors());
- } else {
- toreturn = tomodify;
- }
-
- JCArrayTypeTree arTree = arrayTypeTree(typetree);
- ListBuffer<TypePathEntry> depth = new ListBuffer<>();
- depth = depth.append(TypePathEntry.ARRAY);
- while (arType.elemtype.hasTag(TypeTag.ARRAY)) {
- if (arType.elemtype.isAnnotated()) {
- Type aelemtype = arType.elemtype;
- arType = (Type.ArrayType) aelemtype;
- ArrayType prevToMod = tomodify;
- tomodify = new Type.ArrayType(null, arType.tsym);
- prevToMod.elemtype = tomodify.annotatedType(arType.elemtype.getAnnotationMirrors());
- } else {
- arType = (Type.ArrayType) arType.elemtype;
- tomodify.elemtype = new Type.ArrayType(null, arType.tsym);
- tomodify = (Type.ArrayType) tomodify.elemtype;
- }
- arTree = arrayTypeTree(arTree.elemtype);
- depth = depth.append(TypePathEntry.ARRAY);
- }
- Type arelemType = typeWithAnnotations(arTree.elemtype, arType.elemtype, annotations, onlyTypeAnnotations);
- tomodify.elemtype = arelemType;
- {
- // All annotations share the same position; modify the first one.
- Attribute.TypeCompound a = annotations.get(0);
- TypeAnnotationPosition p = a.position;
- p.location = p.location.prependList(depth.toList());
- }
- typetree.type = toreturn;
- return toreturn;
- } else if (type.hasTag(TypeTag.TYPEVAR)) {
- // Nothing to do for type variables.
- return type;
+ if (type.hasTag(TypeTag.ARRAY))
+ return rewriteArrayType((ArrayType)type, annotations, pos);
+
+ if (type.hasTag(TypeTag.TYPEVAR)) {
+ return type.annotatedType(onlyTypeAnnotations);
} else if (type.getKind() == TypeKind.UNION) {
// There is a TypeKind, but no TypeTag.
- JCTypeUnion tutree = (JCTypeUnion) typetree;
+ JCTypeUnion tutree = (JCTypeUnion)typetree;
JCExpression fst = tutree.alternatives.get(0);
- Type res = typeWithAnnotations(fst, fst.type, annotations, onlyTypeAnnotations);
+ Type res = typeWithAnnotations(fst, fst.type, annotations, onlyTypeAnnotations, pos);
fst.type = res;
// TODO: do we want to set res as first element in uct.alternatives?
// UnionClassType uct = (com.sun.tools.javac.code.Type.UnionClassType)type;
@@ -459,8 +438,8 @@
enclTy.getKind() != TypeKind.NONE &&
enclTy.getKind() != TypeKind.ERROR &&
(enclTr.getKind() == JCTree.Kind.MEMBER_SELECT ||
- enclTr.getKind() == JCTree.Kind.PARAMETERIZED_TYPE ||
- enclTr.getKind() == JCTree.Kind.ANNOTATED_TYPE)) {
+ enclTr.getKind() == JCTree.Kind.PARAMETERIZED_TYPE ||
+ enclTr.getKind() == JCTree.Kind.ANNOTATED_TYPE)) {
// Iterate also over the type tree, not just the type: the type is already
// completely resolved and we cannot distinguish where the annotation
// belongs for a nested type.
@@ -483,20 +462,20 @@
if (enclTy != null &&
enclTy.hasTag(TypeTag.NONE)) {
switch (onlyTypeAnnotations.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:
- log.error(typetree.pos(), "cant.type.annotate.scoping.1",
- onlyTypeAnnotations);
- break;
- default:
- log.error(typetree.pos(), "cant.type.annotate.scoping",
- onlyTypeAnnotations);
+ 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:
+ log.error(typetree.pos(), "cant.type.annotate.scoping.1",
+ onlyTypeAnnotations);
+ break;
+ default:
+ log.error(typetree.pos(), "cant.type.annotate.scoping",
+ onlyTypeAnnotations);
}
return type;
}
@@ -539,15 +518,62 @@
}
}
- private JCArrayTypeTree arrayTypeTree(JCTree typetree) {
- if (typetree.getKind() == JCTree.Kind.ARRAY_TYPE) {
- return (JCArrayTypeTree) typetree;
- } else if (typetree.getKind() == JCTree.Kind.ANNOTATED_TYPE) {
- return (JCArrayTypeTree) ((JCAnnotatedType)typetree).underlyingType;
+ /**
+ * Create a copy of the {@code Type type} with the help of the Tree for a type
+ * {@code JCTree typetree} inserting all type annotations in {@code annotations} to the
+ * innermost array component type.
+ *
+ * SIDE EFFECT: Update position for the annotations to be {@code pos}.
+ */
+ private Type rewriteArrayType(ArrayType type, List<TypeCompound> annotations, TypeAnnotationPosition pos) {
+ ArrayType tomodify = new ArrayType(type);
+ ArrayType res = tomodify;
+
+ List<TypePathEntry> loc = List.nil();
+
+ // peel one and update loc
+ Type tmpType = type.elemtype;
+ loc = loc.prepend(TypePathEntry.ARRAY);
+
+ while (tmpType.hasTag(TypeTag.ARRAY)) {
+ ArrayType arr = (ArrayType)tmpType;
+
+ // Update last type with new element type
+ ArrayType tmp = new ArrayType(arr);
+ tomodify.elemtype = tmp;
+ tomodify = tmp;
+
+ tmpType = arr.elemtype;
+ loc = loc.prepend(TypePathEntry.ARRAY);
+ }
+
+ // Fix innermost element type
+ Type elemType;
+ if (tmpType.getMetadata() != null) {
+ List<TypeCompound> tcs;
+ if (tmpType.getAnnotationMirrors().isEmpty()) {
+ tcs = annotations;
+ } else {
+ // Special case, lets prepend
+ tcs = annotations.appendList(tmpType.getAnnotationMirrors());
+ }
+ elemType = tmpType.cloneWithMetadata(tmpType
+ .getMetadata()
+ .without(Kind.ANNOTATIONS)
+ .combine(new TypeMetadata.Annotations(tcs)));
} else {
- Assert.error("Could not determine array type from type tree: " + typetree);
- return null;
+ elemType = tmpType.cloneWithMetadata(new TypeMetadata(new TypeMetadata.Annotations(annotations)));
}
+ tomodify.elemtype = elemType;
+
+ // Update positions
+ for (TypeCompound tc : annotations) {
+ if (tc.position == null)
+ tc.position = pos;
+ tc.position.location = loc;
+ }
+
+ return res;
}
/** Return a copy of the first type that only differs by
@@ -569,7 +595,6 @@
private Type typeWithAnnotations(final Type type,
final Type stopAt,
final List<Attribute.TypeCompound> annotations) {
- //System.err.println("typeWithAnnotations " + type + " " + annotations + " stopAt " + stopAt);
Visitor<Type, List<TypeCompound>> visitor =
new Type.Visitor<Type, List<Attribute.TypeCompound>>() {
@Override
@@ -660,20 +685,14 @@
/* This is the beginning of the second part of organizing
* type annotations: determine the type annotation positions.
*/
-
- // This method is considered deprecated, and will be removed
- // in the near future. Don't use it for anything new.
private TypeAnnotationPosition
resolveFrame(JCTree tree,
JCTree frame,
List<JCTree> path,
JCLambda currentLambda,
int outer_type_index,
- ListBuffer<TypePathEntry> location) {
- /*
- System.out.println("Resolving tree: " + tree + " kind: " + tree.getKind());
- System.out.println(" Framing tree: " + frame + " kind: " + frame.getKind());
- */
+ ListBuffer<TypePathEntry> location)
+ {
// Note that p.offset is set in
// com.sun.tools.javac.jvm.Gen.setTypeAnnotationPositions(int)
@@ -695,20 +714,17 @@
if (frameNewClass.def != null) {
// Special handling for anonymous class instantiations
final JCClassDecl frameClassDecl = frameNewClass.def;
- if (frameClassDecl.extending == tree) {
- return TypeAnnotationPosition
- .classExtends(location.toList(), currentLambda,
- frame.pos);
- } else if (frameClassDecl.implementing.contains(tree)) {
+ if (frameClassDecl.implementing.contains(tree)) {
final int type_index =
frameClassDecl.implementing.indexOf(tree);
return TypeAnnotationPosition
.classExtends(location.toList(), currentLambda,
type_index, frame.pos);
} else {
- // In contrast to CLASS below, typarams cannot occur here.
- throw new AssertionError("Could not determine position of tree " + tree +
- " within frame " + frame);
+ //for encl.new @TA Clazz(), tree may be different from frameClassDecl.extending
+ return TypeAnnotationPosition
+ .classExtends(location.toList(), currentLambda,
+ frame.pos);
}
} else if (frameNewClass.typeargs.contains(tree)) {
final int type_index =
@@ -1120,29 +1136,31 @@
// Nothing to do for separateAnnotationsKinds if
// there are no annotations of either kind.
// TODO: make sure there are no declaration annotations.
- final TypeAnnotationPosition pos =
- TypeAnnotationPosition.methodReceiver(tree.recvparam.vartype.pos);
- separateAnnotationsKinds(tree.recvparam.vartype,
- tree.recvparam.sym.type,
- tree.recvparam.sym, pos);
+ final TypeAnnotationPosition pos = TypeAnnotationPosition.methodReceiver(tree.recvparam.vartype.pos);
+ push(tree.recvparam);
+ try {
+ separateAnnotationsKinds(tree.recvparam.vartype, tree.recvparam.sym.type, tree.recvparam.sym, pos);
+ } finally {
+ pop();
+ }
}
int i = 0;
for (JCVariableDecl param : tree.params) {
if (!param.mods.annotations.isEmpty()) {
// Nothing to do for separateAnnotationsKinds if
// there are no annotations of either kind.
- final TypeAnnotationPosition pos =
- TypeAnnotationPosition.methodParameter(i, param.vartype.pos);
- separateAnnotationsKinds(param.vartype,
- param.sym.type,
- param.sym, pos);
+ final TypeAnnotationPosition pos = TypeAnnotationPosition.methodParameter(i, param.vartype.pos);
+ push(param);
+ try {
+ separateAnnotationsKinds(param.vartype, param.sym.type, param.sym, pos);
+ } finally {
+ pop();
+ }
}
++i;
}
}
- push(tree);
- // super.visitMethodDef(tree);
if (sigOnly) {
scan(tree.mods);
scan(tree.restype);
@@ -1154,7 +1172,6 @@
scan(tree.defaultValue);
scan(tree.body);
}
- pop();
}
/* Store a reference to the current lambda expression, to
@@ -1172,18 +1189,20 @@
if (!param.mods.annotations.isEmpty()) {
// Nothing to do for separateAnnotationsKinds if
// there are no annotations of either kind.
- final TypeAnnotationPosition pos =
- TypeAnnotationPosition.methodParameter(tree, i,
- param.vartype.pos);
- separateAnnotationsKinds(param.vartype, param.sym.type, param.sym, pos);
+ final TypeAnnotationPosition pos = TypeAnnotationPosition
+ .methodParameter(tree, i, param.vartype.pos);
+ push(param);
+ try {
+ separateAnnotationsKinds(param.vartype, param.sym.type, param.sym, pos);
+ } finally {
+ pop();
+ }
}
++i;
}
- push(tree);
scan(tree.body);
scan(tree.params);
- pop();
} finally {
currentLambda = prevLambda;
}
@@ -1227,17 +1246,14 @@
// No type annotations can occur here.
} else {
// There is nothing else in a variable declaration that needs separation.
- Assert.error("Unhandled variable kind: " + tree + " of kind: " + tree.sym.getKind());
+ Assert.error("Unhandled variable kind");
}
- push(tree);
- // super.visitVarDef(tree);
scan(tree.mods);
scan(tree.vartype);
if (!sigOnly) {
scan(tree.init);
}
- pop();
}
@Override
@@ -1363,31 +1379,37 @@
scan(tree.elems);
}
- private void findPosition(JCTree tree, JCTree frame, List<JCAnnotation> annotations) {
+
+ private void findTypeCompoundPosition(JCTree tree, JCTree frame, List<Attribute.TypeCompound> annotations) {
if (!annotations.isEmpty()) {
- /*
- System.err.println("Finding pos for: " + annotations);
- System.err.println(" tree: " + tree + " kind: " + tree.getKind());
- System.err.println(" frame: " + frame + " kind: " + frame.getKind());
- */
final TypeAnnotationPosition p =
- resolveFrame(tree, frame, frames.toList(), currentLambda, 0,
- new ListBuffer<TypePathEntry>());
+ resolveFrame(tree, frame, frames, currentLambda, 0, new ListBuffer<>());
+ for (TypeCompound tc : annotations)
+ tc.position = p;
+ }
+ }
+
+ private void findPosition(JCTree tree, JCTree frame, List<JCAnnotation> annotations) {
+ if (!annotations.isEmpty())
+ {
+ final TypeAnnotationPosition p =
+ resolveFrame(tree, frame, frames, currentLambda, 0, new ListBuffer<>());
+
setTypeAnnotationPos(annotations, p);
}
}
- private void setTypeAnnotationPos(List<JCAnnotation> annotations,
- TypeAnnotationPosition position) {
+ private void setTypeAnnotationPos(List<JCAnnotation> annotations, TypeAnnotationPosition position)
+ {
+ // attribute might be null during DeferredAttr;
+ // we will be back later.
for (JCAnnotation anno : annotations) {
- // attribute might be null during DeferredAttr;
- // we will be back later.
- if (anno.attribute != null) {
+ if (anno.attribute != null)
((Attribute.TypeCompound) anno.attribute).position = position;
- }
}
}
+
@Override
public String toString() {
return super.toString() + ": sigOnly: " + sigOnly;
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeMetadata.java Thu Apr 09 06:40:21 2015 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeMetadata.java Thu Apr 09 17:37:46 2015 -0700
@@ -30,46 +30,63 @@
import com.sun.tools.javac.util.List;
import java.util.EnumMap;
import java.util.HashSet;
-import java.util.Map;
import java.util.Set;
/**
- * A super-interface for all type metadata elements. Metadata classes
- * can be created for any metadata on types with the following
- * properties:
+ * TypeMetadata is essentially an immutable {@code EnumMap<Entry.Kind, <? extends Entry>>}
*
- * <ul>
- * <li>They have a default value (preferably empty)</li>
- * <li>The field is usually the default value</li>
- * <li>Different values of the field are visible, and denote distinct
- * types</li>
- * </ul>
+ * A metadata class represented by a subtype of Entry can express a property on a Type instance.
+ * Thers should be at most one instance of an Entry per Entry.Kind on any given Type instance.
+ *
+ * Metadata classes of a specific kind are responsible for how they combine themselvs.
+ *
+ * @implNote {@code Entry:combine} need not be commutative.
*/
public class TypeMetadata {
+ public static final TypeMetadata EMPTY = new TypeMetadata();
- public static final TypeMetadata empty = new TypeMetadata();
- private final EnumMap<TypeMetadata.Element.Kind, TypeMetadata.Element> contents;
+ private final EnumMap<Entry.Kind, Entry> contents;
+ /**
+ * Create a new empty TypeMetadata map.
+ */
private TypeMetadata() {
- contents = new EnumMap<Element.Kind, Element>(Element.Kind.class);
+ contents = new EnumMap<>(Entry.Kind.class);
}
- public TypeMetadata(final Element elem) {
+ /**
+ * Create a new TypeMetadata map containing the Entry {@code elem}.
+ *
+ * @param elem the sole contents of this map
+ */
+ public TypeMetadata(Entry elem) {
this();
+ Assert.checkNonNull(elem);
contents.put(elem.kind(), elem);
}
- public TypeMetadata(final TypeMetadata other) {
+ /**
+ * Creates a copy of TypeMetadata {@code other} with a shallow copy the other's metadata contents.
+ *
+ * @param other the TypeMetadata to copy contents from.
+ */
+ public TypeMetadata(TypeMetadata other) {
+ Assert.checkNonNull(other);
contents = other.contents.clone();
}
- public TypeMetadata copy() {
- return new TypeMetadata(this);
- }
+ /**
+ * Return a copy of this TypeMetadata with the metadata entry for {@code elem.kind()} combined
+ * with {@code elem}.
+ *
+ * @param elem the new value
+ * @return a new TypeMetadata updated with {@code Entry elem}
+ */
+ public TypeMetadata combine(Entry elem) {
+ Assert.checkNonNull(elem);
- public TypeMetadata combine(final Element elem) {
- final TypeMetadata out = new TypeMetadata(this);
- final Element.Kind key = elem.kind();
+ TypeMetadata out = new TypeMetadata(this);
+ Entry.Kind key = elem.kind();
if (contents.containsKey(key)) {
out.add(key, this.contents.get(key).combine(elem));
} else {
@@ -78,17 +95,26 @@
return out;
}
- public TypeMetadata combine(final TypeMetadata other) {
- final TypeMetadata out = new TypeMetadata();
- final Set<Element.Kind> keys = new HashSet<>(this.contents.keySet());
+ /**
+ * Return a copy of this TypeMetadata with the metadata entry for all kinds from {@code other}
+ * combined with the same kind from this.
+ *
+ * @param other the TypeMetadata to combine with this
+ * @return a new TypeMetadata updated with all entries from {@code other}
+ */
+ public TypeMetadata combineAll(TypeMetadata other) {
+ Assert.checkNonNull(other);
+
+ TypeMetadata out = new TypeMetadata();
+ Set<Entry.Kind> keys = new HashSet<>(contents.keySet());
keys.addAll(other.contents.keySet());
- for(final Element.Kind key : keys) {
- if (this.contents.containsKey(key)) {
+ for(Entry.Kind key : keys) {
+ if (contents.containsKey(key)) {
if (other.contents.containsKey(key)) {
- out.add(key, this.contents.get(key).combine(other.contents.get(key)));
+ out.add(key, contents.get(key).combine(other.contents.get(key)));
} else {
- out.add(key, this.contents.get(key));
+ out.add(key, contents.get(key));
}
} else if (other.contents.containsKey(key)) {
out.add(key, other.contents.get(key));
@@ -97,26 +123,35 @@
return out;
}
- public Element get(final Element.Kind kind) {
+ /**
+ * Return a TypeMetadata with the metadata entry for {@code kind} removed.
+ *
+ * This may be the same instance or a new TypeMetadata.
+ *
+ * @param kind the {@code Kind} to remove metadata for
+ * @return a new TypeMetadata without {@code Kind kind}
+ */
+ public TypeMetadata without(Entry.Kind kind) {
+ if (this == EMPTY || contents.get(kind) == null)
+ return this;
+
+ TypeMetadata out = new TypeMetadata(this);
+ out.contents.remove(kind);
+ return out.contents.isEmpty() ? EMPTY : out;
+ }
+
+ public Entry get(Entry.Kind kind) {
return contents.get(kind);
}
- public boolean isEmpty() {
- return contents.isEmpty();
- }
-
- private void add(final Element.Kind kind, final Element elem) {
+ private void add(Entry.Kind kind, Entry elem) {
contents.put(kind, elem);
}
- private void addAll(final Map<? extends Element.Kind,? extends Element> m) {
- contents.putAll(m);
- }
-
- public interface Element {
+ public interface Entry {
public enum Kind {
- ANNOTATIONS;
+ ANNOTATIONS
}
/**
@@ -131,16 +166,18 @@
* @param other The metadata with which to combine this one.
* @return The combined metadata.
*/
- public Element combine(Element other);
+ public Entry combine(Entry other);
}
/**
* A type metadata object holding type annotations.
*/
- public static class Annotations implements Element {
- private final List<Attribute.TypeCompound> annos;
+ public static class Annotations implements Entry {
+ private List<Attribute.TypeCompound> annos;
- public Annotations(final List<Attribute.TypeCompound> annos) {
+ public static final List<Attribute.TypeCompound> TO_BE_SET = List.nil();
+
+ public Annotations(List<Attribute.TypeCompound> annos) {
this.annos = annos;
}
@@ -154,18 +191,16 @@
}
@Override
- public Annotations combine(final Element other) {
- // Temporary: we should append the lists, but that won't
- // work with type annotations today. Instead, we replace
- // the list.
- return new Annotations(((Annotations) other).annos);
+ public Annotations combine(Entry other) {
+ Assert.check(annos == TO_BE_SET);
+ annos = ((Annotations)other).annos;
+ return this;
}
@Override
public Kind kind() { return Kind.ANNOTATIONS; }
@Override
- public String toString() { return "ANNOTATIONS { " + annos + " }"; }
+ public String toString() { return "ANNOTATIONS [ " + annos + " ]"; }
}
-
}
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java Thu Apr 09 06:40:21 2015 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java Thu Apr 09 17:37:46 2015 -0700
@@ -40,6 +40,7 @@
import com.sun.tools.javac.code.Attribute.RetentionPolicy;
import com.sun.tools.javac.code.Lint.LintCategory;
import com.sun.tools.javac.code.Type.UndetVar.InferenceBound;
+import com.sun.tools.javac.code.TypeMetadata.Entry.Kind;
import com.sun.tools.javac.comp.AttrContext;
import com.sun.tools.javac.comp.Check;
import com.sun.tools.javac.comp.Enter;
@@ -809,7 +810,7 @@
return isSubtype(t, s, false);
}
public boolean isSubtype(Type t, Type s, boolean capture) {
- if (t == s)
+ if (t.equalsIgnoreMetadata(s))
return true;
if (s.isPartial())
return isSuperType(s, t);
@@ -1081,14 +1082,11 @@
isSameTypeStrict.visit(t, s) :
isSameTypeLoose.visit(t, s);
}
- public boolean isSameAnnotatedType(Type t, Type s) {
- return isSameAnnotatedType.visit(t, s);
- }
// where
abstract class SameTypeVisitor extends TypeRelation {
public Boolean visitType(Type t, Type s) {
- if (t == s)
+ if (t.equalsIgnoreMetadata(s))
return true;
if (s.isPartial())
@@ -1281,39 +1279,6 @@
// </editor-fold>
- TypeRelation isSameAnnotatedType = new LooseSameTypeVisitor() {
- private Boolean compareAnnotations(Type t1, Type t2) {
- List<Attribute.TypeCompound> annos1 = t1.getAnnotationMirrors();
- List<Attribute.TypeCompound> annos2 = t2.getAnnotationMirrors();
- return annos1.containsAll(annos2) && annos2.containsAll(annos1);
- }
-
- @Override
- public Boolean visitType(Type t, Type s) {
- return compareAnnotations(t, s) && super.visitType(t, s);
- }
-
- @Override
- public Boolean visitWildcardType(WildcardType t, Type s) {
- return compareAnnotations(t, s) && super.visitWildcardType(t, s);
- }
-
- @Override
- public Boolean visitClassType(ClassType t, Type s) {
- return compareAnnotations(t, s) && super.visitClassType(t, s);
- }
-
- @Override
- public Boolean visitArrayType(ArrayType t, Type s) {
- return compareAnnotations(t, s) && super.visitArrayType(t, s);
- }
-
- @Override
- public Boolean visitForAll(ForAll t, Type s) {
- return compareAnnotations(t, s) && super.visitForAll(t, s);
- }
- };
-
// <editor-fold defaultstate="collapsed" desc="Contains Type">
public boolean containedBy(Type t, Type s) {
switch (t.getTag()) {
@@ -2167,7 +2132,7 @@
* type parameters in t are deleted.
*/
public Type erasure(Type t) {
- return eraseNotNeeded(t)? t : erasure(t, false);
+ return eraseNotNeeded(t) ? t : erasure(t, false);
}
//where
private boolean eraseNotNeeded(Type t) {
@@ -2187,23 +2152,23 @@
}
// where
private TypeMapping<Boolean> erasure = new TypeMapping<Boolean>() {
- private Type combineMetadata(final Type ty,
- final TypeMetadata md) {
- if (!md.isEmpty()) {
- switch (ty.getKind()) {
- default: return ty.clone(ty.metadata.combine(md));
- case OTHER:
- case UNION:
- case INTERSECTION:
- case PACKAGE:
- case EXECUTABLE:
- case NONE:
- case VOID:
- case ERROR:
- return ty;
+ private Type combineMetadata(final Type s,
+ final Type t) {
+ if (t.getMetadata() != TypeMetadata.EMPTY) {
+ switch (s.getKind()) {
+ case OTHER:
+ case UNION:
+ case INTERSECTION:
+ case PACKAGE:
+ case EXECUTABLE:
+ case NONE:
+ case VOID:
+ case ERROR:
+ return s;
+ default: return s.cloneWithMetadata(s.getMetadata().without(Kind.ANNOTATIONS));
}
} else {
- return ty;
+ return s;
}
}
@@ -2212,7 +2177,7 @@
return t; /*fast special case*/
else {
//other cases already handled
- return combineMetadata(t, t.getMetadata());
+ return combineMetadata(t, t);
}
}
@@ -2220,17 +2185,18 @@
public Type visitClassType(ClassType t, Boolean recurse) {
Type erased = t.tsym.erasure(Types.this);
if (recurse) {
- erased = new ErasedClassType(erased.getEnclosingType(),erased.tsym, t.getMetadata());
+ erased = new ErasedClassType(erased.getEnclosingType(),erased.tsym,
+ t.getMetadata().without(Kind.ANNOTATIONS));
return erased;
} else {
- return combineMetadata(erased, t.getMetadata());
+ return combineMetadata(erased, t);
}
}
@Override
public Type visitTypeVar(TypeVar t, Boolean recurse) {
Type erased = erasure(t.bound, recurse);
- return combineMetadata(erased, t.getMetadata());
+ return combineMetadata(erased, t);
}
};
@@ -2932,7 +2898,7 @@
public List<Type> subst(List<Type> ts,
List<Type> from,
List<Type> to) {
- return new Subst(from, to).subst(ts);
+ return ts.map(new Subst(from, to));
}
/**
@@ -2942,10 +2908,10 @@
* elements of the longer list.
*/
public Type subst(Type t, List<Type> from, List<Type> to) {
- return new Subst(from, to).subst(t);
+ return t.map(new Subst(from, to));
}
- private class Subst extends UnaryVisitor<Type> {
+ private class Subst extends TypeMapping<Void> {
List<Type> from;
List<Type> to;
@@ -2964,49 +2930,12 @@
this.to = to;
}
- Type subst(Type t) {
- if (from.tail == null)
- return t;
- else
- return visit(t);
- }
-
- List<Type> subst(List<Type> ts) {
- if (from.tail == null)
- return ts;
- boolean wild = false;
- if (ts.nonEmpty() && from.nonEmpty()) {
- Type head1 = subst(ts.head);
- List<Type> tail1 = subst(ts.tail);
- if (head1 != ts.head || tail1 != ts.tail)
- return tail1.prepend(head1);
- }
- return ts;
- }
-
- public Type visitType(Type t, Void ignored) {
- return t;
- }
-
- @Override
- public Type visitMethodType(MethodType t, Void ignored) {
- List<Type> argtypes = subst(t.argtypes);
- Type restype = subst(t.restype);
- List<Type> thrown = subst(t.thrown);
- if (argtypes == t.argtypes &&
- restype == t.restype &&
- thrown == t.thrown)
- return t;
- else
- return new MethodType(argtypes, restype, thrown, t.tsym);
- }
-
@Override
public Type visitTypeVar(TypeVar t, Void ignored) {
for (List<Type> from = this.from, to = this.to;
from.nonEmpty();
from = from.tail, to = to.tail) {
- if (t == from.head) {
+ if (t.equalsIgnoreMetadata(from.head)) {
return to.head.withTypeVar(t);
}
}
@@ -3014,26 +2943,12 @@
}
@Override
- public Type visitUndetVar(UndetVar t, Void ignored) {
- //do nothing - we should not replace inside undet variables
- return t;
- }
-
- @Override
public Type visitClassType(ClassType t, Void ignored) {
if (!t.isCompound()) {
- List<Type> typarams = t.getTypeArguments();
- List<Type> typarams1 = subst(typarams);
- Type outer = t.getEnclosingType();
- Type outer1 = subst(outer);
- if (typarams1 == typarams && outer1 == outer)
- return t;
- else
- return new ClassType(outer1, typarams1, t.tsym,
- t.getMetadata());
+ return super.visitClassType(t, ignored);
} else {
- Type st = subst(supertype(t));
- List<Type> is = subst(interfaces(t));
+ Type st = visit(supertype(t));
+ List<Type> is = visit(interfaces(t), ignored);
if (st == supertype(t) && is == interfaces(t))
return t;
else
@@ -3043,26 +2958,11 @@
@Override
public Type visitWildcardType(WildcardType t, Void ignored) {
- Type bound = t.type;
- if (t.kind != BoundKind.UNBOUND)
- bound = subst(bound);
- if (bound == t.type) {
- return t;
- } else {
- if (t.isExtendsBound() && bound.isExtendsBound())
- bound = wildUpperBound(bound);
- return new WildcardType(bound, t.kind, syms.boundClass,
- t.bound, t.getMetadata());
+ WildcardType t2 = (WildcardType)super.visitWildcardType(t, ignored);
+ if (t2 != t && t.isExtendsBound() && t2.type.isExtendsBound()) {
+ t2.type = wildUpperBound(t2.type);
}
- }
-
- @Override
- public Type visitArrayType(ArrayType t, Void ignored) {
- Type elemtype = subst(t.elemtype);
- if (elemtype == t.elemtype)
- return t;
- else
- return new ArrayType(elemtype, t.tsym, t.getMetadata());
+ return t2;
}
@Override
@@ -3075,21 +2975,25 @@
Types.this.subst(t.qtype, t.tvars, freevars));
}
List<Type> tvars1 = substBounds(t.tvars, from, to);
- Type qtype1 = subst(t.qtype);
+ Type qtype1 = visit(t.qtype);
if (tvars1 == t.tvars && qtype1 == t.qtype) {
return t;
} else if (tvars1 == t.tvars) {
- return new ForAll(tvars1, qtype1);
+ return new ForAll(tvars1, qtype1) {
+ @Override
+ public boolean needsStripping() {
+ return true;
+ }
+ };
} else {
- return new ForAll(tvars1,
- Types.this.subst(qtype1, t.tvars, tvars1));
+ return new ForAll(tvars1, Types.this.subst(qtype1, t.tvars, tvars1)) {
+ @Override
+ public boolean needsStripping() {
+ return true;
+ }
+ };
}
}
-
- @Override
- public Type visitErrorType(ErrorType t, Void ignored) {
- return t;
- }
}
public List<Type> substBounds(List<Type> tvars,
@@ -4232,8 +4136,7 @@
}
private boolean containsTypeEquivalent(Type t, Type s) {
- return
- isSameType(t, s) || // shortcut
+ return isSameType(t, s) || // shortcut
containsType(t, s) && containsType(s, t);
}
@@ -4675,7 +4578,7 @@
return getRetention(a.type.tsym);
}
- public RetentionPolicy getRetention(Symbol sym) {
+ public RetentionPolicy getRetention(TypeSymbol sym) {
RetentionPolicy vis = RetentionPolicy.CLASS; // the default
Attribute.Compound c = sym.attribute(syms.retentionType.tsym);
if (c != null) {
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java Thu Apr 09 06:40:21 2015 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java Thu Apr 09 17:37:46 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -25,28 +25,39 @@
package com.sun.tools.javac.comp;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.Map;
+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.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 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.Symbol.*;
-import com.sun.tools.javac.tree.*;
-import com.sun.tools.javac.tree.JCTree.*;
-
-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.
@@ -64,95 +75,98 @@
}
private final Attr attr;
- private final TreeMaker make;
- private final Log log;
- private final Symtab syms;
- private final Names names;
- private final Resolve rs;
- private final Types types;
+ private final Check chk;
private final ConstFold cfolder;
- private final Check chk;
+ private final DeferredLintHandler deferredLintHandler;
+ private final Enter enter;
private final Lint lint;
- private final DeferredLintHandler deferredLintHandler;
- private final Source source;
+ private final Log log;
+ private final Names names;
+ private final Resolve resolve;
+ private final TreeMaker make;
+ private final Symtab syms;
+ private final TypeEnvs typeEnvs;
+ private final Types types;
- 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);
+
+ theUnfinishedDefaultValue = new Attribute.Error(syms.errType);
+
+ Source source = Source.instance(context);
allowRepeatedAnnos = source.allowRepeatedAnnotations();
- allowTypeAnnos = source.allowTypeAnnotations();
}
-/* ********************************************************************
- * Queue maintenance
- *********************************************************************/
-
- private int enterCount = 0;
+ /** Semaphore to delay annotation processing */
+ private int blockCount = 0;
- 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);
- }
-
- public void normal(Worker a) {
- q.append(a);
+ /** Called when annotations processing needs to be postponed. */
+ public void blockAnnotations() {
+ blockCount++;
}
- public void typeAnnotation(Worker a) {
- typesQ.append(a);
- }
-
- public void repeated(Worker a) {
- repeatedQ.append(a);
- }
-
- public void afterRepeated(Worker a) {
- afterRepeatedQ.append(a);
- }
-
- public void validate(Worker 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();
+ /** Called when annotation processing can be resumed. */
+ public void unblockAnnotations() {
+ blockCount--;
+ if (blockCount == 0)
+ flush();
}
/** Variant which allows for a delayed flush of annotations.
* Needed by ClassReader */
- public void enterDoneWithoutFlush() {
- enterCount--;
+ public void unblockAnnotationsNoFlush() {
+ blockCount--;
}
+ /** are we blocking annotation processing? */
+ public boolean annotationsBlocked() {return blockCount > 0; }
+
+ public List<TypeCompound> fromAnnotations(List<JCAnnotation> annotations) {
+ if (annotations.isEmpty()) {
+ return List.nil();
+ }
+
+ ListBuffer<TypeCompound> buf = new ListBuffer<>();
+ for (JCAnnotation anno : annotations) {
+ Assert.checkNonNull(anno.attribute);
+ buf.append((TypeCompound) anno.attribute);
+ }
+ return buf.toList();
+ }
+
+ /** Annotate (used for everything else) */
+ public void normal(Runnable r) {
+ q.append(r);
+ }
+
+ /** Validate, triggers after 'normal' */
+ public void validate(Runnable a) {
+ validateQ.append(a);
+ }
+
+ /** Flush all annotation queues */
public void flush() {
- if (enterCount != 0) return;
- enterCount++;
+ if (annotationsBlocked()) return;
+ if (isFlushing()) return;
+
+ startFlushing();
try {
while (q.nonEmpty()) {
q.next().run();
@@ -160,35 +174,502 @@
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();
+ }
+ }
+
+ 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);
+ }
+
+ /**
+ * 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
+ */
+ public void annotateLater(List<JCAnnotation> annotations, Env<AttrContext> localEnv,
+ Symbol s, DiagnosticPosition deferPos)
+ {
+ if (annotations.isEmpty()) {
+ return;
+ }
+
+ s.resetAnnotations(); // mark Annotations as incomplete for now
+
+ normal(new Runnable() {
+ @Override
+ public String toString() {
+ return "Annotate " + annotations + " onto " + s + " in " + s.owner;
+ }
+
+ @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);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "validate annotations: " + annotations + " on " + s;
+ }
+ });
+ }
+
+
+ /** 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;
+ }
+ });
+
+ 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
+ public String toString() {
+ 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;
+ }
+
+ 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()
+ && 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);
+ }
+ }
+
+ 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);
}
}
- /** 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.
+ /**
+ * 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
*/
- public interface Worker {
- void run();
- String toString();
+ public Attribute.Compound attributeAnnotation(JCAnnotation tree, Type expectedAnnotationType,
+ Env<AttrContext> env)
+ {
+ // The attribute might have been entered if it 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;
+
+ List<Pair<MethodSymbol, Attribute>> elems = attributeAnnotationValues(tree, expectedAnnotationType, env);
+ Attribute.Compound ac = new Attribute.Compound(tree.type, elems);
+
+ return tree.attribute = ac;
+ }
+
+ /** 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 it 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, TypeAnnotationPosition.unknown);
+ a.attribute = tc;
+ return tc;
+ } else {
+ // Use an existing TypeCompound
+ return (Attribute.TypeCompound)a.attribute;
+ }
}
/**
+ * 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));
+ a.type = chk.checkType(a.annotationType.pos(), at, expected);
+
+ boolean isError = a.type.isErroneous();
+ 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;
+ // special case: elided "value=" assumed
+ 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<>();
+ for (List<JCExpression> tl = args; tl.nonEmpty(); tl = tl.tail) {
+ 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)nameValuePair;
+ if (!assign.lhs.hasTag(IDENT)) {
+ 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 = 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 != 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 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 {
+ expectedElementType.tsym.complete();
+ } catch(CompletionFailure e) {
+ log.error(tree.pos(), "cant.resolve", Kinds.kindName(e.sym), e.sym);
+ expectedElementType = syms.errType;
+ }
+
+ if (expectedElementType.hasTag(ARRAY)) {
+ return getAnnotationArrayValue(expectedElementType, tree, env);
+
+ }
+
+ //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) {
+ attributeAnnotationValue(syms.errType,
+ l.head,
+ env);
+ }
+ return new Attribute.Error(syms.errType);
+ }
+
+ if (expectedElementType.tsym.isAnnotationType()) {
+ if (tree.hasTag(ANNOTATION)) {
+ return attributeAnnotation((JCAnnotation)tree, expectedElementType, env);
+ } else {
+ log.error(tree.pos(), "annotation.value.must.be.annotation");
+ expectedElementType = syms.errType;
+ }
+ }
+
+ //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 (expectedElementType.isPrimitive() ||
+ (types.isSameType(expectedElementType, syms.stringType) && !expectedElementType.hasTag(TypeTag.ERROR))) {
+ return getAnnotationPrimitiveValue(expectedElementType, tree, env);
+ }
+
+ if (expectedElementType.tsym == syms.classType.tsym) {
+ return getAnnotationClassValue(expectedElementType, tree, env);
+ }
+
+ 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());
+ }
+ }
+
+ // Class literals look like field accesses of a field named class
+ // at the tree level
+ if (TreeInfo.name(tree) != names._class) {
+ log.error(tree.pos(), "annotation.value.must.be.class.literal");
+ return new Attribute.Error(syms.errType);
+ }
+ return new Attribute.Class(types,
+ (((JCFieldAccess) tree).selected).type);
+ }
+
+ 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);
+ }
+ result = cfolder.coerce(result, expectedElementType);
+ return new Attribute.Constant(expectedElementType, result.constValue());
+ }
+
+ 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 by the completer for repeating annotations.
+ * annotations trees for repeating annotations.
*/
private class AnnotationContext<T extends Attribute.Compound> {
public final Env<AttrContext> env;
@@ -209,280 +690,15 @@
this.pos = pos;
this.isTypeCompound = isTypeCompound;
}
-
- 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 @DefinedBy(Api.LANGUAGE_MODEL)
- 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.
- *********************************************************************/
-
- /** Process a single compound annotation, returning its
- * 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;
- }
- }
-
- 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);
- boolean isError = a.type.isErroneous();
- if ((a.type.tsym.flags() & Flags.ANNOTATION) == 0 && !isError) {
- log.error(a.annotationType.pos(),
- "not.annotation.type", a.type.toString());
- isError = true;
- }
- List<JCExpression> args = a.args;
- boolean elidedValue = false;
- if (args.length() == 1 && !args.head.hasTag(ASSIGN)) {
- // special case: elided "value=" assumed
- elidedValue = true;
- args.head = make.at(args.head.pos).
- Assign(make.Ident(names.value), args.head);
- }
- 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;
- }
- 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(elidedValue ? assign.rhs.pos() : left.pos(),
- env,
- a.type,
- 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();
- }
-
- 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();
- } catch(CompletionFailure e) {
- log.error(tree.pos(), "cant.resolve", Kinds.kindName(e.sym), e.sym);
- expected = 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 (tree.hasTag(NEWARRAY)) { //error recovery
- if (!expected.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,
- 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);
- 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);
- }
- result = cfolder.coerce(result, expected);
- return new Attribute.Constant(expected, result.constValue());
- }
- 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,
- syms.unknownSymbol, syms.classType));
- } else {
- return new Attribute.Error(result.getOriginalType());
- }
- }
-
- // Class literals look like field accesses of a field named class
- // at the tree level
- if (TreeInfo.name(tree) != names._class) {
- log.error(tree.pos(), "annotation.value.must.be.class.literal");
- 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");
- return new Attribute.Error(result.getOriginalType());
- }
- VarSymbol enumerator = (VarSymbol) sym;
- return new Attribute.Enum(expected, enumerator);
- }
- //error recovery:
- if (!expected.isErroneous())
- log.error(tree.pos(), "annotation.value.not.allowable.type");
- return new Attribute.Error(attr.attribExpr(tree, env, expected));
- }
-
- /* *********************************
- * Support for repeating annotations
- ***********************************/
-
/* 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;
@@ -490,14 +706,10 @@
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
@@ -532,18 +744,23 @@
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,
- new Attribute.Array(arrayOfOrigAnnoType, repeated));
+ 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);
+ at = attributeTypeAnnotation(annoTree, targetContainerType, ctx.env);
*/
// However, we directly construct the TypeCompound to keep the
// direct relation to the contained TypeCompounds.
@@ -562,12 +779,13 @@
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")
@@ -579,17 +797,19 @@
}
}
- /** 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)
+ 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);
@@ -597,7 +817,7 @@
}
return filterSame(extractContainingType(ca, pos, origAnnoDecl),
- origAnnoType);
+ origAnnoType);
}
// returns null if t is same as 's', returns 't' otherwise
@@ -611,8 +831,8 @@
/** Extract the actual Type to be used for a containing annotation. */
private Type extractContainingType(Attribute.Compound ca,
- DiagnosticPosition pos,
- TypeSymbol annoDecl)
+ DiagnosticPosition pos,
+ TypeSymbol annoDecl)
{
// The next three checks check that the Repeatable annotation
// on the declaration of the annotation type that is repeating is
@@ -657,7 +877,7 @@
nr_value_elems++;
if (nr_value_elems == 1 &&
- elm.kind == MTH) {
+ elm.kind == MTH) {
containerValueSymbol = (MethodSymbol)elm;
} else {
error = true;
@@ -665,14 +885,14 @@
}
if (error) {
log.error(pos,
- "invalid.repeatable.annotation.multiple.values",
- targetContainerType,
- nr_value_elems);
+ "invalid.repeatable.annotation.multiple.values",
+ targetContainerType,
+ nr_value_elems);
return null;
} else if (nr_value_elems == 0) {
log.error(pos,
- "invalid.repeatable.annotation.no.value",
- targetContainerType);
+ "invalid.repeatable.annotation.no.value",
+ targetContainerType);
return null;
}
@@ -680,8 +900,8 @@
// probably "impossible" to fail this
if (containerValueSymbol.kind != MTH) {
log.error(pos,
- "invalid.repeatable.annotation.invalid.value",
- targetContainerType);
+ "invalid.repeatable.annotation.invalid.value",
+ targetContainerType);
fatalError = true;
}
@@ -690,174 +910,24 @@
Type valueRetType = containerValueSymbol.type.getReturnType();
Type expectedType = types.makeArrayType(originalAnnoType);
if (!(types.isArray(valueRetType) &&
- types.isSameType(expectedType, valueRetType))) {
+ types.isSameType(expectedType, valueRetType))) {
log.error(pos,
- "invalid.repeatable.annotation.value.return",
- targetContainerType,
- valueRetType,
- expectedType);
+ "invalid.repeatable.annotation.value.return",
+ 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
@@ -865,7 +935,8 @@
// 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);
}
}
@@ -874,107 +945,16 @@
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;
- }
-
- @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",
- Kinds.kindName(s), s);
- actualEnterAnnotations(annotations, localEnv, s);
- } finally {
- if (prevLint != null)
- chk.setLint(prevLint);
- deferredLintHandler.setPos(prevLintPos);
- log.useSource(prev);
- }
- }
- });
+ /********************
+ * Type annotations *
+ ********************/
- 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.
+ /**
+ * Attribute the list of annotations and enter them onto s.
*/
- private void actualEnterTypeAnnotations(final List<JCAnnotation> annotations,
- final Env<AttrContext> env,
- final Symbol s,
- final DiagnosticPosition deferPos) {
+ 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;
@@ -983,9 +963,7 @@
prevLintPos = deferredLintHandler.setPos(deferPos);
}
try {
- attachAttributesLater(annotations, env, s, true,
- enterTypeAnnotationsCreator,
- typeAnnotationsAttacher);
+ annotateNow(s, annotations, env, true);
} finally {
if (prevLintPos != null)
deferredLintHandler.setPos(prevLintPos);
@@ -993,21 +971,61 @@
}
}
- public void annotateTypeLater(final JCTree tree,
- final Env<AttrContext> env,
- final Symbol sym,
- final DiagnosticPosition deferPos) {
+ /**
+ * 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 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));
- }
- });
+ normal(new Runnable() {
+ @Override
+ public String toString() {
+ return "type annotate " + tree + " onto " + sym + " in " + sym.owner;
+ }
+
+ @Override
+ public void run() {
+ tree.accept(new TypeAnnotate(env, sym, deferPos));
+ }
+ });
+ }
+
+ /**
+ * 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;
+ }
+
+ @Override
+ public void run() {
+ List<Attribute.TypeCompound> compounds = fromAnnotations(annotations);
+ Assert.check(annotations.size() == compounds.size());
+ storeAt.getMetadataOfKind(Kind.ANNOTATIONS).combine(new TypeMetadata.Annotations(compounds));
+ }
+ });
+ }
+
+ /**
+ * Apply the annotations to the particular type.
+ */
+ public void annotateTypeParameterSecondStage(JCTree tree, List<JCAnnotation> annotations) {
+ typeAnnotation(new Runnable() {
+ @Override
+ public String toString() {
+ return "Type annotate 2:nd stage " + annotations + " onto " + tree;
+ }
+
+ @Override
+ public void run() {
+ List<Attribute.TypeCompound> compounds = fromAnnotations(annotations);
+ Assert.check(annotations.size() == compounds.size());
+ }
+ });
}
/**
@@ -1019,9 +1037,7 @@
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;
@@ -1029,27 +1045,28 @@
}
@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);
@@ -1058,11 +1075,10 @@
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 {
@@ -1094,4 +1110,238 @@
}
}
}
+
+ /*********************
+ * 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;
+ }
+ };
+ }
}
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java Thu Apr 09 06:40:21 2015 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java Thu Apr 09 17:37:46 2015 -0700
@@ -40,6 +40,7 @@
import com.sun.tools.javac.code.Scope.WriteableScope;
import com.sun.tools.javac.code.Symbol.*;
import com.sun.tools.javac.code.Type.*;
+import com.sun.tools.javac.code.TypeMetadata.Annotations;
import com.sun.tools.javac.code.Types.FunctionDescriptorLookupError;
import com.sun.tools.javac.comp.Check.CheckContext;
import com.sun.tools.javac.comp.DeferredAttr.AttrMode;
@@ -103,11 +104,11 @@
final Target target;
final Types types;
final JCDiagnostic.Factory diags;
- final Annotate annotate;
final TypeAnnotations typeAnnotations;
final DeferredLintHandler deferredLintHandler;
final TypeEnvs typeEnvs;
final Dependencies dependencies;
+ final Annotate annotate;
public static Attr instance(Context context) {
Attr instance = context.get(attrKey);
@@ -997,7 +998,7 @@
}
// Attribute all type annotations in the body
- annotate.annotateTypeLater(tree.body, localEnv, m, null);
+ annotate.queueScanTreeAndTypeAnnotate(tree.body, localEnv, m, null);
annotate.flush();
// Attribute method body.
@@ -1020,16 +1021,16 @@
env.info.scope.enter(tree.sym);
} else {
try {
- annotate.enterStart();
+ annotate.blockAnnotations();
memberEnter.memberEnter(tree, env);
} finally {
- annotate.enterDone();
+ annotate.unblockAnnotations();
}
}
} else {
if (tree.init != null) {
// Field initializer expression need to be entered.
- annotate.annotateTypeLater(tree.init, env, tree.sym, tree.pos());
+ annotate.queueScanTreeAndTypeAnnotate(tree.init, env, tree.sym, tree.pos());
annotate.flush();
}
}
@@ -1090,7 +1091,7 @@
if ((tree.flags & STATIC) != 0) localEnv.info.staticLevel++;
// Attribute all type annotations in the block
- annotate.annotateTypeLater(tree, localEnv, localEnv.info.scope.owner, null);
+ annotate.queueScanTreeAndTypeAnnotate(tree, localEnv, localEnv.info.scope.owner, null);
annotate.flush();
attribStats(tree.stats, localEnv);
@@ -1953,9 +1954,16 @@
// Attribute clazz expression and store
// symbol + type back into the attributed tree.
- Type clazztype = TreeInfo.isEnumInit(env.tree) ?
- attribIdentAsEnumType(env, (JCIdent)clazz) :
- attribType(clazz, env);
+ Type clazztype;
+
+ try {
+ env.info.isNewClass = true;
+ clazztype = TreeInfo.isEnumInit(env.tree) ?
+ attribIdentAsEnumType(env, (JCIdent)clazz) :
+ attribType(clazz, env);
+ } finally {
+ env.info.isNewClass = false;
+ }
clazztype = chk.checkDiamond(tree, clazztype);
chk.validate(clazz, localEnv);
@@ -4002,7 +4010,7 @@
TypeVar typeVar = (TypeVar) tree.type;
if (tree.annotations != null && tree.annotations.nonEmpty()) {
- annotateType(tree, tree.annotations);
+ annotate.annotateTypeParameterSecondStage(tree, tree.annotations);
}
if (!typeVar.bound.isErroneous()) {
@@ -4092,45 +4100,17 @@
}
public void visitAnnotation(JCAnnotation tree) {
- Assert.error("should be handled in Annotate");
+ Assert.error("should be handled in annotate");
}
public void visitAnnotatedType(JCAnnotatedType tree) {
- Type underlyingType = attribType(tree.getUnderlyingType(), env);
- this.attribAnnotationTypes(tree.annotations, env);
- annotateType(tree, tree.annotations);
- result = tree.type = underlyingType;
- }
-
- /**
- * Apply the annotations to the particular type.
- */
- public void annotateType(final JCTree tree, final List<JCAnnotation> annotations) {
- annotate.typeAnnotation(new Annotate.Worker() {
- @Override
- public String toString() {
- return "annotate " + annotations + " onto " + tree;
- }
- @Override
- public void run() {
- List<Attribute.TypeCompound> compounds = fromAnnotations(annotations);
- Assert.check(annotations.size() == compounds.size());
- tree.type = tree.type.annotatedType(compounds);
- }
- });
- }
-
- private static List<Attribute.TypeCompound> fromAnnotations(List<JCAnnotation> annotations) {
- if (annotations.isEmpty()) {
- return List.nil();
- }
-
- ListBuffer<Attribute.TypeCompound> buf = new ListBuffer<>();
- for (JCAnnotation anno : annotations) {
- Assert.checkNonNull(anno.attribute);
- buf.append((Attribute.TypeCompound) anno.attribute);
- }
- return buf.toList();
+ attribAnnotationTypes(tree.annotations, env);
+ Type underlyingType = attribType(tree.underlyingType, env);
+ Type annotatedType = underlyingType.annotatedType(Annotations.TO_BE_SET);
+
+ if (!env.info.isNewClass)
+ annotate.annotateTypeSecondStage(tree, tree.annotations, annotatedType);
+ result = tree.type = annotatedType;
}
public void visitErroneous(JCErroneous tree) {
@@ -4298,8 +4278,9 @@
log.error(tree.typarams.head.pos(),
"intf.annotation.cant.have.type.params");
- // If this annotation has a @Repeatable, validate
- Attribute.Compound repeatable = c.attribute(syms.repeatableType.tsym);
+ // If this annotation type has a @Repeatable, validate
+ Attribute.Compound repeatable = c.getAnnotationTypeMetadata().getRepeatable();
+ // If this annotation type has a @Repeatable, validate
if (repeatable != null) {
// get diagnostic position for error reporting
DiagnosticPosition cbPos = getDiagnosticPosition(tree, repeatable.type);
@@ -4675,7 +4656,7 @@
// This method will raise an error for such a type.
for (JCAnnotation ai : annotations) {
if (!ai.type.isErroneous() &&
- typeAnnotations.annotationType(ai.attribute, sym) == TypeAnnotations.AnnotationType.DECLARATION) {
+ typeAnnotations.annotationTargetType(ai.attribute, sym) == TypeAnnotations.AnnotationType.DECLARATION) {
log.error(ai.pos(), "annotation.type.not.applicable");
}
}
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/AttrContext.java Thu Apr 09 06:40:21 2015 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/AttrContext.java Thu Apr 09 17:37:46 2015 -0700
@@ -68,6 +68,11 @@
*/
boolean isAnonymousDiamond = false;
+ /**
+ * Is this an attribution environment for an instance creation expression?
+ */
+ boolean isNewClass = false;
+
/** Are arguments to current function applications boxed into an array for varargs?
*/
Resolve.MethodResolutionPhase pendingResolutionPhase = null;
@@ -106,6 +111,7 @@
info.isSerializable = isSerializable;
info.isSpeculative = isSpeculative;
info.isAnonymousDiamond = isAnonymousDiamond;
+ info.isNewClass = isNewClass;
return info;
}
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java Thu Apr 09 06:40:21 2015 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java Thu Apr 09 17:37:46 2015 -0700
@@ -31,6 +31,7 @@
import com.sun.tools.javac.code.*;
import com.sun.tools.javac.code.Attribute.Compound;
+import com.sun.tools.javac.comp.Annotate.AnnotationTypeMetadata;
import com.sun.tools.javac.jvm.*;
import com.sun.tools.javac.resources.CompilerProperties.Errors;
import com.sun.tools.javac.resources.CompilerProperties.Fragments;
@@ -81,6 +82,7 @@
private final DeferredAttr deferredAttr;
private final Infer infer;
private final Types types;
+ private final TypeAnnotations typeAnnotations;
private final JCDiagnostic.Factory diags;
private boolean warnOnSyntheticConflicts;
private boolean suppressAbortOnBadClassFile;
@@ -120,6 +122,7 @@
deferredAttr = DeferredAttr.instance(context);
infer = Infer.instance(context);
types = Types.instance(context);
+ typeAnnotations = TypeAnnotations.instance(context);
diags = JCDiagnostic.Factory.instance(context);
Options options = Options.instance(context);
lint = Lint.instance(context);
@@ -526,7 +529,7 @@
* @param found The type that was found.
* @param req The type that was required.
*/
- Type checkType(DiagnosticPosition pos, Type found, Type req) {
+ public Type checkType(DiagnosticPosition pos, Type found, Type req) {
return checkType(pos, found, req, basicHandler);
}
@@ -587,7 +590,7 @@
public void report() {
if (lint.isEnabled(Lint.LintCategory.CAST))
log.warning(Lint.LintCategory.CAST,
- tree.pos(), "redundant.cast", tree.expr.type);
+ tree.pos(), "redundant.cast", tree.clazz.type);
}
});
}
@@ -2830,7 +2833,7 @@
}
}
- private void validateRetention(Symbol container, Symbol contained, DiagnosticPosition pos) {
+ private void validateRetention(TypeSymbol container, TypeSymbol contained, DiagnosticPosition pos) {
Attribute.RetentionPolicy containerRetention = types.getRetention(container);
Attribute.RetentionPolicy containedRetention = types.getRetention(contained);
@@ -2869,7 +2872,7 @@
}
}
- private void validateTarget(Symbol container, Symbol contained, DiagnosticPosition pos) {
+ private void validateTarget(TypeSymbol container, TypeSymbol contained, DiagnosticPosition pos) {
// The set of targets the container is applicable to must be a subset
// (with respect to annotation target semantics) of the set of targets
// the contained is applicable to. The target sets may be implicit or
@@ -2996,33 +2999,19 @@
/** Is the annotation applicable to types? */
protected boolean isTypeAnnotation(JCAnnotation a, boolean isTypeParameter) {
- Attribute.Compound atTarget =
- a.annotationType.type.tsym.attribute(syms.annotationTargetType.tsym);
- if (atTarget == null) {
- // An annotation without @Target is not a type annotation.
- return false;
- }
-
- Attribute atValue = atTarget.member(names.value);
- if (!(atValue instanceof Attribute.Array)) {
- return false; // error recovery
+ List<Attribute> targets = typeAnnotations.annotationTargets(a.attribute);
+ return (targets == null) ?
+ false :
+ targets.stream()
+ .anyMatch(attr -> isTypeAnnotation(attr, isTypeParameter));
+ }
+ //where
+ boolean isTypeAnnotation(Attribute a, boolean isTypeParameter) {
+ Attribute.Enum e = (Attribute.Enum)a;
+ return (e.value.name == names.TYPE_USE ||
+ (isTypeParameter && e.value.name == names.TYPE_PARAMETER));
}
- Attribute.Array arr = (Attribute.Array) atValue;
- for (Attribute app : arr.values) {
- if (!(app instanceof Attribute.Enum)) {
- return false; // recovery
- }
- Attribute.Enum e = (Attribute.Enum) app;
-
- if (e.value.name == names.TYPE_USE)
- return true;
- else if (isTypeParameter && e.value.name == names.TYPE_PARAMETER)
- return true;
- }
- return false;
- }
-
/** Is the annotation applicable to the symbol? */
boolean annotationApplicable(JCAnnotation a, Symbol s) {
Attribute.Array arr = getAttributeTargetAttribute(a.annotationType.type.tsym);
@@ -3043,51 +3032,55 @@
}
}
for (Name target : targets) {
- if (target == names.TYPE)
- { if (s.kind == TYP) return true; }
- else if (target == names.FIELD)
- { if (s.kind == VAR && s.owner.kind != MTH) return true; }
- else if (target == names.METHOD)
- { if (s.kind == MTH && !s.isConstructor()) return true; }
- else if (target == names.PARAMETER)
- { if (s.kind == VAR && s.owner.kind == MTH &&
- (s.flags() & PARAMETER) != 0)
+ if (target == names.TYPE) {
+ if (s.kind == TYP)
+ return true;
+ } else if (target == names.FIELD) {
+ if (s.kind == VAR && s.owner.kind != MTH)
return true;
- }
- else if (target == names.CONSTRUCTOR)
- { if (s.kind == MTH && s.isConstructor()) return true; }
- else if (target == names.LOCAL_VARIABLE)
- { if (s.kind == VAR && s.owner.kind == MTH &&
- (s.flags() & PARAMETER) == 0)
+ } else if (target == names.METHOD) {
+ if (s.kind == MTH && !s.isConstructor())
+ return true;
+ } else if (target == names.PARAMETER) {
+ if (s.kind == VAR && s.owner.kind == MTH &&
+ (s.flags() & PARAMETER) != 0) {
return true;
}
- else if (target == names.ANNOTATION_TYPE)
- { if (s.kind == TYP && (s.flags() & ANNOTATION) != 0)
+ } else if (target == names.CONSTRUCTOR) {
+ if (s.kind == MTH && s.isConstructor())
+ return true;
+ } else if (target == names.LOCAL_VARIABLE) {
+ if (s.kind == VAR && s.owner.kind == MTH &&
+ (s.flags() & PARAMETER) == 0) {
+ return true;
+ }
+ } else if (target == names.ANNOTATION_TYPE) {
+ if (s.kind == TYP && (s.flags() & ANNOTATION) != 0) {
return true;
}
- else if (target == names.PACKAGE)
- { if (s.kind == PCK) return true; }
- else if (target == names.TYPE_USE)
- { if (s.kind == TYP || s.kind == VAR ||
- (s.kind == MTH && !s.isConstructor() &&
- !s.type.getReturnType().hasTag(VOID)) ||
- (s.kind == MTH && s.isConstructor()))
+ } else if (target == names.PACKAGE) {
+ if (s.kind == PCK)
+ return true;
+ } else if (target == names.TYPE_USE) {
+ if (s.kind == TYP || s.kind == VAR ||
+ (s.kind == MTH && !s.isConstructor() &&
+ !s.type.getReturnType().hasTag(VOID)) ||
+ (s.kind == MTH && s.isConstructor())) {
return true;
}
- else if (target == names.TYPE_PARAMETER)
- { if (s.kind == TYP && s.type.hasTag(TYPEVAR))
+ } else if (target == names.TYPE_PARAMETER) {
+ if (s.kind == TYP && s.type.hasTag(TYPEVAR))
return true;
- }
- else
- return true; // recovery
+ } else
+ return true; // Unknown ElementType. This should be an error at declaration site,
+ // assume applicable.
}
return false;
}
- Attribute.Array getAttributeTargetAttribute(Symbol s) {
- Attribute.Compound atTarget =
- s.attribute(syms.annotationTargetType.tsym);
+ Attribute.Array getAttributeTargetAttribute(TypeSymbol s) {
+ Attribute.Compound atTarget = s.getAnnotationTypeMetadata().getTarget();
if (atTarget == null) return null; // ok, is applicable
Attribute atValue = atTarget.member(names.value);
if (!(atValue instanceof Attribute.Array)) return null; // error recovery
@@ -3117,32 +3110,33 @@
private boolean validateAnnotation(JCAnnotation a) {
boolean isValid = true;
+ AnnotationTypeMetadata metadata = a.annotationType.type.tsym.getAnnotationTypeMetadata();
+
// collect an inventory of the annotation elements
- Set<MethodSymbol> members = new LinkedHashSet<>();
- for (Symbol sym : a.annotationType.type.tsym.members().getSymbols(NON_RECURSIVE))
- if (sym.kind == MTH && sym.name != names.clinit &&
- (sym.flags() & SYNTHETIC) == 0)
- members.add((MethodSymbol) sym);
+ Set<MethodSymbol> elements = metadata.getAnnotationElements();
// remove the ones that are assigned values
for (JCTree arg : a.args) {
if (!arg.hasTag(ASSIGN)) continue; // recovery
- JCAssign assign = (JCAssign) arg;
+ JCAssign assign = (JCAssign)arg;
Symbol m = TreeInfo.symbol(assign.lhs);
if (m == null || m.type.isErroneous()) continue;
- if (!members.remove(m)) {
+ if (!elements.remove(m)) {
isValid = false;
log.error(assign.lhs.pos(), "duplicate.annotation.member.value",
- m.name, a.type);
+ m.name, a.type);
}
}
// all the remaining ones better have default values
List<Name> missingDefaults = List.nil();
- for (MethodSymbol m : members) {
- if (m.defaultValue == null && !m.type.isErroneous()) {
+ Set<MethodSymbol> membersWithDefault = metadata.getAnnotationElementsWithDefault();
+ for (MethodSymbol m : elements) {
+ if (m.type.isErroneous())
+ continue;
+
+ if (!membersWithDefault.contains(m))
missingDefaults = missingDefaults.append(m.name);
- }
}
missingDefaults = missingDefaults.reverse();
if (missingDefaults.nonEmpty()) {
@@ -3153,12 +3147,18 @@
log.error(a.pos(), key, a.type, missingDefaults);
}
+ return isValid && validateTargetAnnotationValue(a);
+ }
+
+ /* Validate the special java.lang.annotation.Target annotation */
+ boolean validateTargetAnnotationValue(JCAnnotation a) {
// special case: java.lang.annotation.Target must not have
// repeated values in its value member
if (a.annotationType.type.tsym != syms.annotationTargetType.tsym ||
- a.args.tail == null)
- return isValid;
-
+ a.args.tail == null)
+ return true;
+
+ boolean isValid = true;
if (!a.args.head.hasTag(ASSIGN)) return false; // error recovery
JCAssign assign = (JCAssign) a.args.head;
Symbol m = TreeInfo.symbol(assign.lhs);
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java Thu Apr 09 06:40:21 2015 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java Thu Apr 09 17:37:46 2015 -0700
@@ -176,14 +176,14 @@
SpeculativeCache speculativeCache;
DeferredType(JCExpression tree, Env<AttrContext> env) {
- super(null, TypeMetadata.empty);
+ super(null, TypeMetadata.EMPTY);
this.tree = tree;
this.env = attr.copyEnv(env);
this.speculativeCache = new SpeculativeCache();
}
@Override
- public DeferredType clone(TypeMetadata md) {
+ public DeferredType cloneWithMetadata(TypeMetadata md) {
throw new AssertionError("Cannot add metadata to a deferred type");
}
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Enter.java Thu Apr 09 06:40:21 2015 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Enter.java Thu Apr 09 17:37:46 2015 -0700
@@ -25,7 +25,6 @@
package com.sun.tools.javac.comp;
-import java.util.*;
import javax.tools.JavaFileObject;
import javax.tools.JavaFileManager;
@@ -34,7 +33,6 @@
import com.sun.tools.javac.code.Scope.*;
import com.sun.tools.javac.code.Symbol.*;
import com.sun.tools.javac.code.Type.*;
-import com.sun.tools.javac.jvm.*;
import com.sun.tools.javac.main.Option.PkgInfo;
import com.sun.tools.javac.tree.*;
import com.sun.tools.javac.tree.JCTree.*;
@@ -87,11 +85,11 @@
public class Enter extends JCTree.Visitor {
protected static final Context.Key<Enter> enterKey = new Context.Key<>();
+ Annotate annotate;
Log log;
Symtab syms;
Check chk;
TreeMaker make;
- Annotate annotate;
TypeEnter typeEnter;
Types types;
Lint lint;
@@ -253,11 +251,13 @@
Env<AttrContext> prevEnv = this.env;
try {
this.env = env;
+ annotate.blockAnnotations();
tree.accept(this);
return result;
} catch (CompletionFailure ex) {
return chk.completionError(tree.pos(), ex);
} finally {
+ annotate.unblockAnnotations();
this.env = prevEnv;
}
}
@@ -474,7 +474,7 @@
* @param c The class symbol to be processed or null to process all.
*/
public void complete(List<JCCompilationUnit> trees, ClassSymbol c) {
- annotate.enterStart();
+ annotate.blockAnnotations();
ListBuffer<ClassSymbol> prevUncompleted = uncompleted;
if (typeEnter.completionEnabled) uncompleted = new ListBuffer<>();
@@ -497,7 +497,7 @@
}
} finally {
uncompleted = prevUncompleted;
- annotate.enterDone();
+ annotate.unblockAnnotations();
}
}
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java Thu Apr 09 06:40:21 2015 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java Thu Apr 09 17:37:46 2015 -0700
@@ -2766,20 +2766,6 @@
return translationMap;
}
- public void visitAnnotatedType(JCAnnotatedType tree) {
- // No need to retain type annotations in the tree
- // tree.annotations = translate(tree.annotations);
- tree.annotations = List.nil();
- tree.underlyingType = translate(tree.underlyingType);
- // but maintain type annotations in the type.
- if (tree.type.isAnnotated()) {
- tree.type = tree.underlyingType.type.annotatedType(tree.type.getAnnotationMirrors());
- } else if (tree.underlyingType.type.isAnnotated()) {
- tree.type = tree.underlyingType.type;
- }
- result = tree;
- }
-
public void visitTypeCast(JCTypeCast tree) {
tree.clazz = translate(tree.clazz);
if (tree.type.isPrimitive() != tree.expr.type.isPrimitive())
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java Thu Apr 09 06:40:21 2015 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java Thu Apr 09 17:37:46 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -25,8 +25,6 @@
package com.sun.tools.javac.comp;
-import javax.tools.JavaFileObject;
-
import com.sun.tools.javac.code.*;
import com.sun.tools.javac.code.Scope.WriteableScope;
import com.sun.tools.javac.tree.*;
@@ -224,10 +222,12 @@
annotate.annotateLater(tree.mods.annotations, localEnv, m, tree.pos());
// Visit the signature of the method. Note that
// TypeAnnotate doesn't descend into the body.
- annotate.annotateTypeLater(tree, localEnv, m, tree.pos());
+ annotate.queueScanTreeAndTypeAnnotate(tree, localEnv, m, tree.pos());
- if (tree.defaultValue != null)
- annotateDefaultValueLater(tree.defaultValue, localEnv, m, tree.pos());
+ if (tree.defaultValue != null) {
+ m.defaultValue = annotate.unfinishedDefaultValue(); // set it to temporary sentinel for now
+ annotate.annotateDefaultValueLater(tree.defaultValue, localEnv, m, tree.pos());
+ }
}
/** Create a fresh environment for method bodies.
@@ -255,6 +255,7 @@
localEnv.info.staticLevel++;
}
DiagnosticPosition prevLintPos = deferredLintHandler.setPos(tree.pos());
+
try {
if (TreeInfo.isEnumInit(tree)) {
attr.attribIdentAsEnumType(localEnv, (JCIdent)tree.vartype);
@@ -297,7 +298,7 @@
}
annotate.annotateLater(tree.mods.annotations, localEnv, v, tree.pos());
- annotate.annotateTypeLater(tree.vartype, localEnv, v, tree.pos());
+ annotate.queueScanTreeAndTypeAnnotate(tree.vartype, localEnv, v, tree.pos());
v.pos = tree.pos;
}
@@ -434,53 +435,4 @@
Env<AttrContext> iEnv = initEnv(tree, env);
return iEnv;
}
-
- /** Queue processing of an attribute default value. */
- void annotateDefaultValueLater(final JCExpression defaultValue,
- final Env<AttrContext> localEnv,
- final MethodSymbol m,
- final DiagnosticPosition deferPos) {
- annotate.normal(new Annotate.Worker() {
- @Override
- public String toString() {
- return "annotate " + m.owner + "." +
- m + " default " + defaultValue;
- }
-
- @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);
- }
- }
- });
- annotate.validate(new Annotate.Worker() { //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);
- }
- }
- });
- }
-
- /** Enter a default value for an attribute method. */
- private void enterDefaultValue(final JCExpression defaultValue,
- final Env<AttrContext> localEnv,
- final MethodSymbol m) {
- m.defaultValue = annotate.enterAttributeValue(m.type.getReturnType(),
- defaultValue,
- localEnv);
- }
-
}
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java Thu Apr 09 06:40:21 2015 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java Thu Apr 09 17:37:46 2015 -0700
@@ -28,6 +28,7 @@
import java.util.*;
import com.sun.tools.javac.code.*;
+import com.sun.tools.javac.code.Attribute.TypeCompound;
import com.sun.tools.javac.code.Symbol.*;
import com.sun.tools.javac.tree.*;
import com.sun.tools.javac.tree.JCTree.*;
@@ -68,6 +69,7 @@
private TreeMaker make;
private Enter enter;
private Types types;
+ private Annotate annotate;
private final Resolve resolve;
private final CompileStates compileStates;
@@ -91,6 +93,7 @@
Source source = Source.instance(context);
allowInterfaceBridges = source.allowDefaultMethods();
allowGraphInference = source.allowGraphInference();
+ annotate = Annotate.instance(context);
}
/** A hashtable mapping bridge methods to the methods they override after
@@ -751,6 +754,15 @@
result = tree;
}
+ public void visitAnnotatedType(JCAnnotatedType tree) {
+ // For now, we need to keep the annotations in the tree because of the current
+ // MultiCatch implementation wrt type annotations
+ List<TypeCompound> mirrors = annotate.fromAnnotations(tree.annotations);
+ tree.underlyingType = translate(tree.underlyingType);
+ tree.type = tree.underlyingType.type.annotatedType(mirrors);
+ result = tree;
+ }
+
public void visitTypeCast(JCTypeCast tree) {
tree.clazz = translate(tree.clazz, null);
Type originalTarget = tree.type;
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java Thu Apr 09 06:40:21 2015 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java Thu Apr 09 17:37:46 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -36,6 +36,7 @@
import com.sun.tools.javac.code.Scope.NamedImportScope;
import com.sun.tools.javac.code.Scope.StarImportScope;
import com.sun.tools.javac.code.Scope.WriteableScope;
+import com.sun.tools.javac.comp.Annotate.AnnotationTypeMetadata;
import com.sun.tools.javac.tree.*;
import com.sun.tools.javac.util.*;
import com.sun.tools.javac.util.DefinedBy.Api;
@@ -135,6 +136,7 @@
lint = Lint.instance(context);
typeEnvs = TypeEnvs.instance(context);
dependencies = Dependencies.instance(context);
+ Source source = Source.instance(context);
allowTypeAnnos = source.allowTypeAnnotations();
allowDeprecationOnImport = source.allowDeprecationOnImport();
}
@@ -164,7 +166,7 @@
Env<AttrContext> topEnv = enter.topLevelEnv(tree);
finishImports(tree, () -> { completeClass.resolveImports(tree, topEnv); });
}
- }
+ }
}
/* ********************************************************************
@@ -184,7 +186,7 @@
}
try {
- annotate.enterStart();
+ annotate.blockAnnotations();
sym.flags_field |= UNATTRIBUTED;
List<Env<AttrContext>> queue;
@@ -206,7 +208,7 @@
}
}
} finally {
- annotate.enterDone();
+ annotate.unblockAnnotations();
}
}
@@ -780,9 +782,9 @@
Env<AttrContext> baseEnv = baseEnv(tree, env);
if (tree.extending != null)
- annotate.annotateTypeLater(tree.extending, baseEnv, sym, tree.pos());
+ annotate.queueScanTreeAndTypeAnnotate(tree.extending, baseEnv, sym, tree.pos());
for (JCExpression impl : tree.implementing)
- annotate.annotateTypeLater(impl, baseEnv, sym, tree.pos());
+ annotate.queueScanTreeAndTypeAnnotate(impl, baseEnv, sym, tree.pos());
annotate.flush();
attribSuperTypes(env, baseEnv);
@@ -800,7 +802,7 @@
attr.attribTypeVariables(tree.typarams, baseEnv);
for (JCTypeParameter tp : tree.typarams)
- annotate.annotateTypeLater(tp, baseEnv, sym, tree.pos());
+ annotate.queueScanTreeAndTypeAnnotate(tp, baseEnv, sym, tree.pos());
// check that no package exists with same fully qualified name,
// but admit classes in the unnamed package which have the same
@@ -899,6 +901,11 @@
addEnumMembers(tree, env);
}
memberEnter.memberEnter(tree.defs, env);
+
+ if (tree.sym.isAnnotationType()) {
+ Assert.checkNull(tree.sym.completer);
+ tree.sym.setAnnotationTypeMetadata(new AnnotationTypeMetadata(tree.sym, annotate.annotationTypeSourceCompleter()));
+ }
}
/** Add the implicit members for an enum type
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java Thu Apr 09 06:40:21 2015 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java Thu Apr 09 17:37:46 2015 -0700
@@ -36,17 +36,17 @@
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
-
import javax.tools.JavaFileManager;
import javax.tools.JavaFileObject;
-
+import com.sun.tools.javac.comp.Annotate;
+import com.sun.tools.javac.comp.Annotate.AnnotationTypeCompleter;
import com.sun.tools.javac.code.*;
import com.sun.tools.javac.code.Lint.LintCategory;
import com.sun.tools.javac.code.Scope.WriteableScope;
import com.sun.tools.javac.code.Symbol.*;
import com.sun.tools.javac.code.Symtab;
import com.sun.tools.javac.code.Type.*;
-import com.sun.tools.javac.comp.Annotate;
+import com.sun.tools.javac.comp.Annotate.AnnotationTypeMetadata;
import com.sun.tools.javac.file.BaseFileObject;
import com.sun.tools.javac.jvm.ClassFile.NameAndType;
import com.sun.tools.javac.jvm.ClassFile.Version;
@@ -81,7 +81,7 @@
public static final int INITIAL_BUFFER_SIZE = 0x0fff0;
- Annotate annotate;
+ private final Annotate annotate;
/** Switch: verbose output.
*/
@@ -190,6 +190,18 @@
*/
Set<Name> warnedAttrs = new HashSet<>();
+ /**
+ * The prototype @Target Attribute.Compound if this class is an annotation annotated with
+ * @Target
+ */
+ CompoundAnnotationProxy target;
+
+ /**
+ * The prototype @Repetable Attribute.Compound if this class is an annotation annotated with
+ * @Repeatable
+ */
+ CompoundAnnotationProxy repeatable;
+
/** Get the ClassReader instance for this invocation. */
public static ClassReader instance(Context context) {
ClassReader instance = context.get(classReaderKey);
@@ -201,6 +213,7 @@
/** Construct a new class reader. */
protected ClassReader(Context context) {
context.put(classReaderKey, this);
+ annotate = Annotate.instance(context);
names = Names.instance(context);
syms = Symtab.instance(context);
types = Types.instance(context);
@@ -212,9 +225,8 @@
log = Log.instance(context);
Options options = Options.instance(context);
- annotate = Annotate.instance(context);
- verbose = options.isSet(VERBOSE);
- checkClassFile = options.isSet("-checkclassfile");
+ verbose = options.isSet(VERBOSE);
+ checkClassFile = options.isSet("-checkclassfile");
Source source = Source.instance(context);
allowSimplifiedVarargs = source.allowSimplifiedVarargs();
@@ -1304,6 +1316,13 @@
ListBuffer<CompoundAnnotationProxy> proxies = new ListBuffer<>();
for (int i = 0; i<numAttributes; i++) {
CompoundAnnotationProxy proxy = readCompoundAnnotation();
+
+ if (proxy.type.tsym == syms.annotationTargetType.tsym) {
+ target = proxy;
+ } else if (proxy.type.tsym == syms.repeatableType.tsym) {
+ repeatable = proxy;
+ }
+
proxies.append(proxy);
}
annotate.normal(new AnnotationCompleter(sym, proxies.toList()));
@@ -1705,8 +1724,11 @@
}
class AnnotationDeproxy implements ProxyVisitor {
- private ClassSymbol requestingOwner = currentOwner.kind == MTH
- ? currentOwner.enclClass() : (ClassSymbol)currentOwner;
+ private ClassSymbol requestingOwner;
+
+ AnnotationDeproxy(ClassSymbol owner) {
+ this.requestingOwner = owner;
+ }
List<Attribute.Compound> deproxyCompoundList(List<CompoundAnnotationProxy> pl) {
// also must fill in types!!!!
@@ -1855,19 +1877,19 @@
}
}
- class AnnotationDefaultCompleter extends AnnotationDeproxy implements Annotate.Worker {
+ class AnnotationDefaultCompleter extends AnnotationDeproxy implements Runnable {
final MethodSymbol sym;
final Attribute value;
final JavaFileObject classFile = currentClassFile;
- @Override
- public String toString() {
- return " ClassReader store default for " + sym.owner + "." + sym + " is " + value;
- }
+
AnnotationDefaultCompleter(MethodSymbol sym, Attribute value) {
+ super(currentOwner.kind == MTH
+ ? currentOwner.enclClass() : (ClassSymbol)currentOwner);
this.sym = sym;
this.value = value;
}
- // implement Annotate.Worker.run()
+
+ @Override
public void run() {
JavaFileObject previousClassFile = currentClassFile;
try {
@@ -1880,22 +1902,27 @@
currentClassFile = previousClassFile;
}
}
+
+ @Override
+ public String toString() {
+ return " ClassReader store default for " + sym.owner + "." + sym + " is " + value;
+ }
}
- class AnnotationCompleter extends AnnotationDeproxy implements Annotate.Worker {
+ class AnnotationCompleter extends AnnotationDeproxy implements Runnable {
final Symbol sym;
final List<CompoundAnnotationProxy> l;
final JavaFileObject classFile;
- @Override
- public String toString() {
- return " ClassReader annotate " + sym.owner + "." + sym + " with " + l;
- }
+
AnnotationCompleter(Symbol sym, List<CompoundAnnotationProxy> l) {
+ super(currentOwner.kind == MTH
+ ? currentOwner.enclClass() : (ClassSymbol)currentOwner);
this.sym = sym;
this.l = l;
this.classFile = currentClassFile;
}
- // implement Annotate.Worker.run()
+
+ @Override
public void run() {
JavaFileObject previousClassFile = currentClassFile;
try {
@@ -1910,6 +1937,11 @@
currentClassFile = previousClassFile;
}
}
+
+ @Override
+ public String toString() {
+ return " ClassReader annotate " + sym.owner + "." + sym + " with " + l;
+ }
}
class TypeAnnotationCompleter extends AnnotationCompleter {
@@ -2298,6 +2330,8 @@
currentClassFile = c.classfile;
warnedAttrs.clear();
filling = true;
+ target = null;
+ repeatable = null;
try {
bp = 0;
buf = readInputStream(buf, c.classfile.openInputStream());
@@ -2318,6 +2352,12 @@
Name name = missingTypeVariables.head.tsym.name;
throw badClassFile("undecl.type.var", name);
}
+
+ if ((c.flags_field & Flags.ANNOTATION) != 0) {
+ c.setAnnotationTypeMetadata(new AnnotationTypeMetadata(c, new CompleterDeproxy(c, target, repeatable)));
+ } else {
+ c.setAnnotationTypeMetadata(AnnotationTypeMetadata.notAnAnnotationType());
+ }
} catch (IOException ex) {
throw badClassFile("unable.to.access.file", ex.getMessage());
} catch (ArrayIndexOutOfBoundsException ex) {
@@ -2515,4 +2555,42 @@
return name.hashCode();
}
}
+
+ private class CompleterDeproxy implements AnnotationTypeCompleter {
+ ClassSymbol proxyOn;
+ CompoundAnnotationProxy target;
+ CompoundAnnotationProxy repeatable;
+
+ public CompleterDeproxy(ClassSymbol c, CompoundAnnotationProxy target,
+ CompoundAnnotationProxy repeatable)
+ {
+ this.proxyOn = c;
+ this.target = target;
+ this.repeatable = repeatable;
+ }
+
+ @Override
+ public void complete(ClassSymbol sym) {
+ Assert.check(proxyOn == sym);
+ Attribute.Compound theTarget = null, theRepeatable = null;
+ AnnotationDeproxy deproxy;
+
+ try {
+ if (target != null) {
+ deproxy = new AnnotationDeproxy(proxyOn);
+ theTarget = deproxy.deproxyCompound(target);
+ }
+
+ if (repeatable != null) {
+ deproxy = new AnnotationDeproxy(proxyOn);
+ theRepeatable = deproxy.deproxyCompound(repeatable);
+ }
+ } catch (Exception e) {
+ throw new CompletionFailure(sym, e.getMessage());
+ }
+
+ sym.getAnnotationTypeMetadata().setTarget(theTarget);
+ sym.getAnnotationTypeMetadata().setRepeatable(theRepeatable);
+ }
+ }
}
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java Thu Apr 09 06:40:21 2015 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java Thu Apr 09 17:37:46 2015 -0700
@@ -75,6 +75,7 @@
private final Types types;
private final Lower lower;
private final Flow flow;
+ private final Annotate annotate;
/** Format of stackmap tables to be generated. */
private final Code.StackMapFormat stackMap;
@@ -142,6 +143,7 @@
}
this.jsrlimit = setjsrlimit;
this.useJsrLocally = false; // reset in visitTry
+ annotate = Annotate.instance(context);
}
/** Switches
@@ -1468,21 +1470,18 @@
int startpc, int endpc,
List<Integer> gaps) {
if (startpc != endpc) {
- List<JCExpression> subClauses = TreeInfo.isMultiCatch(tree) ?
- ((JCTypeUnion)tree.param.vartype).alternatives :
- List.of(tree.param.vartype);
+ List<Pair<List<Attribute.TypeCompound>, JCExpression>> catchTypeExprs
+ = catchTypesWithAnnotations(tree);
while (gaps.nonEmpty()) {
- for (JCExpression subCatch : subClauses) {
+ for (Pair<List<Attribute.TypeCompound>, JCExpression> subCatch1 : catchTypeExprs) {
+ JCExpression subCatch = subCatch1.snd;
int catchType = makeRef(tree.pos(), subCatch.type);
int end = gaps.head.intValue();
registerCatch(tree.pos(),
startpc, end, code.curCP(),
catchType);
- if (subCatch.type.isAnnotated()) {
- for (Attribute.TypeCompound tc :
- subCatch.type.getAnnotationMirrors()) {
+ for (Attribute.TypeCompound tc : subCatch1.fst) {
tc.position.setCatchInfo(catchType, startpc);
- }
}
}
gaps = gaps.tail;
@@ -1490,16 +1489,14 @@
gaps = gaps.tail;
}
if (startpc < endpc) {
- for (JCExpression subCatch : subClauses) {
+ for (Pair<List<Attribute.TypeCompound>, JCExpression> subCatch1 : catchTypeExprs) {
+ JCExpression subCatch = subCatch1.snd;
int catchType = makeRef(tree.pos(), subCatch.type);
registerCatch(tree.pos(),
startpc, endpc, code.curCP(),
catchType);
- if (subCatch.type.isAnnotated()) {
- for (Attribute.TypeCompound tc :
- subCatch.type.getAnnotationMirrors()) {
- tc.position.setCatchInfo(catchType, startpc);
- }
+ for (Attribute.TypeCompound tc : subCatch1.fst) {
+ tc.position.setCatchInfo(catchType, startpc);
}
}
}
@@ -1507,7 +1504,7 @@
code.statBegin(tree.pos);
code.markStatBegin();
int limit = code.nextreg;
- int exlocal = code.newLocal(exparam);
+ code.newLocal(exparam);
items.makeLocalItem(exparam).store();
code.statBegin(TreeInfo.firstStatPos(tree.body));
genStat(tree.body, env, CRT_BLOCK);
@@ -1515,6 +1512,30 @@
code.statBegin(TreeInfo.endPos(tree.body));
}
}
+ // where
+ List<Pair<List<Attribute.TypeCompound>, JCExpression>> catchTypesWithAnnotations(JCCatch tree) {
+ return TreeInfo.isMultiCatch(tree) ?
+ catchTypesWithAnnotationsFromMulticatch((JCTypeUnion)tree.param.vartype, tree.param.sym.getRawTypeAttributes()) :
+ List.of(new Pair<>(tree.param.sym.getRawTypeAttributes(), tree.param.vartype));
+ }
+ // where
+ List<Pair<List<Attribute.TypeCompound>, JCExpression>> catchTypesWithAnnotationsFromMulticatch(JCTypeUnion tree, List<TypeCompound> first) {
+ List<JCExpression> alts = tree.alternatives;
+ List<Pair<List<TypeCompound>, JCExpression>> res = List.of(new Pair<>(first, alts.head));
+ alts = alts.tail;
+
+ while(alts != null && alts.head != null) {
+ JCExpression alt = alts.head;
+ if (alt instanceof JCAnnotatedType) {
+ JCAnnotatedType a = (JCAnnotatedType)alt;
+ res = res.prepend(new Pair<>(annotate.fromAnnotations(a.annotations), alt));
+ } else {
+ res = res.prepend(new Pair<>(List.nil(), alt));
+ }
+ alts = alts.tail;
+ }
+ return res.reverse();
+ }
/** Register a catch clause in the "Exceptions" code-attribute.
*/
@@ -2052,7 +2073,7 @@
code.emitop2(new_, makeRef(pos, stringBufferType));
code.emitop0(dup);
callMethod(
- pos, stringBufferType, names.init, List.<Type>nil(), false);
+ pos, stringBufferType, names.init, List.<Type>nil(), false);
}
/** Append value (on tos) to string buffer (on tos - 1).
@@ -2100,11 +2121,11 @@
*/
void bufferToString(DiagnosticPosition pos) {
callMethod(
- pos,
- stringBufferType,
- names.toString,
- List.<Type>nil(),
- false);
+ pos,
+ stringBufferType,
+ names.toString,
+ List.<Type>nil(),
+ false);
}
/** Complete generating code for operation, with left operand
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/UninitializedType.java Thu Apr 09 06:40:21 2015 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/UninitializedType.java Thu Apr 09 17:37:46 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -59,7 +59,7 @@
}
@Override
- public UninitializedType clone(final TypeMetadata md) {
+ public UninitializedType cloneWithMetadata(final TypeMetadata md) {
return new UninitializedType(tag, qtype, offset, md);
}
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacTypes.java Thu Apr 09 06:40:21 2015 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacTypes.java Thu Apr 09 17:37:46 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -25,11 +25,13 @@
package com.sun.tools.javac.model;
+import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
+import java.util.stream.Collectors;
import javax.lang.model.element.*;
import javax.lang.model.type.*;
@@ -115,14 +117,17 @@
@DefinedBy(Api.LANGUAGE_MODEL)
public List<Type> directSupertypes(TypeMirror t) {
validateTypeNotIn(t, EXEC_OR_PKG);
- return types.directSupertypes((Type) t);
+ Type ty = (Type)t;
+ return types.directSupertypes(ty).stream()
+ .map(Type::stripMetadataIfNeeded)
+ .collect(Collectors.toList());
}
@DefinedBy(Api.LANGUAGE_MODEL)
public TypeMirror erasure(TypeMirror t) {
if (t.getKind() == TypeKind.PACKAGE)
throw new IllegalArgumentException(t.toString());
- return types.erasure((Type) t);
+ return types.erasure((Type)t).stripMetadataIfNeeded();
}
@DefinedBy(Api.LANGUAGE_MODEL)
@@ -143,7 +148,7 @@
@DefinedBy(Api.LANGUAGE_MODEL)
public TypeMirror capture(TypeMirror t) {
validateTypeNotIn(t, EXEC_OR_PKG);
- return types.capture((Type) t);
+ return types.capture((Type)t).stripMetadataIfNeeded();
}
@DefinedBy(Api.LANGUAGE_MODEL)
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java Thu Apr 09 06:40:21 2015 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java Thu Apr 09 17:37:46 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -34,8 +34,6 @@
import javax.tools.JavaFileObject;
import com.sun.source.tree.*;
-import com.sun.source.tree.LambdaExpressionTree.BodyKind;
-import com.sun.source.tree.MemberReferenceTree.ReferenceMode;
import com.sun.tools.javac.code.*;
import com.sun.tools.javac.code.Scope.*;
import com.sun.tools.javac.code.Symbol.*;
@@ -2502,12 +2500,6 @@
public JCTree annotationType;
public List<JCExpression> args;
-
- // Attribute.Compound if tag is ANNOTATION
- // Attribute.TypeCompound if tag is TYPE_ANNOTATION
- //
- // NOTE: This field is slated for removal in the future. Do
- // not use it for anything new.
public Attribute.Compound attribute;
protected JCAnnotation(Tag tag, JCTree annotationType, List<JCExpression> args) {
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/RichDiagnosticFormatter.java Thu Apr 09 06:40:21 2015 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/RichDiagnosticFormatter.java Thu Apr 09 17:37:46 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -234,6 +234,8 @@
}
private boolean unique(TypeVar typevar) {
+ typevar = (TypeVar)typevar.stripMetadataIfNeeded();
+
int found = 0;
for (Type t : whereClauses.get(WhereClauseKind.TYPEVAR).keySet()) {
if (t.toString().equals(typevar.toString())) {
@@ -542,6 +544,7 @@
@Override
public Void visitTypeVar(TypeVar t, Void ignored) {
+ t = (TypeVar)t.stripMetadataIfNeeded();
if (indexOf(t, WhereClauseKind.TYPEVAR) == -1) {
//access the bound type and skip error types
Type bound = t.bound;
--- a/langtools/test/tools/javac/annotations/typeAnnotations/api/AnnotatedArrayOrder.java Thu Apr 09 06:40:21 2015 -0700
+++ b/langtools/test/tools/javac/annotations/typeAnnotations/api/AnnotatedArrayOrder.java Thu Apr 09 17:37:46 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -23,6 +23,7 @@
/*
* @test
+ * @bug 8031744
* @summary Checks the annotation types targeting array types
*/
@@ -34,7 +35,6 @@
import java.util.Map;
import java.util.HashMap;
import java.lang.annotation.*;
-import javax.tools.JavaFileManager;
import javax.tools.JavaFileObject;
import com.sun.source.tree.*;
import com.sun.source.util.JavacTask;
--- a/langtools/test/tools/javac/annotations/typeAnnotations/newlocations/BasicTest.java Thu Apr 09 06:40:21 2015 -0700
+++ b/langtools/test/tools/javac/annotations/typeAnnotations/newlocations/BasicTest.java Thu Apr 09 17:37:46 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -23,7 +23,7 @@
/*
* @test
- * @bug 6843077 8006775
+ * @bug 6843077 8006775 8031744
* @summary random tests for new locations
* @author Matt Papi
* @compile BasicTest.java
@@ -41,12 +41,16 @@
@interface C {}
@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
@interface D {}
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@interface E {}
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@interface F {}
/**
* Tests basic JSR 308 parser functionality. We don't really care about what
* the parse tree looks like, just that these annotations can be parsed.
*/
-class BasicTest<T extends @A Object> extends @B LinkedList<T> implements @C List<T> {
+class BasicTest<@D T extends @A Object> extends @B LinkedList<@E T> implements @C List<@F T> {
void test() {
--- a/langtools/test/tools/javac/lib/DPrinter.java Thu Apr 09 06:40:21 2015 -0700
+++ b/langtools/test/tools/javac/lib/DPrinter.java Thu Apr 09 17:37:46 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -477,7 +477,7 @@
out.print(label);
out.println(": " +
info(sym.getClass(),
- String.format("0x%x--%s", sym.kind, Kinds.kindName(sym)),
+ String.format("0x%x--%s", sym.kind.ordinal(), Kinds.kindName(sym)),
sym.getKind())
+ " " + sym.name
+ " " + hashString(sym));
--- a/langtools/test/tools/javac/processing/model/type/BasicAnnoTests.java Thu Apr 09 06:40:21 2015 -0700
+++ b/langtools/test/tools/javac/processing/model/type/BasicAnnoTests.java Thu Apr 09 17:37:46 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -23,21 +23,27 @@
/*
* @test
- * @bug 8013852
+ * @bug 8013852 8031744
* @summary Annotations on types
* @library /tools/javac/lib
- * @ignore 8057688 type annotations in type argument position are lost
- * @ignore 8031744 Annotations on many Language Model elements are not returned
* @build JavacTestingAbstractProcessor DPrinter BasicAnnoTests
* @compile/process -processor BasicAnnoTests -proc:only BasicAnnoTests.java
*/
import java.io.PrintWriter;
+import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.annotation.ElementType;
+import java.lang.annotation.Repeatable;
import java.lang.annotation.Target;
+import java.util.ArrayList;
+
+import java.util.HashSet;
+import java.util.List;
import java.util.Map;
+import java.util.NavigableMap;
import java.util.Set;
+import java.util.TreeMap;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
@@ -48,15 +54,23 @@
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.ArrayType;
+import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.ExecutableType;
+import javax.lang.model.type.IntersectionType;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.type.TypeVariable;
import javax.lang.model.type.WildcardType;
+import javax.lang.model.util.Types;
import javax.tools.Diagnostic.Kind;
+import com.sun.tools.javac.code.Attribute;
import com.sun.tools.javac.code.Symbol;
-import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.processing.JavacProcessingEnvironment;
+import com.sun.tools.javac.util.Name;
+
+import static com.sun.tools.javac.code.Attribute.Array;
+import static com.sun.tools.javac.code.Attribute.Constant;
+import static com.sun.tools.javac.code.Attribute.Compound;
/**
* The test scans this file looking for test cases annotated with @Test.
@@ -77,7 +91,7 @@
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
TestElementScanner s = new TestElementScanner();
for (Element e: roundEnv.getRootElements()) {
- s.scan(e);
+ s.scan(e, null);
}
return true;
}
@@ -95,17 +109,17 @@
*/
class TestElementScanner extends ElementScanner<Void,Void> {
public Void scan(Element elem, Void ignore) {
+ List<AnnotationMirror> tests = new ArrayList<>();
AnnotationMirror test = getAnnotation(elem, Test.class.getName().replace('$', '.'));
if (test != null) {
+ tests.add(test);
+ }
+ tests.addAll(getAnnotations(elem, Tests.class.getName().replace('$', '.')));
+
+ if (tests.size() > 0) {
out.println("Test: " + elem + " " + test);
- TestTypeScanner s = new TestTypeScanner(elem, test);
- s.scan(elem.asType(), null);
- if (getPosn(test) >= s.count)
- error(elem, "position " + getPosn(test) + " not found");
- if (!s.found) {
- dprinter.printSymbol("element", (Symbol) elem);
- dprinter.printType("type", (Type) elem.asType());
- }
+ TestTypeScanner s = new TestTypeScanner(elem, tests, types);
+ s.test(elem.asType());
out.println();
}
return super.scan(elem, ignore);
@@ -118,45 +132,110 @@
*/
class TestTypeScanner extends TypeScanner<Void, Void> {
Element elem;
- AnnotationMirror test;
+ NavigableMap<Integer, AnnotationMirror> toBeFound;
int count = 0;
- boolean found = false;
+ Set<TypeMirror> seen = new HashSet<>();
+
+ TestTypeScanner(Element elem, List<AnnotationMirror> tests, Types types) {
+ super(types);
+ this.elem = elem;
- TestTypeScanner(Element elem, AnnotationMirror test) {
- this.elem = elem;
- this.test = test;
+ NavigableMap<Integer, AnnotationMirror> testByPos = new TreeMap<>();
+ for (AnnotationMirror test : tests) {
+ for (int pos : getPosn(test)) {
+ testByPos.put(pos, test);
+ }
+ }
+ this.toBeFound = testByPos;
+ }
+
+ public void test(TypeMirror t) {
+ scan(t, null);
}
@Override
Void scan(TypeMirror t, Void ignore) {
if (t == null)
return DEFAULT_VALUE;
- if (verbose)
- out.println("scan " + count + ": " + t);
- if (count == getPosn(test)) {
- String annoType = getAnnoType(test);
- AnnotationMirror anno = getAnnotation(t, annoType);
- if (anno == null) {
- error(elem, "annotation not found on " + count + ": " + t);
- } else {
- String v = getValue(anno, "value").toString();
- if (v.equals(getExpect(test))) {
- out.println("found " + anno + " as expected");
- found = true;
+
+ if (!seen.contains(t)) {
+ try {
+ seen.add(t);
+ if (verbose)
+ out.println("scan " + count + ": " + t);
+ if (toBeFound.size() > 0) {
+ if (toBeFound.firstKey().equals(count)) {
+ AnnotationMirror test = toBeFound.pollFirstEntry().getValue();
+ String annoType = getAnnoType(test);
+ AnnotationMirror anno = getAnnotation(t, annoType);
+ if (anno == null) {
+ error(elem, "annotation not found on " + count + ": " + t);
+ } else {
+ String v = getValue(anno, "value").toString();
+ if (v.equals(getExpect(test))) {
+ out.println("found " + anno + " as expected");
+ } else {
+ error(elem, "Unexpected value: " + v + ", expected: " + getExpect(test));
+ }
+ }
+ } else if (count > toBeFound.firstKey()) {
+ rescue();
+ } else {
+ List<? extends AnnotationMirror> annos = t.getAnnotationMirrors();
+ if (annos.size() > 0) {
+ for (AnnotationMirror a : annos)
+ error(elem, "annotation " + a + " found on " + count + ": " + t);
+ }
+ }
} else {
- error(elem, "Unexpected value: " + v + ", expected: " + getExpect(test));
+ List<? extends AnnotationMirror> annos = t.getAnnotationMirrors();
+ if (annos.size() > 0) {
+ for (AnnotationMirror a : annos)
+ error(elem, "annotation " + a + " found on " + count + ": " + t);
+ }
}
+ count++;
+ return super.scan(t, ignore);
+
+ } finally {
+ seen.remove(t);
}
}
- count++;
- return super.scan(t, ignore);
+
+ return DEFAULT_VALUE;
+
+ }
+
+ private void rescue() {
+ while (toBeFound.size() > 0 && toBeFound.firstKey() >= count)
+ toBeFound.pollFirstEntry();
}
}
- /** Get the position value from an @Test annotation mirror. */
- static int getPosn(AnnotationMirror test) {
+ /** Get the position value from an element annotated with a @Test annotation mirror. */
+ static int[] getPosn(Element elem) {
+ return elem.getAnnotation(Test.class).posn();
+ }
+
+ /** Get the position value from a @Test annotation mirror. */
+ static Integer[] getPosn(AnnotationMirror test) {
AnnotationValue v = getValue(test, "posn");
- return (Integer) v.getValue();
+ Object value = v.getValue();
+ Integer i = 0;
+ if (value instanceof Constant) {
+ i = (Integer)((Constant)value).getValue();
+ Integer[] res = new Integer[1];
+ res[0] = i;
+ return res;
+ } else if (value instanceof List) {
+ List<Constant> l = (List<Constant>)value;
+ Integer[] res = new Integer[l.size()];
+ for (int c = 0; c < l.size(); c++) {
+ res[c] = (Integer)l.get(c).getValue();
+ }
+ return res;
+ }
+ return null;
}
/** Get the expect value from an @Test annotation mirror. */
@@ -185,6 +264,25 @@
return null;
}
+ static List<AnnotationMirror> getAnnotations(Element e, String name) {
+ Name valueName = ((Symbol)e).getSimpleName().table.names.value;
+ List<AnnotationMirror> res = new ArrayList<>();
+
+ for (AnnotationMirror m : e.getAnnotationMirrors()) {
+ TypeElement te = (TypeElement) m.getAnnotationType().asElement();
+ if (te.getQualifiedName().contentEquals(name)) {
+ Compound theAnno = (Compound)m;
+ Array valueArray = (Array)theAnno.member(valueName);
+ for (Attribute a : valueArray.getValue()) {
+ AnnotationMirror theMirror = (AnnotationMirror) a;
+
+ res.add(theMirror);
+ }
+ }
+ }
+ return res;
+ }
+
/**
* Get a specific value from an annotation mirror.
*/
@@ -203,6 +301,13 @@
* one sufficient for our needs.
*/
static class TypeScanner<R, P> extends SimpleTypeVisitor<R, P> {
+ private Types types;
+
+ public TypeScanner(Types types) {
+ super();
+ this.types = types;
+ }
+
@Override
public R visitArray(ArrayType t, P p) {
scan(t.getComponentType(), p);
@@ -211,17 +316,34 @@
@Override
public R visitExecutable(ExecutableType t, P p) {
+ //out.println(" type parameters: " + t.getTypeVariables());
+ scan(t.getTypeVariables(), p);
+ //out.println(" return: " + t.getReturnType());
+ scan(t.getReturnType(), p);
+ //out.println(" receiver: " + t.getReceiverTypes());
scan(t.getReceiverType());
//out.println(" params: " + t.getParameterTypes());
scan(t.getParameterTypes(), p);
- //out.println(" return: " + t.getReturnType());
- scan(t.getReturnType(), p);
//out.println(" throws: " + t.getThrownTypes());
scan(t.getThrownTypes(), p);
return super.visitExecutable(t, p);
}
@Override
+ public R visitDeclared(DeclaredType t, P p) {
+ scan(t.getTypeArguments(), p);
+ // don't scan enclosing
+ scan(types.directSupertypes(t), p);
+ return super.visitDeclared(t, p);
+ }
+
+ @Override
+ public R visitIntersection(IntersectionType t, P p) {
+ scan(t.getBounds(), p);
+ return super.visitIntersection(t, p);
+ }
+
+ @Override
public R visitTypeVariable(TypeVariable t, P p) {
scan(t.getLowerBound(), p);
scan(t.getUpperBound(), p);
@@ -254,36 +376,194 @@
}
/** Annotation to identify test cases. */
+ @Repeatable(Tests.class)
@interface Test {
/** Where to look for the annotation, expressed as a scan index. */
- int posn();
+ int[] posn();
/** The annotation to look for. */
Class<? extends Annotation> annoType();
/** The string representation of the annotation's value. */
String expect();
}
+ @interface Tests {
+ Test[] value();
+ }
+
/** Type annotation to use in test cases. */
@Target(ElementType.TYPE_USE)
public @interface TA {
int value();
}
+ @Target(ElementType.TYPE_USE)
+ public @interface TB {
+ int value();
+ }
+
+ // Test cases
+
+ // TODO: add more cases for arrays
+ // all annotated
+ // all but one annotated
+ // vary position of one not annotated
+ // only one annotated
+ // vary position of one annotated
+ // the three above with the corner case of the ambiguos decl + type anno added
@Test(posn=0, annoType=TA.class, expect="1")
public @TA(1) int f1;
+ @Test(posn=0, annoType=TA.class, expect="11")
+ @TA(11) public int f11;
+
+ @Test(posn=1, annoType=TA.class, expect="111")
+ @TA(111) public int [] f111;
+
+ @Test(posn=1, annoType=TA.class, expect="1120")
+ @Test(posn=0, annoType=TB.class, expect="1121")
+ @TA(1120) public int @TB(1121) [] f112;
+
+ @Test(posn=0, annoType=TB.class, expect="11211")
+ @Test(posn=1, annoType=TA.class, expect="11200")
+ public @TA(11200) int @TB(11211) [] f112b;
+
+ @Test(posn=1, annoType=TB.class, expect="1131")
+ @Test(posn=2, annoType=TA.class, expect="1130")
+ @TA(1130) public int [] @TB(1131) [] f113;
+
+ @Test(posn=5, annoType=TA.class, expect="12")
+ public @TA(12) int [] [] [] [] [] f12;
+
+ @Test(posn=6, annoType=TA.class, expect="13")
+ public @TA(13) int [] [] [] [] [] [] f13;
+
+ @Test(posn=7, annoType=TA.class, expect="14")
+ @TA(14) public int [] [] [] [] [] [] [] f14;
+
+ @Test(posn=6, annoType=TA.class, expect="150")
+ @Test(posn=7, annoType=TB.class, expect="151")
+ @TB(151) public int [] [] [] [] [] [] @TA(150) [] f15;
+
+ @Test(posn=0, annoType=TB.class, expect="1511")
+ @Test(posn=3, annoType=TA.class, expect="1512")
+ @Test(posn=6, annoType=TA.class, expect="150")
+ @Test(posn=7, annoType=TB.class, expect="151")
+ @TB(151) public int @TB(1511) [] [] [] @TA(1512) [] [] [] @TA(150) [] f15b;
+
+ @Test(posn=0, annoType=TB.class, expect="1521")
+ @Test(posn=3, annoType=TA.class, expect="1522")
+ @Test(posn=6, annoType=TA.class, expect="152")
+ public int @TB(1521) [] [] [] @TA(1522) [] [] [] @TA(152) [] f15c;
+
+ @Test(posn=5, annoType=TA.class, expect="160")
+ @Test(posn=6, annoType=TB.class, expect="161")
+ public int [] [] [] [] [] @TA(160) [] @TB(161) [] f16;
+
@Test(posn=0, annoType=TA.class, expect="2")
public int @TA(2) [] f2;
+ @Test(posn=0, annoType=TB.class, expect="33")
@Test(posn=1, annoType=TA.class, expect="3")
- public @TA(3) int [] f3;
+ public @TA(3) int @TB(33) [] f3;
- @Test(posn=1, annoType=TA.class, expect="4")
+ @Test(posn=2, annoType=TA.class, expect="4")
public int m1(@TA(4) float a) throws Exception { return 0; }
- @Test(posn=2, annoType=TA.class, expect="5")
+ @Test(posn=1, annoType=TA.class, expect="5")
public @TA(5) int m2(float a) throws Exception { return 0; }
@Test(posn=3, annoType=TA.class, expect="6")
public int m3(float a) throws @TA(6) Exception { return 0; }
+
+ // Also tests that a decl anno on a typevar doesn't show up on the Type
+ @Test(posn=7, annoType=TA.class, expect="8")
+ public <@TA(7) M> M m4(@TA(8) float a) throws Exception { return null; }
+
+ // Also tests that a decl anno on a typevar doesn't show up on the Type
+ @Test(posn=4, annoType=TA.class, expect="10")
+ public class Inner1<@TA(9) S> extends @TA(10) Object implements Cloneable {}
+
+ // Also tests that a decl anno on a typevar doesn't show up on the Type
+ @Test(posn=5, annoType=TA.class, expect="12")
+ public class Inner2<@TA(11) S> extends Object implements @TA(12) Cloneable {}
+
+ @Test(posn={3,6}, annoType=TA.class, expect="13")
+ public <M extends @TA(13) Object> M m5(float a) { return null; }
+
+ @Test(posn=3, annoType=TA.class, expect="14")
+ public class Inner3<QQQ extends @TA(14) Map> {}
+
+ @Test(posn=4, annoType=TA.class, expect="15")
+ public class Inner4<T extends @TA(15) Object & Cloneable & Serializable> {}
+
+ @Test(posn=5, annoType=TA.class, expect="16")
+ public class Inner5<T extends Object & @TA(16) Cloneable & Serializable> {}
+
+ @Test(posn=7, annoType=TA.class, expect="17")
+ public class Inner6<T extends Object & Cloneable & @TA(17) Serializable> {}
+
+ // Test annotated bounds
+
+ @Test(posn=1, annoType=TA.class, expect="18")
+ public Set<@TA(18) ? extends Object> f4;
+
+ @Test(posn=2, annoType=TA.class, expect="19")
+ public Set<? extends @TA(19) Object> f5;
+
+ @Test(posn=3, annoType=TA.class, expect="20")
+ public Set<? extends Set<@TA(20) ? extends Object>> f6;
+
+ @Test(posn=4, annoType=TA.class, expect="21")
+ public Set<? extends Set<? extends @TA(21) Object>> f7;
+
+ @Test(posn=1, annoType=TA.class, expect="22")
+ public Set<@TA(22) ?> f8;
+
+ @Test(posn=1, annoType=TA.class, expect="23")
+ public Set<@TA(23) ? super Object> f9;
+
+ // Test type use annotations on uses of type variables
+ @Test(posn=5, annoType = TA.class, expect = "25")
+ @Test(posn=5, annoType = TB.class, expect = "26")
+ <T> void m6(@TA(25) @TB(26) T t) { }
+
+ class Inner7<T> {
+ @Test(posn=0, annoType = TA.class, expect = "30")
+ @Test(posn=0, annoType = TB.class, expect = "31")
+ @TA(30) @TB(31) T f;
+ }
+
+ // Test type use annotations on uses of type variables
+ @Test(posn=5, annoType = TB.class, expect = "41")
+ <@TA(40) T> void m7(@TB(41) T t) { }
+
+ class Inner8<@TA(50) T> {
+ @Test(posn=0, annoType = TB.class, expect = "51")
+ @TB(51) T f;
+ }
+
+ // Test type use annotations on uses of Class types
+ @Test(posn=5, annoType = TA.class, expect = "60")
+ @Test(posn=5, annoType = TB.class, expect = "61")
+ <T> void m60(@TA(60) @TB(61) String t) { }
+
+ class Inner70<T> {
+ @Test(posn=0, annoType = TA.class, expect = "70")
+ @Test(posn=0, annoType = TB.class, expect = "71")
+ @TA(70) @TB(71) String f;
+ }
+
+ // Test type use annotations on uses of type variables
+ @Test(posn=5, annoType = TB.class, expect = "81")
+ <@TA(80) T> void m80(@TB(81) String t) { }
+
+ class Inner90<@TA(90) T> {
+ @Test(posn=0, annoType = TB.class, expect = "91")
+ @TB(91) String f;
+ }
+
+ // Recursive bound
+ @Test(posn=4, annoType = TB.class, expect = "100")
+ class Inner100<T extends Inner100<@TB(100) T>> {
+ }
}
--- a/langtools/test/tools/javac/warnings/6747671/T6747671.out Thu Apr 09 06:40:21 2015 -0700
+++ b/langtools/test/tools/javac/warnings/6747671/T6747671.out Thu Apr 09 17:37:46 2015 -0700
@@ -7,6 +7,6 @@
T6747671.java:32:9: compiler.warn.raw.class.use: T6747671.A, T6747671<E>.A<X>
T6747671.java:32:20: compiler.warn.raw.class.use: T6747671.A, T6747671<E>.A<X>
T6747671.java:33:16: compiler.warn.raw.class.use: T6747671.A.Z, T6747671<E>.A<X>.Z<Y>
-T6747671.java:36:9: compiler.warn.raw.class.use: @T6747671.TA T6747671.B, T6747671.B<X>
+T6747671.java:36:9: compiler.warn.raw.class.use: T6747671.B, T6747671.B<X>
T6747671.java:36:27: compiler.warn.raw.class.use: T6747671.B, T6747671.B<X>
11 warnings