package checkers.types;
import java.lang.annotation.Annotation;
import java.util.*;
import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.*;
import javax.lang.model.type.*;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
import com.sun.source.tree.ClassTree;
import com.sun.source.tree.Tree;
import checkers.types.visitors.AnnotatedTypeScanner;
import checkers.types.visitors.AnnotatedTypeVisitor;
import checkers.types.visitors.SimpleAnnotatedTypeVisitor;
import checkers.util.AnnotationUtils;
import checkers.util.ElementUtils;
import checkers.util.TreeUtils;
import checkers.util.TypesUtils;
import checkers.nullness.quals.NonNull;
import checkers.quals.TypeQualifier;
/**
* Represents an annotated type in the Java programming language.
* Types include primitive types, declared types (class and interface types),
* array types, type variables, and the null type.
* Also represented are wildcard type arguments,
* the signature and return types of executables,
* and pseudo-types corresponding to packages and to the keyword {@code void}.
*
* <p> Types should be compared using the utility methods in {@link
* AnnotatedTypes}. There is no guarantee that any particular type will always
* be represented by the same object.
*
* <p> To implement operations based on the class of an {@code
* AnnotatedTypeMirror} object, either
* use a visitor or use the result of the {@link #getKind()} method.
*
* @see TypeMirror
* @since 1.6
*/
public abstract class AnnotatedTypeMirror {
/**
* Creates the appropriate AnnotatedTypeMirror specific wrapper for the
* provided type
*
* @param type
* @param env
* @param typeFactory
* @return [to document]
*/
public static AnnotatedTypeMirror createType(TypeMirror type,
ProcessingEnvironment env, AnnotatedTypeFactory typeFactory) {
if (type == null)
return null;
if (replacer == null)
replacer = new Replacer(typeFactory.types);
switch (type.getKind()) {
case ARRAY:
return new AnnotatedArrayType((ArrayType)type, env, typeFactory);
case DECLARED:
return new AnnotatedDeclaredType((DeclaredType)type, env, typeFactory);
case ERROR:
throw new AssertionError("Input should type-checked already...");
case EXECUTABLE:
return new AnnotatedExecutableType((ExecutableType)type, env, typeFactory);
case VOID:
case PACKAGE:
case NONE:
return new AnnotatedNoType((NoType)type, env, typeFactory);
case NULL:
return new AnnotatedNullType((NullType)type, env, typeFactory);
case TYPEVAR: {
AnnotatedTypeVariable atype = new AnnotatedTypeVariable((TypeVariable)type, env, typeFactory);
return atype;
}
case WILDCARD: {
AnnotatedWildcardType atype = new AnnotatedWildcardType((WildcardType)type, env, typeFactory);
return atype;
}
default:
if (type.getKind().isPrimitive())
return new AnnotatedPrimitiveType((PrimitiveType)type, env, typeFactory);
throw new AssertionError("Unidentified type " + type);
}
}
public List<? extends AnnotatedTypeMirror> directSuperTypes() {
return directSuperTypes(this);
}
/** Processing Environment of the current round **/
protected final ProcessingEnvironment env;
/** The factory to use for lazily creating annotations. */
protected final AnnotationUtils annotationFactory;
/** The factory to use for lazily creating annotated types. */
protected final AnnotatedTypeFactory typeFactory;
/** Actual type wrapped with this AnnotatedTypeMirror **/
protected final TypeMirror actualType;
/** the Element associated with this instance value, if one exists **/
// TODO: Clarify, with value not the element of the type.
// I.e. For 'Integer i;' the element would be for 'i' not 'Integer'
protected Element element;
/** The enclosing Type **/
protected AnnotatedTypeMirror enclosingType;
/** The annotations on this type. */
// AnnotationMirror doesn't override Object.hashCode, .equals, so we use
// the class name of Annotation instead
// Caution: Assumes that a type can have at most one AnnotationMirror for
// any Annotation type. JSR308 is pushing to have this change.
protected final Set<AnnotationMirror> annotations = AnnotationUtils.createAnnotationSet();
private static int uidCounter = 0;
public int uid;
/**
* Constructor for AnnotatedTypeMirror.
*
* @param type the underlying type
* @param env Processing Environment
* @param typeFactory TODO
*/
// TODO: Have static factory methods
private AnnotatedTypeMirror(TypeMirror type, ProcessingEnvironment env,
AnnotatedTypeFactory typeFactory) {
this.actualType = type;
this.env = env;
this.annotationFactory = AnnotationUtils.getInstance(env);
assert typeFactory != null;
this.typeFactory = typeFactory;
uid = ++uidCounter;
}
@Override
public boolean equals(Object o) {
if (!(o instanceof AnnotatedTypeMirror))
return false;
AnnotatedTypeMirror t = (AnnotatedTypeMirror)o;
if (this.env.getTypeUtils().isSameType(this.actualType, t.actualType)
&& AnnotationUtils.areSame(getAnnotations(), t.getAnnotations()))
return true;
return false;
}
@Override
public int hashCode() {
return this.annotations.toString().hashCode() * 17
+ this.actualType.toString().hashCode() * 13;
}
/**
* Applies a visitor to this type.
*
* @param <R> the return type of the visitor's methods
* @param <P> the type of the additional parameter to the visitor's methods
* @param v the visitor operating on this type
* @param p additional parameter to the visitor
* @return a visitor-specified result
*/
public abstract <R, P> R accept(AnnotatedTypeVisitor<R, P> v, P p);
/**
* Returns the {@code kind} of this type
* @return the kind of this type
*/
public TypeKind getKind() {
return actualType.getKind();
}
/**
* Returns the underlying unannotated Java type wrapped with this
*
* @return the underlying type
*/
public TypeMirror getUnderlyingType() {
return actualType;
}
/**
* Sets the enclosing type
*
* @param enclosingType
*/
void setEnclosingType(AnnotatedTypeMirror enclosingType) {
this.enclosingType = enclosingType;
}
/**
* Returns the enclosing type, as in the type of {@code A} in the type
* {@code A.B}.
*
* @return enclosingType the enclosing type
*/
public AnnotatedTypeMirror getEnclosingType() {
return enclosingType;
}
/**
* Returns true if an annotation targets this type location.
*
* It doesn't account for annotations in deep types (type arguments,
* array components, etc).
*
*/
public boolean isAnnotated() {
return !annotations.isEmpty();
}
/**
* Returns the annotations on this type.
*
* It does not include annotations in deep types (type arguments, array
* components, etc).
*
* @return a set of the annotations on this
*/
public Set<AnnotationMirror> getAnnotations() {
return Collections.unmodifiableSet(annotations);
}
/**
* Returns the actual annotation mirror used to annotate this type,
* whose name equals the passed annotationName if one exist, null otherwise.
*
* @param annotationName
* @return the annotation mirror for annotationName
*/
public AnnotationMirror getAnnotation(String annotationName) {
assert annotationName != null : annotationName + " cannot be null";
Name name = env.getElementUtils().getName(annotationName);
return getAnnotation(name);
}
/**
* Returns the actual annotation mirror used to annotate this type,
* whose name equals the passed annotationName if one exist, null otherwise.
*
* @param annotationName
* @return the annotation mirror for annotationName
*/
public AnnotationMirror getAnnotation(Name annotationName) {
assert annotationName != null : annotationName + " cannot be null";
for (AnnotationMirror anno : getAnnotations())
if (AnnotationUtils.annotationName(anno).equals(annotationName))
return anno;
return null;
}
/**
* Returns the actual annotation mirror used to annotate this type,
* whose name equals the passed annotationName if one exist, null otherwise.
*
* @param anno annotation class
* @return the annotation mirror for anno
*/
public AnnotationMirror getAnnotation(Class<? extends Annotation> anno) {
return getAnnotation(anno.getCanonicalName());
}
/**
* Determines whether this type contains an annotation with the same
* annotation type as a particular annotation. This method does not
* consider an annotation's values.
*
* @param a the annotation to check for
* @return true iff the type contains an annotation with the same type as
* the annotation given by {@code a}
*/
public boolean hasAnnotation(AnnotationMirror a) {
return getAnnotations().contains(a);
}
/**
* Determines whether this type contains an annotation with the same
* annotation type as a particular annotation. This method does not
* consider an annotation's values.
*
* @param a the class of annotation to check for
* @return true iff the type contains an annotation with the same type as
* the annotation given by {@code a}
*/
public boolean hasAnnotation(Class<? extends Annotation> a) {
return getAnnotation(a) != null;
}
/**
* Adds an annotation to this type. If the annotation does not have the
* {@link TypeQualifier} meta-annotation, this method has no effect.
*
* @param a the annotation to add
*/
public void addAnnotation(AnnotationMirror a) {
if (a == null) return;
if (typeFactory.isSupportedQualifier(a))
this.annotations.add(a);
else {
AnnotationMirror aliased = typeFactory.aliasedAnnotation(a);
addAnnotation(aliased);
}
}
/**
* Adds an annotation to this type. If the annotation does not have the
* {@link TypeQualifier} meta-annotation, this method has no effect.
*
* @param a the class of the annotation to add
*/
public void addAnnotation(Class<? extends Annotation> a) {
AnnotationMirror anno = annotationFactory.fromClass(a);
addAnnotation(anno);
}
/**
* Adds multiple annotations to this type.
*
* @param annotations the annotations to add
*/
public void addAnnotations(Iterable<? extends AnnotationMirror> annotations) {
for (AnnotationMirror a : annotations)
this.addAnnotation(a);
}
/**
* Removes an annotation from the type.
*
* @param a the annotation to remove
* @return true if the annotation was removed, false if the type's
* annotations were unchanged
*/
public boolean removeAnnotation(AnnotationMirror a) {
return annotations.remove(getAnnotation(AnnotationUtils.annotationName(a)));
}
public boolean removeAnnotation(Class<? extends Annotation> a) {
return removeAnnotation(annotationFactory.fromClass(a));
}
/**
* Removes multiple annotations from the type.
*
* @param annotations the annotations to remove
* @return true if at least one annotation was removed, false if the type's
* annotations were unchanged
*/
public boolean removeAnnotations(Iterable<? extends AnnotationMirror> annotations) {
boolean changed = false;
for (AnnotationMirror a : annotations)
changed |= this.removeAnnotation(a);
return changed;
}
/**
* Removes all annotations on this type
*/
public void clearAnnotations() {
annotations.clear();
}
// A Helper method to print annotations separated with a space
protected final static String formatAnnotationString(Collection<? extends AnnotationMirror> lst) {
StringBuilder sb = new StringBuilder();
for (AnnotationMirror obj : lst) {
if (!obj.getElementValues().isEmpty()) {
sb.append(obj.toString());
sb.append(" ");
continue;
}
sb.append("@");
sb.append(obj.getAnnotationType().asElement().getSimpleName());
sb.append(" ");
}
return sb.toString();
}
@Override
public String toString() {
return formatAnnotationString(getAnnotations())
+ this.actualType;
}
public String toStringDebug() {
return toString() + " " + getClass().getSimpleName() + "#" + uid;
}
/**
* Sets the Element associated with the value of this type, if one exists
*
* @param elem the element of this type value
*/
void setElement(Element elem) {
this.element = elem;
}
/**
* Returns the element associated with the value the type represent, if any.
* I.e. For 'Integer i;' the element would be for 'i' not 'Integer'
*
* @return the {@code Element} of the value of this type, if one exists
*/
public Element getElement() {
return element;
}
/**
* Returns the erasure type of the this type, according to JLS
* specifications.
*
* @return the erasure of this
*/
public AnnotatedTypeMirror getErased() {
return this;
}
/**
* Copy the fields on this type onto the passed type.
* This method needs to be overriden by any subclass of
* {@code AnnotatedTypeMirror}
*
* @param type an empty type where fields of this are copied to
* @param annotation whether annotations are copied or not
*/
protected AnnotatedTypeMirror copyFields(AnnotatedTypeMirror type, boolean annotation) {
type.setElement(getElement());
type.setEnclosingType(getEnclosingType());
if (annotation)
type.addAnnotations(annotations);
return type;
}
/**
* Returns a shallow copy of this type.
*
* @param annotation
* whether copy should have annotations
*/
public abstract AnnotatedTypeMirror getCopy(boolean annotation);
protected static AnnotatedDeclaredType createTypeOfObject(AnnotatedTypeFactory typeFactory) {
AnnotatedDeclaredType objectType =
typeFactory.fromElement(
typeFactory.elements.getTypeElement(
Object.class.getCanonicalName()));
return objectType;
}
/**
* Sub
*
* @param mappings
*/
public AnnotatedTypeMirror substitute(
Map<? extends AnnotatedTypeMirror,
? extends AnnotatedTypeMirror> mappings) {
if (mappings.containsKey(this))
return mappings.get(this).getCopy(true);
return this.getCopy(true);
}
public static interface AnnotatedReferenceType {
// No members.
}
/**
* Represents a declared type (whether class or interface).
*/
public static class AnnotatedDeclaredType extends AnnotatedTypeMirror
implements AnnotatedReferenceType {
/** Parametrized Type Arguments **/
protected List<AnnotatedTypeMirror> typeArgs;
/** Supertype of this type **/
@Deprecated
protected AnnotatedDeclaredType superclass;
/** The interfaces that this type implements **/
@Deprecated
protected List<AnnotatedDeclaredType> interfaces;
boolean isGeneric = false;
protected final DeclaredType actualType;
protected List<AnnotatedDeclaredType> supertypes;
/**
* Constructor for this type
*
* @param type underlying kind of this type
* @param env the processing environment
* @param typeFactory TODO
*/
AnnotatedDeclaredType(DeclaredType type,
ProcessingEnvironment env, AnnotatedTypeFactory typeFactory) {
super(type, env, typeFactory);
this.actualType = type;
DeclaredType elem = (DeclaredType)((TypeElement)type.asElement()).asType();
isGeneric = !elem.getTypeArguments().isEmpty();
this.interfaces = new LinkedList<AnnotatedDeclaredType>();
this.supertypes = null;
}
@Override
public String toString() {
final Element typeElt = this.getUnderlyingType().asElement();
StringBuilder sb = new StringBuilder();
sb.append(formatAnnotationString(getAnnotations()));
sb.append(typeElt.getSimpleName());
if (!this.getTypeArguments().isEmpty()) {
sb.append("<");
boolean isFirst = true;
for (AnnotatedTypeMirror typeArg : getTypeArguments()) {
if (!isFirst) sb.append(", ");
sb.append(typeArg);
isFirst = false;
}
sb.append(">");
}
return sb.toString();
}
@Override
public <R, P> R accept(AnnotatedTypeVisitor<R, P> v, P p) {
return v.visitDeclared(this, p);
}
/**
* Sets the type arguments on this type
* @param t the type arguments
*/
void setTypeArguments(List<? extends AnnotatedTypeMirror> ts) {
typeArgs = Collections.unmodifiableList(new ArrayList<AnnotatedTypeMirror>(ts));
}
/**
* @return the type argument for this type
*/
public List<AnnotatedTypeMirror> getTypeArguments() {
if (typeArgs == null) {
typeArgs = new ArrayList<AnnotatedTypeMirror>();
if (!actualType.getTypeArguments().isEmpty()) { // lazy init
for (TypeMirror t : actualType.getTypeArguments())
typeArgs.add(createType(t, env, typeFactory));
}
typeArgs = Collections.unmodifiableList(typeArgs);
}
return typeArgs;
}
/**
* @return the super type of this
*/
@Deprecated
public AnnotatedTypeMirror getSuperclass() {
TypeElement elt = (TypeElement)this.actualType.asElement();
assert elt.getSuperclass() != null;
AnnotatedTypeMirror type = createType(elt.asType(), env, typeFactory);
// Some types don't have a supertype (e.g., java.lang.Cloneable),
// so we return a copy of their NoType.
if (type instanceof AnnotatedNoType) return type.getCopy(true);
assert type instanceof AnnotatedDeclaredType : "not a declared type: "
+ type;
AnnotatedDeclaredType at = (AnnotatedDeclaredType)type;
at.addAnnotations(this.getAnnotations());
return at;
}
/**
* Returns true if the type is generic, even if the type is erased
* or used as a RAW type.
*
* @return true iff the type is generic
*/
public boolean isGeneric() {
return isGeneric;
}
/**
* Returns true if the type is a generic type and the type declaration
* is parameterized. Otherwise, it returns false, in cases where a
* type is a raw type or a non-generic type.
*
* Note: Even if the type is a raw type, the framework actually adds
* type arguments to the type.
*/
public boolean isParameterized() {
return !getTypeArguments().isEmpty()
&& !getUnderlyingType().getTypeArguments().isEmpty();
}
/**
* @return the interfaces of this type
*/
@Deprecated
public List<AnnotatedDeclaredType> getInterfaces() {
TypeElement elt = (TypeElement)this.actualType.asElement();
List<AnnotatedDeclaredType> myInterfaces = new LinkedList<AnnotatedDeclaredType>();
for (TypeMirror dt : elt.getInterfaces()) {
AnnotatedDeclaredType at =
(AnnotatedDeclaredType)createType(dt, env, typeFactory);
at.addAnnotations(this.getAnnotations());
myInterfaces.add(at);
}
return Collections.unmodifiableList(myInterfaces);
}
@Override
public DeclaredType getUnderlyingType() {
return actualType;
}
void setDirectSuperTypes(List<AnnotatedDeclaredType> supertypes) {
this.supertypes = new ArrayList<AnnotatedDeclaredType>(supertypes);
}
@Override
public List<AnnotatedDeclaredType> directSuperTypes() {
if (supertypes == null) {
supertypes = directSuperTypes(this);
}
return Collections.unmodifiableList(supertypes);
}
@Override
public AnnotatedDeclaredType getCopy(boolean annotation) {
AnnotatedDeclaredType type =
new AnnotatedDeclaredType(this.getUnderlyingType(), this.env, this.typeFactory);
copyFields(type, annotation);
type.setTypeArguments(getTypeArguments());
return type;
}
@Override
public AnnotatedTypeMirror substitute(
Map<? extends AnnotatedTypeMirror,
? extends AnnotatedTypeMirror> mapping) {
if (mapping.containsKey(this))
return mapping.get(this);
AnnotatedDeclaredType type = getCopy(true);
// No need to substitute type params for now!
//
// Why is this the case? The following was necessary to get the
// Interning checker's Generics test case to work. -MP
List<AnnotatedTypeMirror> typeArgs = new ArrayList<AnnotatedTypeMirror>();
for (AnnotatedTypeMirror t : getTypeArguments())
typeArgs.add(t.substitute(mapping));
type.setTypeArguments(typeArgs);
if (TypesUtils.isAnonymousType(actualType)
&& this.supertypes != null) {
// watch need to copy upper bound as well
List<AnnotatedDeclaredType> supertypes = new ArrayList<AnnotatedDeclaredType>();
for (AnnotatedDeclaredType t : directSuperTypes())
supertypes.add((AnnotatedDeclaredType)t.substitute(mapping));
type.setDirectSuperTypes(supertypes);
}
return type;
}
@Override
public AnnotatedDeclaredType getErased() {
// 1. |G<T_1, ..., T_n>| = |G|
// 2. |T.C| = |T|.C
if (!getTypeArguments().isEmpty()) {
// Handle case 1.
AnnotatedDeclaredType rType =
(AnnotatedDeclaredType)AnnotatedTypeMirror.createType(
env.getTypeUtils().erasure(actualType),
env, typeFactory);
rType.addAnnotations(getAnnotations());
rType.setElement(element);
rType.setTypeArguments(Collections.<AnnotatedTypeMirror> emptyList());
return rType.getErased();
} else if ((getEnclosingType() != null) &&
(getEnclosingType().getKind() != TypeKind.NONE)) {
// Handle case 2
// TODO: Test this
AnnotatedDeclaredType rType = getCopy(true);
AnnotatedTypeMirror et = getEnclosingType();
rType.setEnclosingType(et.getErased());
return rType;
} else {
return this;
}
}
}
/**
* Represents a type of an executable. An executable is a method, constructor, or initializer.
*/
public static class AnnotatedExecutableType extends AnnotatedTypeMirror {
private final ExecutableType actualType;
AnnotatedExecutableType(ExecutableType type,
ProcessingEnvironment env, AnnotatedTypeFactory factory) {
super(type, env, factory);
this.actualType = type;
}
final private List<AnnotatedTypeMirror> paramTypes =
new LinkedList<AnnotatedTypeMirror>();
private AnnotatedDeclaredType receiverType;
private AnnotatedTypeMirror returnType;
final private List<AnnotatedTypeMirror> throwsTypes =
new LinkedList<AnnotatedTypeMirror>();
final private List<AnnotatedTypeVariable> typeVarTypes =
new LinkedList<AnnotatedTypeVariable>();
/**
* @return true if this type represents a varargs method
*/
public boolean isVarArgs() {
if (this.element instanceof ExecutableElement)
return ((ExecutableElement)this.element).isVarArgs();
return false;
}
@Override
public <R, P> R accept(AnnotatedTypeVisitor<R, P> v, P p) {
return v.visitExecutable(this, p);
}
@Override
public ExecutableType getUnderlyingType() {
return this.actualType;
}
/**
* Sets the parameter types of this executable type
* @param params the parameter types
*/
void setParameterTypes(
List<? extends AnnotatedTypeMirror> params) {
paramTypes.clear();
paramTypes.addAll(params);
}
/**
* @return the parameter types of this executable type
*/
public List<AnnotatedTypeMirror> getParameterTypes() {
if (paramTypes.isEmpty()
&& !actualType.getParameterTypes().isEmpty()) { // lazy init
for (TypeMirror t : actualType.getParameterTypes())
paramTypes.add(createType(t, env, typeFactory));
}
return Collections.unmodifiableList(paramTypes);
}
/**
* Sets the return type of this executable type
* @param returnType the return type
*/
void setReturnType(AnnotatedTypeMirror returnType) {
this.returnType = returnType;
}
/**
* @return the return type of this executable type
*/
public AnnotatedTypeMirror getReturnType() {
if (returnType == null
&& actualType.getReturnType() != null) // lazy init
returnType = createType(
actualType.getReturnType(), env, typeFactory);
return returnType;
}
/**
* Sets the receiver type on this executable type
* @param receiverType the receiver type
*/
void setReceiverType(AnnotatedDeclaredType receiverType) {
this.receiverType = receiverType;
}
/**
* @return the receiver type of this executable type
*/
public AnnotatedDeclaredType getReceiverType() {
if (receiverType == null) {
TypeElement encl = ElementUtils.enclosingClass(getElement());
AnnotatedTypeMirror type = createType(encl.asType(), env, typeFactory);
assert type instanceof AnnotatedDeclaredType;
receiverType = (AnnotatedDeclaredType)type;
}
return receiverType;
}
/**
* Sets the thrown types of this executable type
*
* @param thrownTypes the thrown types
*/
void setThrownTypes(
List<? extends AnnotatedTypeMirror> thrownTypes) {
this.throwsTypes.clear();
this.throwsTypes.addAll(thrownTypes);
}
/**
* @return the thrown types of this executable type
*/
public List<AnnotatedTypeMirror> getThrownTypes() {
if (throwsTypes.isEmpty()
&& !actualType.getThrownTypes().isEmpty()) { // lazy init
for (TypeMirror t : actualType.getThrownTypes())
throwsTypes.add(createType(t, env, typeFactory));
}
return Collections.unmodifiableList(throwsTypes);
}
/**
* Sets the type variables associated with this executable type
*
* @param types the type variables of this executable type
*/
void setTypeVariables(List<AnnotatedTypeVariable> types) {
typeVarTypes.clear();
typeVarTypes.addAll(types);
}
/**
* @return the type variables of this executable type, if any
*/
public List<AnnotatedTypeVariable> getTypeVariables() {
if (typeVarTypes.isEmpty()
&& !actualType.getTypeVariables().isEmpty()) { // lazy init
for (TypeMirror t : actualType.getTypeVariables())
typeVarTypes.add((AnnotatedTypeVariable)createType(
t, env, typeFactory));
}
return Collections.unmodifiableList(typeVarTypes);
}
@Override
public AnnotatedExecutableType getCopy(boolean annotation) {
AnnotatedExecutableType type =
new AnnotatedExecutableType(getUnderlyingType(), env, typeFactory);
copyFields(type, annotation);
type.setParameterTypes(getParameterTypes());
type.setReceiverType(getReceiverType());
type.setReturnType(getReturnType());
type.setThrownTypes(getThrownTypes());
type.setTypeVariables(getTypeVariables());
return type;
}
@Override
public /*@NonNull*/ ExecutableElement getElement() {
return (ExecutableElement) super.getElement();
}
@Override
public AnnotatedExecutableType getErased() {
AnnotatedExecutableType type =
new AnnotatedExecutableType(
(ExecutableType) env.getTypeUtils().erasure(getUnderlyingType()),
env, typeFactory);
copyFields(type, true);
type.setParameterTypes(erasureList(getParameterTypes()));
type.setReceiverType(getReceiverType().getErased());
type.setReturnType(getReturnType().getErased());
type.setThrownTypes(erasureList(getThrownTypes()));
return type;
}
private List<AnnotatedTypeMirror> erasureList(List<? extends AnnotatedTypeMirror> lst) {
List<AnnotatedTypeMirror> erased = new ArrayList<AnnotatedTypeMirror>();
for (AnnotatedTypeMirror t : lst)
erased.add(t.getErased());
return erased;
}
@Override
public AnnotatedExecutableType substitute(
Map<? extends AnnotatedTypeMirror,
? extends AnnotatedTypeMirror> mappings) {
// Shouldn't substitute for methods!
AnnotatedExecutableType type = getCopy(true);
// Params
{
List<AnnotatedTypeMirror> params = new ArrayList<AnnotatedTypeMirror>();
for (AnnotatedTypeMirror t : getParameterTypes()) {
params.add(t.substitute(mappings));
}
type.setParameterTypes(params);
}
if (getReceiverType() != null)
type.setReceiverType((AnnotatedDeclaredType)getReceiverType().substitute(mappings));
type.setReturnType(getReturnType().substitute(mappings));
// Throws
{
List<AnnotatedTypeMirror> throwns = new ArrayList<AnnotatedTypeMirror>();
for (AnnotatedTypeMirror t : getThrownTypes()) {
throwns.add(t.substitute(mappings));
}
type.setThrownTypes(throwns);
}
// Worry about type variable
return type;
}
@Override
public String toString() {
return getReturnType()
+ (getTypeVariables().isEmpty() ? "" : " <" + getTypeVariables() + ">")
+ (getParameterTypes().isEmpty() ? " ()" : " (" + getParameterTypes() + ")")
+ " " + getReceiverType()
+ (getThrownTypes().isEmpty() ? "" : " throws " + getThrownTypes());
}
}
/**
* Represents Array types in java. A multidimensional array type is
* represented as an array type whose component type is also an
* array type.
*/
public static class AnnotatedArrayType extends AnnotatedTypeMirror
implements AnnotatedReferenceType {
private final ArrayType actualType;
AnnotatedArrayType(ArrayType type,
ProcessingEnvironment env, AnnotatedTypeFactory factory) {
super(type, env, factory);
this.actualType = type;
}
/** The component type of this array type */
private AnnotatedTypeMirror componentType;
@Override
public <R, P> R accept(AnnotatedTypeVisitor<R, P> v, P p) {
return v.visitArray(this, p);
}
@Override
public ArrayType getUnderlyingType() {
return this.actualType;
}
/**
* Sets the component type of this array
*
* @param type the component type
*/
void setComponentType(AnnotatedTypeMirror type) {
this.componentType = type;
}
/**
* @return the component type of this array
*/
public AnnotatedTypeMirror getComponentType() {
if (componentType == null) // lazy init
setComponentType(createType(
actualType.getComponentType(), env, typeFactory));
return componentType;
}
@Override
public AnnotatedArrayType getCopy(boolean annotation) {
AnnotatedArrayType type = new AnnotatedArrayType(actualType, env, typeFactory);
copyFields(type, annotation);
type.setComponentType(getComponentType());
return type;
}
@Override
public AnnotatedTypeMirror substitute(
Map<? extends AnnotatedTypeMirror,
? extends AnnotatedTypeMirror> mappings) {
if (mappings.containsKey(this))
return mappings.get(this);
AnnotatedArrayType type = getCopy(true);
type.setComponentType(getComponentType().substitute(mappings));
return type;
}
@Override
public AnnotatedArrayType getErased() {
// | T[ ] | = |T| [ ]
AnnotatedArrayType at = getCopy(true);
AnnotatedTypeMirror ct = at.getComponentType().getErased();
at.setComponentType(ct);
return at;
}
public String toStringAsCanonical() {
StringBuilder sb = new StringBuilder();
AnnotatedArrayType array = this;
AnnotatedTypeMirror component;
while (true) {
component = array.getComponentType();
sb.append(' ');
sb.append(formatAnnotationString(array.getAnnotations()).trim());
sb.append(" []");
if (!(component instanceof AnnotatedArrayType)) {
sb.insert(0, component.getUnderlyingType().toString());
break;
}
array = (AnnotatedArrayType) component;
}
sb.insert(0, formatAnnotationString(component.getAnnotations()));
return sb.toString();
}
@Override
public String toString() {
return toStringAsCanonical();
}
}
/**
* Represents a type variable. A type variable may be explicitly declared by
* a type parameter of a type, method, or constructor. A type variable may
* also be declared implicitly, as by the capture conversion of a wildcard
* type argument (see chapter 5 of The Java Language Specification, Third
* Edition).
*
*/
public static class AnnotatedTypeVariable extends AnnotatedTypeMirror
implements AnnotatedReferenceType {
private final TypeVariable actualType;
@Deprecated
AnnotatedTypeVariable(TypeVariable type,
ProcessingEnvironment env, AnnotatedTypeFactory factory) {
super(type, env, factory);
this.actualType = type;
}
/** The element of the type variable **/
private Element typeVarElement;
/** The lower bound of the type variable **/
private AnnotatedTypeMirror lowerBound;
/** The upper bound of the type variable **/
private AnnotatedTypeMirror upperBound;
@Override
public <R, P> R accept(AnnotatedTypeVisitor<R, P> v, P p) {
return v.visitTypeVariable(this, p);
}
@Override
public TypeVariable getUnderlyingType() {
return this.actualType;
}
/**
* Set the element of the type variable
*
* @param element the type variable element
*/
void setTypeVariableElement(Element element) {
this.typeVarElement = element;
}
/**
* @return the element of the type variable in this
*/
public Element getTypeVariableElement() {
return typeVarElement;
}
/**
* Set the lower bound of this variable type
*
* Returns the lower bound of this type variable. While a type
* parameter cannot include an explicit lower bound declaration,
* capture conversion can produce a type variable with a non-trivial
* lower bound. Type variables otherwise have a lower bound of
* NullType.
*
* @param type the lower bound type
*/
void setLowerBound(AnnotatedTypeMirror type) {
this.lowerBound = type;
}
/**
* @return the lower bound type of this type variable
*/
public AnnotatedTypeMirror getLowerBound() {
if (lowerBound == null && actualType.getLowerBound() != null) // lazy init
setLowerBound(createType(actualType.getLowerBound(), env, typeFactory));
return lowerBound;
}
/**
* Set the upper bound of this variable type
* @param type the upper bound type
*/
void setUpperBound(AnnotatedTypeMirror type) {
this.upperBound = type;
AnnotatedTypeMirror upperBound = type.substitute(Collections.singletonMap(this, this));
this.upperBound = upperBound;
}
/**
* @return the upper bound type of this type variable
*/
public AnnotatedTypeMirror getUpperBound() {
if (upperBound == null
&& actualType.getUpperBound() != null) // lazy init
setUpperBound(createType(
actualType.getUpperBound(), env, typeFactory));
return upperBound;
}
@Override
public AnnotatedTypeVariable getCopy(boolean annotation) {
AnnotatedTypeVariable type =
new AnnotatedTypeVariable(actualType, env, typeFactory);
copyFields(type, annotation);
type.setTypeVariableElement(getTypeVariableElement());
if (type.getUpperBound().isAnnotated())
type.setUpperBound(getUpperBound());
return type;
}
@Override
public AnnotatedTypeMirror getErased() {
// |T extends A&B| = |A|
return this.getUpperBound().getErased();
}
private static <K extends AnnotatedTypeMirror, V extends AnnotatedTypeMirror>
V mapGetHelper(
Map<K, V> mappings, AnnotatedTypeVariable key) {
for (Map.Entry<K, V> entry : mappings.entrySet()) {
K possible = entry.getKey();
if (possible == key) return entry.getValue();
if (possible instanceof AnnotatedTypeVariable) {
AnnotatedTypeVariable other = (AnnotatedTypeVariable)possible;
Element oElt = other.getUnderlyingType().asElement();
if (key.getUnderlyingType().asElement().equals(oElt)) {
if (!key.annotations.isEmpty()
&& !AnnotationUtils.areSame(key.annotations, other.annotations)) {
@SuppressWarnings("unchecked")
V found = (V)entry.getValue().getCopy(false);
found.addAnnotations(key.annotations);
return found;
} else
return entry.getValue();
}
}
}
return null;
}
@Override
public AnnotatedTypeMirror substitute(
Map<? extends AnnotatedTypeMirror,
? extends AnnotatedTypeMirror> mappings) {
AnnotatedTypeMirror found = mapGetHelper(mappings, this);
if (found != null) return found;
AnnotatedTypeVariable type = getCopy(true);
Map<AnnotatedTypeMirror, AnnotatedTypeMirror> newMappings =
new HashMap<AnnotatedTypeMirror, AnnotatedTypeMirror>(mappings);
newMappings.put(this, type);
type.setLowerBound(getLowerBound().substitute(newMappings));
if (getUpperBound() != null)
type.setUpperBound(getUpperBound().substitute(newMappings));
return type;
}
@Override
public boolean isAnnotated() {
return (super.isAnnotated()
|| (getUpperBound() != null && getUpperBound().isAnnotated()));
}
public Set<AnnotationMirror> getAnnotationsOnTypeVar() {
return super.getAnnotations();
}
@Override
public Set<AnnotationMirror> getAnnotations() {
if (!super.isAnnotated() && getUpperBound() != null)
return getUpperBound().getAnnotations();
return super.getAnnotations();
}
@Override
public void addAnnotation(AnnotationMirror anno) {
super.addAnnotation(anno);
this.getUpperBound().addAnnotation(anno);
}
// Style taken from Type
boolean isPrintingBound = false;
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(formatAnnotationString(getAnnotations()));
sb.append(actualType);
if (!isPrintingBound) {
try {
isPrintingBound = true;
if (getLowerBound() != null && getLowerBound().getKind() != TypeKind.NULL) {
sb.append(" super ");
sb.append(getLowerBound());
}
if (getUpperBound() != null && getUpperBound().getKind() != TypeKind.NULL) {
sb.append(" extends ");
sb.append(getUpperBound());
}
} finally {
isPrintingBound = false;
}
}
return sb.toString();
}
@Override
public int hashCode() {
return this.getUnderlyingType().hashCode();
}
@Override
public boolean equals(Object o) {
if (!(o instanceof AnnotatedTypeVariable))
return false;
AnnotatedTypeVariable other = (AnnotatedTypeVariable) o;
boolean isSame =
this.getUnderlyingType() == other.getUnderlyingType()
&& AnnotationUtils.areSame(this.annotations, other.annotations);
return isSame;
}
}
/**
* A pseudo-type used where no actual type is appropriate. The kinds of
* NoType are:
*
* <ul>
* <li>VOID - corresponds to the keyword void.</li>
* <li> PACKAGE - the pseudo-type of a package element.</li>
* <li> NONE - used in other cases where no actual type is appropriate;
* for example, the superclass of java.lang.Object. </li>
* </ul>
*/
public static class AnnotatedNoType extends AnnotatedTypeMirror {
private final NoType actualType;
AnnotatedNoType(NoType type, ProcessingEnvironment env, AnnotatedTypeFactory factory) {
super(type, env, factory);
this.actualType = type;
}
// No need for methods
// Might like to override annotate(), include(), execlude()
// AS NoType does not accept any annotations
@Override
public <R, P> R accept(AnnotatedTypeVisitor<R, P> v, P p) {
return v.visitNoType(this, p);
}
@Override
public NoType getUnderlyingType() {
return this.actualType;
}
@Override
public AnnotatedNoType getCopy(boolean annotation) {
AnnotatedNoType type = new AnnotatedNoType(actualType, env, typeFactory);
copyFields(type, annotation);
return type;
}
@Override
public AnnotatedTypeMirror substitute(
Map<? extends AnnotatedTypeMirror,
? extends AnnotatedTypeMirror> mappings) {
// Cannot substitute
return getCopy(true);
}
}
/**
* Represents the null type. This is the type of the expression {@code null}.
*/
public static class AnnotatedNullType extends AnnotatedTypeMirror
implements AnnotatedReferenceType {
private final NullType actualType;
AnnotatedNullType(NullType type, ProcessingEnvironment env, AnnotatedTypeFactory factory) {
super(type, env, factory);
this.actualType = type;
}
@Override
public <R, P> R accept(AnnotatedTypeVisitor<R, P> v, P p) {
return v.visitNull(this, p);
}
@Override
public NullType getUnderlyingType() {
return this.actualType;
}
@Override
public AnnotatedNullType getCopy(boolean annotation) {
AnnotatedNullType type = new AnnotatedNullType(actualType, env, typeFactory);
copyFields(type, annotation);
return type;
}
@Override
public AnnotatedTypeMirror substitute(
Map<? extends AnnotatedTypeMirror,
? extends AnnotatedTypeMirror> mappings) {
// cannot substitute
return getCopy(true);
}
@Override
public String toString() {
return "null";
}
}
/**
* Represents a primitive type. These include {@code boolean},
* {@code byte}, {@code short}, {@code int}, {@code long}, {@code char},
* {@code float}, and {@code double}.
*/
public static class AnnotatedPrimitiveType extends AnnotatedTypeMirror
implements AnnotatedReferenceType {
private final PrimitiveType actualType;
AnnotatedPrimitiveType(PrimitiveType type,
ProcessingEnvironment env, AnnotatedTypeFactory factory) {
super(type, env, factory);
this.actualType = type;
}
@Override
public <R, P> R accept(AnnotatedTypeVisitor<R, P> v, P p) {
return v.visitPrimitive(this, p);
}
@Override
public PrimitiveType getUnderlyingType() {
return this.actualType;
}
@Override
public AnnotatedPrimitiveType getCopy(boolean annotation) {
AnnotatedPrimitiveType type =
new AnnotatedPrimitiveType(actualType, env, typeFactory);
copyFields(type, annotation);
return type;
}
@Override
public AnnotatedTypeMirror substitute(
Map<? extends AnnotatedTypeMirror,
? extends AnnotatedTypeMirror> mappings) {
// cannot substitute
return getCopy(true);
}
}
/**
* Represents a wildcard type argument. Examples include:
*
* ?
* ? extends Number
* ? super T
*
* A wildcard may have its upper bound explicitly set by an extends
* clause, its lower bound explicitly set by a super clause, or neither
* (but not both).
*/
public static class AnnotatedWildcardType extends AnnotatedTypeMirror {
/** SuperBound **/
private AnnotatedTypeMirror superBound;
/** ExtendBound **/
private AnnotatedTypeMirror extendsBound;
private final WildcardType actualType;
@Deprecated
AnnotatedWildcardType(WildcardType type, ProcessingEnvironment env, AnnotatedTypeFactory factory) {
super(type, env, factory);
this.actualType = type;
}
/**
* Sets the super bound of this wild card
*
* @param type the type of the lower bound
*/
void setSuperBound(AnnotatedTypeMirror type) {
this.superBound = type;
}
/**
* @return the lower bound of this wildcard. If no lower bound is
* explicitly declared, {@code null} is returned.
*/
public AnnotatedTypeMirror getSuperBound() {
if (superBound == null
&& actualType.getSuperBound() != null) // lazy init
setSuperBound(createType(
actualType.getSuperBound(), env, typeFactory));
return this.superBound;
}
/**
* Sets the upper bound of this wild card
*
* @param type the type of the upper bound
*/
void setExtendsBound(AnnotatedTypeMirror type) {
this.extendsBound = type;
}
/**
* @return the lower bound of this wildcard. If no lower bound is
* explicitly declared, {@code null} is returned.
*/
public AnnotatedTypeMirror getExtendsBound() {
if (extendsBound == null) { // lazy init
TypeMirror superType = actualType.getExtendsBound();
if (superType == null)
superType = env.getElementUtils().getTypeElement("java.lang.Object").asType();
setExtendsBound(createType(superType, env, typeFactory));
}
return this.extendsBound;
}
@Override
public <R, P> R accept(AnnotatedTypeVisitor<R, P> v, P p) {
return v.visitWildcard(this, p);
}
@Override
public WildcardType getUnderlyingType() {
return this.actualType;
}
@Override
public AnnotatedWildcardType getCopy(boolean annotation) {
AnnotatedWildcardType type = new AnnotatedWildcardType(actualType, env, typeFactory);
copyFields(type, annotation);
type.setExtendsBound(getExtendsBound());
type.setSuperBound(getSuperBound());
return type;
}
@Override
public AnnotatedTypeMirror substitute(
Map<? extends AnnotatedTypeMirror,
? extends AnnotatedTypeMirror> mappings) {
if (mappings.containsKey(this))
return mappings.get(this);
AnnotatedWildcardType type = getCopy(true);
// Prevent looping
Map<AnnotatedTypeMirror, AnnotatedTypeMirror> newMapping =
new HashMap<AnnotatedTypeMirror, AnnotatedTypeMirror>(mappings);
newMapping.put(this, type);
// The extends and super bounds can be null because the underlying
// type's extends and super bounds can be null.
if (getExtendsBound() != null)
type.setExtendsBound(getExtendsBound().substitute(newMapping));
if (getSuperBound() != null)
type.setSuperBound(getSuperBound().substitute(newMapping));
return type;
}
@Override
public AnnotatedTypeMirror getErased() {
// |T extends A&B| = |A|
if (getExtendsBound() != null)
return getExtendsBound().getErased();
return createTypeOfObject(typeFactory);
}
boolean isPrintingBound = false;
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("?");
if (!isPrintingBound) {
try {
isPrintingBound = true;
if (getExtendsBound() != null && getExtendsBound().getKind() != TypeKind.NONE) {
sb.append(" extends ");
sb.append(getExtendsBound());
}
if (getSuperBound() != null && getSuperBound().getKind() != TypeKind.NULL) {
sb.append(" super ");
sb.append(getSuperBound());
}
} finally {
isPrintingBound = false;
}
}
return sb.toString();
}
@Override
public boolean isAnnotated() {
return (super.isAnnotated()
|| (getExtendsBound() != null && getExtendsBound().isAnnotated()));
}
@Override
public Set<AnnotationMirror> getAnnotations() {
if (!super.isAnnotated() && getExtendsBound() != null)
return getExtendsBound().getAnnotations();
return super.getAnnotations();
}
}
protected final List<AnnotatedDeclaredType>
directSuperTypes(AnnotatedDeclaredType type) {
setSuperTypeFinder(type.typeFactory);
List<AnnotatedDeclaredType> supertypes =
superTypeFinder.visitDeclared(type, null);
typeFactory.postDirectSuperTypes(type, supertypes);
return supertypes;
}
private final List<? extends AnnotatedTypeMirror> directSuperTypes(
AnnotatedTypeMirror type) {
setSuperTypeFinder(type.typeFactory);
List<? extends AnnotatedTypeMirror> supertypes =
superTypeFinder.visit(type, null);
typeFactory.postDirectSuperTypes(type, supertypes);
return supertypes;
}
private static void setSuperTypeFinder(AnnotatedTypeFactory factory) {
if (superTypeFinder == null || superTypeFinder.typeFactory != factory)
superTypeFinder = new SuperTypeFinder(factory);
}
private static SuperTypeFinder superTypeFinder;
private static class SuperTypeFinder extends
SimpleAnnotatedTypeVisitor<List<? extends AnnotatedTypeMirror>, Void> {
private Types types;
private final AnnotatedTypeFactory typeFactory;
SuperTypeFinder(AnnotatedTypeFactory typeFactory) {
this.typeFactory = typeFactory;
this.types = typeFactory.env.getTypeUtils();
}
@Override
public List<AnnotatedTypeMirror> defaultAction(AnnotatedTypeMirror t, Void p) {
return new ArrayList<AnnotatedTypeMirror>();
}
/**
* Primitive Rules:
*
* double >1 float
* float >1 long
* long >1 int
* int >1 char
* int >1 short
* short >1 byte
*
* For easiness:
* boxed(primitiveType) >: primitiveType
*/
@Override
public List<AnnotatedTypeMirror> visitPrimitive(AnnotatedPrimitiveType type, Void p) {
List<AnnotatedTypeMirror> superTypes =
new ArrayList<AnnotatedTypeMirror>();
Set<AnnotationMirror> annotations = type.getAnnotations();
// Find Boxed type
TypeElement boxed = types.boxedClass(type.getUnderlyingType());
AnnotatedDeclaredType boxedType = typeFactory.getAnnotatedType(boxed);
if (!annotations.isEmpty())
boxedType.clearAnnotations();
boxedType.addAnnotations(annotations);
superTypes.add(boxedType);
TypeKind superPrimitiveType = null;
if (type.getKind() == TypeKind.BOOLEAN) {
// Nothing
} else if (type.getKind() == TypeKind.BYTE) {
superPrimitiveType = TypeKind.SHORT;
} else if (type.getKind() == TypeKind.CHAR) {
superPrimitiveType = TypeKind.INT;
} else if (type.getKind() == TypeKind.DOUBLE) {
// Nothing
} else if (type.getKind() == TypeKind.FLOAT) {
superPrimitiveType = TypeKind.DOUBLE;
} else if (type.getKind() == TypeKind.INT) {
superPrimitiveType = TypeKind.LONG;
} else if (type.getKind() == TypeKind.LONG) {
superPrimitiveType = TypeKind.FLOAT;
} else if (type.getKind() == TypeKind.SHORT) {
superPrimitiveType = TypeKind.INT;
} else
assert false: "Forgot the primitive " + type;
if (superPrimitiveType != null) {
AnnotatedPrimitiveType superPrimitive = (AnnotatedPrimitiveType)
typeFactory.toAnnotatedType(types.getPrimitiveType(superPrimitiveType));
superPrimitive.addAnnotations(annotations);
superTypes.add(superPrimitive);
}
return superTypes;
}
@Override
public List<AnnotatedDeclaredType> visitDeclared(AnnotatedDeclaredType type, Void p) {
List<AnnotatedDeclaredType> supertypes =
new ArrayList<AnnotatedDeclaredType>();
Set<AnnotationMirror> annotations = type.getAnnotations();
TypeElement typeElement =
(TypeElement) type.getUnderlyingType().asElement();
// Mapping of type variable to actual types
Map<TypeParameterElement, AnnotatedTypeMirror> mapping =
new HashMap<TypeParameterElement, AnnotatedTypeMirror>();
final boolean isRaw = !type.isParameterized() && type.isGeneric();
for (int i = 0; i < typeElement.getTypeParameters().size() &&
i < type.getTypeArguments().size(); ++i) {
mapping.put(typeElement.getTypeParameters().get(i),
type.getTypeArguments().get(i));
}
ClassTree classTree = typeFactory.trees.getTree(typeElement);
// Testing against enum and annotation. idealy we can simply use element!
if (classTree != null) {
supertypes.addAll(supertypesFromTree(classTree));
} else {
supertypes.addAll(supertypesFromElement(typeElement));
final Element elem = type.getElement() == null ? typeElement : type.getElement();
}
for (AnnotatedDeclaredType dt : supertypes) {
if (isRaw)
dt.setTypeArguments(Collections.<AnnotatedTypeMirror>emptyList());
else if (!mapping.isEmpty())
replacer.visit(dt, mapping);
}
return supertypes;
}
private List<AnnotatedDeclaredType> supertypesFromElement(TypeElement typeElement) {
List<AnnotatedDeclaredType> supertypes = new ArrayList<AnnotatedDeclaredType>();
// Find the super types: Start with superclass
if (typeElement.getSuperclass().getKind() != TypeKind.NONE) {
DeclaredType superClass = (DeclaredType) typeElement.getSuperclass();
AnnotatedDeclaredType dt =
(AnnotatedDeclaredType)typeFactory.toAnnotatedType(superClass);
supertypes.add(dt);
} else if (!ElementUtils.isObject(typeElement)) {
supertypes.add(createTypeOfObject(typeFactory));
}
for (TypeMirror st : typeElement.getInterfaces()) {
AnnotatedDeclaredType ast =
(AnnotatedDeclaredType)typeFactory.toAnnotatedType(st);
supertypes.add(ast);
}
TypeFromElement.annotateSupers(supertypes, typeElement);
return supertypes;
}
private List<AnnotatedDeclaredType> supertypesFromTree(ClassTree classTree) {
List<AnnotatedDeclaredType> supertypes = new ArrayList<AnnotatedDeclaredType>();
if (classTree.getExtendsClause() != null) {
AnnotatedDeclaredType adt = (AnnotatedDeclaredType)
typeFactory.fromTypeTree(classTree.getExtendsClause());
supertypes.add(adt);
} else if (!ElementUtils.isObject(TreeUtils.elementFromDeclaration(classTree))) {
supertypes.add(createTypeOfObject(typeFactory));
}
for (Tree implemented : classTree.getImplementsClause()) {
AnnotatedDeclaredType adt = (AnnotatedDeclaredType)
typeFactory.getAnnotatedTypeFromTypeTree(implemented);
supertypes.add(adt);
}
TypeElement elem = TreeUtils.elementFromDeclaration(classTree);
if (elem.getKind() == ElementKind.ENUM) {
DeclaredType dt = (DeclaredType) elem.getSuperclass();
AnnotatedDeclaredType adt = (AnnotatedDeclaredType)typeFactory.toAnnotatedType(dt);
supertypes.add(adt);
} else if (elem.getKind() == ElementKind.ANNOTATION_TYPE) {
DeclaredType dt = (DeclaredType) typeFactory.elements.getTypeElement("java.lang.annotation.Annotation").asType();
AnnotatedDeclaredType adt = (AnnotatedDeclaredType)typeFactory.toAnnotatedType(dt);
supertypes.add(adt);
}
return supertypes;
}
/**
* For type = A[ ] ==>
* Object >: A[ ]
* Clonable >: A[ ]
* java.io.Serializable >: A[ ]
*
* if A is reference type, then also
* B[ ] >: A[ ] for any B[ ] >: A[ ]
*/
@Override
public List<AnnotatedTypeMirror> visitArray(AnnotatedArrayType type, Void p) {
List<AnnotatedTypeMirror> superTypes = new ArrayList<AnnotatedTypeMirror>();
Set<AnnotationMirror> annotations = type.getAnnotations();
Elements elements = typeFactory.elements;
final AnnotatedTypeMirror objectType =
typeFactory.getAnnotatedType(elements.getTypeElement("java.lang.Object"));
objectType.addAnnotations(annotations);
superTypes.add(objectType);
final AnnotatedTypeMirror cloneableType =
typeFactory.getAnnotatedType(elements.getTypeElement("java.lang.Cloneable"));
cloneableType.addAnnotations(annotations);
superTypes.add(cloneableType);
final AnnotatedTypeMirror serializableType =
typeFactory.getAnnotatedType(elements.getTypeElement("java.io.Serializable"));
serializableType.addAnnotations(annotations);
superTypes.add(serializableType);
if (type.getComponentType() instanceof AnnotatedReferenceType) {
for (AnnotatedTypeMirror sup : type.getComponentType().directSuperTypes()) {
ArrayType arrType = typeFactory.types.getArrayType(sup.getUnderlyingType());
AnnotatedArrayType aarrType = (AnnotatedArrayType)
typeFactory.toAnnotatedType(arrType);
aarrType.setComponentType(sup);
aarrType.addAnnotations(annotations);
superTypes.add(aarrType);
}
}
return superTypes;
}
@Override
public List<AnnotatedTypeMirror> visitTypeVariable(AnnotatedTypeVariable type, Void p) {
List<AnnotatedTypeMirror> superTypes = new ArrayList<AnnotatedTypeMirror>();
if (type.getUpperBound() != null)
superTypes.add(type.getUpperBound());
return superTypes;
}
@Override
public List<AnnotatedTypeMirror> visitWildcard(AnnotatedWildcardType type, Void p) {
List<AnnotatedTypeMirror> superTypes = new ArrayList<AnnotatedTypeMirror>();
if (type.getExtendsBound() != null)
superTypes.add(type.getExtendsBound());
return superTypes;
}
};
private static AnnotatedTypeScanner<Void, Map<TypeParameterElement, AnnotatedTypeMirror>>
replacer;
static class Replacer extends AnnotatedTypeScanner<Void, Map<TypeParameterElement, AnnotatedTypeMirror>> {
final Types types;
public Replacer(Types types) {
this.types = types;
}
public Void visitDeclared(AnnotatedDeclaredType type, Map<TypeParameterElement, AnnotatedTypeMirror> mapping) {
List<AnnotatedTypeMirror> args = new ArrayList<AnnotatedTypeMirror>();
for (AnnotatedTypeMirror arg : type.getTypeArguments()) {
Element elem = types.asElement(arg.getUnderlyingType());
if ((elem != null) &&
(elem.getKind() == ElementKind.TYPE_PARAMETER) &&
(mapping.containsKey(elem))) {
AnnotatedTypeMirror other = mapping.get(elem);
if (!arg.annotations.isEmpty()) {
other.clearAnnotations();
other.addAnnotations(arg.annotations);
}
args.add(other);
} else
args.add(arg);
}
type.setTypeArguments(args);
return super.visitDeclared(type, mapping);
}
};
}