blob: 2b07a02a47be371e3eafdc1e71fdf008ea92c5f6 [file] [log] [blame]
package org.checkerframework.framework.type;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Types;
import org.checkerframework.checker.interning.qual.FindDistinct;
import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedArrayType;
import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedDeclaredType;
import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedIntersectionType;
import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedPrimitiveType;
import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedTypeVariable;
import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedUnionType;
import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedWildcardType;
import org.checkerframework.framework.type.visitor.AbstractAtmComboVisitor;
import org.checkerframework.framework.util.AnnotatedTypes;
import org.checkerframework.javacutil.AnnotationUtils;
import org.checkerframework.javacutil.BugInCF;
import org.checkerframework.javacutil.TypesUtils;
/**
* Implements asSuper {@link AnnotatedTypes#asSuper(AnnotatedTypeFactory, AnnotatedTypeMirror,
* AnnotatedTypeMirror)}.
*/
public class AsSuperVisitor extends AbstractAtmComboVisitor<AnnotatedTypeMirror, Void> {
/** Type utilities. */
private final Types types;
/** The type factory. */
private final AnnotatedTypeFactory atypeFactory;
/**
* Whether or not the type being visited is an uninferred type argument. If true, then the
* underlying type may not have the correct relationship with the supertype.
*/
private boolean isUninferredTypeArgument = false;
/**
* Create a new AsSuperVisitor.
*
* @param atypeFactory the type factory
*/
public AsSuperVisitor(AnnotatedTypeFactory atypeFactory) {
this.atypeFactory = atypeFactory;
types = atypeFactory.types;
}
/**
* Implements asSuper. See {@link AnnotatedTypes#asSuper(AnnotatedTypeFactory,
* AnnotatedTypeMirror, AnnotatedTypeMirror)} for details.
*
* @param <T> the type of the supertype
* @param type type from which to copy annotations
* @param superType a type whose erased Java type is a supertype of {@code type}'s erased Java
* type.
* @return a copy of {@code superType} with annotations copied from {@code type} and type
* variables substituted from {@code type}.
*/
@SuppressWarnings({
"unchecked",
"interning:not.interned" // optimized special case
})
public <T extends AnnotatedTypeMirror> T asSuper(AnnotatedTypeMirror type, T superType) {
if (type == null || superType == null) {
throw new BugInCF("AsSuperVisitor type and supertype cannot be null.");
}
if (type == superType) {
return (T) type.deepCopy();
}
// This visitor modifies superType and may return type, so pass it copies so that the
// parameters to asSuper are not changed and a copy is returned.
AnnotatedTypeMirror copyType = type.deepCopy();
AnnotatedTypeMirror copySuperType = superType.deepCopy();
reset();
AnnotatedTypeMirror result = visit(copyType, copySuperType, null);
if (result == null) {
throw new BugInCF(
"AsSuperVisitor returned null.%ntype: %s%nsuperType: %s", type, copySuperType);
}
return (T) result;
}
private void reset() {
isUninferredTypeArgument = false;
}
@Override
public AnnotatedTypeMirror visit(
AnnotatedTypeMirror type, AnnotatedTypeMirror superType, Void p) {
ensurePrimaryIsCorrectForUnions(type);
return super.visit(type, superType, p);
}
/**
* The code in this class is assuming that the primary annotation of an {@link AnnotatedUnionType}
* is the least upper bound of its alternatives. This method makes this assumption true.
*
* @param type any kind of {@code AnnotatedTypeMirror}
*/
private void ensurePrimaryIsCorrectForUnions(AnnotatedTypeMirror type) {
if (type.getKind() == TypeKind.UNION) {
AnnotatedUnionType annotatedUnionType = (AnnotatedUnionType) type;
Set<AnnotationMirror> lubs = null;
for (AnnotatedDeclaredType altern : annotatedUnionType.getAlternatives()) {
if (lubs == null) {
lubs = altern.getAnnotations();
} else {
Set<AnnotationMirror> newLubs = AnnotationUtils.createAnnotationSet();
for (AnnotationMirror lub : lubs) {
AnnotationMirror anno = altern.getAnnotationInHierarchy(lub);
newLubs.add(atypeFactory.getQualifierHierarchy().leastUpperBound(anno, lub));
}
lubs = newLubs;
}
}
type.replaceAnnotations(lubs);
}
}
@Override
protected String defaultErrorMessage(
AnnotatedTypeMirror type, AnnotatedTypeMirror superType, Void p) {
return String.format(
"AsSuperVisitor: Unexpected combination: type: %s superType: %s.%n"
+ "type: %s%nsuperType: %s",
type.getKind(), superType.getKind(), type, superType);
}
private AnnotatedTypeMirror errorTypeNotErasedSubtypeOfSuperType(
AnnotatedTypeMirror type, AnnotatedTypeMirror superType, Void p) {
if (TypesUtils.isString(superType.getUnderlyingType())) {
// Any type can be converted to String
return visit(atypeFactory.getStringType(type), superType, p);
}
if (isUninferredTypeArgument) {
return copyPrimaryAnnos(type, superType);
}
throw new BugInCF(
"AsSuperVisitor: type is not an erased subtype of supertype." + "%ntype: %s%nsuperType: %s",
type, superType);
}
private AnnotatedTypeMirror copyPrimaryAnnos(AnnotatedTypeMirror from, AnnotatedTypeMirror to) {
// There may have been annotations added by a recursive call to asSuper, so replace existing
// annotations
to.replaceAnnotations(new ArrayList<>(from.getAnnotations()));
// if to is a Typevar or Wildcard, then replaceAnnotations also sets primary annotations on
// the bounds to from.getAnnotations()
if (to.getKind() == TypeKind.UNION) {
// Make sure that the alternatives have a primary annotations
// Alternatives cannot have type arguments, so asSuper isn't called recursively
AnnotatedUnionType unionType = (AnnotatedUnionType) to;
for (AnnotatedDeclaredType altern : unionType.getAlternatives()) {
altern.addMissingAnnotations(unionType.getAnnotations());
}
}
return to;
}
/**
* A helper method for asSuper(AMT, Wildcard) methods to use to annotate the wildcard's lower
* bound.
*
* <p>If the lower bound of superType is Null, then return copyPrimarayAnnos(type, superType)
*
* <p>otherwise, return asSuper(type, superType.getLowerBound()
*
* <p>An error is issued if type is a Primitive or Wildcard -- those case are handled in
* asSuper(Primitive, Wildcard) and asSuper(Wildcard, Wildcard)
*
* <p>An error is issued if the lower bound of superType is not Null and type is not a subtype of
* the lower bound.
*/
private AnnotatedTypeMirror asSuperWildcardLowerBound(
AnnotatedTypeMirror type, AnnotatedWildcardType superType, Void p) {
AnnotatedTypeMirror lowerBound = superType.getSuperBound();
return asSuperLowerBound(type, p, lowerBound);
}
/** Same as #asSuperWildcardLowerBound, but for Typevars. */
private AnnotatedTypeMirror asSuperTypevarLowerBound(
AnnotatedTypeMirror type, AnnotatedTypeVariable superType, Void p) {
AnnotatedTypeMirror lowerBound = superType.getLowerBound();
return asSuperLowerBound(type, p, lowerBound);
}
private AnnotatedTypeMirror asSuperLowerBound(
AnnotatedTypeMirror type, Void p, AnnotatedTypeMirror lowerBound) {
if (lowerBound.getKind() == TypeKind.NULL) {
Set<AnnotationMirror> typeLowerBound =
AnnotatedTypes.findEffectiveLowerBoundAnnotations(
atypeFactory.getQualifierHierarchy(), type);
lowerBound.replaceAnnotations(typeLowerBound);
return lowerBound;
}
if (areErasedJavaTypesEquivalent(type, lowerBound)) {
return visit(type, lowerBound, p);
}
// If type and lowerBound are not the same type, then lowerBound is a subtype of type,
// but there is no way to convert type to a subtype -- there is not an asSub method. So,
// just copy the primary annotations.
return copyPrimaryAnnos(type, lowerBound);
}
/**
* Returns true if the underlying, erased Java type of {@code subtype} is a subtype of the
* underlying, erased Java type of {@code supertype}.
*
* @param subtype a type
* @param supertype a type
* @return true if the underlying, erased Java type of {@code subtype} is a subtype of the
* underlying, erased Java type of {@code supertype}
*/
private boolean isErasedJavaSubtype(
AnnotatedDeclaredType subtype, AnnotatedDeclaredType supertype) {
TypeMirror javaSubtype = types.erasure(subtype.getUnderlyingType());
TypeMirror javaSupertype = types.erasure(supertype.getUnderlyingType());
return types.isSubtype(javaSubtype, javaSupertype);
}
/**
* Returns true if the underlying, erased Java type of {@code typeA} and {@code typeB} are
* equivalent.
*
* @param typeA a type
* @param typeB a type
* @return true if the underlying, erased Java type of {@code typeA} and {@code typeB} are
* equivalent
*/
private boolean areErasedJavaTypesEquivalent(
AnnotatedTypeMirror typeA, AnnotatedTypeMirror typeB) {
TypeMirror underlyingTypeA = types.erasure(typeA.getUnderlyingType());
TypeMirror underlyingTypeB = types.erasure(typeB.getUnderlyingType());
return types.isSameType(underlyingTypeA, underlyingTypeB);
}
// <editor-fold defaultstate="collapsed" desc="visitArray_Other methods">
@Override
public AnnotatedTypeMirror visitArray_Array(
AnnotatedArrayType type, AnnotatedArrayType superType, Void p) {
AnnotatedTypeMirror asSuperCT = visit(type.getComponentType(), superType.getComponentType(), p);
superType.setComponentType(asSuperCT);
return copyPrimaryAnnos(type, superType);
}
@Override
public AnnotatedTypeMirror visitArray_Intersection(
AnnotatedArrayType type, AnnotatedIntersectionType superType, Void p) {
for (AnnotatedTypeMirror bounds : superType.getBounds()) {
if (!(TypesUtils.isObject(bounds.getUnderlyingType())
|| TypesUtils.isDeclaredOfName(bounds.getUnderlyingType(), "java.lang.Cloneable")
|| TypesUtils.isDeclaredOfName(bounds.getUnderlyingType(), "java.io.Serializable"))) {
return errorTypeNotErasedSubtypeOfSuperType(type, superType, p);
}
copyPrimaryAnnos(type, bounds);
}
return copyPrimaryAnnos(type, superType);
}
@Override
public AnnotatedTypeMirror visitArray_Declared(
AnnotatedArrayType type, AnnotatedDeclaredType superType, Void p) {
TypeElement array = TypesUtils.getTypeElement(type.getUnderlyingType());
TypeElement possibleArray = TypesUtils.getTypeElement(superType.getUnderlyingType());
// If the TypeElements of type and superType are equal, then superType's underlyingType is
// Array.class. Array.class is the receiver of methods such as clone() of which an array
// can be the receiver. (new int[].clone())
boolean isArrayClass = array.equals(possibleArray);
if (isArrayClass
|| TypesUtils.isObject(superType.getUnderlyingType())
|| TypesUtils.isDeclaredOfName(superType.getUnderlyingType(), "java.lang.Cloneable")
|| TypesUtils.isDeclaredOfName(superType.getUnderlyingType(), "java.io.Serializable")) {
return copyPrimaryAnnos(type, superType);
}
return errorTypeNotErasedSubtypeOfSuperType(type, superType, p);
}
@Override
public AnnotatedTypeMirror visitArray_Typevar(
AnnotatedArrayType type, AnnotatedTypeVariable superType, Void p) {
AnnotatedTypeMirror upperBound = visit(type, superType.getUpperBound(), p);
superType.setUpperBound(upperBound);
AnnotatedTypeMirror lowerBound = asSuperTypevarLowerBound(type, superType, p);
superType.setLowerBound(lowerBound);
return copyPrimaryAnnos(type, superType);
}
@Override
public AnnotatedTypeMirror visitArray_Wildcard(
AnnotatedArrayType type, AnnotatedWildcardType superType, Void p) {
AnnotatedTypeMirror upperBound = visit(type, superType.getExtendsBound(), p);
superType.setExtendsBound(upperBound);
AnnotatedTypeMirror lowerBound = asSuperWildcardLowerBound(type, superType, p);
superType.setSuperBound(lowerBound);
return copyPrimaryAnnos(type, superType);
}
// </editor-fold>
// <editor-fold defaultstate="collapsed" desc="visitDeclared_Other methods">
@Override
public AnnotatedTypeMirror visitDeclared_Declared(
AnnotatedDeclaredType type, AnnotatedDeclaredType superType, Void p) {
if (areErasedJavaTypesEquivalent(type, superType)) {
return type;
}
// Not same erased Java type.
// Walk up the directSupertypes.
// directSupertypes() annotates type variables correctly and handles substitution.
for (AnnotatedDeclaredType dst : type.directSupertypes()) {
if (isErasedJavaSubtype(dst, superType)) {
// If two direct supertypes of type, dst1 and dst2, are subtypes of superType then
// asSuper(dst1, superType) and asSuper(dst2, superType) return equivalent ATMs, so
// return the first one found.
return visit(dst, superType, p);
}
}
return errorTypeNotErasedSubtypeOfSuperType(type, superType, p);
}
@Override
public AnnotatedTypeMirror visitDeclared_Intersection(
AnnotatedDeclaredType type, AnnotatedIntersectionType superType, Void p) {
List<AnnotatedTypeMirror> newBounds = new ArrayList<>();
// Each type in the intersection must be a supertype of type, so call asSuper on all types
// in the intersection.
for (AnnotatedTypeMirror superBound : superType.getBounds()) {
if (types.isSubtype(type.getUnderlyingType(), superBound.getUnderlyingType())) {
AnnotatedTypeMirror found = visit(type, superBound, p);
newBounds.add(found);
}
}
// The ATM for each type in an intersection is stored in the direct super types field.
superType.setBounds(newBounds);
return copyPrimaryAnnos(type, superType);
}
@Override
public AnnotatedTypeMirror visitDeclared_Primitive(
AnnotatedDeclaredType type, AnnotatedPrimitiveType superType, Void p) {
if (!TypesUtils.isBoxedPrimitive(type.getUnderlyingType())) {
throw new BugInCF("AsSuperVisitor Declared_Primitive: type is not a boxed primitive.");
}
AnnotatedTypeMirror unboxedType = atypeFactory.getUnboxedType(type);
return copyPrimaryAnnos(unboxedType, superType);
}
@Override
public AnnotatedTypeMirror visitDeclared_Typevar(
AnnotatedDeclaredType type, AnnotatedTypeVariable superType, Void p) {
// setUpperBound() may have a side effect on parameter "type" when the upper bound of
// "superType" equals to "type" (referencing the same object: changes will be shared)
// copy before visiting to avoid
// without fix, this would fail:
// https://github.com/typetools/checker-framework/blob/ed340b2dfa1e51bbc0a7313f22638179d15bf2df/checker/tests/nullness/Issue2432b.java
AnnotatedTypeMirror typeCopy = type.deepCopy();
AnnotatedTypeMirror upperBound = visit(typeCopy, superType.getUpperBound(), p).asUse();
superType.setUpperBound(upperBound);
AnnotatedTypeMirror lowerBound = asSuperTypevarLowerBound(type, superType, p).asUse();
superType.setLowerBound(lowerBound);
return copyPrimaryAnnos(type, superType);
}
@Override
public AnnotatedTypeMirror visitDeclared_Union(
AnnotatedDeclaredType type, AnnotatedUnionType superType, Void p) {
// Alternatives in a union type can't have type args, so just copy the primary annotation
return copyPrimaryAnnos(type, superType);
}
@Override
public AnnotatedTypeMirror visitDeclared_Wildcard(
AnnotatedDeclaredType type, AnnotatedWildcardType superType, Void p) {
AnnotatedTypeMirror upperBound = visit(type, superType.getExtendsBound(), p).asUse();
superType.setExtendsBound(upperBound);
AnnotatedTypeMirror lowerBound = asSuperWildcardLowerBound(type, superType, p).asUse();
superType.setSuperBound(lowerBound);
return copyPrimaryAnnos(type, superType);
}
// </editor-fold>
// <editor-fold defaultstate="collapsed" desc="visitIntersection_Other methods">
@Override
public AnnotatedTypeMirror visitIntersection_Declared(
AnnotatedIntersectionType type, AnnotatedDeclaredType superType, Void p) {
for (AnnotatedTypeMirror bound : type.getBounds()) {
// Find the directSuperType that is a subtype of superType, then recur on that type so that
// type arguments in superType are annotated correctly.
if (bound.getKind() == TypeKind.DECLARED
&& isErasedJavaSubtype((AnnotatedDeclaredType) bound, superType)) {
AnnotatedTypeMirror asSuper = visit(bound, superType, p);
// The directSuperType might have a primary annotation that is a supertype of primary
// annotation on type. Copy the primary annotation, because it is more precise.
return copyPrimaryAnnos(type, asSuper);
}
}
return errorTypeNotErasedSubtypeOfSuperType(type, superType, p);
}
@Override
public AnnotatedTypeMirror visitIntersection_Intersection(
AnnotatedIntersectionType type, AnnotatedIntersectionType superType, Void p) {
List<AnnotatedTypeMirror> newDirectSupertypes = new ArrayList<>();
for (AnnotatedTypeMirror superBound : superType.getBounds()) {
AnnotatedTypeMirror found = null;
TypeMirror javaSupertype = types.erasure(superBound.getUnderlyingType());
for (AnnotatedTypeMirror bound : type.getBounds()) {
TypeMirror javaSubtype = types.erasure(bound.getUnderlyingType());
if (types.isSubtype(javaSubtype, javaSupertype)) {
found = visit(bound, superBound, p);
newDirectSupertypes.add(found);
break;
}
}
if (found == null) {
throw new BugInCF(
"AsSuperVisitor visitIntersection_Intersection:%ntype: %s superType: %s",
type, superType);
}
}
superType.setBounds(newDirectSupertypes);
return copyPrimaryAnnos(type, superType);
}
@Override
public AnnotatedTypeMirror visitIntersection_Primitive(
AnnotatedIntersectionType type, AnnotatedPrimitiveType superType, Void p) {
for (AnnotatedTypeMirror bound : type.getBounds()) {
// Find the directSuperType that is a subtype of superType, then recur on that type
// so that type arguments in superType are annotated correctly
if (TypesUtils.isBoxedPrimitive(bound.getUnderlyingType())) {
AnnotatedTypeMirror asSuper = visit(bound, superType, p);
// The directSuperType might have a primary annotation that is a supertype of primary
// annotation on type. Copy the primary annotation, because it is more precise.
return copyPrimaryAnnos(type, asSuper);
}
}
// Cannot happen: one of the types in the intersection must be a subtype of superType.
throw new BugInCF(
"AsSuperVisitor visitIntersection_Primitive:%ntype: %s superType: %s", type, superType);
}
@Override
public AnnotatedTypeMirror visitIntersection_Typevar(
AnnotatedIntersectionType type, AnnotatedTypeVariable superType, Void p) {
AnnotatedTypeMirror upperBound = visit(type, superType.getUpperBound(), p);
superType.setUpperBound(upperBound);
AnnotatedTypeMirror lowerBound = asSuperTypevarLowerBound(type, superType, p);
superType.setLowerBound(lowerBound);
return copyPrimaryAnnos(type, superType);
}
@Override
public AnnotatedTypeMirror visitIntersection_Union(
AnnotatedIntersectionType type, AnnotatedUnionType superType, Void p) {
TypeMirror javaSupertype = types.erasure(type.getUnderlyingType());
for (AnnotatedTypeMirror bound : type.getBounds()) {
TypeMirror javaSubtype = types.erasure(superType.getUnderlyingType());
if (types.isSubtype(javaSubtype, javaSupertype)) {
AnnotatedTypeMirror asSuper = visit(bound, superType, p);
return copyPrimaryAnnos(type, asSuper);
}
}
// Cannot happen: one of the types in the intersection must be a subtype of superType.
throw new BugInCF(
"AsSuperVisitor visitIntersection_Union:%ntype: %s%nsuperType: %s", type, superType);
}
@Override
public AnnotatedTypeMirror visitIntersection_Wildcard(
AnnotatedIntersectionType type, AnnotatedWildcardType superType, Void p) {
AnnotatedTypeMirror upperBound = visit(type, superType.getExtendsBound(), p);
superType.setExtendsBound(upperBound);
AnnotatedTypeMirror lowerBound = asSuperWildcardLowerBound(type, superType, p);
superType.setSuperBound(lowerBound);
return copyPrimaryAnnos(type, superType);
}
// </editor-fold>
// <editor-fold defaultstate="collapsed" desc="visitPrimitive_Other methods">
@Override
public AnnotatedTypeMirror visitPrimitive_Primitive(
AnnotatedPrimitiveType type, AnnotatedPrimitiveType superType, Void p) {
return copyPrimaryAnnos(type, superType);
}
/**
* A helper method for visiting a primitive and a non-primitive.
*
* @param type a primitive type
* @param superType some other type
* @param p ignore
* @return {@code type}, viewed as a {@code superType}
*/
private AnnotatedTypeMirror visitPrimitive_Other(
AnnotatedPrimitiveType type, AnnotatedTypeMirror superType, Void p) {
return visit(atypeFactory.getBoxedType(type), superType, p);
}
@Override
public AnnotatedTypeMirror visitPrimitive_Declared(
AnnotatedPrimitiveType type, AnnotatedDeclaredType superType, Void p) {
if (TypesUtils.isBoxedPrimitive(superType.getUnderlyingType())) {
TypeMirror unboxedSuper = types.unboxedType(superType.getUnderlyingType());
if (unboxedSuper.getKind() != type.getKind()
&& canBeNarrowingPrimitiveConversion(unboxedSuper)) {
AnnotatedPrimitiveType narrowedType = atypeFactory.getNarrowedPrimitive(type, unboxedSuper);
return visit(narrowedType, superType, p);
}
}
return visitPrimitive_Other(type, superType, p);
}
/**
* Returns true if the type is byte, short, char, Byte, Short, or Character. All other narrowings
* require a cast. See JLS 5.1.3.
*
* @param type a type
* @return true if assignment to the type may be a narrowing
*/
private boolean canBeNarrowingPrimitiveConversion(TypeMirror type) {
// See CFGBuilder.CFGTranslationPhaseOne#conversionRequiresNarrowing()
TypeMirror unboxedType = TypesUtils.isBoxedPrimitive(type) ? types.unboxedType(type) : type;
TypeKind unboxedKind = unboxedType.getKind();
return unboxedKind == TypeKind.BYTE
|| unboxedKind == TypeKind.SHORT
|| unboxedKind == TypeKind.CHAR;
}
@Override
public AnnotatedTypeMirror visitPrimitive_Intersection(
AnnotatedPrimitiveType type, AnnotatedIntersectionType superType, Void p) {
return visitPrimitive_Other(type, superType, p);
}
@Override
public AnnotatedTypeMirror visitPrimitive_Typevar(
AnnotatedPrimitiveType type, AnnotatedTypeVariable superType, Void p) {
return visitPrimitive_Other(type, superType, p);
}
@Override
public AnnotatedTypeMirror visitPrimitive_Union(
AnnotatedPrimitiveType type, AnnotatedUnionType superType, Void p) {
return visitPrimitive_Other(type, superType, p);
}
@Override
public AnnotatedTypeMirror visitPrimitive_Wildcard(
AnnotatedPrimitiveType type, AnnotatedWildcardType superType, Void p) {
return visitPrimitive_Other(type, superType, p);
}
// </editor-fold>
// <editor-fold defaultstate="collapsed" desc="visitTypevar_Other methods">
private AnnotatedTypeMirror visitTypevar_NotTypevarNorWildcard(
AnnotatedTypeVariable type, AnnotatedTypeMirror superType, Void p) {
AnnotatedTypeMirror asSuper = visit(type.getUpperBound(), superType, p);
return copyPrimaryAnnos(type, asSuper);
}
@Override
public AnnotatedTypeMirror visitTypevar_Declared(
AnnotatedTypeVariable type, AnnotatedDeclaredType superType, Void p) {
return visitTypevar_NotTypevarNorWildcard(type, superType, p);
}
@Override
public AnnotatedTypeMirror visitTypevar_Intersection(
AnnotatedTypeVariable type, AnnotatedIntersectionType superType, Void p) {
return visitTypevar_NotTypevarNorWildcard(type, superType, p);
}
@Override
public AnnotatedTypeMirror visitTypevar_Primitive(
AnnotatedTypeVariable type, AnnotatedPrimitiveType superType, Void p) {
return visitTypevar_NotTypevarNorWildcard(type, superType, p);
}
@Override
public AnnotatedTypeMirror visitTypevar_Typevar(
AnnotatedTypeVariable type, AnnotatedTypeVariable superType, Void p) {
// Clear the superType annotations and copy over the primary annotations before computing
// bounds, so that the superType annotations don't override the type annotations on the bounds.
superType.clearAnnotations();
copyPrimaryAnnos(type, superType);
AnnotatedTypeMirror upperBound = visit(type.getUpperBound(), superType.getUpperBound(), p);
superType.setUpperBound(upperBound);
AnnotatedTypeMirror lowerBound;
if (type.getLowerBound().getKind() == TypeKind.NULL
&& superType.getLowerBound().getKind() == TypeKind.NULL) {
lowerBound = copyPrimaryAnnos(type.getLowerBound(), superType.getLowerBound());
} else if (type.getLowerBound().getKind() == TypeKind.NULL) {
lowerBound = visit(type, superType.getLowerBound(), p);
} else {
lowerBound = asSuperTypevarLowerBound(type.getLowerBound(), superType, p);
}
superType.setLowerBound(lowerBound);
return superType;
}
@Override
public AnnotatedTypeMirror visitTypevar_Union(
AnnotatedTypeVariable type, AnnotatedUnionType superType, Void p) {
return visitTypevar_NotTypevarNorWildcard(type, superType, p);
}
@Override
public AnnotatedTypeMirror visitTypevar_Wildcard(
AnnotatedTypeVariable type, AnnotatedWildcardType superType, Void p) {
AnnotatedTypeMirror upperBound = visit(type.getUpperBound(), superType.getExtendsBound(), p);
superType.setExtendsBound(upperBound);
AnnotatedTypeMirror lowerBound;
if (type.getLowerBound().getKind() == TypeKind.NULL
&& superType.getSuperBound().getKind() == TypeKind.NULL) {
lowerBound = copyPrimaryAnnos(type.getLowerBound(), superType.getSuperBound());
} else if (type.getLowerBound().getKind() == TypeKind.NULL) {
lowerBound = visit(type, superType.getSuperBound(), p);
} else {
lowerBound = asSuperWildcardLowerBound(type.getLowerBound(), superType, p);
}
superType.setSuperBound(lowerBound);
return copyPrimaryAnnos(type, superType);
}
// </editor-fold>
/* The primary annotation on a union type is the LUB of the primary annotations on its alternatives. #ensurePrimaryIsCorrectForUnions ensures that this is the case.
All the alternatives in a union type must be subtype of Throwable and cannot have type arguments;
however, a union type can be a subtype of an interface with a type argument. For example:
interface Interface<T>{}
class MyException1 extends Throwable implements Interface<Number>{}
class MyException2 extends Throwable implements Interface<Number>{}
MyException1 <: MyException1 | MyException2 <: Interface<Number>
MyException1 | MyException2 <: Throwable & Interface<Number>
*/
// <editor-fold defaultstate="collapsed" desc="visitUnion_Other methods">
private AnnotatedTypeMirror visitUnion_Other(
AnnotatedUnionType type, AnnotatedTypeMirror superType, Void p) {
// asSuper on any of the alternatives is the same, so just use the first one.
AnnotatedTypeMirror asSuper = visit(type.getAlternatives().get(0), superType, p);
return copyPrimaryAnnos(type, asSuper);
}
@Override
public AnnotatedTypeMirror visitUnion_Declared(
AnnotatedUnionType type, AnnotatedDeclaredType superType, Void p) {
return visitUnion_Other(type, superType, p);
}
@Override
public AnnotatedTypeMirror visitUnion_Intersection(
AnnotatedUnionType type, AnnotatedIntersectionType superType, Void p) {
return visitUnion_Other(type, superType, p);
}
@Override
public AnnotatedTypeMirror visitUnion_Typevar(
AnnotatedUnionType type, AnnotatedTypeVariable superType, Void p) {
return visitUnion_Other(type, superType, p);
}
@Override
public AnnotatedTypeMirror visitUnion_Union(
AnnotatedUnionType type, AnnotatedUnionType superType, Void p) {
for (AnnotatedTypeMirror superAltern : superType.getAlternatives()) {
copyPrimaryAnnos(type, superAltern);
}
return copyPrimaryAnnos(type, superType);
}
@Override
public AnnotatedTypeMirror visitUnion_Wildcard(
AnnotatedUnionType type, AnnotatedWildcardType superType, Void p) {
return visitUnion_Other(type, superType, p);
}
// </editor-fold>
// <editor-fold defaultstate="collapsed" desc="visitWildCard_Other methods">
private AnnotatedTypeMirror visitWildcard_NotTypvarNorWildcard(
AnnotatedWildcardType type, AnnotatedTypeMirror superType, Void p) {
boolean oldIsUninferredTypeArgument = isUninferredTypeArgument;
if (type.isUninferredTypeArgument()) {
isUninferredTypeArgument = true;
}
AnnotatedTypeMirror asSuper = visit(type.getExtendsBound(), superType, p);
isUninferredTypeArgument = oldIsUninferredTypeArgument;
atypeFactory.addDefaultAnnotations(superType);
return copyPrimaryAnnos(type, asSuper);
}
@Override
public AnnotatedTypeMirror visitWildcard_Array(
AnnotatedWildcardType type, AnnotatedArrayType superType, Void p) {
return visitWildcard_NotTypvarNorWildcard(type, superType, p);
}
@Override
public AnnotatedTypeMirror visitWildcard_Declared(
AnnotatedWildcardType type, AnnotatedDeclaredType superType, Void p) {
return visitWildcard_NotTypvarNorWildcard(type, superType, p);
}
@Override
public AnnotatedTypeMirror visitWildcard_Intersection(
AnnotatedWildcardType type, AnnotatedIntersectionType superType, Void p) {
return visitWildcard_NotTypvarNorWildcard(type, superType, p);
}
@Override
public AnnotatedTypeMirror visitWildcard_Primitive(
AnnotatedWildcardType type, AnnotatedPrimitiveType superType, Void p) {
return visitWildcard_NotTypvarNorWildcard(type, superType, p);
}
@Override
public AnnotatedTypeMirror visitWildcard_Typevar(
AnnotatedWildcardType type, AnnotatedTypeVariable superType, Void p) {
boolean oldIsUninferredTypeArgument = isUninferredTypeArgument;
if (type.isUninferredTypeArgument()) {
isUninferredTypeArgument = true;
}
AnnotatedTypeMirror upperBound = visit(type.getExtendsBound(), superType.getUpperBound(), p);
superType.setUpperBound(upperBound);
AnnotatedTypeMirror lowerBound;
if (type.getSuperBound().getKind() == TypeKind.NULL
&& superType.getLowerBound().getKind() == TypeKind.NULL) {
lowerBound = copyPrimaryAnnos(type.getSuperBound(), superType.getLowerBound());
} else if (type.getSuperBound().getKind() == TypeKind.NULL) {
lowerBound = visit(type, superType.getLowerBound(), p);
} else {
lowerBound = asSuperTypevarLowerBound(type.getSuperBound(), superType, p);
}
superType.setLowerBound(lowerBound);
isUninferredTypeArgument = oldIsUninferredTypeArgument;
atypeFactory.addDefaultAnnotations(superType);
return copyPrimaryAnnos(type, superType);
}
@Override
public AnnotatedTypeMirror visitWildcard_Union(
AnnotatedWildcardType type, AnnotatedUnionType superType, Void p) {
return visitWildcard_NotTypvarNorWildcard(type, superType, p);
}
@Override
public AnnotatedTypeMirror visitWildcard_Wildcard(
AnnotatedWildcardType type, AnnotatedWildcardType superType, Void p) {
boolean oldIsUninferredTypeArgument = isUninferredTypeArgument;
if (type.isUninferredTypeArgument()) {
isUninferredTypeArgument = true;
superType.setUninferredTypeArgument();
}
if (types.isSubtype(
type.getExtendsBound().getUnderlyingType(),
superType.getExtendsBound().getUnderlyingType())) {
AnnotatedTypeMirror upperBound =
visit(type.getExtendsBound(), superType.getExtendsBound(), p);
superType.setExtendsBound(upperBound);
} else {
// The upper bound of a wildcard can be a super type of upper bound of the type
// parameter for which it is an argument.
// See org.checkerframework.framework.type.AnnotatedTypeFactory.widenToUpperBound for an
// example. In these cases, the upper bound of type might be a super type of the
// upper bound of superType.
// The underlying type of the annotated type mirror returned by asSuper must be the
// same as the passed type, so just copy the primary annotations.
copyPrimaryAnnos(type.getExtendsBound(), superType.getExtendsBound());
// Add defaults in case any locations are missing annotations.
atypeFactory.addDefaultAnnotations(superType.getExtendsBound());
}
AnnotatedTypeMirror lowerBound;
if (type.getSuperBound().getKind() == TypeKind.NULL
&& superType.getSuperBound().getKind() == TypeKind.NULL) {
lowerBound = copyPrimaryAnnos(type.getSuperBound(), superType.getSuperBound());
} else if (type.getSuperBound().getKind() == TypeKind.NULL) {
lowerBound = visit(type, superType.getSuperBound(), p);
} else {
lowerBound = asSuperWildcardLowerBound(type.getSuperBound(), superType, p);
}
superType.setSuperBound(lowerBound);
isUninferredTypeArgument = oldIsUninferredTypeArgument;
atypeFactory.addDefaultAnnotations(superType);
return copyPrimaryAnnos(type, superType);
}
/**
* Returns true if the atypeFactory for this is the given value.
*
* @param atypeFactory a factory to compare to that of this
* @return true if the atypeFactory for this is the given value
*/
public boolean sameAnnotatedTypeFactory(@FindDistinct AnnotatedTypeFactory atypeFactory) {
return this.atypeFactory == atypeFactory;
}
// </editor-fold>
}