AbstractTypes.java
- package net.florianschoppmann.java.type;
- import javax.annotation.Nullable;
- import javax.lang.model.element.Element;
- import javax.lang.model.element.ElementKind;
- 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.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.WildcardType;
- import javax.lang.model.util.Types;
- import java.io.Serializable;
- import java.lang.reflect.Type;
- import java.util.ArrayList;
- import java.util.Arrays;
- import java.util.Collections;
- import java.util.HashMap;
- import java.util.Iterator;
- import java.util.LinkedHashMap;
- import java.util.LinkedHashSet;
- import java.util.List;
- import java.util.Map;
- import java.util.Objects;
- import java.util.Set;
- /**
- * Abstract skeletal implementation of {@link Types}.
- *
- * <p>This class provides a skeletal implementation of the {@link Types} interface. Specifically, it implements all
- * methods pertaining to §4.10 (subtyping) in the Java Language Specification (JLS). Concrete subclasses are expected to
- * implement the abstract methods in this class, which are responsible for creating appropriate type-mirror instances.
- * This class does not place any additional constraints on the concrete {@link TypeMirror} and {@link Element}
- * implementations, so mutability and thread-safety are implementation-defined. However, this class crucially relies on
- * the {@code equals} method being well-defined. That is, {@link Element} objects that have equal names and equal
- * enclosing elements must compare equal. Likewise, {@link TypeMirror} objects that contain equal values must compare
- * equal. In particular, multiple instances created by one of the {@code get}-methods must compare equal when the given
- * arguments compare equal.
- *
- * <p>Besides subtype-related methods, this class also provides method
- * {@link #resolveActualTypeArguments(TypeElement, TypeMirror)} for resolving formal type parameters to actual type
- * arguments. For instance, given type {@code List<String>}, this method determines the actual type argument for the
- * formal type parameter of {@code Collection<E>} (that is, {@code String} in this simple example).
- *
- * <p>Unless explicitly stated otherwise, all methods in this class expect non-null arguments. Passing null where not
- * expected will cause a {@link NullPointerException} to be thrown. Implementations typically place additional
- * restrictions on method arguments not captured by the types of the formal parameters (which stem from
- * {@link javax.lang.model} and its subpackages). While the details are implementation-defined, typically this means
- * that arguments must have been crated by the same implementation, or otherwise an {@link IllegalArgumentException}
- * will be thrown. Implementations must override {@link #requireValidType(TypeMirror)} and
- * {@link #requireValidElement(Element)}, as these methods are expected to perform any necessary validation.
- */
- public abstract class AbstractTypes implements Types {
- private static final List<TypeKind> REFERENCE_TYPES = Collections.unmodifiableList(Arrays.asList(
- TypeKind.ARRAY, TypeKind.DECLARED, TypeKind.NULL, TypeKind.TYPEVAR
- ));
- private static final int DEFAULT_STRING_BUILDER_SIZE = 256;
- private final SubstitutionVisitor substitutionVisitor = new SubstitutionVisitor();
- private final ErasureVisitor erasureVisitor = new ErasureVisitor();
- private final ToStringVisitor toStringVisitor = new ToStringVisitor();
- private final SubtypeVisitor subtypeVisitor = new SubtypeVisitor();
- private final DeclaredTypeSubtypeVisitor declaredTypeSubtypeVisitor = new DeclaredTypeSubtypeVisitor();
- /**
- * Verifies that the given {@link Element} is valid for use with this class.
- *
- * <p>The meaning of valid is implementation-defined, but typically a valid {@link Element} must have been created
- * by the implementation that belongs to the current {@code AbstractTypes} instance.
- *
- * @param element element
- * @throws NullPointerException if the argument is null
- * @throws IllegalArgumentException if the given {@link Element} cannot be used with this class
- */
- protected abstract void requireValidElement(Element element);
- /**
- * Verifies that the given {@link TypeMirror} is valid for use with this class, or that it is {@code null}.
- *
- * <p>The meaning of valid is implementation-defined, but typically a valid {@link TypeMirror} must have been
- * created by the implementation that belongs to the current {@code AbstractTypes} instance. A {@code null} argument
- * is always valid. The rationale is that {@code null} {@link TypeMirror} arguments have a special meaning for some
- * methods such as {@link #getWildcardType(TypeMirror, TypeMirror)} or
- * {@link #createTypeVariable(TypeParameterElement, WildcardType)}.
- *
- * @param type type mirror, may be {@code null}
- * @throws IllegalArgumentException if the given {@link TypeMirror} instance is non-null and it cannot be used with
- * this class
- */
- protected abstract void requireValidType(@Nullable TypeMirror type);
- /**
- * Verifies that the given array is non-null and contains valid types that are not null.
- *
- * @param types array of types
- * @throws NullPointerException if the given array or any of its elements are null
- * @throws IllegalArgumentException if {@link #requireValidType(TypeMirror)} throws an exception for one of the
- * array elements
- */
- protected final void requireValidTypes(TypeMirror[] types) {
- for (TypeMirror typeArg: types) {
- Objects.requireNonNull(typeArg, "TypeMirror array must not contain null elements.");
- requireValidType(typeArg);
- }
- }
- /**
- * Returns a type mirror corresponding to the given Java reflection type.
- *
- * <p>Subclasses are required to return the appropriate {@link DeclaredType} instances for the following
- * {@link Class} instances:
- * <ul><li>
- * {@link Object}
- * </li><li>
- * {@link Serializable}
- * </li><li>
- * {@link Cloneable}
- * </li></ul>
- *
- * <p>Support for other types is not required and implementation-defined.
- *
- * @param type type as represented by Java Reflection API
- * @throws UnsupportedOperationException If the given type is not one of the above {@link Class} objects and
- * this type-utilities implementation does not support mirroring arbitrary Java reflection types.
- * @return the type mirror corresponding to the given reflection type
- */
- protected abstract TypeMirror typeMirror(Type type);
- /**
- * Internal class that contains both the substitution map passed to {@link #substitute(TypeMirror, Map)} and the
- * set of fresh type variables created at the beginning of that method.
- */
- private static final class Substitutions {
- private final Map<TypeParameterElement, ? extends TypeMirror> map;
- private final Map<TypeParameterElement, TypeVariable> freshTypeVariables;
- private Substitutions(Map<TypeParameterElement, ? extends TypeMirror> map,
- Map<TypeParameterElement, TypeVariable> freshTypeVariables) {
- this.map = map;
- this.freshTypeVariables = freshTypeVariables;
- }
- }
- /**
- * Visitor of a type mirror. Returns a new type mirror after performing the substitutions passed as visitor
- * argument.
- *
- * <p>This visitor is only used within this class and only on <em>valid</em> {@link TypeMirror} instances. Hence, it
- * can be asserted that the visitor parameter is always non-null.
- *
- * @see #substitutionVisitor
- * @see #requireValidType(TypeMirror)
- */
- private final class SubstitutionVisitor extends ExtendedTypeKindVisitor7<TypeMirror, Substitutions> {
- private TypeMirror[] substituteInList(List<? extends TypeMirror> types, Substitutions substitutions) {
- TypeMirror[] substituted = new TypeMirror[types.size()];
- int i = 0;
- for (TypeMirror type: types) {
- substituted[i] = type.accept(this, substitutions);
- ++i;
- }
- return substituted;
- }
- @Override
- public TypeMirror visitDeclared(DeclaredType declaredType, @Nullable Substitutions substitutions) {
- assert substitutions != null;
- TypeMirror enclosingType = declaredType.getEnclosingType();
- TypeElement typeDeclaration = (TypeElement) declaredType.asElement();
- TypeMirror[] substitutedArguments = substituteInList(declaredType.getTypeArguments(), substitutions);
- if (enclosingType.getKind() == TypeKind.DECLARED) {
- return getDeclaredType((DeclaredType) enclosingType, typeDeclaration, substitutedArguments);
- } else {
- return getDeclaredType(typeDeclaration, substitutedArguments);
- }
- }
- @Override
- public TypeMirror visitArray(ArrayType arrayType, @Nullable Substitutions substitutions) {
- assert substitutions != null;
- return getArrayType(arrayType.getComponentType().accept(this, substitutions));
- }
- @Override
- public TypeMirror visitTypeVariable(TypeVariable typeVariable, @Nullable Substitutions substitutions) {
- assert substitutions != null;
- TypeParameterElement formalTypeParameter = (TypeParameterElement) typeVariable.asElement();
- @Nullable TypeVariable freshTypeVariable = substitutions.freshTypeVariables.get(formalTypeParameter);
- if (freshTypeVariable != null && formalTypeParameter.asType().equals(typeVariable)) {
- return freshTypeVariable;
- }
- @Nullable TypeMirror substitution = substitutions.map.get(formalTypeParameter);
- if (substitution != null) {
- return substitution;
- }
- return getTypeVariable(
- formalTypeParameter,
- typeVariable.getUpperBound().accept(this, substitutions),
- typeVariable.getLowerBound().accept(this, substitutions),
- capturedTypeArgument(typeVariable)
- );
- }
- @Override
- public TypeMirror visitWildcard(WildcardType wildcardType, @Nullable Substitutions substitutions) {
- assert substitutions != null;
- @Nullable TypeMirror extendsBounds = wildcardType.getExtendsBound();
- @Nullable TypeMirror superBound = wildcardType.getSuperBound();
- return getWildcardType(
- extendsBounds != null
- ? extendsBounds.accept(this, substitutions)
- : null,
- superBound != null
- ? superBound.accept(this, substitutions)
- : null
- );
- }
- @Override
- public TypeMirror visitIntersection(IntersectionType intersectionType, @Nullable Substitutions substitutions) {
- assert substitutions != null;
- return getIntersectionType(substituteInList(intersectionType.getBounds(), substitutions));
- }
- @Override
- protected TypeMirror defaultAction(TypeMirror type, Substitutions substitutions) {
- return type;
- }
- }
- /**
- * Replaces formal type parameters in the given type.
- *
- * <p>This method requires that {@code type} does not contain transitive references to itself, unless through
- * {@link DeclaredType#asElement()} → {@link TypeElement#asType()} or {@link TypeVariable#asElement()} →
- * {@link TypeParameterElement#asType()}. Otherwise, this method might run into an infinite recursion, resulting in
- * a {@link StackOverflowError}.
- *
- * <p>Moreover, this method requires that any type variable transitively referenced by {@code substitutionMap} must
- * not contain a transitive reference (through {@link TypeVariable#getUpperBound()} or
- * {@link TypeVariable#getLowerBound()}) to itself. Instead, any instance of {@link TypeVariable} (transitively)
- * referenced by a value in {@code substitutionMap} must be the result of {@link TypeParameterElement#asType()}.
- *
- * <p>This method creates a fresh type variable for each formal type parameter that is to be substituted by a type
- * variable for the same formal type parameter. For instance, suppose {@code T extends Object} is a formal type
- * parameter, and {@code substitutionMap} specifies to replace it with the type variable {@code T extends U<T>}. In
- * this case, {@link #createTypeVariable(TypeParameterElement, WildcardType)} will be called with the formal type
- * parameter {@code T extends Object} as (first) argument. Once all fresh types have been created,
- * {@link #setTypeVariableBounds(TypeVariable, TypeMirror, TypeMirror)} will then be called with {@code U<T>} as
- * upper bound, where {@code T} is the fresh type variable {@code T extends U<T>}.
- *
- * @param type type in which the type parameters will be replaced recursively, guaranteed non-null
- * @param substitutionMap mapping from formal type parameters to substituted type, guaranteed non-null
- * @return new port type, guaranteed non-null
- */
- protected TypeMirror substitute(TypeMirror type, Map<TypeParameterElement, ? extends TypeMirror> substitutionMap) {
- Objects.requireNonNull(type);
- Objects.requireNonNull(substitutionMap);
- requireValidType(type);
- for (TypeMirror substitutionType: substitutionMap.values()) {
- Objects.requireNonNull(substitutionType, "Substitution type cannot be null.");
- requireValidType(substitutionType);
- }
- Map<TypeParameterElement, TypeVariable> freshTypeVariables = new LinkedHashMap<>();
- for (Map.Entry<TypeParameterElement, ? extends TypeMirror> entry: substitutionMap.entrySet()) {
- TypeMirror value = entry.getValue();
- if (value.getKind() == TypeKind.TYPEVAR) {
- TypeParameterElement formalTypeParameter = entry.getKey();
- TypeVariable typeVariable = (TypeVariable) value;
- if (entry.getKey().equals(typeVariable.asElement())) {
- assert !freshTypeVariables.containsKey(formalTypeParameter);
- freshTypeVariables.put(
- formalTypeParameter,
- createTypeVariable(formalTypeParameter, capturedTypeArgument(typeVariable))
- );
- }
- }
- }
- Substitutions substitutions = new Substitutions(substitutionMap, freshTypeVariables);
- for (Map.Entry<TypeParameterElement, TypeVariable> entry: freshTypeVariables.entrySet()) {
- TypeVariable substitution = (TypeVariable) substitutionMap.get(entry.getKey());
- setTypeVariableBounds(
- entry.getValue(),
- substitution.getUpperBound().accept(substitutionVisitor, substitutions),
- substitution.getLowerBound().accept(substitutionVisitor, substitutions)
- );
- }
- return type.accept(substitutionVisitor, substitutions);
- }
- /**
- * Returns the actual type arguments of a type declaration given a subtype (typically with its own actual type
- * arguments).
- *
- * <p>This method "projects" the actual type arguments of {@code subtype}, as well as all actual type arguments of
- * super types in the type hierarchy between {@code typeElement} and {@code subType}, onto the type declaration
- * represented by {@code typeElement}.
- *
- * <p>For example, {@code typeElement} may be the (generic) type declaration {@code Comparable<T>}, and
- * {@code subType} may be the (non-generic) type {@link Integer}. The result in this case would be a singleton list
- * containing the type {@link Integer}.
- *
- * <p>More generally, resolution works as follows: First, the shortest inheritance path from {@code subType} to
- * {@code typeElement} is found. Note that while Java allows multiple inheritance for interfaces, JLS §8.1.5
- * disallows inheriting from the same interface with different type parameters (both directly and transitively).
- * Hence, the shortest path contains all information that is necessary to resolve formal type parameters to actual
- * parameters. This method then propagates the actual type arguments bottom-up along the inheritance path.
- * Note that the inheritance path consists of {@link DeclaredType} instances, and it may consist of generic types,
- * non-generic types, and raw types.
- *
- * <p>If the inheritance path contains a raw type <em>before</em> the last path element, this method proceeds
- * by using the "prototypical" type returned by {@link Element#asType()} instead. Correspondingly, it is possible
- * that the returned list may contain type variables from a type declaration along the inheritance path. However, if
- * the <em>last</em> inheritance path element is a raw type, the returned list will be empty. Otherwise, if a
- * non-null non-empty {@link List} is returned, it is guaranteed to have the same number of elements as
- * {@code typeElement.getTypeParameters()}.
- *
- * @param typeElement type declaration
- * @param subType potential subtype of {@code typeElement}, must be a non-generic type declaration, raw type,
- * generic type declaration, or parameterized type
- * @return actual type arguments for the formal parameters of {@code typeElement} (empty list if the <em>last</em>
- * path element in the inheritance path from {@code subType} to {@code typeElement} is a raw type), or
- * {@code null} if {@code subType} is not a subtype of {@code typeElement}
- * @throws IllegalArgumentException if the arguments do not satisfy the constraints mentioned above
- */
- @Nullable
- public final List<? extends TypeMirror> resolveActualTypeArguments(TypeElement typeElement, TypeMirror subType) {
- requireValidElement(Objects.requireNonNull(typeElement));
- requireValidType(Objects.requireNonNull(subType));
- if (subType.getKind() != TypeKind.DECLARED) {
- return null;
- }
- DeclaredType declaredSubType = (DeclaredType) subType;
- // getShortestPathToSuperType() will throw an exception if subType does not satisfy the constraints mentioned
- // above.
- @Nullable List<DeclaredType> path = getShortestPathToSuperType(typeElement, declaredSubType);
- if (path == null) {
- return null;
- }
- // Early exit if there is nothing to resolve. However, we must not move this early exit any earlier, because
- // we do want to return null if subType is not a subtype of typeElement.
- if (typeElement.getTypeParameters().isEmpty()) {
- return Collections.emptyList();
- }
- Iterator<DeclaredType> pathIterator = path.iterator();
- DeclaredType current = pathIterator.next();
- while (pathIterator.hasNext()) {
- TypeElement currentTypeElement = (TypeElement) current.asElement();
- // Check whether "current" is a raw type. This may happen in the first loop iteration if subType is a raw
- // type, or in subsequent iterations if the type that was previously "current" (during the last iteration
- // of the for-loop) derived from a raw type. If yes, use instead the "prototypical" type returned by
- // Element#asType().
- if (current.getTypeArguments().isEmpty() && !currentTypeElement.getTypeParameters().isEmpty()) {
- current = (DeclaredType) currentTypeElement.asType();
- }
- List<? extends TypeParameterElement> currentFormalParameters = currentTypeElement.getTypeParameters();
- List<? extends TypeMirror> currentActualParameters = current.getTypeArguments();
- Map<TypeParameterElement, TypeMirror> currentFormalToActual = new LinkedHashMap<>();
- for (int index = 0; index < currentFormalParameters.size(); ++index) {
- currentFormalToActual.put(currentFormalParameters.get(index), currentActualParameters.get(index));
- }
- current = (DeclaredType) substitute(pathIterator.next(), currentFormalToActual);
- }
- return current.getTypeArguments();
- }
- /**
- * Visitor of a type mirror. Returns whether the visited type mirror is a subtype of the visitor argument (of type
- * {@link DeclaredType}).
- *
- * <p>This visitor is only used within this class and only on <em>valid</em> {@link TypeMirror} instances. Hence, it
- * can be asserted that the visitor parameter is always non-null.
- *
- * @see #declaredTypeSubtypeVisitor
- * @see #requireValidType(TypeMirror)
- */
- private final class DeclaredTypeSubtypeVisitor extends ExtendedTypeKindVisitor7<Boolean, DeclaredType> {
- private DeclaredTypeSubtypeVisitor() {
- super(false);
- }
- /**
- * Returns whether the first declared type is a subtype of the second declared type.
- *
- * <p>This method proceeds by computing the actual type arguments when {@code subType} is projected onto the
- * type declaration corresponding to {@code superType}. It then tests if all actual type arguments of
- * {@code subType} are <em>contained</em> in those of {@code superType}.
- */
- @Override
- public Boolean visitDeclared(DeclaredType subType, @Nullable DeclaredType superType) {
- assert superType != null;
- DeclaredType actualSubType = subType;
- // First test if there subType has at least one wildcard type argument. In that case, we need to perform a
- // capture conversion first.
- // Note that this is the right place to do capture conversion: JLS §8.1.4 and §9.1.3 state about class types
- // and interfaces type listed in the extends or implements clause of a class/interface declaration:
- // - "If the ClassType has type arguments, it must denote a well-formed parameterized type (§4.5), and none
- // of the type arguments may be wildcard type arguments, or a compile-time error occurs."
- // - "If an InterfaceType has type arguments, it must denote a well-formed parameterized type (§4.5), and
- // none of the type arguments may be wildcard type arguments, or a compile-time error occurs."
- // Hence, wildcards do not appear on the "inheritance path" between subType and superType.
- for (TypeMirror subTypeArgument: subType.getTypeArguments()) {
- if (subTypeArgument.getKind() == TypeKind.WILDCARD) {
- actualSubType = (DeclaredType) capture(subType);
- break;
- }
- }
- // Resolve the actual type parameters of subType when projected onto the superType
- TypeElement superTypeDeclaration = (TypeElement) superType.asElement();
- @Nullable List<? extends TypeMirror> projectedTypeArguments
- = resolveActualTypeArguments(superTypeDeclaration, actualSubType);
- if (projectedTypeArguments == null) {
- // subType is not a subtype of the type declaration
- return false;
- }
- List<? extends TypeMirror> superTypeArguments = superType.getTypeArguments();
- if (projectedTypeArguments.isEmpty() && !superTypeArguments.isEmpty()) {
- // the projection of subType onto superType resulted in a raw type, which is neither a subtype of any
- // parametrized type of the generic type declaration of superType, nor the generic type declaration
- // itself
- return false;
- }
- // Note that superType could be a raw type, in which case superTypeArguments is empty. In that case, the
- // loop would not be executed at all.
- Iterator<? extends TypeMirror> projectedTypeArgumentsIterator = projectedTypeArguments.iterator();
- for (TypeMirror to: superTypeArguments) {
- TypeMirror from = projectedTypeArgumentsIterator.next();
- if (!contains(to, from)) {
- return false;
- }
- }
- return true;
- }
- /**
- * Returns whether the array type is a subtype of the declared type.
- *
- * <p>According to JLS §4.10.3, an array type can only be a subtype of a declared type if the latter represents
- * one of {@link Object}, {@link Cloneable}, or {@link Serializable}.
- */
- @Override
- public Boolean visitArray(ArrayType subType, @Nullable DeclaredType superType) {
- assert superType != null;
- return typeMirror(Object.class).equals(superType)
- || typeMirror(Cloneable.class).equals(superType)
- || typeMirror(Serializable.class).equals(superType);
- }
- /**
- * Returns whether the type variable is a subtype of the declared type.
- *
- * <p>According to JLS §4.10.2, the direct supertypes of a type variable are the types listed in its bound.
- * Hence, this method returns true if {@link TypeVariable#getUpperBound()} is a subtype of {@code superType}.
- */
- @Override
- public Boolean visitTypeVariable(TypeVariable subType, @Nullable DeclaredType superType) {
- assert superType != null;
- return isSubtype(subType.getUpperBound(), superType);
- }
- /**
- * Returns whether the intersection type is a subtype of the declared type.
- *
- * <p>According to JLS §4.10.2, the direct supertypes of an intersection type {@code T_1 & ... T_n} are
- * {@code T_1}, ..., {@code T_n}. Hence, this method returns true if at least one of
- * {@link IntersectionType#getBounds()} is a subtype of {@code superType}.
- */
- @Override
- public Boolean visitIntersection(IntersectionType subType, @Nullable DeclaredType superType) {
- assert superType != null;
- for (TypeMirror bound: subType.getBounds()) {
- if (isSubtype(bound, superType)) {
- return true;
- }
- }
- return false;
- }
- }
- /**
- * Visitor of a type mirror. Returns whether the visited type mirror is a supertype of the visitor argument.
- *
- * <p>This visitor does not have to deal with the null-type, which has been dealt with before. It has to make a
- * decision for {@link ArrayType}, {@link DeclaredType}, {@link PrimitiveType}, and {@link TypeVariable}.
- *
- * <p>Java 8 introduces {@code IntersectionType}, but this code currently uses Java 7. Moreover, there are other
- * types that are currently not supported, such as {@link javax.lang.model.type.UnionType}. Finally,
- * {@link WildcardType} is not a type, but only a type argument, so it is not necessary to be dealt with here.
- * Likewise, {@link NoType} is not used to model proper types, but only empty bounds, non-existence of interface
- * super classes, etc.
- *
- * <p>This visitor is only used within this class and only on <em>valid</em> {@link TypeMirror} instances. Hence, it
- * can be asserted that the visitor parameter is always non-null.
- *
- * @see #subtypeVisitor
- * @see #requireValidType(TypeMirror)
- */
- private final class SubtypeVisitor extends ExtendedTypeKindVisitor7<Boolean, TypeMirror> {
- private SubtypeVisitor() {
- super(false);
- }
- /**
- * Returns whether the array type is a super type of the type given as second argument.
- *
- * <p>According to JLS §4.10.3, array component types are covariant; for instance, {@code Integer[]} is a proper
- * subtype of {@code Number[]}. Moreover, all subtypes of an array type are again array types. Hence, this
- * method simply reduces the problem to testing if {@code subType} is also an array type and then applying
- * {@link AbstractTypes#isSubtype(TypeMirror, TypeMirror)} to the component types.
- */
- @Override
- public Boolean visitArray(ArrayType superType, @Nullable TypeMirror subType) {
- assert subType != null;
- return subType.getKind() == TypeKind.ARRAY
- && isSubtype(((ArrayType) subType).getComponentType(), superType.getComponentType());
- }
- /**
- * Returns whether the declared type is a super type of the type given as second argument.
- *
- * <p>This method has {@link DeclaredTypeSubtypeVisitor} visit {@code subType}.
- */
- @Override
- public Boolean visitDeclared(DeclaredType superType, @Nullable TypeMirror subType) {
- assert subType != null;
- return subType.accept(declaredTypeSubtypeVisitor, superType);
- }
- private final List<TypeKind> numericKindEnumValues = Collections.unmodifiableList(Arrays.asList(
- TypeKind.DOUBLE, TypeKind.FLOAT, TypeKind.LONG, TypeKind.INT, TypeKind.SHORT, TypeKind.BYTE
- ));
- private final int intIndex = numericKindEnumValues.indexOf(TypeKind.INT);
- /**
- * Returns whether the primitive type is a supertype of the given type.
- */
- @Override
- public Boolean visitPrimitive(PrimitiveType superType, @Nullable TypeMirror subType) {
- assert subType != null;
- if (!subType.getKind().isPrimitive()) {
- return false;
- }
- int superTypeIndex = numericKindEnumValues.indexOf(superType.getKind());
- int subTypeIndex = numericKindEnumValues.indexOf(subType.getKind());
- return (subType.getKind() == TypeKind.CHAR && 0 <= superTypeIndex && superTypeIndex <= intIndex)
- || (0 <= superTypeIndex && superTypeIndex <= subTypeIndex);
- }
- /**
- * Returns whether the type variable is a super type of the given type.
- *
- * <p>A type variable is only a supertype of its lower bound.
- */
- @Override
- public Boolean visitTypeVariable(TypeVariable superType, @Nullable TypeMirror subType) {
- assert subType != null;
- return isSameType(superType.getLowerBound(), subType);
- }
- /**
- * Returns whether the given intersection type is a super type of the given type.
- *
- * <p>While one might expect that the set of supertypes of an intersection type {@code T_1 & ... & T_n} includes
- * the intersection of any (non-empty) subset of {@code T_1}, ..., {@code T_n}, this seems is not specified by
- * JLS §4.10 (which only says that "the direct supertypes of an intersection type {@code T_1 & ... & T_n} are
- * {@code T_i} (1 ≤ i ≤ n)"). See also issue
- * <a href="https://bugs.openjdk.java.net/browse/JDK-6718388">JDK-6718388</a>.
- *
- * <p>Therefore, an intersection type is only a supertype of itself.
- */
- @Override
- public Boolean visitIntersection(IntersectionType superType, @Nullable TypeMirror subType) {
- assert subType != null;
- return isSameType(superType, subType);
- }
- }
- /**
- * Returns whether the first type is a subtype of the second type, as specified by JLS §4.10.
- *
- * <p>The subtype relationship is transitive and reflexive.
- *
- * @param t1 the first type
- * @param t2 the second type
- * @return {@code true} if and only if the first type is a subtype of the second
- * @throws NullPointerException if an argument is null
- * @throws IllegalArgumentException if given an executable or package type
- */
- @Override
- public final boolean isSubtype(TypeMirror t1, TypeMirror t2) {
- requireValidType(Objects.requireNonNull(t1));
- requireValidType(Objects.requireNonNull(t2));
- // §4.10.2: The direct supertypes of the null type are all reference types other than the null type itself.
- if (t1.getKind() == TypeKind.NULL && REFERENCE_TYPES.contains(t2.getKind())) {
- return true;
- }
- return t2.accept(subtypeVisitor, t1);
- }
- /**
- * Returns whether the first type argument <em>contains</em> the second type argument, as specified by JLS §4.5.1.
- *
- * <p>Using the JLS notation, this method returns true if {@code t2 <= t1}. As JLS §4.10 states, "subtyping does not
- * extend through parameterized types." Hence, this method is necessarily different from
- * {@link #isSubtype(TypeMirror, TypeMirror)}. In particular, the super-type relationship does not include types
- * with covariant type arguments.
- *
- * @param t1 the first type
- * @param t2 the second type
- * @return {@code true} if and only if the first type contains the second
- * @throws IllegalArgumentException if given an executable or package type
- */
- @Override
- public final boolean contains(TypeMirror t1, TypeMirror t2) {
- Objects.requireNonNull(t1);
- Objects.requireNonNull(t2);
- requireValidType(t1);
- requireValidType(t2);
- // We need to cover these cases (JLS §4.5.1):
- //
- // (a) wildcard t2 <= wildcard t1
- // 1. ? extends T <= ? extends S if T <: S
- // 2. ? extends T <= ?
- // 3. ? super T <= ? super S if S <: T
- // 4. ? super T <= ?
- // 5. ? super T <= ? extends Object
- //
- // (b) other type t2 <= other type t1
- // 1. T <= T
- //
- // (c) other type t2 <= wildcard t1
- // 1. T <= ? extends T
- // 2. T <= ? super T
- if (t1.getKind() == TypeKind.WILDCARD) {
- @Nullable TypeMirror t1ExtendsBound = ((WildcardType) t1).getExtendsBound();
- @Nullable TypeMirror t1SuperBound = ((WildcardType) t1).getSuperBound();
- boolean t1HasExtendsBound = t1ExtendsBound != null;
- boolean t1HasSuperBound = t1SuperBound != null;
- if (t2.getKind() == TypeKind.WILDCARD) {
- // Handle (a).
- @Nullable TypeMirror t2ExtendsBound = ((WildcardType) t2).getExtendsBound();
- @Nullable TypeMirror t2SuperBound = ((WildcardType) t2).getSuperBound();
- if (t2ExtendsBound != null) {
- if (t1ExtendsBound != null) {
- // (a) 1.
- return isSubtype(t2ExtendsBound, t1ExtendsBound);
- } else if (t1SuperBound == null) {
- // (a) 2.
- return true;
- }
- // Note that "? super S" never contains a type argument of form "? extends T"
- return false;
- } else if (t2SuperBound != null) {
- if (t1SuperBound != null) {
- // (a) 3.
- return isSubtype(t1SuperBound, t2SuperBound);
- } else {
- // (a) 4. and 5.: Handle case "? super T <= ?" (always true) or "? super S <= ? extends T" (only
- // if T is Object)
- return t1ExtendsBound == null
- || isSameType(t1ExtendsBound, typeMirror(Object.class));
- }
- } else {
- // Handle special case of (a), namely "? <= ? extends T" (only if T is Object), "? <= ? super T"
- // (always false), or "? <= ?" (which is equivalent to "? extends Object <= ? extends Object" and
- // therefore true).
- return t1SuperBound == null && (
- t1ExtendsBound == null || isSameType(t1ExtendsBound, typeMirror(Object.class))
- );
- }
- } else {
- // Handle (c). Reduce to case (a).
- if (t1HasExtendsBound) {
- // (c) 1.
- return contains(t1, getWildcardType(t2, null));
- } else if (t1HasSuperBound) {
- // (c) 2.
- return contains(t1, getWildcardType(null, t2));
- }
- // Combining (c) 1. with (a) 2. or (c) 2. with (a) 4., we immediately have "T <= ?"
- return true;
- }
- } else {
- // Handle (b).
- return isSameType(t1, t2);
- }
- }
- /**
- * Returns the direct super types of the given type declaration, as defined by JLS §4.10.2.
- */
- private List<DeclaredType> directSupertypesOfTypeDeclaration(TypeElement typeElement) {
- TypeMirror superClass = typeElement.getSuperclass();
- List<? extends TypeMirror> interfaces = typeElement.getInterfaces();
- List<DeclaredType> newSuperTypes = new ArrayList<>(1 + interfaces.size());
- if (superClass.getKind() == TypeKind.DECLARED) {
- newSuperTypes.add((DeclaredType) superClass);
- }
- for (TypeMirror superInterface: interfaces) {
- newSuperTypes.add((DeclaredType) superInterface);
- }
- if (typeElement.getKind() == ElementKind.INTERFACE && interfaces.isEmpty()) {
- newSuperTypes.add((DeclaredType) typeMirror(Object.class));
- }
- return newSuperTypes;
- }
- /**
- * Internal class to keep state for the Dijkstra shortest-path algorithm in
- * {@link #getShortestPathToSuperType(TypeElement, DeclaredType)}.
- */
- private static final class TypeDeclarationVertexState {
- private int distance;
- private boolean visited;
- private final TypeElement typeElement;
- /**
- * The type as contained in {@code previous.typeDeclaration.getSuperTypes()}.
- */
- private final DeclaredType declaredType;
- @Nullable private TypeDeclarationVertexState previous;
- private TypeDeclarationVertexState(int distance, boolean visited, TypeElement typeElement,
- DeclaredType declaredType) {
- this.distance = distance;
- this.visited = visited;
- this.typeElement = typeElement;
- this.declaredType = declaredType;
- }
- /**
- * Returns the path induced by this node, starting with {@code derived} and ending with {@link #declaredType}.
- *
- * <p>The path is obtained by following {@link #previous} until {@code null}. Each element in the path (except
- * for the first) is the {@link #declaredType} of the current instance.
- *
- * @param derived the first element in the path
- * @return the path induced by this node
- */
- private List<DeclaredType> toPath(DeclaredType derived) {
- DeclaredType[] path = new DeclaredType[distance + 1];
- int count = path.length;
- TypeDeclarationVertexState pathElement = this;
- while (pathElement.previous != null) {
- --count;
- path[count] = pathElement.declaredType;
- pathElement = pathElement.previous;
- }
- path[0] = derived;
- return Arrays.asList(path);
- }
- }
- /**
- * Returns the shortest inheritance path between a type declaration and a subtype (starting with
- * {@code derived} and ending with {@code base}).
- *
- * <p>Each element in the returned path is a non-generic type, a raw type, or a parameterized type. The
- * {@link DeclaredType} at position {@code i} is always contained in the result of
- * {@link #directSupertypesOfTypeDeclaration(TypeElement)} applied to the type declaration of the type at position
- * {@code (i - 1)}.
- *
- * <p>This methods runs a Dijkstra shortest-path algorithm. It relies on {@link TypeElement#equals(Object)}
- * being well-defined (two object representing the same type declaration must compare equal). Consequently, if
- * {@link DeclaredType} instances have an identity, it must be guaranteed that there are no two instances
- * representing the same type declaration.
- *
- * @param base base type declaration
- * @param derived derived type
- * @return If there is an inheritance path from {@code derived} to {@code base}, then a {@code List<DeclaredType>}
- * {@code p} such that {@code p.get(0).equals(toGenericType(derived))} and
- * {@code toRawTypeDeclaration(p.get(p.size() - 1)).equals(base)} are {@code true}. Otherwise, {@code null} to
- * indicate that there is no such path.
- */
- @Nullable
- private List<DeclaredType> getShortestPathToSuperType(TypeElement base, DeclaredType derived) {
- TypeElement typeElement = (TypeElement) derived.asElement();
- Set<TypeElement> boundary = new LinkedHashSet<>();
- Map<TypeElement, TypeDeclarationVertexState> dijkstraState = new HashMap<>();
- // Distance from derived to itself is 0
- dijkstraState.put(typeElement, new TypeDeclarationVertexState(0, false, typeElement, derived));
- // Start off with derived
- boundary.add(typeElement);
- // Invariants:
- // - boundary only contains nodes that have *not* been visited
- // - For all visited nodes, the shortest path is known
- while (!boundary.isEmpty()) {
- // shortest := vertex in boundary with smallest distance from typeElement
- @Nullable TypeDeclarationVertexState shortest = null;
- for (TypeElement currentDeclaration: boundary) {
- TypeDeclarationVertexState current = dijkstraState.get(currentDeclaration);
- if (shortest == null || current.distance < shortest.distance) {
- shortest = current;
- }
- }
- // Since boundary is non-empty, shortest was assigned in the previous loop. Also note that due to the above
- // invariant, shortest has not been visited.
- assert shortest != null && !shortest.visited;
- // Terminate if we found base. Since shortest.distance is non-decreasing over the loop iterations, it is
- // impossible to find a shorter path in future iterations.
- if (shortest.typeElement.equals(base)) {
- return shortest.toPath(derived);
- }
- // Remove shortest from boundary.
- boundary.remove(shortest.typeElement);
- shortest.visited = true;
- for (DeclaredType superType: directSupertypesOfTypeDeclaration(shortest.typeElement)) {
- // A direct super type of a type declaration is either a non-generic type declaration or a raw type (in
- // both cases represented as DeclaredType with no actual type parameters) or a parameterized type
- TypeElement superDeclaration = (TypeElement) superType.asElement();
- @Nullable TypeDeclarationVertexState stats = dijkstraState.get(superDeclaration);
- if (stats == null) {
- stats = new TypeDeclarationVertexState(Integer.MAX_VALUE, false, superDeclaration, superType);
- dijkstraState.put(superDeclaration, stats);
- }
- int alt = shortest.distance + 1;
- if (!stats.visited && alt < stats.distance) {
- stats.distance = alt;
- stats.previous = shortest;
- boundary.add(superDeclaration);
- }
- }
- }
- return null;
- }
- /**
- * Visitor of a type mirror. Returns the erasure of the visited type mirror.
- *
- * @see #erasureVisitor
- */
- private final class ErasureVisitor extends ExtendedTypeKindVisitor7<TypeMirror, Void> {
- @Override
- public TypeMirror visitDeclared(DeclaredType declaredType, @Nullable Void ignored) {
- TypeMirror originalEnclosingType = declaredType.getEnclosingType();
- @Nullable DeclaredType newEnclosingType = originalEnclosingType.getKind() == TypeKind.NONE
- ? null
- : (DeclaredType) erasure(declaredType.getEnclosingType());
- return getDeclaredType(newEnclosingType, (TypeElement) declaredType.asElement());
- }
- /**
- * Returns the array type corresponding to the erasure of the component type.
- */
- @Override
- public TypeMirror visitArray(ArrayType arrayType, @Nullable Void ignored) {
- return getArrayType(erasure(arrayType.getComponentType()));
- }
- /**
- * Returns the erasure of the leftmost bound of the given type variable.
- *
- * <p>The erasure of a type variable is the erasure of its leftmost bound (JLS §4.6). If multiple bounds are
- * present, the upper bound is modelled as an intersection type. The erasure of an intersection type is
- * guaranteed to have see right form (see {@link #visitIntersection(IntersectionType, Void)}).
- */
- @Override
- public TypeMirror visitTypeVariable(TypeVariable typeVariable, @Nullable Void ignored) {
- return erasure(typeVariable.getUpperBound());
- }
- /**
- * Returns the erasure of the leftmost member of the given intersection type.
- *
- * <p>While JLS §4.6 does not mention intersection types (and thus, strictly speaking, the erasure of an
- * intersection type should be the unmodified intersection type itself), this implementation computes the
- * erasure of an intersection type as the erasure of its left-most type.
- */
- @Override
- public TypeMirror visitIntersection(IntersectionType intersectionType, @Nullable Void ignored) {
- return erasure(intersectionType.getBounds().get(0));
- }
- /**
- * Returns the given type itself.
- *
- * <p>JLS §4.6 specifies: "The erasure of every other type is the type itself."
- */
- @Override
- protected TypeMirror defaultAction(TypeMirror type, Void ignored) {
- return type;
- }
- }
- /**
- * Returns the erasure of a type, as specified by JLS §4.6.
- *
- * @param type the type to be erased
- * @return the erasure of the given type
- * @throws IllegalArgumentException if given a package type
- */
- @Override
- public final TypeMirror erasure(TypeMirror type) {
- Objects.requireNonNull(type);
- requireValidType(type);
- return type.accept(erasureVisitor, null);
- }
- /**
- * Returns the element corresponding to a type.
- *
- * <p>The type may be a {@code DeclaredType} or {@code TypeVariable}. Returns {@code null} if the type is not one
- * with a corresponding element.
- *
- * @param type the type
- * @return the element corresponding to the given type
- */
- @Override
- public final Element asElement(TypeMirror type) {
- Objects.requireNonNull(type);
- requireValidType(type);
- if (type.getKind() == TypeKind.DECLARED) {
- return ((DeclaredType) type).asElement();
- } else if (type.getKind() == TypeKind.TYPEVAR) {
- return ((TypeVariable) type).asElement();
- } else {
- return null;
- }
- }
- /**
- * Returns whether the two given type arguments represent the same type.
- *
- * <p>If either of the arguments to this method represents a wildcard, this method will return false. As a
- * consequence, a wildcard is not the same type as itself.
- *
- * @param t1 the first type
- * @param t2 the second type
- * @return {@code true} if and only if the two types are the same
- */
- @Override
- public final boolean isSameType(TypeMirror t1, TypeMirror t2) {
- requireValidType(Objects.requireNonNull(t1));
- requireValidType(Objects.requireNonNull(t2));
- return t1.getKind() != TypeKind.WILDCARD && t1.equals(t2);
- }
- /**
- * Returns the greatest lower bound (glb) of a wildcard extends bound and an upper bound of a type parameter.
- *
- * <p>This method is only called from {@link #capture(TypeMirror)}. JLS §5.1.10 defines the greatest lower bound
- * {@code glb(V_1, ..., V_m)} as {@code V_1 & ... & V_m}. Unfortunately, the specification provides no clarity
- * whether intersection types are allowed to be nested. This implementation takes the interpretation that
- * intersection types should not be nested. Therefore, the bounds contained in {@code originalUpperBound} are
- * unwrapped.
- *
- * @param wildcardExtendsBound extends bound of the wildcard type argument
- * @param originalUpperBound original upper bound of the type parameter
- * @return the greatest lower bound
- */
- private static TypeMirror[] greatestLowerBound(TypeMirror wildcardExtendsBound, TypeMirror originalUpperBound) {
- @Nullable TypeMirror[] result = null;
- if (originalUpperBound instanceof IntersectionType) {
- IntersectionType originalIntersectionBound = (IntersectionType) originalUpperBound;
- if (originalIntersectionBound.isIntersectionType()) {
- List<? extends TypeMirror> originalBounds = originalIntersectionBound.getBounds();
- result = new TypeMirror[1 + originalBounds.size()];
- int i = 0;
- for (TypeMirror originalBound: originalBounds) {
- ++i;
- result[i] = originalBound;
- }
- }
- }
- if (result == null) {
- result = new TypeMirror[2];
- result[1] = originalUpperBound;
- }
- result[0] = wildcardExtendsBound;
- return result;
- }
- /**
- * Returns the caputure conversion of (just) the given wildcard argument.
- *
- * <p>This method is only called by {@link #capture(TypeMirror)}.
- */
- private TypeVariable captureWildcardArgument(WildcardType wildcardArgument, TypeParameterElement typeParameter) {
- TypeVariable originalTypeVariable = (TypeVariable) typeParameter.asType();
- // Denoted U_i in JLS 5.1.10
- TypeMirror originalUpperBound = originalTypeVariable.getUpperBound();
- // Both of the following are denoted B_i in JLS 5.1.10 (in "? extends B_i" and "? super B_i", respectively)
- @Nullable TypeMirror wildcardExtendsBound = wildcardArgument.getExtendsBound();
- @Nullable TypeMirror wildcardSuperBound = wildcardArgument.getSuperBound();
- TypeMirror newUpperBound;
- TypeMirror newLowerBound;
- // There exists a capture conversion from a parameterized type G<T_1,...,T_n> (§4.5) to a parameterized type
- // G<S_1, ..., S_n>, where, for 1 <= i <= n:
- if (wildcardExtendsBound == null && wildcardSuperBound == null) {
- // If T_i is a wildcard type argument (§4.5.1) of the form ?, then S_i is a fresh type variable whose
- // upper bound is U_i[A_1 := S_1, ..., A_n := S_n] and whose lower bound is the null type (§4.1).
- newUpperBound = originalUpperBound;
- newLowerBound = getNullType();
- } else if (wildcardSuperBound == null) {
- // If T_i is a wildcard type argument of the form ? extends B_i, then S_i is a fresh type variable whose
- // upper bound is glb(B_i, U_i[A_1 := S_1, ..., A_n := S_n]) and whose lower bound is the null type.
- //
- // glb(V_1, ..., V_m) is defined as V_1 & ... & V_m.
- // It is a compile-time error if, for any two classes (not interfaces) V_i and V_j, V_i is not a
- // subclass of V_j or vice versa.
- newUpperBound = getIntersectionType(greatestLowerBound(wildcardExtendsBound, originalUpperBound));
- newLowerBound = getNullType();
- } else {
- // If T_i is a wildcard type argument of the form ? super B_i, then S_i is a fresh type variable whose
- // upper bound is U_i[A_1 := S1, ..., A_n := S_n] and whose lower bound is B_i.
- assert wildcardExtendsBound == null;
- newUpperBound = originalUpperBound;
- newLowerBound = wildcardSuperBound;
- }
- return getTypeVariable(typeParameter, newUpperBound, newLowerBound, wildcardArgument);
- }
- /**
- * Returns the capture conversion of the given type, as specified by JLS §5.1.10.
- *
- * @param type the type to be converted
- * @return the result of applying capture conversion
- * @throws IllegalArgumentException if given an executable or package type
- */
- @Override
- public final TypeMirror capture(TypeMirror type) {
- Objects.requireNonNull(type);
- requireValidType(type);
- // JLS §5.1.10 states: "Capture conversion on any type other than a parameterized type (§4.5) acts as an
- // identity conversion (§5.1.1)."
- if (type.getKind() != TypeKind.DECLARED) {
- return type;
- }
- DeclaredType declaredType = (DeclaredType) type;
- List<? extends TypeMirror> typeArguments = declaredType.getTypeArguments();
- if (typeArguments.isEmpty()) {
- return declaredType;
- }
- TypeElement typeDeclaration = (TypeElement) declaredType.asElement();
- Iterator<? extends TypeMirror> typeArgumentIterator = typeArguments.iterator();
- Iterator<? extends TypeParameterElement> typeParameterIterator = typeDeclaration.getTypeParameters().iterator();
- TypeMirror[] newArguments = new TypeMirror[typeArguments.size()];
- Map<TypeParameterElement, TypeMirror> substitutions = new LinkedHashMap<>();
- for (int index = 0; index < newArguments.length; ++index) {
- TypeMirror typeArgument = typeArgumentIterator.next();
- TypeParameterElement typeParameter = typeParameterIterator.next();
- TypeMirror substitution;
- if (typeArgument.getKind() != TypeKind.WILDCARD) {
- newArguments[index] = typeArgument;
- substitution = typeArgument;
- } else {
- // For the intermediate declared type (see below), we need the original type variable corresponding to
- // the formal type parameter. Only original type variables will be replaced by the substitutionVisitor.
- newArguments[index] = typeParameter.asType();
- substitution = captureWildcardArgument((WildcardType) typeArgument, typeParameter);
- }
- substitutions.put(typeParameter, substitution);
- }
- TypeMirror enclosingType = declaredType.getEnclosingType();
- // Construct intermediateDeclaredType that already has type variables in its argument list instead of wildcard
- // arguments.
- DeclaredType intermediateDeclaredType;
- if (enclosingType.getKind() == TypeKind.DECLARED) {
- intermediateDeclaredType = getDeclaredType((DeclaredType) enclosingType, typeDeclaration, newArguments);
- } else {
- intermediateDeclaredType = getDeclaredType(typeDeclaration, newArguments);
- }
- return substitute(intermediateDeclaredType, substitutions);
- }
- /**
- * Returns a new type variable that corresponds to the given formal type parameter and that has the given actual
- * upper and lower bounds.
- *
- * <p>This method is primarily needed during capture conversion, in order to create a fresh type variable that
- * overrides the bounds of the formal type parameter it represents. This method is also called during substitution.
- * As an example, given a formal type parameter {@code T extends Object} and an upper bound {@code Number}, this
- * method returns the type variable {@code T} with upper bound {@code Number}.
- *
- * <p>This method is not suited for creating type variables with recursive type bounds if these bounds override the
- * bounds of the formal type parameter (as only happens during capture conversion). In order to create such a type
- * variable, this method may be used to create an interim type variable, where the (overridden) upper and lower
- * bounds should only reference the type variable returned by {@link TypeParameterElement#asType()}. As a second
- * step, {@link #substitute(TypeMirror, Map)} may then be used to substitute the original type variable with the
- * interim type variable. The result will be a fresh type variable with the overridden bounds, and these bounds
- * will reference the fresh type variable instead of the original type variable.
- *
- * @param typeParameter the formal type parameter
- * @param upperBound the upper bound for the new type variable, may contain recursive references to
- * {@code typeParameter.asType()}
- * @param lowerBound the lower bound for the new type variable, may contain recursive references to
- * {@code typeParameter.asType()}
- * @param capturedTypeArgument the wildcard type argument that new type variable captures as part of a capture
- * conversion (§5.1.10 JLS), or {@code null} if the new type variable is not the result of a capture conversion
- * @return the new type variable
- * @throws NullPointerException if any of the first three arguments is null
- */
- protected TypeVariable getTypeVariable(TypeParameterElement typeParameter, TypeMirror upperBound,
- TypeMirror lowerBound, @Nullable WildcardType capturedTypeArgument) {
- Objects.requireNonNull(typeParameter);
- Objects.requireNonNull(upperBound);
- Objects.requireNonNull(lowerBound);
- requireValidType(upperBound);
- requireValidType(lowerBound);
- requireValidType(capturedTypeArgument);
- TypeVariable typeVariable = createTypeVariable(typeParameter, capturedTypeArgument);
- setTypeVariableBounds(typeVariable, upperBound, lowerBound);
- return typeVariable;
- }
- /**
- * Creates a new <em>unfinished</em> type variable for the given formal parameter.
- *
- * <p>Whenever this method is called within this class, the returned type variable is guaranteed to be passed to
- * {@link #setTypeVariableBounds(TypeVariable, TypeMirror, TypeMirror)} before being used as a {@link TypeVariable}
- * instance. That is, the returned type variable is considered to be under construction until being passed to
- * {@link #setTypeVariableBounds(TypeVariable, TypeMirror, TypeMirror)}, and only after that method call, the type
- * variable will have to satisfy the contract specified by interface {@link TypeVariable} and its super-interfaces.
- *
- * <p>Before {@link #setTypeVariableBounds(TypeVariable, TypeMirror, TypeMirror)} is called on the returned
- * {@link TypeVariable}, calling either {@link TypeVariable#getUpperBound()} or {@link TypeVariable#getLowerBound()}
- * must trigger an {@link IllegalStateException}.
- *
- * <p>Note that the previous paragraph does not guarantee that
- * {@link #setTypeVariableBounds(TypeVariable, TypeMirror, TypeMirror)} is always called on the newly returned
- * type-variable instance. If any exception occurs before the new type-variable could be used, then
- * {@link #setTypeVariableBounds(TypeVariable, TypeMirror, TypeMirror)} may not be called (even if the exception is
- * unrelated to the construction of the new type-variable instance).
- *
- * <p>The {@link TypeVariable} interface does not provide access to captured wildcard type arguments. It can be
- * retrieved by calling {@link #capturedTypeArgument(TypeVariable)} instead.
- *
- * @param typeParameter the formal type parameter
- * @param capturedTypeArgument the wildcard type argument that new type variable captures as part of a capture
- * conversion (§5.1.10 JLS), or {@code null} if the new type variable is not the result of a capture conversion
- * @return new unfinished type variable for the given formal parameter, which may not yet satisfy the contracts
- * of {@link TypeVariable}
- * @see #setTypeVariableBounds(TypeVariable, TypeMirror, TypeMirror)
- * @see #capturedTypeArgument(TypeVariable)
- * @throws NullPointerException if {@code typeParameter} is null
- */
- protected abstract TypeVariable createTypeVariable(TypeParameterElement typeParameter,
- @Nullable WildcardType capturedTypeArgument);
- /**
- * Sets the bounds of a type variable previously returned by
- * {@link #createTypeVariable(TypeParameterElement, WildcardType)}.
- *
- * <p>Before an (unfinished) type-variable instance returned by
- * {@link #createTypeVariable(TypeParameterElement, WildcardType)} is used by this class, this method is guaranteed
- * to be called exactly once.
- *
- * <p>Implementations that create effectively immutable {@link TypeMirror} instances may use this method to "freeze"
- * the given type-variable instance.
- *
- * @param typeVariable type variable previously returned by
- * {@link #createTypeVariable(TypeParameterElement, WildcardType)}
- * @param upperBound Upper bound for the given type variable. If no explicit upper bound is used, a
- * {@link DeclaredType} representing {@link Object} will be passed.
- * @param lowerBound Lower bound for the given type variable. This may a {@link NullType} instance, unless capture
- * conversion produced a type variable with a non-trivial lower bound.
- * @see #createTypeVariable(TypeParameterElement, WildcardType)
- */
- protected abstract void setTypeVariableBounds(TypeVariable typeVariable, TypeMirror upperBound,
- TypeMirror lowerBound);
- /**
- * Returns the captured wildcard type argument of the given type variable, or null if the given type variable is not
- * the result of a capture conversion.
- *
- * <p>This method returns the wildcard type argument that was previously passed to
- * {@link #createTypeVariable(TypeParameterElement, WildcardType)}.
- *
- * @param typeVariable the type variable that may be the result of a capture conversion
- * @return the captured wildcard type argument, or null if not applicable
- */
- @Nullable
- protected abstract WildcardType capturedTypeArgument(TypeVariable typeVariable);
- /**
- * Returns a new intersection type. At least one bounds needs to be given.
- *
- * @param bounds the bounds of the new intersection type
- * @return the new intersection type
- * @throws IllegalArgumentException if the given array is empty
- */
- public abstract IntersectionType getIntersectionType(TypeMirror... bounds);
- /**
- * Visitor of {@link TypeMirror} instances that appends the {@link String} representation to the
- * {@link StringBuilder} instance passed as visitor argument.
- *
- * <p>This visitor is only used within this class and only on <em>valid</em> {@link TypeMirror} instances. Hence, it
- * can be asserted that the visitor parameter is always non-null.
- *
- * @see #requireValidType(TypeMirror)
- */
- private final class ToStringVisitor extends ExtendedTypeKindVisitor7<Void, StringBuilder> {
- @Override
- public Void visitPrimitive(PrimitiveType primitiveType, @Nullable StringBuilder stringBuilder) {
- assert stringBuilder != null;
- stringBuilder.append(primitiveType.getKind().toString().toLowerCase());
- return null;
- }
- @Override
- public Void visitNull(NullType nullType, @Nullable StringBuilder stringBuilder) {
- assert stringBuilder != null;
- stringBuilder.append("null");
- return null;
- }
- @Override
- public Void visitNoType(NoType noType, @Nullable StringBuilder stringBuilder) {
- assert stringBuilder != null;
- stringBuilder.append(noType.getKind().toString().toLowerCase());
- return null;
- }
- @Override
- public Void visitDeclared(DeclaredType declaredType, @Nullable StringBuilder stringBuilder) {
- assert stringBuilder != null;
- TypeMirror enclosingType = declaredType.getEnclosingType();
- TypeElement typeElement = (TypeElement) declaredType.asElement();
- if (enclosingType.getKind() == TypeKind.DECLARED) {
- visitDeclared((DeclaredType) enclosingType, stringBuilder);
- stringBuilder.append('.').append(typeElement.getSimpleName());
- } else {
- stringBuilder.append(typeElement.getQualifiedName());
- }
- List<? extends TypeMirror> typeArguments = declaredType.getTypeArguments();
- if (!typeArguments.isEmpty()) {
- stringBuilder.append('<');
- appendList(stringBuilder, typeArguments, ", ");
- stringBuilder.append('>');
- }
- return null;
- }
- @Override
- public Void visitArray(ArrayType arrayType, @Nullable StringBuilder stringBuilder) {
- assert stringBuilder != null;
- arrayType.getComponentType().accept(this, stringBuilder);
- stringBuilder.append("[]");
- return null;
- }
- @Override
- public Void visitTypeVariable(TypeVariable typeVariable, @Nullable StringBuilder stringBuilder) {
- assert stringBuilder != null;
- @Nullable WildcardType capturedTypeArgument = capturedTypeArgument(typeVariable);
- if (capturedTypeArgument != null) {
- stringBuilder.append("capture<");
- capturedTypeArgument.accept(this, stringBuilder);
- stringBuilder.append('>');
- } else {
- stringBuilder.append(typeVariable.asElement().getSimpleName());
- }
- return null;
- }
- @Override
- public Void visitWildcard(WildcardType wildcardTypeArgument, @Nullable StringBuilder stringBuilder) {
- assert stringBuilder != null;
- stringBuilder.append('?');
- @Nullable TypeMirror extendsBound = wildcardTypeArgument.getExtendsBound();
- if (extendsBound != null) {
- stringBuilder.append(" extends ");
- extendsBound.accept(this, stringBuilder);
- }
- @Nullable TypeMirror superBound = wildcardTypeArgument.getSuperBound();
- if (superBound != null) {
- stringBuilder.append(" super ");
- superBound.accept(this, stringBuilder);
- }
- return null;
- }
- @Override
- public Void visitIntersection(IntersectionType intersectionType, @Nullable StringBuilder stringBuilder) {
- assert stringBuilder != null;
- appendList(stringBuilder, intersectionType.getBounds(), " & ");
- return null;
- }
- private void appendList(StringBuilder stringBuilder, List<? extends TypeMirror> types, String glue) {
- assert !types.isEmpty();
- boolean first = true;
- for (TypeMirror type: types) {
- if (first) {
- first = false;
- } else {
- stringBuilder.append(glue);
- }
- type.accept(this, stringBuilder);
- }
- }
- }
- /**
- * Returns the canonical string representation of the given type.
- *
- * @param type type
- * @return canonical string representation of the given type
- */
- public final String toString(TypeMirror type) {
- requireValidType(Objects.requireNonNull(type));
- StringBuilder stringBuilder = new StringBuilder(DEFAULT_STRING_BUILDER_SIZE);
- type.accept(toStringVisitor, stringBuilder);
- return stringBuilder.toString();
- }
- }