8031744: Annotations on many Language Model elements are not returned

Co-authored-by: Maurizio Cimadamore <maurizio.cimadamore@oracle.com>
Reviewed-by: jfranck, mcimadamore, emc, jlahoda, jjg
This commit is contained in:
Joel Borggren-Franck 2015-04-07 11:04:29 -07:00 committed by Jonathan Gibbons
parent 90173f9875
commit 7d3885b239
29 changed files with 2201 additions and 1557 deletions

View File

@ -696,7 +696,8 @@ public class JavacTrees extends DocTrees {
@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)

View File

@ -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.JavaFileObject;
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 @@ public class ClassFinder {
ClassReader reader;
Annotate annotate;
private final Annotate annotate;
/** Switch: verbose output.
*/
@ -272,18 +272,13 @@ public class ClassFinder {
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) {

View File

@ -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 java.util.concurrent.Callable;
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 @@ public abstract class Symbol extends AnnoConstruct implements Element {
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 abstract class Symbol extends AnnoConstruct implements Element {
*/
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 @@ public abstract class Symbol extends AnnoConstruct implements Element {
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 @@ public abstract class Symbol extends AnnoConstruct implements Element {
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 @@ public abstract class Symbol extends AnnoConstruct implements Element {
/** 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.
*/

View File

@ -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 java.util.function.Function;
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 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
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 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
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 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
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 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
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 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
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 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
}
/**
* 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);
public Type combineMetadata(final TypeMetadata.Element md) {
return clone(metadata.combine(md));
protected Type typeNoMetadata() {
return metadata == TypeMetadata.EMPTY ? this : baseType();
}
/**
* 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 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
}
/**
* 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 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
* 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 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
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 abstract class Type extends AnnoConstruct implements TypeMirror {
}
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 abstract class Type extends AnnoConstruct implements TypeMirror {
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 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
}
@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 abstract class Type extends AnnoConstruct implements TypeMirror {
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 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
}
@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 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
@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 abstract class Type extends AnnoConstruct implements TypeMirror {
public boolean contains(Type elem) {
return
elem == this
elem.equalsIgnoreMetadata(this)
|| (isParameterized()
&& (getEnclosingType().contains(elem) || contains(getTypeArguments(), elem)))
|| (isCompound()
@ -1073,10 +1139,6 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
}
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 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
}
@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 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
}
@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 abstract class Type extends AnnoConstruct implements TypeMirror {
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 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
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 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
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 abstract class Type extends AnnoConstruct implements TypeMirror {
}
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 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
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 abstract class Type extends AnnoConstruct implements TypeMirror {
}
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 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
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 abstract class Type extends AnnoConstruct implements TypeMirror {
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 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
}
@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 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
}
@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 abstract class Type extends AnnoConstruct implements TypeMirror {
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 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
}
@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 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
}
@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 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
// 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 abstract class Type extends AnnoConstruct implements TypeMirror {
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 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
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 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
}
@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 abstract class Type extends AnnoConstruct implements TypeMirror {
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");
}

View File

@ -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 class TypeAnnotationPosition {
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.

View File

@ -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.lang.model.type.TypeKind;
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.TypePathEntry;
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.List;
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 @@ public class TypeAnnotations {
syms = Symtab.instance(context);
annotate = Annotate.instance(context);
attr = Attr.instance(context);
Options options = Options.instance(context);
}
/**
@ -113,12 +112,9 @@ public class TypeAnnotations {
* 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 @@ public class TypeAnnotations {
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 @@ public class TypeAnnotations {
log.useSource(oldSource);
}
}
} );
});
}
/**
@ -155,101 +151,106 @@ public class TypeAnnotations {
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 at1;
}
}
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;
}
/** 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 class TypeAnnotationPositions extends TreeScanner {
private final boolean sigOnly;
@ -262,18 +263,29 @@ public class TypeAnnotations {
* 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 @@ public class TypeAnnotations {
* 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 @@ public class TypeAnnotations {
// 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 @@ public class TypeAnnotations {
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 @@ public class TypeAnnotations {
// 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);
if (type.hasTag(TypeTag.ARRAY))
return rewriteArrayType((ArrayType)type, annotations, pos);
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.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 @@ public class TypeAnnotations {
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 @@ public class TypeAnnotations {
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 @@ public class TypeAnnotations {
}
}
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;
} else {
Assert.error("Could not determine array type from type tree: " + typetree);
return null;
/**
* 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 {
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 @@ public class TypeAnnotations {
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 @@ public class TypeAnnotations {
/* 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 @@ public class TypeAnnotations {
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 @@ public class TypeAnnotations {
// 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 @@ public class TypeAnnotations {
scan(tree.defaultValue);
scan(tree.body);
}
pop();
}
/* Store a reference to the current lambda expression, to
@ -1172,18 +1189,20 @@ public class TypeAnnotations {
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 @@ public class TypeAnnotations {
// 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 @@ public class TypeAnnotations {
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;

View File

@ -30,46 +30,63 @@ import com.sun.tools.javac.util.Assert;
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 @@ public class TypeMetadata {
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 @@ public class TypeMetadata {
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 @@ public class TypeMetadata {
* @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 @@ public class TypeMetadata {
}
@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 + " ]"; }
}
}

View File

@ -40,6 +40,7 @@ import javax.tools.JavaFileObject;
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 @@ public class Types {
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 @@ public class Types {
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 @@ public class Types {
// </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 @@ public class Types {
* 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 @@ public class Types {
}
// 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 @@ public class Types {
return t; /*fast special case*/
else {
//other cases already handled
return combineMetadata(t, t.getMetadata());
return combineMetadata(t, t);
}
}
@ -2220,17 +2185,18 @@ public class Types {
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 class Types {
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 @@ public class Types {
* 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,76 +2930,25 @@ public class Types {
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);
}
}
return t;
}
@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 @@ public class Types {
@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 @@ public class Types {
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 @@ public class Types {
}
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 @@ public class Types {
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) {

View File

@ -40,6 +40,7 @@ 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.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 @@ public class Attr extends JCTree.Visitor {
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 @@ public class Attr extends JCTree.Visitor {
}
// 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 @@ public class Attr extends JCTree.Visitor {
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 @@ public class Attr extends JCTree.Visitor {
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 @@ public class Attr extends JCTree.Visitor {
// 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 @@ public class Attr extends JCTree.Visitor {
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 class Attr extends JCTree.Visitor {
}
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;
}
attribAnnotationTypes(tree.annotations, env);
Type underlyingType = attribType(tree.underlyingType, env);
Type annotatedType = underlyingType.annotatedType(Annotations.TO_BE_SET);
/**
* 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();
if (!env.info.isNewClass)
annotate.annotateTypeSecondStage(tree, tree.annotations, annotatedType);
result = tree.type = annotatedType;
}
public void visitErroneous(JCErroneous tree) {
@ -4298,8 +4278,9 @@ public class Attr extends JCTree.Visitor {
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 @@ public class Attr extends JCTree.Visitor {
// 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");
}
}

View File

@ -68,6 +68,11 @@ public class AttrContext {
*/
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 @@ public class AttrContext {
info.isSerializable = isSerializable;
info.isSpeculative = isSpeculative;
info.isAnonymousDiamond = isAnonymousDiamond;
info.isNewClass = isNewClass;
return info;
}

View File

@ -31,6 +31,7 @@ import javax.tools.JavaFileManager;
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 @@ public class Check {
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 @@ public class Check {
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 @@ public class Check {
* @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 class Check {
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 @@ public class Check {
}
}
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 @@ public class Check {
}
}
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,32 +2999,18 @@ public class Check {
/** 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
}
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;
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));
}
/** Is the annotation applicable to the symbol? */
boolean annotationApplicable(JCAnnotation a, Symbol s) {
@ -3043,51 +3032,55 @@ public class Check {
}
}
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.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.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.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)
} 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 @@ public class Check {
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 @@ public class Check {
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);

View File

@ -176,14 +176,14 @@ public class DeferredAttr extends JCTree.Visitor {
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");
}

View File

@ -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.Kinds.KindSelector;
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 @@ import static com.sun.tools.javac.code.Kinds.Kind.*;
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 @@ public class Enter extends JCTree.Visitor {
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 @@ public class Enter extends JCTree.Visitor {
* @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 @@ public class Enter extends JCTree.Visitor {
}
} finally {
uncompleted = prevUncompleted;
annotate.enterDone();
annotate.unblockAnnotations();
}
}

View File

@ -2766,20 +2766,6 @@ public class Lower extends TreeTranslator {
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())

View File

@ -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 @@ public class MemberEnter extends JCTree.Visitor {
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 @@ public class MemberEnter extends JCTree.Visitor {
localEnv.info.staticLevel++;
}
DiagnosticPosition prevLintPos = deferredLintHandler.setPos(tree.pos());
try {
if (TreeInfo.isEnumInit(tree)) {
attr.attribIdentAsEnumType(localEnv, (JCIdent)tree.vartype);
@ -297,7 +298,7 @@ public class MemberEnter extends JCTree.Visitor {
}
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 @@ public class MemberEnter extends JCTree.Visitor {
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);
}
}

View File

@ -28,6 +28,7 @@ package com.sun.tools.javac.comp;
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 @@ public class TransTypes extends TreeTranslator {
private TreeMaker make;
private Enter enter;
private Types types;
private Annotate annotate;
private final Resolve resolve;
private final CompileStates compileStates;
@ -91,6 +93,7 @@ public class TransTypes extends TreeTranslator {
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 @@ public class TransTypes extends TreeTranslator {
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;

View File

@ -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.ImportFilter;
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 @@ public class TypeEnter implements Completer {
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 @@ public class TypeEnter implements Completer {
Env<AttrContext> topEnv = enter.topLevelEnv(tree);
finishImports(tree, () -> { completeClass.resolveImports(tree, topEnv); });
}
}
}
}
/* ********************************************************************
@ -184,7 +186,7 @@ public class TypeEnter implements Completer {
}
try {
annotate.enterStart();
annotate.blockAnnotations();
sym.flags_field |= UNATTRIBUTED;
List<Env<AttrContext>> queue;
@ -206,7 +208,7 @@ public class TypeEnter implements Completer {
}
}
} finally {
annotate.enterDone();
annotate.unblockAnnotations();
}
}
@ -780,9 +782,9 @@ public class TypeEnter implements Completer {
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 @@ public class TypeEnter implements Completer {
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 @@ public class TypeEnter implements Completer {
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

View File

@ -36,17 +36,17 @@ import java.util.HashMap;
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 class ClassReader {
public static final int INITIAL_BUFFER_SIZE = 0x0fff0;
Annotate annotate;
private final Annotate annotate;
/** Switch: verbose output.
*/
@ -190,6 +190,18 @@ public class ClassReader {
*/
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 @@ public class ClassReader {
/** 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 @@ public class ClassReader {
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 @@ public class ClassReader {
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 @@ public class ClassReader {
}
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 @@ public class ClassReader {
}
}
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 @@ public class ClassReader {
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 @@ public class ClassReader {
currentClassFile = previousClassFile;
}
}
@Override
public String toString() {
return " ClassReader annotate " + sym.owner + "." + sym + " with " + l;
}
}
class TypeAnnotationCompleter extends AnnotationCompleter {
@ -2298,6 +2330,8 @@ public class ClassReader {
currentClassFile = c.classfile;
warnedAttrs.clear();
filling = true;
target = null;
repeatable = null;
try {
bp = 0;
buf = readInputStream(buf, c.classfile.openInputStream());
@ -2318,6 +2352,12 @@ public class ClassReader {
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 @@ public class ClassReader {
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);
}
}
}

View File

@ -75,6 +75,7 @@ public class Gen extends JCTree.Visitor {
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 @@ public class Gen extends JCTree.Visitor {
}
this.jsrlimit = setjsrlimit;
this.useJsrLocally = false; // reset in visitTry
annotate = Annotate.instance(context);
}
/** Switches
@ -1468,21 +1470,18 @@ public class Gen extends JCTree.Visitor {
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 @@ public class Gen extends JCTree.Visitor {
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 @@ public class Gen extends JCTree.Visitor {
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 @@ public class Gen extends JCTree.Visitor {
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 @@ public class Gen extends JCTree.Visitor {
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 @@ public class Gen extends JCTree.Visitor {
*/
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

View File

@ -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 @@ class UninitializedType extends Type.DelegatedType {
}
@Override
public UninitializedType clone(final TypeMetadata md) {
public UninitializedType cloneWithMetadata(final TypeMetadata md) {
return new UninitializedType(tag, qtype, offset, md);
}

View File

@ -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 @@ public class JavacTypes implements javax.lang.model.util.Types {
@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 @@ public class JavacTypes implements javax.lang.model.util.Types {
@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)

View File

@ -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.lang.model.type.TypeKind;
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 abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
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) {

View File

@ -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 @@ public class RichDiagnosticFormatter extends
}
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 @@ public class RichDiagnosticFormatter extends
@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;

View File

@ -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.List;
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;

View File

@ -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 @@ import java.io.*;
@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() {

View File

@ -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 @@ public class DPrinter {
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));

View File

@ -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.Element;
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 class BasicAnnoTests extends JavacTestingAbstractProcessor {
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 @@ public class BasicAnnoTests extends JavacTestingAbstractProcessor {
*/
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 @@ public class BasicAnnoTests extends JavacTestingAbstractProcessor {
*/
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, AnnotationMirror test) {
TestTypeScanner(Element elem, List<AnnotationMirror> tests, Types types) {
super(types);
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 @@ public class BasicAnnoTests extends JavacTestingAbstractProcessor {
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 @@ public class BasicAnnoTests extends JavacTestingAbstractProcessor {
* 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,16 +316,33 @@ public class BasicAnnoTests extends JavacTestingAbstractProcessor {
@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);
@ -254,36 +376,194 @@ public class BasicAnnoTests extends JavacTestingAbstractProcessor {
}
/** 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>> {
}
}

View File

@ -7,6 +7,6 @@ T6747671.java:29:28: compiler.warn.raw.class.use: T6747671.B, T6747671.B<X>
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