All Downloads are FREE. Search and download functionalities are using the official Maven repository.

framework.src.org.checkerframework.framework.type.AnnotatedTypeMirror Maven / Gradle / Ivy

Go to download

The Checker Framework enhances Java’s type system to make it more powerful and useful. This lets software developers detect and prevent errors in their Java programs. The Checker Framework includes compiler plug-ins ("checkers") that find bugs or verify their absence. It also permits you to write your own compiler plug-ins.

There is a newer version: 3.42.0
Show newest version
package org.checkerframework.framework.type;

/*>>>
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.checkerframework.checker.interning.qual.*;
*/

import org.checkerframework.dataflow.qual.Pure;
import org.checkerframework.dataflow.qual.SideEffectFree;
import org.checkerframework.framework.type.visitor.AnnotatedTypeVisitor;
import org.checkerframework.framework.util.AnnotatedTypes;
import org.checkerframework.javacutil.AnnotationUtils;
import org.checkerframework.javacutil.ElementUtils;
import org.checkerframework.javacutil.ErrorReporter;

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.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Name;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.ArrayType;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.ExecutableType;
import javax.lang.model.type.IntersectionType;
import javax.lang.model.type.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 com.sun.tools.javac.code.Symbol.MethodSymbol;

/**
 * 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}.
 *
 * 

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. * *

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 the appropriate AnnotatedTypeMirror specific wrapper for the * provided type * * @param isDeclaration true if the result should is a type declaration */ public static AnnotatedTypeMirror createType(TypeMirror type, AnnotatedTypeFactory atypeFactory, boolean isDeclaration) { if (type == null) { ErrorReporter.errorAbort("AnnotatedTypeMirror.createType: input type must not be null!"); return 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: ErrorReporter.errorAbort("AnnotatedTypeMirror.createType: input should type-check already! Found error type: " + type); return null; // dead code 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; } ErrorReporter.errorAbort("AnnotatedTypeMirror.createType: unidentified type " + type + " (" + type.getKind() + ")"); return null; // dead code } /*if (jctype.isAnnotated()) { result.addAnnotations(jctype.getAnnotationMirrors()); }*/ return result; } protected static final EqualityAtmComparer equalityComparer = new EqualityAtmComparer(); protected static final HashcodeAtmVisitor hashcodeVisitor = new HashcodeAtmVisitor(); /** The factory to use for lazily creating annotated types. */ protected final AnnotatedTypeFactory atypeFactory; /** Actual type wrapped with this AnnotatedTypeMirror **/ protected final TypeMirror actualType; /** Used to format AnnotatedTypeMirrors into strings for printing. */ protected final AnnotatedTypeFormatter formatter; /** 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. private final Set 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 explicitannotations = AnnotationUtils.createAnnotationSet(); /** * Constructor for AnnotatedTypeMirror. * * @param type the underlying type * @param atypeFactory used to create further types and to access * global information (Types, Elements, ...) */ private AnnotatedTypeMirror(TypeMirror type, AnnotatedTypeFactory atypeFactory) { this.actualType = type; assert atypeFactory != null; this.atypeFactory = atypeFactory; this.formatter = atypeFactory.typeFormatter; } @Override public final boolean equals(Object o) { if (o == this) { return true; } if (o == null || !(o instanceof AnnotatedTypeMirror)) { return false; } return equalityComparer.visit(this, (AnnotatedTypeMirror) o, null); } @Pure @Override public final int hashCode() { return hashcodeVisitor.visit(this); } /** * Applies a visitor to this type. * * @param the return type of the visitor's methods * @param

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 accept(AnnotatedTypeVisitor 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, which this wraps * * @return the underlying type */ public TypeMirror getUnderlyingType() { return actualType; } /** * Returns true if this type mirror represents a declaration, rather than a * use, of a type. * * For example, class List<T> { ... } declares a new type * {@code List}, while {@code List} 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. * * 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. * * 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 getAnnotationInHierarchy(AnnotationMirror p) { AnnotationMirror aliased = p; if (!atypeFactory.isSupportedQualifier(aliased)) { aliased = atypeFactory.aliasedAnnotation(p); } if (atypeFactory.isSupportedQualifier(aliased)) { QualifierHierarchy qualHier = this.atypeFactory.getQualifierHierarchy(); AnnotationMirror anno = qualHier.findCorrespondingAnnotation(aliased, annotations); 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. * * 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.aliasedAnnotation(p); } if (atypeFactory.isSupportedQualifier(aliased)) { QualifierHierarchy qualHier = this.atypeFactory.getQualifierHierarchy(); AnnotationMirror anno = qualHier.findCorrespondingAnnotation(aliased, getEffectiveAnnotations()); 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). * * @return a unmodifiable set of the annotations on this */ public final Set getAnnotations() { return Collections.unmodifiableSet(annotations); } /** * Returns the annotations on this type. * * It does not include annotations in deep types (type arguments, array * components, etc). * * 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, directly */ protected final Set getAnnotationsField() { return annotations; } /** * 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 getEffectiveAnnotations() { Set 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.toString(); return effectiveAnnotations; } /** * Returns the actual annotation mirror used to annotate this type, * whose name equals the passed annotationName if one exists, null otherwise. * * @return the annotation mirror for annotationName */ public AnnotationMirror getAnnotation(Name annotationName) { assert annotationName != null : "Null annotationName in getAnnotation"; return getAnnotation(annotationName.toString().intern()); } /** * Returns the actual annotation mirror used to annotate this type, * whose name equals the string argument if one exists, null otherwise. * * @return the annotation mirror for annotationStr */ public AnnotationMirror getAnnotation(/*@Interned*/ String annotationStr) { assert annotationStr != null : "Null annotationName in getAnnotation"; for (AnnotationMirror anno : getAnnotations()) { if (AnnotationUtils.areSameByName(anno, annotationStr)) { return anno; } } return null; } /** * 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 annoClass) { for (AnnotationMirror annoMirror : getAnnotations()) { if (AnnotationUtils.areSameByClass(annoMirror, annoClass)) { return annoMirror; } } return null; } /** * Returns the set of explicitly written annotations 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. * * @return the set of explicitly written annotations supported by this checker */ public Set getExplicitAnnotations() { // TODO JSR 308: The explicit type annotations should be always present Set explicitAnnotations = AnnotationUtils.createAnnotationSet(); List typeAnnotations = this.getUnderlyingType().getAnnotationMirrors(); Set validAnnotations = atypeFactory.getQualifierHierarchy().getTypeQualifiers(); for (AnnotationMirror explicitAnno : typeAnnotations) { for (AnnotationMirror validAnno : validAnnotations) { if (AnnotationUtils.areSameIgnoringValues(explicitAnno, validAnno)) { 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. * * 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(getAnnotations(), a); } /** * Determines whether this type contains the given annotation. * * @param a the annotation name to check for * @return true iff the type contains the annotation {@code a} * * @see #hasAnnotationRelaxed(AnnotationMirror) */ public boolean hasAnnotation(Name a) { return getAnnotation(a) != null; } /** * 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 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 annoClass) { for (AnnotationMirror annoMirror : getEffectiveAnnotations()) { if (AnnotationUtils.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 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 * "@A("s") @B(3) Object" a call with "@A("t") or "@A" will * return false, whereas a call with "@B(3)" will return true. * * In contrast to {@link #hasExplicitAnnotationRelaxed(AnnotationMirror)} * this method also compares annotation values. * * @param a the annotation to check for * @return true iff the annotation {@code a} is explicitly written * on the type * * @see #hasExplicitAnnotationRelaxed(AnnotationMirror) */ 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.containsSameIgnoringValues(getAnnotations(), 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.containsSameIgnoringValues(getEffectiveAnnotations(), a); } /** * A version of hasAnnotationRelaxed that only considers annotations that * are explicitly written on the type. * * @see #hasAnnotationRelaxed(AnnotationMirror) */ public boolean hasExplicitAnnotationRelaxed(AnnotationMirror a) { return AnnotationUtils.containsSameIgnoringValues(getExplicitAnnotations(), a); } /** * Determines whether this type contains an explictly written 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 explicitly written annotation * with the same type as the annotation given by {@code a} */ public boolean hasExplicitAnnotation(Class a) { return AnnotationUtils.containsSameIgnoringValues(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) { ErrorReporter.errorAbort("AnnotatedTypeMirror.addAnnotation: null is not a valid annotation."); } if (atypeFactory.isSupportedQualifier(a)) { this.annotations.add(a); } else { AnnotationMirror aliased = atypeFactory.aliasedAnnotation(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 a) { AnnotationMirror anno = AnnotationUtils.fromClass(atypeFactory.elements, a); addAnnotation(anno); } /** * Adds multiple annotations to this type. * * @param annotations the annotations to add */ public void addAnnotations(Iterable annotations) { for (AnnotationMirror a : annotations) { this.addAnnotation(a); } } /** * Adds those annotations to the current type, for which no annotation * from the same qualifier hierarchy is present. * * @param annotations the annotations to add */ public void addMissingAnnotations(Iterable 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 replAnnos) { for (AnnotationMirror a : replAnnos) { this.removeAnnotationInHierarchy(a); 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) { // Going from the AnnotationMirror to its name and then calling // getAnnotation ensures that we get the canonical AnnotationMirror that can be // removed. // TODO: however, this also means that if we are annotated with "@I(1)" and // remove "@I(2)" it will be removed. Is this what we want? // It's currently necessary for the Lock Checker. AnnotationMirror anno = getAnnotation(AnnotationUtils.annotationName(a)); if (anno != null) { return annotations.remove(anno); } else { return false; } } public boolean removeAnnotation(Class a) { AnnotationMirror anno = AnnotationUtils.fromClass(atypeFactory.elements, a); if (anno == null || !atypeFactory.isSupportedQualifier(anno)) { ErrorReporter.errorAbort("AnnotatedTypeMirror.removeAnnotation called with un-supported class: " + a); } return removeAnnotation(anno); } /** * 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 annotations) { boolean changed = false; for (AnnotationMirror a : annotations) { changed |= this.removeAnnotation(a); } return changed; } /** * Removes all annotations on this type. * Make sure to add an annotation again, e.g. Unqualified. * * 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 formatter.format(this); } @SideEffectFree public final String toString(boolean printInvisibles) { return formatter.format(this, printInvisibles); } /** * Returns the erasure type of the this type, according to JLS * specifications. * * @see https://docs.oracle.com/javase/specs/jls/se8/html/jls-4.html#jls-4.6 * * @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. * * Note: deepCopy provides two important properties in the returned copy: * 1) Structure preservation - The exact structure of the original AnnotatedTypeMirror is preserved in the copy * including all component types. * 2) Annotation preservation - All of the annotations from the original AnnotatedTypeMirror and its components * have been copied to the new type. * * 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); /** * @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 copie. * * @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. * @see #shallowCopy(boolean) */ public abstract AnnotatedTypeMirror shallowCopy(); protected static AnnotatedDeclaredType createTypeOfObject(AnnotatedTypeFactory atypeFactory) { AnnotatedDeclaredType objectType = atypeFactory.fromElement( atypeFactory.elements.getTypeElement( Object.class.getCanonicalName())); return objectType; } /** * Represents a declared type (whether class or interface). */ public static class AnnotatedDeclaredType extends AnnotatedTypeMirror { /** Parametrized Type Arguments **/ protected List 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. * * 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 **/ protected AnnotatedDeclaredType enclosingType; protected List supertypes = null; private boolean declaration; /** * Constructor for this type * * @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, true); } else if (encl.getKind() != TypeKind.NONE) { ErrorReporter.errorAbort("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; List newArgs = new ArrayList<>(); for (AnnotatedTypeMirror arg : result.getTypeArguments()) { switch (arg.getKind()) { case TYPEVAR: AnnotatedTypeVariable paramTypevar = (AnnotatedTypeVariable)arg; newArgs.add(paramTypevar.asUse()); break; case WILDCARD: AnnotatedWildcardType paramWildcard = (AnnotatedWildcardType)arg; newArgs.add(paramWildcard.asUse()); break; default: newArgs.add(arg); } } result.setTypeArguments(newArgs); return result; } @Override public R accept(AnnotatedTypeVisitor 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 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 uses = new ArrayList<>(); for (AnnotatedTypeMirror t : ts) { uses.add(t.asUse()); } typeArgs = Collections.unmodifiableList(uses); } } } /** * @return the type argument for this type */ public List getTypeArguments() { if (typeArgs == null) { typeArgs = new ArrayList(); if (!((DeclaredType)actualType).getTypeArguments().isEmpty()) { // lazy init for (TypeMirror t : ((DeclaredType)actualType).getTypeArguments()) { typeArgs.add(createType(t, atypeFactory, declaration)); } } typeArgs = Collections.unmodifiableList(typeArgs); } 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) actualType; } @Override public List directSuperTypes() { if (supertypes == null) { supertypes = Collections.unmodifiableList(SupertypeFinder.directSuperTypes(this)); } return supertypes; } /* * Return the direct super types field without lazy initialization; * originally to prevent infinite recursion in IGJATF.postDirectSuperTypes. * TODO: find a nicer way, see the single caller in QualifierDefaults * for comment. */ public List directSuperTypesField() { return supertypes; } @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() { // 1. |G| = |G| // 2. |T.C| = |T|.C if (!getTypeArguments().isEmpty()) { // Handle case 1. AnnotatedDeclaredType rType = (AnnotatedDeclaredType)AnnotatedTypeMirror.createType( atypeFactory.types.erasure(actualType), atypeFactory, declaration); rType.addAnnotations(getAnnotations()); rType.setTypeArguments(Collections. emptyList()); return rType.getErased(); } else if ((getEnclosingType() != null) && (getEnclosingType().getKind() != TypeKind.NONE)) { // Handle case 2 // Shallow copy provides a fresh type when there are no type arguments // and we set the enclosing type // Therefore, we do not need to use deepCopy AnnotatedDeclaredType rType = shallowCopy(); AnnotatedDeclaredType et = getEnclosingType(); rType.setEnclosingType(et.getErased()); return rType; } else { return this.deepCopy(); } } /* Using this equals method resulted in an infinite recursion * with type variables. TODO: Keep track of visited type variables? @Override public boolean equals(Object o) { boolean res = super.equals(o); if (res && (o instanceof AnnotatedDeclaredType)) { AnnotatedDeclaredType dt = (AnnotatedDeclaredType) o; List mytas = this.getTypeArguments(); List othertas = dt.getTypeArguments(); for (int i = 0; i < mytas.size(); ++i) { if (!mytas.get(i).equals(othertas.get(i))) { System.out.println("in AnnotatedDeclaredType; this: " + this + " and " + o); res = false; break; } } } return res; } */ /** * Sets the enclosing type */ /*default-visibility*/ void setEnclosingType(AnnotatedDeclaredType 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 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 paramTypes = new ArrayList(); protected AnnotatedDeclaredType receiverType; protected AnnotatedTypeMirror returnType; protected final List throwsTypes = new ArrayList(); protected final List typeVarTypes = new ArrayList(); /** * @return true if this type represents a varargs method */ public boolean isVarArgs() { return this.element.isVarArgs(); } @Override public R accept(AnnotatedTypeVisitor v, P p) { return v.visitExecutable(this, p); } @Override public ExecutableType getUnderlyingType() { return (ExecutableType) this.actualType; } /* TODO: it never makes sense to add annotations to an executable type - * instead, they should be added to the right component. * For simpler, more regular use, we might want to allow querying for annotations. * @Override public void addAnnotations(Iterable annotations) { // Thread.dumpStack(); super.addAnnotations(annotations); } @Override public void addAnnotation(AnnotationMirror a) { // Thread.dumpStack(); super.addAnnotation(a); } @Override public void addAnnotation(Class a) { // Thread.dumpStack(); super.addAnnotation(a); } @Override public Set getAnnotations() { Thread.dumpStack(); return null; } @Override public boolean equals(Object o) { if (!(o instanceof AnnotatedExecutableType)) { return false; } // TODO compare components return true; } */ /** * Sets the parameter types of this executable type * @param params the parameter types */ void setParameterTypes( List params) { paramTypes.clear(); paramTypes.addAll(params); } /** * @return the parameter types of this executable type */ public List getParameterTypes() { if (paramTypes.isEmpty() && !((ExecutableType) actualType).getParameterTypes().isEmpty()) { // lazy init for (TypeMirror t : ((ExecutableType) actualType).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) actualType).getReturnType() != null) {// lazy init TypeMirror aret = ((ExecutableType) actualType).getReturnType(); if (((MethodSymbol)element).isConstructor()) { // For constructors, the underlying return type is void. // Take the type of the enclosing class instead. aret = element.getEnclosingElement().asType(); } 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; } /** * @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 // Static methods don't have a receiver && !ElementUtils.isStatic(getElement()) // Array constructors should also not have a receiver. Array members have a getEnclosingElement().getEnclosingElement() of NONE && (!(getElement().getKind() == ElementKind.CONSTRUCTOR && getElement().getEnclosingElement().getSimpleName().toString().equals("Array") && getElement().getEnclosingElement().getEnclosingElement().asType().getKind() == TypeKind.NONE)) // Top-level constructors don't have a receiver && (getElement().getKind() != ElementKind.CONSTRUCTOR || getElement().getEnclosingElement().getEnclosingElement().getKind() != ElementKind.PACKAGE)) { TypeElement encl = ElementUtils.enclosingClass(getElement()); if (getElement().getKind() == ElementKind.CONSTRUCTOR) { // Can only reach this branch if we're the constructor of a nested class encl = ElementUtils.enclosingClass(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 thrownTypes) { this.throwsTypes.clear(); this.throwsTypes.addAll(thrownTypes); } /** * @return the thrown types of this executable type */ public List getThrownTypes() { if (throwsTypes.isEmpty() && !((ExecutableType) actualType).getThrownTypes().isEmpty()) { // lazy init for (TypeMirror t : ((ExecutableType) actualType).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 types) { typeVarTypes.clear(); typeVarTypes.addAll(types); } /** * @return the type variables of this executable type, if any */ public List getTypeVariables() { if (typeVarTypes.isEmpty() && !((ExecutableType) actualType).getTypeVariables().isEmpty()) { // lazy init for (TypeMirror t : ((ExecutableType) actualType).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; } private List erasureList(Iterable lst) { List erased = new ArrayList(); for (AnnotatedTypeMirror t : lst) { erased.add(t.getErased()); } return erased; } } /** * 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 accept(AnnotatedTypeVisitor v, P p) { return v.visitArray(this, p); } @Override public ArrayType getUnderlyingType() { return (ArrayType) this.actualType; } /** * Sets the component type of this array * * @param type the component type */ // WMD public void setComponentType(AnnotatedTypeMirror type) { this.componentType = type; } /** * @return the component type of this array */ public AnnotatedTypeMirror getComponentType() { if (componentType == null) // lazy init setComponentType(createType( ((ArrayType) actualType).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) actualType, 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; } } /** * 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 accept(AnnotatedTypeVisitor v, P p) { return v.visitTypeVariable(this, p); } @Override public TypeVariable getUnderlyingType() { return (TypeVariable) this.actualType; } /** * 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) { if (type != null) { type = type.asUse(); } this.lowerBound = type; } /** * Sets the lower bound of this type variable without calling asUse (and therefore making a copy) */ void setLowerBoundField(AnnotatedTypeMirror type) { this.lowerBound = type; if (lowerBound != null) { 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; } /** * @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 actualType, 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. // The type of "@Nullable X" has to be "@Nullable X extends @Nullable Object", // because otherwise the annotations are inconsistent. private void fixupBoundAnnotations() { // We allow the above replacement first because primary annotations might not have annotations for // all hierarchies, so we don't want to avoid placing bottom on the lower bound for those hierarchies that // don't have a qualifier in primaryAnnotations if (!this.getAnnotationsField().isEmpty()) { if (upperBound != null) { replaceUpperBoundAnnotations(); } // 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(this.getAnnotationsField()); } } } /** * Replaces (or adds if none exist) the primary annotation of all upper bounds of typeVar, * the AnnotatedTypeVariable with the annotations provided. The AnnotatedTypeVariable will only * have multiple upper bounds if the upper bound is an intersection. */ private void replaceUpperBoundAnnotations() { if (upperBound.getKind() == TypeKind.INTERSECTION) { final List bounds = ((AnnotatedIntersectionType) upperBound).directSuperTypes(); for (final AnnotatedDeclaredType bound : bounds) { bound.replaceAnnotations(this.getAnnotationsField()); } } else { upperBound.replaceAnnotations(this.getAnnotationsField()); } } /** * Set the upper bound of this variable type * @param type the upper bound type */ void setUpperBound(AnnotatedTypeMirror type) { if (type.isDeclaration()) { ErrorReporter.errorAbort("Upper bounds should never contain declarations.\n" + "type=" + type); } this.upperBound = type; } /** * Set the upper bound of this variable type without making a copy using asUse * @param type the upper bound type */ void setUpperBoundField(final AnnotatedTypeMirror type) { this.upperBound = type; if (upperBound != null) { 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)actualType), 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. * <E extends T>, T extends S, S extends List<String>> * A call to getErased will return the type List * @return the erasure of the upper bound of this type * * 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: * *

    *
  • VOID - corresponds to the keyword void.
  • *
  • PACKAGE - the pseudo-type of a package element.
  • *
  • NONE - used in other cases where no actual type is appropriate; * for example, the superclass of java.lang.Object.
  • *
*/ 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 accept(AnnotatedTypeVisitor v, P p) { return v.visitNoType(this, p); } @Override public NoType getUnderlyingType() { return (NoType) this.actualType; } @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) actualType, 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 accept(AnnotatedTypeVisitor v, P p) { return v.visitNull(this, p); } @Override public NullType getUnderlyingType() { return (NullType) this.actualType; } @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) actualType, 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 accept(AnnotatedTypeVisitor v, P p) { return v.visitPrimitive(this, p); } @Override public PrimitiveType getUnderlyingType() { return (PrimitiveType) this.actualType; } @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) actualType, atypeFactory); if (copyAnnotations) { type.addAnnotations(this.getAnnotationsField()); } return type; } @Override public AnnotatedPrimitiveType shallowCopy() { return shallowCopy(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 AnnotatedWildcardType(WildcardType type, AnnotatedTypeFactory factory) { super(type, factory); } @Override public void addAnnotation(AnnotationMirror a) { super.addAnnotation(a); fixupBoundAnnotations(); } /** * Sets the super bound of this wild card * * @param type the type of the lower bound */ void setSuperBound(AnnotatedTypeMirror type) { if (type != null) { type = type.asUse(); } this.superBound = type; if (superBound != null) { fixupBoundAnnotations(); } } public AnnotatedTypeMirror getSuperBoundField() { return superBound; } /** * @return the lower bound of this wildcard. If no lower bound is * explicitly declared, {@code null} is returned. */ public AnnotatedTypeMirror getSuperBound() { if (superBound == null) { BoundsInitializer.initializeSuperBound(this); fixupBoundAnnotations(); } return this.superBound; } /** * Sets the upper bound of this wild card * * @param type the type of the upper bound */ void setExtendsBound(AnnotatedTypeMirror type) { if (type != null) { type = type.asUse(); } this.extendsBound = type; if (extendsBound != null) { fixupBoundAnnotations(); } } public AnnotatedTypeMirror getExtendsBoundField() { return extendsBound; } /** * @return the upper bound of this wildcard. If no upper bound is * explicitly declared, the upper bound of the type variable to which * the wildcard is bound is used. */ 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()); } } } @Override public R accept(AnnotatedTypeVisitor v, P p) { return v.visitWildcard(this, p); } @Override public WildcardType getUnderlyingType() { return (WildcardType) this.actualType; } @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) actualType, atypeFactory); type.setExtendsBound(getExtendsBound().shallowCopy()); type.setSuperBound(getSuperBound().shallowCopy()); if (copyAnnotations) { type.addAnnotations(this.getAnnotationsField()); } type.typeArgHack = typeArgHack; 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 typeArgHack once method type // argument inference and raw type handling is improved. private boolean typeArgHack = false; /* package-scope */ void setTypeArgHack() { typeArgHack = true; } /* package-scope */ boolean isTypeArgHack() { return typeArgHack; } } public static class AnnotatedIntersectionType extends AnnotatedTypeMirror { /** * AnnotatedIntersectionTypes are created by type parameters whose bounds include an & * e.g. * {@code >} * * The bound {@code MyObject & Serializable & Comparable} * is an intersection type * with direct supertypes [MyObject, Serializable, Comparable] * * @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); } @Override public R accept(AnnotatedTypeVisitor v, P p) { return v.visitIntersection(this, p); } @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) actualType, atypeFactory); if (copyAnnotations) { type.addAnnotations(this.getAnnotationsField()); } type.supertypes = this.supertypes; return type; } @Override public AnnotatedIntersectionType shallowCopy() { return shallowCopy(true); } protected List supertypes; @Override public List directSuperTypes() { if (supertypes == null) { List ubounds = ((IntersectionType)actualType).getBounds(); List res = new ArrayList(ubounds.size()); for (TypeMirror bnd : ubounds) { res.add((AnnotatedDeclaredType) createType(bnd, atypeFactory, false)); } supertypes = Collections.unmodifiableList(res); } return supertypes; } public List directSuperTypesField() { return supertypes; } void setDirectSuperTypes(List supertypes) { this.supertypes = new ArrayList(supertypes); } } // TODO: Ensure union types are handled everywhere. // TODO: Should field "annotations" contain anything? public static class AnnotatedUnionType extends AnnotatedTypeMirror { /** * Constructor for this type * * @param type underlying kind of this type * @param atypeFactory TODO */ private AnnotatedUnionType(UnionType type, AnnotatedTypeFactory atypeFactory) { super(type, atypeFactory); } @Override public R accept(AnnotatedTypeVisitor 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) actualType, atypeFactory); if (copyAnnotations) { type.addAnnotations(this.getAnnotationsField()); } type.alternatives = this.alternatives; return type; } @Override public AnnotatedUnionType shallowCopy() { return shallowCopy(true); } protected List alternatives; public List getAlternatives() { if (alternatives == null) { List ualts = ((UnionType)actualType).getAlternatives(); List res = new ArrayList(ualts.size()); for (TypeMirror alt : ualts) { res.add((AnnotatedDeclaredType) createType(alt, atypeFactory, false)); } alternatives = Collections.unmodifiableList(res); } return alternatives; } } /** @see Types#directSupertypes(TypeMirror) */ public List directSuperTypes() { return SupertypeFinder.directSuperTypes(this); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy