blob: e50e9199529375b18c1554d85f588545c57a63c0 [file] [log] [blame]
package org.checkerframework.framework.type;
import com.sun.tools.javac.code.Symbol.MethodSymbol;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.TypeParameterElement;
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.NoType;
import javax.lang.model.type.NullType;
import javax.lang.model.type.PrimitiveType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.type.TypeVariable;
import javax.lang.model.type.UnionType;
import javax.lang.model.type.WildcardType;
import javax.lang.model.util.Types;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.checkerframework.dataflow.qual.Pure;
import org.checkerframework.dataflow.qual.SideEffectFree;
import org.checkerframework.framework.type.visitor.AnnotatedTypeVisitor;
import org.checkerframework.framework.util.element.ElementAnnotationUtil.ErrorTypeKindException;
import org.checkerframework.javacutil.AnnotationBuilder;
import org.checkerframework.javacutil.AnnotationUtils;
import org.checkerframework.javacutil.BugInCF;
import org.checkerframework.javacutil.ElementUtils;
import org.checkerframework.javacutil.TypeKindUtils;
import org.plumelib.util.CollectionsPlume;
/**
* 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>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
*/
public abstract class AnnotatedTypeMirror {
/**
* Creates an AnnotatedTypeMirror for the provided type. The result contains no annotations.
*
* @param type the underlying type for the resulting AnnotatedTypeMirror
* @param atypeFactory the type factory that will build the result
* @param isDeclaration true if the result should represent a declaration, rather than a use, of a
* type
* @return an AnnotatedTypeMirror whose underlying type is {@code type}
*/
public static AnnotatedTypeMirror createType(
TypeMirror type, AnnotatedTypeFactory atypeFactory, boolean isDeclaration) {
if (type == null) {
throw new BugInCF("AnnotatedTypeMirror.createType: input type must not be null");
}
AnnotatedTypeMirror result;
switch (type.getKind()) {
case ARRAY:
result = new AnnotatedArrayType((ArrayType) type, atypeFactory);
break;
case DECLARED:
result = new AnnotatedDeclaredType((DeclaredType) type, atypeFactory, isDeclaration);
break;
case ERROR:
throw new BugInCF(
"AnnotatedTypeMirror.createType: input is not compilable. Found error type: " + type);
case EXECUTABLE:
result = new AnnotatedExecutableType((ExecutableType) type, atypeFactory);
break;
case VOID:
case PACKAGE:
case NONE:
result = new AnnotatedNoType((NoType) type, atypeFactory);
break;
case NULL:
result = new AnnotatedNullType((NullType) type, atypeFactory);
break;
case TYPEVAR:
result = new AnnotatedTypeVariable((TypeVariable) type, atypeFactory, isDeclaration);
break;
case WILDCARD:
result = new AnnotatedWildcardType((WildcardType) type, atypeFactory);
break;
case INTERSECTION:
result = new AnnotatedIntersectionType((IntersectionType) type, atypeFactory);
break;
case UNION:
result = new AnnotatedUnionType((UnionType) type, atypeFactory);
break;
default:
if (type.getKind().isPrimitive()) {
result = new AnnotatedPrimitiveType((PrimitiveType) type, atypeFactory);
break;
}
throw new BugInCF(
"AnnotatedTypeMirror.createType: unidentified type "
+ type
+ " ("
+ type.getKind()
+ ")");
}
/*if (jctype.isAnnotated()) {
result.addAnnotations(jctype.getAnnotationMirrors());
}*/
return result;
}
protected static final EqualityAtmComparer EQUALITY_COMPARER = new EqualityAtmComparer();
protected static final HashcodeAtmVisitor HASHCODE_VISITOR = new HashcodeAtmVisitor();
/** The factory to use for lazily creating annotated types. */
protected final AnnotatedTypeFactory atypeFactory;
/** Actual type wrapped with this AnnotatedTypeMirror. */
protected final TypeMirror underlyingType;
/**
* Saves the result of {@code underlyingType.toString().hashcode()} to use when computing the hash
* code of this. (Because AnnotatedTypeMirrors are mutable, the hash code for this cannot be
* saved.) Call {@link #getUnderlyingTypeHashCode()} rather than using the field directly.
*/
private int underlyingTypeHashCode = -1;
/** 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.
protected final Set<AnnotationMirror> annotations = AnnotationUtils.createAnnotationSet();
/** The explicitly written annotations on this type. */
// TODO: use this to cache the result once computed? For generic types?
// protected final Set<AnnotationMirror> explicitannotations =
// AnnotationUtils.createAnnotationSet();
/**
* Constructor for AnnotatedTypeMirror.
*
* @param underlyingType the underlying type
* @param atypeFactory used to create further types and to access global information (Types,
* Elements, ...)
*/
private AnnotatedTypeMirror(TypeMirror underlyingType, AnnotatedTypeFactory atypeFactory) {
this.underlyingType = underlyingType;
assert atypeFactory != null;
this.atypeFactory = atypeFactory;
}
@Override
public final boolean equals(Object o) {
if (o == this) {
return true;
}
if (!(o instanceof AnnotatedTypeMirror)) {
return false;
}
return EQUALITY_COMPARER.visit(this, (AnnotatedTypeMirror) o, null);
}
@Pure
@Override
public final int hashCode() {
return HASHCODE_VISITOR.visit(this);
}
/**
* 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 underlyingType.getKind();
}
/**
* Given a primitive type, return its kind. Given a boxed primitive type, return the corresponding
* primitive type kind. Otherwise, return null.
*
* @return a primitive type kind if this is a primitive type or boxed primitive type; otherwise
* null
*/
public TypeKind getPrimitiveKind() {
return TypeKindUtils.primitiveOrBoxedToTypeKind(getUnderlyingType());
}
/**
* Returns the underlying unannotated Java type, which this wraps.
*
* @return the underlying type
*/
public TypeMirror getUnderlyingType() {
return underlyingType;
}
/**
* Returns true if this type mirror represents a declaration, rather than a use, of a type.
*
* <p>For example, {@code class List<T> { ... }} declares a new type {@code List<T>}, while {@code
* List<Integer>} is a use of the type.
*
* @return true if this represents a declaration
*/
public boolean isDeclaration() {
return false;
}
public AnnotatedTypeMirror asUse() {
return this;
}
/**
* Returns true if an annotation from the given sub-hierarchy targets this type.
*
* <p>It doesn't account for annotations in deep types (type arguments, array components, etc).
*
* @param p the qualifier hierarchy to check for
* @return true iff an annotation from the same hierarchy as p is present
*/
public boolean isAnnotatedInHierarchy(AnnotationMirror p) {
return getAnnotationInHierarchy(p) != null;
}
/**
* Returns an annotation from the given sub-hierarchy, if such an annotation targets this type;
* otherwise returns null.
*
* <p>It doesn't account for annotations in deep types (type arguments, array components, etc).
*
* <p>If there is only one hierarchy, you can use {@link #getAnnotation()} instead.
*
* <p>May return null if the receiver is a type variable or a wildcard without a primary
* annotation, or if the receiver is not yet fully annotated.
*
* @param p the qualifier hierarchy to check for
* @return an annotation from the same hierarchy as p if present
*/
public AnnotationMirror getAnnotationInHierarchy(AnnotationMirror p) {
AnnotationMirror aliased = p;
if (!atypeFactory.isSupportedQualifier(aliased)) {
aliased = atypeFactory.canonicalAnnotation(p);
}
if (atypeFactory.isSupportedQualifier(aliased)) {
QualifierHierarchy qualHier = this.atypeFactory.getQualifierHierarchy();
AnnotationMirror anno = qualHier.findAnnotationInSameHierarchy(annotations, aliased);
if (anno != null) {
return anno;
}
}
return null;
}
/**
* Returns an annotation from the given sub-hierarchy, if such an annotation is present on this
* type or on its extends bounds; otherwise returns null.
*
* <p>It doesn't account for annotations in deep types (type arguments, array components, etc).
*
* @param p the qualifier hierarchy to check for
* @return an annotation from the same hierarchy as p if present
*/
public AnnotationMirror getEffectiveAnnotationInHierarchy(AnnotationMirror p) {
AnnotationMirror aliased = p;
if (!atypeFactory.isSupportedQualifier(aliased)) {
aliased = atypeFactory.canonicalAnnotation(p);
}
if (atypeFactory.isSupportedQualifier(aliased)) {
QualifierHierarchy qualHier = this.atypeFactory.getQualifierHierarchy();
AnnotationMirror anno =
qualHier.findAnnotationInSameHierarchy(getEffectiveAnnotations(), aliased);
if (anno != null) {
return anno;
}
}
return null;
}
/**
* Returns the annotations on this type. It does not include annotations in deep types (type
* arguments, array components, etc).
*
* <p>To get the single annotation in a particular hierarchy, use {@link
* #getAnnotationInHierarchy}. If there is only one hierarchy, you can use {@link #getAnnotation}.
*
* @return a unmodifiable set of the annotations on this
*/
public final Set<AnnotationMirror> getAnnotations() {
return Collections.unmodifiableSet(annotations);
}
/**
* Returns the annotations on this type; mutations affect this object, because the return type is
* an alias of the {@code annotations} field. It does not include annotations in deep types (type
* arguments, array components, etc).
*
* <p>The returned set should not be modified, but for efficiency reasons modification is not
* prevented. Modifications might break invariants.
*
* @return the set of the annotations on this; mutations affect this object
*/
protected final Set<AnnotationMirror> getAnnotationsField() {
return annotations;
}
/**
* Returns the single annotation on this type. It does not include annotations in deep types (type
* arguments, array components, etc).
*
* <p>This method requires that there is only a single hierarchy. In that case, it is equivalent
* to {@link #getAnnotationInHierarchy}.
*
* @see #getAnnotations
* @return the annotation on this, or null if none (which can only happen if {@code this} is a
* type variable or wildcard)
*/
public final @Nullable AnnotationMirror getAnnotation() {
if (annotations.isEmpty()) {
// This AnnotatedTypeMirror must be a type variable or wildcard.
return null;
}
if (annotations.size() != 1) {
throw new BugInCF("Bad annotation size for getAnnotation(): " + this);
}
return annotations.iterator().next();
}
/**
* Returns the "effective" annotations on this type, i.e. the annotations on the type itself, or
* on the upper/extends bound of a type variable/wildcard (recursively, until a class type is
* reached).
*
* @return a set of the annotations on this
*/
public Set<AnnotationMirror> getEffectiveAnnotations() {
Set<AnnotationMirror> effectiveAnnotations = getErased().getAnnotations();
// assert atypeFactory.qualHierarchy.getWidth() == effectiveAnnotations
// .size() : "Invalid number of effective annotations ("
// + effectiveAnnotations + "). Should be "
// + atypeFactory.qualHierarchy.getWidth() + " but is "
// + effectiveAnnotations.size() + ". Type: " + this;
return effectiveAnnotations;
}
/**
* Returns the actual annotation mirror used to annotate this type, whose Class equals the passed
* annoClass if one exists, null otherwise.
*
* @param annoClass annotation class
* @return the annotation mirror for anno
*/
public AnnotationMirror getAnnotation(Class<? extends Annotation> annoClass) {
for (AnnotationMirror annoMirror : annotations) {
if (atypeFactory.areSameByClass(annoMirror, annoClass)) {
return annoMirror;
}
}
return null;
}
/**
* Returns the actual annotation mirror used to annotate this type, whose name equals the passed
* {@code annoName} if one exists, null otherwise.
*
* @param annoName annotation name
* @return the annotation mirror for annoName
*/
public AnnotationMirror getAnnotation(String annoName) {
for (AnnotationMirror annoMirror : annotations) {
if (AnnotationUtils.areSameByName(annoMirror, annoName)) {
return annoMirror;
}
}
return null;
}
/**
* Returns the set of explicitly written annotations on this type that are supported by this
* checker. This is useful to check the validity of annotations explicitly present on a type, as
* flow inference might add annotations that were not previously present. Note that since
* AnnotatedTypeMirror instances are created for type uses, this method will return explicit
* annotations in type use locations but will not return explicit annotations that had an impact
* on defaulting, such as an explicit annotation on a class declaration. For example, given:
*
* <p>{@code @MyExplicitAnno class MyClass {}; MyClass myClassInstance; }
*
* <p>the result of calling {@code
* atypeFactory.getAnnotatedType(variableTreeForMyClassInstance).getExplicitAnnotations()}
*
* <p>will not contain {@code @MyExplicitAnno}.
*
* @return the set of explicitly written annotations on this type that are supported by this
* checker
*/
public Set<AnnotationMirror> getExplicitAnnotations() {
// TODO JSR 308: The explicit type annotations should be always present
Set<AnnotationMirror> explicitAnnotations = AnnotationUtils.createAnnotationSet();
List<? extends AnnotationMirror> typeAnnotations =
this.getUnderlyingType().getAnnotationMirrors();
for (AnnotationMirror explicitAnno : typeAnnotations) {
if (atypeFactory.isSupportedQualifier(explicitAnno)) {
explicitAnnotations.add(explicitAnno);
}
}
return explicitAnnotations;
}
/**
* Determines whether this type contains the given annotation. This method considers the
* annotation's values, that is, if the type is "@A("s") @B(3) Object" a call with "@A("t") or
* "@A" will return false, whereas a call with "@B(3)" will return true.
*
* <p>In contrast to {@link #hasAnnotationRelaxed(AnnotationMirror)} this method also compares
* annotation values.
*
* @param a the annotation to check for
* @return true iff the type contains the annotation {@code a}
* @see #hasAnnotationRelaxed(AnnotationMirror)
*/
public boolean hasAnnotation(AnnotationMirror a) {
return AnnotationUtils.containsSame(annotations, 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;
}
/**
* Returns the actual effective annotation mirror used to annotate this type, whose Class equals
* the passed annoClass if one exists, null otherwise.
*
* @param annoClass annotation class
* @return the annotation mirror for anno
*/
public AnnotationMirror getEffectiveAnnotation(Class<? extends Annotation> annoClass) {
for (AnnotationMirror annoMirror : getEffectiveAnnotations()) {
if (atypeFactory.areSameByClass(annoMirror, annoClass)) {
return annoMirror;
}
}
return null;
}
/**
* A version of hasAnnotation that considers annotations on the upper bound of wildcards and type
* variables.
*
* @see #hasAnnotation(Class)
*/
public boolean hasEffectiveAnnotation(Class<? extends Annotation> a) {
return getEffectiveAnnotation(a) != null;
}
/**
* A version of hasAnnotation that considers annotations on the upper bound of wildcards and type
* variables.
*
* @see #hasAnnotation(AnnotationMirror)
*/
public boolean hasEffectiveAnnotation(AnnotationMirror a) {
return AnnotationUtils.containsSame(getEffectiveAnnotations(), a);
}
/**
* Determines whether this type contains the given annotation explicitly written at declaration.
* This method considers the annotation's values, that is, if the type is {@code @A("s") @B(3)
* Object}, a call with {@code @A("t")} or {@code @A} will return false, whereas a call with
* {@code @B(3)} will return true.
*
* <p>In contrast to {@link #hasExplicitAnnotationRelaxed(AnnotationMirror)} this method also
* compares annotation values.
*
* <p>See the documentation for {@link #getExplicitAnnotations()} for details on which explicit
* annotations are not included.
*
* @param a the annotation to check for
* @return true iff the annotation {@code a} is explicitly written on the type
* @see #hasExplicitAnnotationRelaxed(AnnotationMirror)
* @see #getExplicitAnnotations()
*/
public boolean hasExplicitAnnotation(AnnotationMirror a) {
return AnnotationUtils.containsSame(getExplicitAnnotations(), 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, that is, if the
* type is "@A("s") @B(3) Object" a call with "@A("t"), "@A", or "@B" will return true.
*
* @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}
* @see #hasAnnotation(AnnotationMirror)
*/
public boolean hasAnnotationRelaxed(AnnotationMirror a) {
return AnnotationUtils.containsSameByName(annotations, a);
}
/**
* A version of hasAnnotationRelaxed that considers annotations on the upper bound of wildcards
* and type variables.
*
* @see #hasAnnotationRelaxed(AnnotationMirror)
*/
public boolean hasEffectiveAnnotationRelaxed(AnnotationMirror a) {
return AnnotationUtils.containsSameByName(getEffectiveAnnotations(), a);
}
/**
* A version of hasAnnotationRelaxed that only considers annotations that are explicitly written
* on the type.
*
* <p>See the documentation for {@link #getExplicitAnnotations()} for details on which explicit
* annotations are not included.
*
* @see #hasAnnotationRelaxed(AnnotationMirror)
* @see #getExplicitAnnotations()
*/
public boolean hasExplicitAnnotationRelaxed(AnnotationMirror a) {
return AnnotationUtils.containsSameByName(getExplicitAnnotations(), a);
}
/**
* Determines whether this type contains an explicitly written annotation with the same annotation
* type as a particular annotation. This method does not consider an annotation's values.
*
* <p>See the documentation for {@link #getExplicitAnnotations()} for details on which explicit
* annotations are not included.
*
* @param a the class of annotation to check for
* @return true iff the type contains an explicitly written annotation with the same type as the
* annotation given by {@code a}
* @see #getExplicitAnnotations()
*/
public boolean hasExplicitAnnotation(Class<? extends Annotation> a) {
return AnnotationUtils.containsSameByName(getExplicitAnnotations(), getAnnotation(a));
}
/**
* Adds an annotation to this type. Only annotations supported by the type factory are added.
*
* @param a the annotation to add
*/
public void addAnnotation(AnnotationMirror a) {
if (a == null) {
throw new BugInCF("AnnotatedTypeMirror.addAnnotation: null argument.");
}
if (atypeFactory.isSupportedQualifier(a)) {
this.annotations.add(a);
} else {
AnnotationMirror aliased = atypeFactory.canonicalAnnotation(a);
if (atypeFactory.isSupportedQualifier(aliased)) {
addAnnotation(aliased);
}
}
}
/**
* Adds an annotation to this type, removing any existing annotation from the same qualifier
* hierarchy first.
*
* @param a the annotation to add
*/
public void replaceAnnotation(AnnotationMirror a) {
this.removeAnnotationInHierarchy(a);
this.addAnnotation(a);
}
/**
* Adds an annotation to this type.
*
* @param a the class of the annotation to add
*/
public void addAnnotation(Class<? extends Annotation> a) {
AnnotationMirror anno = AnnotationBuilder.fromClass(atypeFactory.elements, 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);
}
}
/**
* Adds each of the given annotations to the current type, only if no annotation from the same
* qualifier hierarchy is present.
*
* @param annotations the annotations to add
*/
public void addMissingAnnotations(Iterable<? extends AnnotationMirror> annotations) {
for (AnnotationMirror a : annotations) {
if (!this.isAnnotatedInHierarchy(a)) {
this.addAnnotation(a);
}
}
}
/**
* Adds multiple annotations to this type, removing any existing annotations from the same
* qualifier hierarchy first.
*
* @param replAnnos the annotations to replace
*/
public void replaceAnnotations(Iterable<? extends AnnotationMirror> replAnnos) {
for (AnnotationMirror a : replAnnos) {
this.replaceAnnotation(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) {
AnnotationMirror anno = AnnotationUtils.getSame(annotations, a);
if (anno != null) {
return annotations.remove(anno);
}
return false;
}
/**
* Removes an annotation of the given class from the type.
*
* @param a the class of the annotation to remove
* @return true if the annotation was removed, false if the type's annotations were unchanged
*/
public boolean removeAnnotationByClass(Class<? extends Annotation> a) {
AnnotationMirror anno = atypeFactory.getAnnotationByClass(annotations, a);
if (anno != null) {
return annotations.remove(anno);
}
return false;
}
/**
* Remove any annotation that is in the same qualifier hierarchy as the parameter.
*
* @param a an annotation from the same qualifier hierarchy
* @return if an annotation was removed
*/
public boolean removeAnnotationInHierarchy(AnnotationMirror a) {
AnnotationMirror prev = this.getAnnotationInHierarchy(a);
if (prev != null) {
return this.removeAnnotation(prev);
}
return false;
}
/**
* Remove an annotation that is in the same qualifier hierarchy as the parameter, unless it's the
* top annotation.
*
* @param a an annotation from the same qualifier hierarchy
* @return if an annotation was removed
*/
public boolean removeNonTopAnnotationInHierarchy(AnnotationMirror a) {
AnnotationMirror prev = this.getAnnotationInHierarchy(a);
QualifierHierarchy qualHier = this.atypeFactory.getQualifierHierarchy();
if (prev != null && !prev.equals(qualHier.getTopAnnotation(a))) {
return this.removeAnnotation(prev);
}
return false;
}
/**
* 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 primary annotations on this type. Make sure to add an annotation after calling
* this.
*
* <p>This method should only be used in very specific situations. For individual type systems, it
* is generally better to use {@link #removeAnnotation(AnnotationMirror)} and similar methods.
*/
public void clearAnnotations() {
annotations.clear();
}
@SideEffectFree
@Override
public final String toString() {
return atypeFactory.getAnnotatedTypeFormatter().format(this);
}
@SideEffectFree
public final String toString(boolean verbose) {
return atypeFactory.getAnnotatedTypeFormatter().format(this, verbose);
}
/**
* Returns the erasure type of the this type, according to JLS specifications.
*
* @see <a
* href="https://docs.oracle.com/javase/specs/jls/se11/html/jls-4.html#jls-4.6">https://docs.oracle.com/javase/specs/jls/se11/html/jls-4.html#jls-4.6</a>
* @return the erasure of this AnnotatedTypeMirror, this is always a copy even if the erasure and
* the original type are equivalent
*/
public AnnotatedTypeMirror getErased() {
return deepCopy();
}
/**
* Returns a deep copy of this type. A deep copy implies that each component type is copied
* recursively and the returned type refers to those copies in its component locations.
*
* <p>Note: deepCopy provides two important properties in the returned copy:
*
* <ol>
* <li>Structure preservation -- The exact structure of the original AnnotatedTypeMirror is
* preserved in the copy including all component types.
* <li>Annotation preservation -- All of the annotations from the original AnnotatedTypeMirror
* and its components have been copied to the new type.
* </ol>
*
* If copyAnnotations is set to false, the second property, Annotation preservation, is removed.
* This is useful for cases in which the user may want to copy the structure of a type exactly but
* NOT its annotations.
*
* @return a deep copy
*/
public abstract AnnotatedTypeMirror deepCopy(final boolean copyAnnotations);
/**
* Returns a deep copy of this type with annotations.
*
* <p>Each subclass implements this method with the subclass return type. The method body must
* always be a call to deepCopy(true).
*
* @return a deep copy of this type with annotations
* @see #deepCopy(boolean)
*/
public abstract AnnotatedTypeMirror deepCopy();
/**
* Returns a shallow copy of this type. A shallow copy implies that each component type in the
* output copy refers to the same object as the object being copied.
*
* @param copyAnnotations whether copy should have annotations, i.e. whether field {@code
* annotations} should be copied.
*/
public abstract AnnotatedTypeMirror shallowCopy(boolean copyAnnotations);
/**
* Returns a shallow copy of this type with annotations.
*
* <p>Each subclass implements this method with the subclass return type. The method body must
* always be a call to shallowCopy(true).
*
* @see #shallowCopy(boolean)
* @return a shallow copy of this type with annotations
*/
public abstract AnnotatedTypeMirror shallowCopy();
/**
* Returns whether this type or any component type is a wildcard type for which Java 7 type
* inference is insufficient. See issue 979, or the documentation on AnnotatedWildcardType.
*
* @return whether this type or any component type is a wildcard type for which Java 7 type
* inference is insufficient
*/
public boolean containsUninferredTypeArguments() {
return atypeFactory.containsUninferredTypeArguments(this);
}
/**
* Create an {@link AnnotatedDeclaredType} with the underlying type of {@link Object}. It includes
* any annotations placed by {@link AnnotatedTypeFactory#fromElement(Element)}.
*
* @param atypeFactory type factory to use
* @return AnnotatedDeclaredType for Object
*/
protected static AnnotatedDeclaredType createTypeOfObject(AnnotatedTypeFactory atypeFactory) {
AnnotatedDeclaredType objectType =
atypeFactory.fromElement(
atypeFactory.elements.getTypeElement(Object.class.getCanonicalName()));
objectType.declaration = false;
return objectType;
}
/**
* Returns the result of calling {@code underlyingType.toString().hashcode()}. This method saves
* the result in a field so that it isn't recomputed each time.
*
* @return the result of calling {@code underlyingType.toString().hashcode()}
*/
public int getUnderlyingTypeHashCode() {
if (underlyingTypeHashCode == -1) {
underlyingTypeHashCode = underlyingType.toString().hashCode();
}
return underlyingTypeHashCode;
}
/** Represents a declared type (whether class or interface). */
public static class AnnotatedDeclaredType extends AnnotatedTypeMirror {
/** Parametrized Type Arguments. */
protected List<AnnotatedTypeMirror> typeArgs;
/**
* Whether the type was initially raw, i.e. the user did not provide the type arguments.
* typeArgs will contain inferred type arguments, which might be too conservative at the moment.
* TODO: improve inference.
*
* <p>Ideally, the field would be final. However, when we determine the supertype of a raw type,
* we need to set wasRaw for the supertype.
*/
private boolean wasRaw;
/** The enclosing type. May be null. */
protected @Nullable AnnotatedDeclaredType enclosingType;
/** True if this represents a declaration, rather than a use, of a type. */
private boolean declaration;
/**
* Constructor for this type. The result contains no annotations.
*
* @param type underlying kind of this type
* @param atypeFactory the AnnotatedTypeFactory used to create this type
*/
private AnnotatedDeclaredType(
DeclaredType type, AnnotatedTypeFactory atypeFactory, boolean declaration) {
super(type, atypeFactory);
TypeElement typeelem = (TypeElement) type.asElement();
DeclaredType declty = (DeclaredType) typeelem.asType();
wasRaw = !declty.getTypeArguments().isEmpty() && type.getTypeArguments().isEmpty();
TypeMirror encl = type.getEnclosingType();
if (encl.getKind() == TypeKind.DECLARED) {
this.enclosingType = (AnnotatedDeclaredType) createType(encl, atypeFactory, declaration);
} else if (encl.getKind() == TypeKind.NONE) {
this.enclosingType = null;
} else {
throw new BugInCF(
"AnnotatedDeclaredType: unsupported enclosing type: "
+ type.getEnclosingType()
+ " ("
+ encl.getKind()
+ ")");
}
this.declaration = declaration;
}
@Override
public boolean isDeclaration() {
return declaration;
}
@Override
public AnnotatedDeclaredType deepCopy(boolean copyAnnotations) {
return (AnnotatedDeclaredType) new AnnotatedTypeCopier(copyAnnotations).visit(this);
}
@Override
public AnnotatedDeclaredType deepCopy() {
return deepCopy(true);
}
@Override
public AnnotatedDeclaredType asUse() {
if (!this.isDeclaration()) {
return this;
}
AnnotatedDeclaredType result = this.shallowCopy(true);
result.declaration = false;
// setTypeArguments calls asUse on all the new type arguments.
result.setTypeArguments(typeArgs);
return result;
}
@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 ts the type arguments
*/
// WMD
public void setTypeArguments(List<? extends AnnotatedTypeMirror> ts) {
if (ts == null || ts.isEmpty()) {
typeArgs = Collections.emptyList();
} else {
if (isDeclaration()) {
// TODO: check that all args are really declarations
typeArgs = Collections.unmodifiableList(ts);
} else {
List<AnnotatedTypeMirror> uses = CollectionsPlume.mapList(AnnotatedTypeMirror::asUse, ts);
typeArgs = Collections.unmodifiableList(uses);
}
}
}
/**
* Returns the type argument for this type.
*
* @return the type argument for this type
*/
public List<AnnotatedTypeMirror> getTypeArguments() {
if (typeArgs != null) {
return typeArgs;
} else if (wasRaw()) {
// Initialize the type arguments with uninferred wildcards.
BoundsInitializer.initializeTypeArgs(this);
return typeArgs;
} else if (getUnderlyingType().getTypeArguments().isEmpty()) {
typeArgs = Collections.emptyList();
return typeArgs;
} else {
// Initialize type argument for a non-raw declared type that has type arguments/
BoundsInitializer.initializeTypeArgs(this);
return typeArgs;
}
}
/**
* Returns true if the type was raw, that is, type arguments were not provided but instead
* inferred.
*
* @return true iff the type was raw
*/
public boolean wasRaw() {
return wasRaw;
}
/**
* Set the wasRaw flag to true. This should only be necessary when determining the supertypes of
* a raw type.
*/
protected void setWasRaw() {
this.wasRaw = true;
}
@Override
public DeclaredType getUnderlyingType() {
return (DeclaredType) underlyingType;
}
@Override
public List<AnnotatedDeclaredType> directSupertypes() {
return Collections.unmodifiableList(SupertypeFinder.directSupertypes(this));
}
@Override
public AnnotatedDeclaredType shallowCopy() {
return shallowCopy(true);
}
@Override
public AnnotatedDeclaredType shallowCopy(boolean copyAnnotations) {
AnnotatedDeclaredType type =
new AnnotatedDeclaredType(getUnderlyingType(), atypeFactory, declaration);
if (copyAnnotations) {
type.addAnnotations(this.getAnnotationsField());
}
type.setEnclosingType(getEnclosingType());
type.setTypeArguments(getTypeArguments());
return type;
}
/**
* Return the declared type with its type arguments removed. This also replaces the underlying
* type with its erasure.
*
* @return a fresh copy of the declared type with no type arguments
*/
@Override
public AnnotatedDeclaredType getErased() {
AnnotatedDeclaredType erased =
(AnnotatedDeclaredType)
AnnotatedTypeMirror.createType(
atypeFactory.types.erasure(underlyingType), atypeFactory, declaration);
erased.addAnnotations(this.getAnnotations());
AnnotatedDeclaredType erasedEnclosing = erased.getEnclosingType();
AnnotatedDeclaredType thisEnclosing = this.getEnclosingType();
while (erasedEnclosing != null) {
erasedEnclosing.addAnnotations(thisEnclosing.getAnnotations());
erasedEnclosing = erasedEnclosing.getEnclosingType();
thisEnclosing = thisEnclosing.getEnclosingType();
}
return erased;
}
/**
* Sets the enclosing type.
*
* @param enclosingType the new enclosing type
*/
/*default-visibility*/ void setEnclosingType(@Nullable AnnotatedDeclaredType enclosingType) {
this.enclosingType = enclosingType;
}
/**
* Returns the enclosing type, as in the type of {@code A} in the type {@code A.B}. May return
* null.
*
* @return enclosingType the enclosing type, or null if this is a top-level type
*/
public @Nullable AnnotatedDeclaredType getEnclosingType() {
return enclosingType;
}
}
/** Represents a type of an executable. An executable is a method, constructor, or initializer. */
public static class AnnotatedExecutableType extends AnnotatedTypeMirror {
private ExecutableElement element;
private AnnotatedExecutableType(ExecutableType type, AnnotatedTypeFactory factory) {
super(type, factory);
}
protected final List<AnnotatedTypeMirror> paramTypes = new ArrayList<>();
protected AnnotatedDeclaredType receiverType;
protected AnnotatedTypeMirror returnType;
protected final List<AnnotatedTypeMirror> throwsTypes = new ArrayList<>();
protected final List<AnnotatedTypeVariable> typeVarTypes = new ArrayList<>();
/**
* Returns true if this type represents a varargs method.
*
* @return true if this type represents a varargs method
*/
public boolean isVarArgs() {
return this.element.isVarArgs();
}
@Override
public <R, P> R accept(AnnotatedTypeVisitor<R, P> v, P p) {
return v.visitExecutable(this, p);
}
@Override
public ExecutableType getUnderlyingType() {
return (ExecutableType) this.underlyingType;
}
/**
* It never makes sense to add annotations to an executable type - instead, they should be added
* to the right component.
*/
@Override
public void addAnnotation(AnnotationMirror a) {
assert false : "AnnotatedExecutableType.addAnnotation should never be called";
}
/**
* Sets the parameter types of this executable type, excluding the receiver.
*
* @param params the parameter types, excluding the receiver
*/
void setParameterTypes(List<? extends AnnotatedTypeMirror> params) {
paramTypes.clear();
paramTypes.addAll(params);
}
/**
* Returns the parameter types of this executable type, excluding the receiver.
*
* @return the parameter types of this executable type, excluding the receiver
*/
public List<AnnotatedTypeMirror> getParameterTypes() {
if (paramTypes.isEmpty()
&& !((ExecutableType) underlyingType).getParameterTypes().isEmpty()) { // lazy init
for (TypeMirror t : ((ExecutableType) underlyingType).getParameterTypes()) {
paramTypes.add(createType(t, atypeFactory, false));
}
}
return Collections.unmodifiableList(paramTypes);
}
/**
* Sets the return type of this executable type.
*
* @param returnType the return type
*/
void setReturnType(AnnotatedTypeMirror returnType) {
this.returnType = returnType;
}
/**
* The return type of a method or constructor. For constructors, the return type is not VOID,
* but the type of the enclosing class.
*
* @return the return type of this executable type
*/
public AnnotatedTypeMirror getReturnType() {
if (returnType == null
&& element != null
&& ((ExecutableType) underlyingType).getReturnType() != null) { // lazy init
TypeMirror aret = ((ExecutableType) underlyingType).getReturnType();
if (aret.getKind() == TypeKind.ERROR) {
// Maybe the input is uncompilable, or maybe the type is not completed yet (see Issue
// #244).
throw new ErrorTypeKindException(
"Problem with return type of %s.%s: %s [%s %s]",
element, element.getEnclosingElement(), aret, aret.getKind(), aret.getClass());
}
if (((MethodSymbol) element).isConstructor()) {
// For constructors, the underlying return type is void.
// Take the type of the enclosing class instead.
aret = element.getEnclosingElement().asType();
if (aret.getKind() == TypeKind.ERROR) {
throw new ErrorTypeKindException(
"Input is not compilable; problem with constructor %s return type: %s [%s %s]"
+ " (enclosing element = %s [%s])",
element,
aret,
aret.getKind(),
aret.getClass(),
element.getEnclosingElement(),
element.getEnclosingElement().getClass());
}
}
returnType = createType(aret, atypeFactory, false);
}
return returnType;
}
/**
* Sets the receiver type on this executable type.
*
* @param receiverType the receiver type
*/
void setReceiverType(AnnotatedDeclaredType receiverType) {
this.receiverType = receiverType;
}
/**
* Returns the receiver type of this executable type; null for static methods and constructors
* of top-level classes.
*
* @return the receiver type of this executable type; null for static methods and constructors
* of top-level classes
*/
public @Nullable AnnotatedDeclaredType getReceiverType() {
if (receiverType == null && ElementUtils.hasReceiver(getElement())) {
TypeElement encl = ElementUtils.enclosingTypeElement(getElement());
if (getElement().getKind() == ElementKind.CONSTRUCTOR) {
// Can only reach this branch if we're the constructor of a nested class
encl = ElementUtils.enclosingTypeElement(encl.getEnclosingElement());
}
AnnotatedTypeMirror type = createType(encl.asType(), atypeFactory, false);
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);
}
/**
* Returns the thrown types of this executable type.
*
* @return the thrown types of this executable type
*/
public List<AnnotatedTypeMirror> getThrownTypes() {
if (throwsTypes.isEmpty()
&& !((ExecutableType) underlyingType).getThrownTypes().isEmpty()) { // lazy init
for (TypeMirror t : ((ExecutableType) underlyingType).getThrownTypes()) {
throwsTypes.add(createType(t, atypeFactory, false));
}
}
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);
}
/**
* Returns the type variables of this executable type, if any.
*
* @return the type variables of this executable type, if any
*/
public List<AnnotatedTypeVariable> getTypeVariables() {
if (typeVarTypes.isEmpty()
&& !((ExecutableType) underlyingType).getTypeVariables().isEmpty()) { // lazy init
for (TypeMirror t : ((ExecutableType) underlyingType).getTypeVariables()) {
typeVarTypes.add((AnnotatedTypeVariable) createType(t, atypeFactory, true));
}
}
return Collections.unmodifiableList(typeVarTypes);
}
@Override
public AnnotatedExecutableType deepCopy(boolean copyAnnotations) {
return (AnnotatedExecutableType) new AnnotatedTypeCopier(copyAnnotations).visit(this);
}
@Override
public AnnotatedExecutableType deepCopy() {
return deepCopy(true);
}
@Override
public AnnotatedExecutableType shallowCopy(boolean copyAnnotations) {
AnnotatedExecutableType type = new AnnotatedExecutableType(getUnderlyingType(), atypeFactory);
type.setElement(getElement());
type.setParameterTypes(getParameterTypes());
type.setReceiverType(getReceiverType());
type.setReturnType(getReturnType());
type.setThrownTypes(getThrownTypes());
type.setTypeVariables(getTypeVariables());
return type;
}
@Override
public AnnotatedExecutableType shallowCopy() {
return shallowCopy(true);
}
public @NonNull ExecutableElement getElement() {
return element;
}
public void setElement(@NonNull ExecutableElement elem) {
this.element = elem;
}
@Override
public AnnotatedExecutableType getErased() {
AnnotatedExecutableType type =
new AnnotatedExecutableType(
(ExecutableType) atypeFactory.types.erasure(getUnderlyingType()), atypeFactory);
type.setElement(getElement());
type.setParameterTypes(erasureList(getParameterTypes()));
if (getReceiverType() != null) {
type.setReceiverType(getReceiverType().getErased());
} else {
type.setReceiverType(null);
}
type.setReturnType(getReturnType().getErased());
type.setThrownTypes(erasureList(getThrownTypes()));
return type;
}
/**
* Returns the erased types corresponding to the given types.
*
* @param lst annotated type mirrors
* @return erased annotated type mirrors
*/
private List<AnnotatedTypeMirror> erasureList(Iterable<? extends AnnotatedTypeMirror> lst) {
return CollectionsPlume.mapList(AnnotatedTypeMirror::getErased, lst);
}
}
/**
* 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 {
private AnnotatedArrayType(ArrayType type, AnnotatedTypeFactory factory) {
super(type, factory);
}
/** 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 (ArrayType) this.underlyingType;
}
/**
* Sets the component type of this array.
*
* @param type the component type
*/
// WMD
public void setComponentType(AnnotatedTypeMirror type) {
this.componentType = type;
}
/**
* Returns the component type of this array.
*
* @return the component type of this array
*/
public AnnotatedTypeMirror getComponentType() {
if (componentType == null) { // lazy init
setComponentType(
createType(((ArrayType) underlyingType).getComponentType(), atypeFactory, false));
}
return componentType;
}
@Override
public AnnotatedArrayType deepCopy(boolean copyAnnotations) {
return (AnnotatedArrayType) new AnnotatedTypeCopier(copyAnnotations).visit(this);
}
@Override
public AnnotatedArrayType deepCopy() {
return deepCopy(true);
}
@Override
public AnnotatedArrayType shallowCopy(boolean copyAnnotations) {
AnnotatedArrayType type = new AnnotatedArrayType((ArrayType) underlyingType, atypeFactory);
if (copyAnnotations) {
type.addAnnotations(this.getAnnotationsField());
}
type.setComponentType(getComponentType());
return type;
}
@Override
public AnnotatedArrayType shallowCopy() {
return shallowCopy(true);
}
@Override
public AnnotatedArrayType getErased() {
// IMPORTANT NOTE: The returned type is a fresh Object because
// the componentType is the only component of arrays and the
// call to getErased will return a fresh object.
// | T[ ] | = |T| [ ]
AnnotatedArrayType at = shallowCopy();
AnnotatedTypeMirror ct = at.getComponentType().getErased();
at.setComponentType(ct);
return at;
}
}
/**
* Throw an exception if the boundType is null or a declaration.
*
* @param boundDescription the variety of bound: "Lower", "Super", or "Extends"
* @param boundType the type being tested
* @param thisType the object for which boundType is a bound
*/
private static void checkBound(
String boundDescription, AnnotatedTypeMirror boundType, AnnotatedTypeMirror thisType) {
if (boundType == null || boundType.isDeclaration()) {
throw new BugInCF(
"%s bounds should never be null or a declaration.%n new bound = %s%n type = %s",
boundDescription, boundType, thisType);
}
}
/**
* 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 {
private AnnotatedTypeVariable(
TypeVariable type, AnnotatedTypeFactory atypeFactory, boolean declaration) {
super(type, atypeFactory);
this.declaration = declaration;
}
/** The lower bound of the type variable. */
private AnnotatedTypeMirror lowerBound;
/** The upper bound of the type variable. */
private AnnotatedTypeMirror upperBound;
private boolean declaration;
@Override
public boolean isDeclaration() {
return declaration;
}
@Override
public void addAnnotation(AnnotationMirror a) {
super.addAnnotation(a);
fixupBoundAnnotations();
}
/**
* Change whether this {@code AnnotatedTypeVariable} is considered a use or a declaration (use
* this method with caution).
*
* @param declaration true if this type variable should be considered a declaration
*/
public void setDeclaration(boolean declaration) {
this.declaration = declaration;
}
@Override
public AnnotatedTypeVariable asUse() {
if (!this.isDeclaration()) {
return this;
}
AnnotatedTypeVariable result = this.shallowCopy();
result.declaration = false;
return result;
}
@Override
public <R, P> R accept(AnnotatedTypeVisitor<R, P> v, P p) {
return v.visitTypeVariable(this, p);
}
@Override
public TypeVariable getUnderlyingType() {
return (TypeVariable) this.underlyingType;
}
/**
* Set the lower bound of this variable type.
*
* <p>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) {
checkBound("Lower", type, this);
this.lowerBound = type;
fixupBoundAnnotations();
}
/**
* Get the lower bound field directly, bypassing any lazy initialization. This method is
* necessary to prevent infinite recursions in initialization. In general, prefer getLowerBound.
*
* @return the lower bound field
*/
public AnnotatedTypeMirror getLowerBoundField() {
return lowerBound;
}
/**
* Returns the lower bound type of this type variable.
*
* @return the lower bound type of this type variable
*/
public AnnotatedTypeMirror getLowerBound() {
if (lowerBound == null) { // lazy init
BoundsInitializer.initializeBounds(this);
fixupBoundAnnotations();
}
return lowerBound;
}
// If the lower bound was not present in underlyingType, then its annotation was defaulted from
// the AnnotatedTypeFactory. If the lower bound annotation is a supertype of the upper bound
// annotation, then the type is ill-formed. In that case, change the defaulted lower bound to
// be consistent with the explicitly-written upper bound.
//
// As a concrete example, if the default annotation is @Nullable, then the type "X extends
// @NonNull Y" should not be converted into "X extends @NonNull Y super @Nullable bottomtype"
// but be converted into "X extends @NonNull Y super @NonNull bottomtype".
//
// In addition, ensure consistency of annotations on type variables
// and the upper bound. Assume class C<X extends @Nullable Object>.
// The type of "@Nullable X" has to be "@Nullable X extends @Nullable Object",
// because otherwise the annotations are inconsistent.
private void fixupBoundAnnotations() {
if (!this.getAnnotationsField().isEmpty()) {
Set<AnnotationMirror> newAnnos = this.getAnnotationsField();
if (upperBound != null) {
upperBound.replaceAnnotations(newAnnos);
}
// Note:
// if the lower bound is a type variable
// then when we place annotations on the primary annotation
// this will actually cause the type variable to be exact and propagate the primary
// annotation to the type variable because primary annotations overwrite the upper and
// lower bounds of type variables when getUpperBound/getLowerBound is called
if (lowerBound != null) {
lowerBound.replaceAnnotations(newAnnos);
}
}
}
/**
* Set the upper bound of this variable type.
*
* @param type the upper bound type
*/
void setUpperBound(AnnotatedTypeMirror type) {
checkBound("Upper", type, this);
this.upperBound = type;
fixupBoundAnnotations();
}
/**
* Get the upper bound field directly, bypassing any lazy initialization. This method is
* necessary to prevent infinite recursions in initialization. In general, prefer getUpperBound.
*
* @return the upper bound field
*/
public AnnotatedTypeMirror getUpperBoundField() {
return upperBound;
}
/**
* Get the upper bound of the type variable, possibly lazily initializing it. Attention: If the
* upper bound is lazily initialized, it will not contain any annotations! Callers of the method
* have to make sure that an AnnotatedTypeFactory first processed the bound.
*
* @return the upper bound type of this type variable
*/
public AnnotatedTypeMirror getUpperBound() {
if (upperBound == null) { // lazy init
BoundsInitializer.initializeBounds(this);
fixupBoundAnnotations();
}
return upperBound;
}
public AnnotatedTypeParameterBounds getBounds() {
return new AnnotatedTypeParameterBounds(getUpperBound(), getLowerBound());
}
public AnnotatedTypeParameterBounds getBoundFields() {
return new AnnotatedTypeParameterBounds(getUpperBoundField(), getLowerBoundField());
}
/** Used to terminate recursion into upper bounds. */
private boolean inUpperBounds = false;
@Override
public AnnotatedTypeVariable deepCopy(boolean copyAnnotations) {
return (AnnotatedTypeVariable) new AnnotatedTypeCopier(copyAnnotations).visit(this);
}
@Override
public AnnotatedTypeVariable deepCopy() {
return deepCopy(true);
}
@Override
public AnnotatedTypeVariable shallowCopy(boolean copyAnnotations) {
AnnotatedTypeVariable type =
new AnnotatedTypeVariable(((TypeVariable) underlyingType), atypeFactory, declaration);
if (copyAnnotations) {
type.addAnnotations(this.getAnnotationsField());
}
if (!inUpperBounds) {
inUpperBounds = true;
type.inUpperBounds = true;
type.setUpperBound(getUpperBound().shallowCopy());
inUpperBounds = false;
type.inUpperBounds = false;
}
type.setLowerBound(getLowerBound().shallowCopy());
return type;
}
@Override
public AnnotatedTypeVariable shallowCopy() {
return shallowCopy(true);
}
/**
* This method will traverse the upper bound of this type variable calling getErased until it
* finds the concrete upper bound. e.g.
*
* <pre>{@code <E extends T>, T extends S, S extends List<String>>}</pre>
*
* A call to getErased will return the type List
*
* @return the erasure of the upper bound of this type
* <p>IMPORTANT NOTE: getErased should always return a FRESH object. This will occur for
* type variables if all other getErased methods are implemented appropriately. Therefore,
* to avoid extra copy calls, this method will not call deepCopy on getUpperBound
*/
@Override
public AnnotatedTypeMirror getErased() {
// |T extends A&B| = |A|
return this.getUpperBound().getErased();
}
}
/**
* A pseudo-type used where no actual type is appropriate. The kinds of NoType are:
*
* <ul>
* <li>VOID -- corresponds to the keyword void.
* <li>PACKAGE -- the pseudo-type of a package element.
* <li>NONE -- used in other cases where no actual type is appropriate; for example, the
* superclass of java.lang.Object.
* </ul>
*/
public static class AnnotatedNoType extends AnnotatedTypeMirror {
private AnnotatedNoType(NoType type, AnnotatedTypeFactory factory) {
super(type, factory);
}
// 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 (NoType) this.underlyingType;
}
@Override
public AnnotatedNoType deepCopy(boolean copyAnnotations) {
return (AnnotatedNoType) new AnnotatedTypeCopier(copyAnnotations).visit(this);
}
@Override
public AnnotatedNoType deepCopy() {
return deepCopy(true);
}
@Override
public AnnotatedNoType shallowCopy(boolean copyAnnotations) {
AnnotatedNoType type = new AnnotatedNoType((NoType) underlyingType, atypeFactory);
if (copyAnnotations) {
type.addAnnotations(this.getAnnotationsField());
}
return type;
}
@Override
public AnnotatedNoType shallowCopy() {
return shallowCopy(true);
}
}
/** Represents the null type. This is the type of the expression {@code null}. */
public static class AnnotatedNullType extends AnnotatedTypeMirror {
private AnnotatedNullType(NullType type, AnnotatedTypeFactory factory) {
super(type, factory);
}
@Override
public <R, P> R accept(AnnotatedTypeVisitor<R, P> v, P p) {
return v.visitNull(this, p);
}
@Override
public NullType getUnderlyingType() {
return (NullType) this.underlyingType;
}
@Override
public AnnotatedNullType deepCopy(boolean copyAnnotations) {
return (AnnotatedNullType) new AnnotatedTypeCopier(copyAnnotations).visit(this);
}
@Override
public AnnotatedNullType deepCopy() {
return deepCopy(true);
}
@Override
public AnnotatedNullType shallowCopy(boolean copyAnnotations) {
AnnotatedNullType type = new AnnotatedNullType((NullType) underlyingType, atypeFactory);
if (copyAnnotations) {
type.addAnnotations(this.getAnnotationsField());
}
return type;
}
@Override
public AnnotatedNullType shallowCopy() {
return shallowCopy(true);
}
}
/**
* 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 {
private AnnotatedPrimitiveType(PrimitiveType type, AnnotatedTypeFactory factory) {
super(type, factory);
}
@Override
public <R, P> R accept(AnnotatedTypeVisitor<R, P> v, P p) {
return v.visitPrimitive(this, p);
}
@Override
public PrimitiveType getUnderlyingType() {
return (PrimitiveType) this.underlyingType;
}
@Override
public AnnotatedPrimitiveType deepCopy(boolean copyAnnotations) {
return (AnnotatedPrimitiveType) new AnnotatedTypeCopier(copyAnnotations).visit(this);
}
@Override
public AnnotatedPrimitiveType deepCopy() {
return deepCopy(true);
}
@Override
public AnnotatedPrimitiveType shallowCopy(boolean copyAnnotations) {
AnnotatedPrimitiveType type =
new AnnotatedPrimitiveType((PrimitiveType) underlyingType, atypeFactory);
if (copyAnnotations) {
type.addAnnotations(this.getAnnotationsField());
}
return type;
}
@Override
public AnnotatedPrimitiveType shallowCopy() {
return shallowCopy(true);
}
}
/**
* Represents a wildcard type argument. Examples include:
*
* <p>? ? extends Number ? super T
*
* <p>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 {
/** Lower ({@code super}) bound. */
private AnnotatedTypeMirror superBound;
/** Upper ({@code extends} bound. */
private AnnotatedTypeMirror extendsBound;
/**
* The type variable to which this wildcard is an argument. Used to initialize the upper bound
* of unbounded wildcards and wildcards in raw types.
*/
private TypeVariable typeVariable = null;
private AnnotatedWildcardType(WildcardType type, AnnotatedTypeFactory factory) {
super(type, factory);
}
@Override
public void addAnnotation(AnnotationMirror a) {
super.addAnnotation(a);
fixupBoundAnnotations();
}
/**
* Sets the super bound of this wildcard.
*
* @param type the type of the lower bound
*/
void setSuperBound(AnnotatedTypeMirror type) {
checkBound("Super", type, this);
this.superBound = type;
fixupBoundAnnotations();
}
public AnnotatedTypeMirror getSuperBoundField() {
return superBound;
}
/**
* Returns the lower bound of this wildcard. If no lower bound is explicitly declared, returns
* {@code null}.
*
* @return the lower bound of this wildcard, or null if none is explicitly declared
*/
public AnnotatedTypeMirror getSuperBound() {
if (superBound == null) {
BoundsInitializer.initializeSuperBound(this);
fixupBoundAnnotations();
}
return this.superBound;
}
/**
* Sets the upper bound of this wildcard.
*
* @param type the type of the upper bound
*/
void setExtendsBound(AnnotatedTypeMirror type) {
checkBound("Extends", type, this);
this.extendsBound = type;
fixupBoundAnnotations();
}
public AnnotatedTypeMirror getExtendsBoundField() {
return extendsBound;
}
/**
* Returns the upper bound of this wildcard. If no upper bound is explicitly declared, returns
* the upper bound of the type variable to which the wildcard is bound.
*
* @return the upper bound of this wildcard. If no upper bound is explicitly declared, returns
* the upper bound of the type variable to which the wildcard is bound.
*/
public AnnotatedTypeMirror getExtendsBound() {
if (extendsBound == null) {
BoundsInitializer.initializeExtendsBound(this);
fixupBoundAnnotations();
}
return this.extendsBound;
}
private void fixupBoundAnnotations() {
if (!this.getAnnotationsField().isEmpty()) {
if (superBound != null) {
superBound.replaceAnnotations(this.getAnnotationsField());
}
if (extendsBound != null) {
extendsBound.replaceAnnotations(this.getAnnotationsField());
}
}
}
/**
* Sets type variable to which this wildcard is an argument. This method should only be called
* during initialization of the type.
*/
void setTypeVariable(TypeParameterElement typeParameterElement) {
this.typeVariable = (TypeVariable) typeParameterElement.asType();
}
/**
* Sets type variable to which this wildcard is an argument. This method should only be called
* during initialization of the type.
*/
void setTypeVariable(TypeVariable typeVariable) {
this.typeVariable = typeVariable;
}
/**
* Returns the type variable to which this wildcard is an argument. Used to initialize the upper
* bound of unbounded wildcards and wildcards in raw types.
*
* @return the type variable to which this wildcard is an argument
*/
public TypeVariable getTypeVariable() {
return typeVariable;
}
@Override
public <R, P> R accept(AnnotatedTypeVisitor<R, P> v, P p) {
return v.visitWildcard(this, p);
}
@Override
public WildcardType getUnderlyingType() {
return (WildcardType) this.underlyingType;
}
@Override
public AnnotatedWildcardType deepCopy(boolean copyAnnotations) {
return (AnnotatedWildcardType) new AnnotatedTypeCopier(copyAnnotations).visit(this);
}
@Override
public AnnotatedWildcardType deepCopy() {
return deepCopy(true);
}
@Override
public AnnotatedWildcardType shallowCopy(boolean copyAnnotations) {
AnnotatedWildcardType type =
new AnnotatedWildcardType((WildcardType) underlyingType, atypeFactory);
type.setExtendsBound(getExtendsBound().shallowCopy());
type.setSuperBound(getSuperBound().shallowCopy());
if (copyAnnotations) {
type.addAnnotations(this.getAnnotationsField());
}
type.uninferredTypeArgument = uninferredTypeArgument;
type.typeVariable = typeVariable;
return type;
}
@Override
public AnnotatedWildcardType shallowCopy() {
return shallowCopy(true);
}
/**
* @see
* org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedTypeVariable#getErased()
*/
@Override
public AnnotatedTypeMirror getErased() {
// |? extends A&B| = |A|
return getExtendsBound().getErased();
}
// Remove the uninferredTypeArgument once method type
// argument inference and raw type handling is improved.
private boolean uninferredTypeArgument = false;
/**
* Set that this wildcard is from an uninferred type argument. This method should only be used
* within the framework. Once issues that depend on this hack, in particular Issue 979, are
* fixed, this must be removed.
*/
public void setUninferredTypeArgument() {
uninferredTypeArgument = true;
}
/**
* Returns whether or not this wildcard is a type argument for which inference failed to infer a
* type.
*
* @return true if this wildcard is a type argument for which inference failed
*/
public boolean isUninferredTypeArgument() {
return uninferredTypeArgument;
}
}
/**
* Represents an intersection type.
*
* <p>For example: {@code MyObject & Serializable & Comparable<MyObject>}
*/
public static class AnnotatedIntersectionType extends AnnotatedTypeMirror {
/** A list of the bounds of this which are also its direct super types. */
protected List<AnnotatedTypeMirror> bounds;
/**
* Creates an {@code AnnotatedIntersectionType} with the underlying type {@code type}. The
* result contains no annotations.
*
* @param type underlying kind of this type
* @param atypeFactory the factory used to construct this intersection type
*/
private AnnotatedIntersectionType(IntersectionType type, AnnotatedTypeFactory atypeFactory) {
super(type, atypeFactory);
}
/**
* {@inheritDoc}
*
* <p>Also, copies {@code a} to all the bounds.
*
* @param a the annotation to add
*/
@Override
public void addAnnotation(AnnotationMirror a) {
super.addAnnotation(a);
fixupBoundAnnotations();
}
/**
* Copies {@link #annotations} to all the bounds, replacing any existing annotations in the same
* hierarchy.
*/
private void fixupBoundAnnotations() {
if (!this.getAnnotationsField().isEmpty()) {
Set<AnnotationMirror> newAnnos = this.getAnnotationsField();
if (bounds != null) {
for (AnnotatedTypeMirror bound : bounds) {
if (bound.getKind() != TypeKind.TYPEVAR) {
bound.replaceAnnotations(newAnnos);
}
}
}
}
}
@Override
public <R, P> R accept(AnnotatedTypeVisitor<R, P> v, P p) {
return v.visitIntersection(this, p);
}
@Override
public IntersectionType getUnderlyingType() {
return (IntersectionType) super.getUnderlyingType();
}
@Override
public AnnotatedIntersectionType deepCopy(boolean copyAnnotations) {
return (AnnotatedIntersectionType) new AnnotatedTypeCopier(copyAnnotations).visit(this);
}
@Override
public AnnotatedIntersectionType deepCopy() {
return deepCopy(true);
}
@Override
public AnnotatedIntersectionType shallowCopy(boolean copyAnnotations) {
AnnotatedIntersectionType type =
new AnnotatedIntersectionType((IntersectionType) underlyingType, atypeFactory);
if (copyAnnotations) {
type.addAnnotations(this.getAnnotationsField());
}
type.bounds = this.bounds;
return type;
}
@Override
public AnnotatedIntersectionType shallowCopy() {
return shallowCopy(true);
}
/**
* {@inheritDoc}
*
* <p>This returns the same types as {@link #getBounds()}.
*
* @return the direct super types of this
*/
@Override
public List<? extends AnnotatedTypeMirror> directSupertypes() {
return getBounds();
}
/**
* This returns the bounds of the intersection type. Although only declared types can appear in
* an explicitly written intersections, during capture conversion, intersections with other
* kinds of types are created.
*
* <p>This returns the same types as {@link #directSupertypes()}.
*
* @return the bounds of this, which are also the direct super types of this
*/
public List<AnnotatedTypeMirror> getBounds() {
if (bounds == null) {
List<? extends TypeMirror> ubounds = ((IntersectionType) underlyingType).getBounds();
List<AnnotatedTypeMirror> res =
CollectionsPlume.mapList(
(TypeMirror bnd) -> createType(bnd, atypeFactory, false), ubounds);
bounds = Collections.unmodifiableList(res);
fixupBoundAnnotations();
}
return bounds;
}
/**
* Sets the bounds.
*
* @param bounds bounds to use
*/
/*default-visibility*/ void setBounds(List<AnnotatedTypeMirror> bounds) {
this.bounds = bounds;
}
/**
* Copy the first annotation (in each hierarchy) on a bound to the primary annotation location
* of the intersection type.
*
* <p>For example, in the type {@code @NonNull Object & @Initialized @Nullable Serializable},
* {@code @Nullable} and {@code @Initialized} are copied to the primary annotation location.
*/
public void copyIntersectionBoundAnnotations() {
Set<AnnotationMirror> annos = AnnotationUtils.createAnnotationSet();
for (AnnotatedTypeMirror bound : getBounds()) {
for (AnnotationMirror a : bound.getAnnotations()) {
if (atypeFactory.getQualifierHierarchy().findAnnotationInSameHierarchy(annos, a)
== null) {
annos.add(a);
}
}
}
addAnnotations(annos);
}
}
// TODO: Ensure union types are handled everywhere.
// TODO: Should field "annotations" contain anything?
public static class AnnotatedUnionType extends AnnotatedTypeMirror {
/**
* Creates a new AnnotatedUnionType.
*
* @param type underlying kind of this type
* @param atypeFactory type factory
*/
private AnnotatedUnionType(UnionType type, AnnotatedTypeFactory atypeFactory) {
super(type, atypeFactory);
}
@Override
public <R, P> R accept(AnnotatedTypeVisitor<R, P> v, P p) {
return v.visitUnion(this, p);
}
@Override
public AnnotatedUnionType deepCopy(boolean copyAnnotations) {
return (AnnotatedUnionType) new AnnotatedTypeCopier(copyAnnotations).visit(this);
}
@Override
public AnnotatedUnionType deepCopy() {
return deepCopy(true);
}
@Override
public AnnotatedUnionType shallowCopy(boolean copyAnnotations) {
AnnotatedUnionType type = new AnnotatedUnionType((UnionType) underlyingType, atypeFactory);
if (copyAnnotations) {
type.addAnnotations(this.getAnnotationsField());
}
type.alternatives = this.alternatives;
return type;
}
@Override
public AnnotatedUnionType shallowCopy() {
return shallowCopy(true);
}
/** The types that are unioned to form this AnnotatedUnionType. */
protected List<AnnotatedDeclaredType> alternatives;
/**
* Returns the types that are unioned to form this AnnotatedUnionType.
*
* @return the types that are unioned to form this AnnotatedUnionType
*/
public List<AnnotatedDeclaredType> getAlternatives() {
if (alternatives == null) {
List<? extends TypeMirror> ualts = ((UnionType) underlyingType).getAlternatives();
List<AnnotatedDeclaredType> res =
CollectionsPlume.mapList(
(TypeMirror alt) -> (AnnotatedDeclaredType) createType(alt, atypeFactory, false),
ualts);
alternatives = Collections.unmodifiableList(res);
}
return alternatives;
}
}
/**
* This method returns a list of AnnotatedTypeMirrors where the Java type of each ATM is an
* immediate supertype (class or interface) of the Java type of this. The interface types, if any,
* appear at the end of the list. If the directSuperType has type arguments, then the annotations
* on those type arguments are taken with proper translation from the declaration of the Java type
* of this.
*
* <p>For example,
*
* <pre>
* {@code class B<T> { ... } }
* {@code class A extends B<@NonNull String> { ... } }
* {@code @Nullable A a;}
* </pre>
*
* The direct supertype of the ATM {@code @Nullable A} is {@code @Nullable B<@NonNull String>}.
*
* <p>An example with more complex type arguments:
*
* <pre>
* {@code class D<Q,R> { ... } }
* {@code class A<T,S> extends D<S,T> { ... } }
* {@code @Nullable A<@NonNull String, @NonNull Object> a;}
* </pre>
*
* The direct supertype of the ATM {@code @Nullable A<@NonNull String, @NonNull Object>} is
* {@code @Nullable B<@NonNull Object, @NonNull String>}.
*
* <p>An example with more than one direct supertype:
*
* <pre>
* {@code class B<T> implements List<Integer> { ... } }
* {@code class A extends B<@NonNull String> implements List<Integer> { ... } }
* {@code @Nullable A a;}
* </pre>
*
* The direct supertypes of the ATM {@code @Nullable A} are {@code @Nullable B <@NonNull String>}
* and {@code @Nullable List<@NonNull Integer>}.
*
* @return the immediate supertypes of this
* @see Types#directSupertypes(TypeMirror)
*/
public List<? extends AnnotatedTypeMirror> directSupertypes() {
return SupertypeFinder.directSupertypes(this);
}
}