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:
parent
90173f9875
commit
7d3885b239
@ -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)
|
||||
|
@ -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) {
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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");
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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 + " ]"; }
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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) {
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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");
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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");
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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())
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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() {
|
||||
|
||||
|
@ -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));
|
||||
|
@ -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>> {
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user