diff options
Diffstat (limited to 'third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/TypesUtils.java')
-rw-r--r-- | third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/TypesUtils.java | 296 |
1 files changed, 209 insertions, 87 deletions
diff --git a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/TypesUtils.java b/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/TypesUtils.java index f024a60feb..fe7456f6d2 100644 --- a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/TypesUtils.java +++ b/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/TypesUtils.java @@ -1,8 +1,19 @@ package org.checkerframework.javacutil; +import static com.sun.tools.javac.code.TypeTag.WILDCARD; + +import com.sun.tools.javac.code.Symtab; +import com.sun.tools.javac.code.Type; +import com.sun.tools.javac.code.TypeTag; +import com.sun.tools.javac.model.JavacTypes; +import com.sun.tools.javac.processing.JavacProcessingEnvironment; +import com.sun.tools.javac.util.Context; import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.element.Element; import javax.lang.model.element.Name; +import javax.lang.model.element.NestingKind; 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.TypeKind; @@ -12,26 +23,18 @@ import javax.lang.model.type.WildcardType; import javax.lang.model.util.Elements; import javax.lang.model.util.Types; -import com.sun.tools.javac.code.Symtab; -import com.sun.tools.javac.code.Type; -import com.sun.tools.javac.code.TypeTag; -import com.sun.tools.javac.model.JavacTypes; -import com.sun.tools.javac.processing.JavacProcessingEnvironment; -import com.sun.tools.javac.util.Context; - -/** - * A utility class that helps with {@link TypeMirror}s. - * - */ +/** A utility class that helps with {@link TypeMirror}s. */ // TODO: This class needs significant restructuring public final class TypesUtils { // Class cannot be instantiated - private TypesUtils() { throw new AssertionError("Class TypesUtils cannot be instantiated."); } + private TypesUtils() { + throw new AssertionError("Class TypesUtils cannot be instantiated."); + } /** - * Gets the fully qualified name for a provided type. It returns an empty - * name if type is an anonymous type. + * Gets the fully qualified name for a provided type. It returns an empty name if type is an + * anonymous type. * * @param type the declared type * @return the name corresponding to that type @@ -44,7 +47,7 @@ public final class TypesUtils { /** * Checks if the type represents a java.lang.Object declared type. * - * @param type the type + * @param type the type * @return true iff type represents java.lang.Object */ public static boolean isObject(TypeMirror type) { @@ -54,7 +57,7 @@ public final class TypesUtils { /** * Checks if the type represents a java.lang.Class declared type. * - * @param type the type + * @param type the type * @return true iff type represents java.lang.Class */ public static boolean isClass(TypeMirror type) { @@ -62,11 +65,11 @@ public final class TypesUtils { } /** - * Checks if the type represents a java.lang.String declared type. - * TODO: it would be cleaner to use String.class.getCanonicalName(), but - * the two existing methods above don't do that, I guess for performance reasons. + * Checks if the type represents a java.lang.String declared type. TODO: it would be cleaner to + * use String.class.getCanonicalName(), but the two existing methods above don't do that, I + * guess for performance reasons. * - * @param type the type + * @param type the type * @return true iff type represents java.lang.String */ public static boolean isString(TypeMirror type) { @@ -74,8 +77,8 @@ public final class TypesUtils { } /** - * Checks if the type represents a boolean type, that is either boolean - * (primitive type) or java.lang.Boolean. + * Checks if the type represents a boolean type, that is either boolean (primitive type) or + * java.lang.Boolean. * * @param type the type to test * @return true iff type represents a boolean type @@ -93,14 +96,15 @@ public final class TypesUtils { */ public static boolean isDeclaredOfName(TypeMirror type, CharSequence qualifiedName) { return type.getKind() == TypeKind.DECLARED - && getQualifiedName((DeclaredType)type).contentEquals(qualifiedName); + && getQualifiedName((DeclaredType) type).contentEquals(qualifiedName); } public static boolean isBoxedPrimitive(TypeMirror type) { - if (type.getKind() != TypeKind.DECLARED) + if (type.getKind() != TypeKind.DECLARED) { return false; + } - String qualifiedName = getQualifiedName((DeclaredType)type).toString(); + String qualifiedName = getQualifiedName((DeclaredType) type).toString(); return (qualifiedName.equals("java.lang.Boolean") || qualifiedName.equals("java.lang.Byte") @@ -112,44 +116,57 @@ public final class TypesUtils { || qualifiedName.equals("java.lang.Float")); } - /** @return type represents a Throwable type (e.g. Exception, Error) **/ + /** @return type represents a Throwable type (e.g. Exception, Error) */ public static boolean isThrowable(TypeMirror type) { while (type != null && type.getKind() == TypeKind.DECLARED) { DeclaredType dt = (DeclaredType) type; TypeElement elem = (TypeElement) dt.asElement(); Name name = elem.getQualifiedName(); - if ("java.lang.Throwable".contentEquals(name)) + if ("java.lang.Throwable".contentEquals(name)) { return true; + } type = elem.getSuperclass(); } return false; } /** + * Returns true iff the argument is an anonymous type. + * + * @return whether the argument is an anonymous type + */ + public static boolean isAnonymous(TypeMirror type) { + return (type instanceof DeclaredType) + && (((TypeElement) ((DeclaredType) type).asElement()) + .getNestingKind() + .equals(NestingKind.ANONYMOUS)); + } + + /** * Returns true iff the argument is a primitive type. * - * @return whether the argument is a primitive type + * @return whether the argument is a primitive type */ public static boolean isPrimitive(TypeMirror type) { switch (type.getKind()) { - case BOOLEAN: - case BYTE: - case CHAR: - case DOUBLE: - case FLOAT: - case INT: - case LONG: - case SHORT: - return true; - default: - return false; + case BOOLEAN: + case BYTE: + case CHAR: + case DOUBLE: + case FLOAT: + case INT: + case LONG: + case SHORT: + return true; + default: + return false; } } /** * Returns true iff the arguments are both the same primitive types. * - * @return whether the arguments are the same primitive types + * @return whether the arguments are the same primitive types */ public static boolean areSamePrimitiveTypes(TypeMirror left, TypeMirror right) { if (!isPrimitive(left) || !isPrimitive(right)) { @@ -162,65 +179,64 @@ public final class TypesUtils { /** * Returns true iff the argument is a primitive numeric type. * - * @return whether the argument is a primitive numeric type + * @return whether the argument is a primitive numeric type */ public static boolean isNumeric(TypeMirror type) { switch (type.getKind()) { - case BYTE: - case CHAR: - case DOUBLE: - case FLOAT: - case INT: - case LONG: - case SHORT: - return true; - default: - return false; + case BYTE: + case CHAR: + case DOUBLE: + case FLOAT: + case INT: + case LONG: + case SHORT: + return true; + default: + return false; } } /** * Returns true iff the argument is an integral type. * - * @return whether the argument is an integral type + * @return whether the argument is an integral type */ public static boolean isIntegral(TypeMirror type) { switch (type.getKind()) { - case BYTE: - case CHAR: - case INT: - case LONG: - case SHORT: - return true; - default: - return false; + case BYTE: + case CHAR: + case INT: + case LONG: + case SHORT: + return true; + default: + return false; } } /** * Returns true iff the argument is a floating point type. * - * @return whether the argument is a floating point type + * @return whether the argument is a floating point type */ public static boolean isFloating(TypeMirror type) { switch (type.getKind()) { - case DOUBLE: - case FLOAT: - return true; - default: - return false; + case DOUBLE: + case FLOAT: + return true; + default: + return false; } } /** - * Returns the widened numeric type for an arithmetic operation - * performed on a value of the left type and the right type. - * Defined in JLS 5.6.2. We return a {@link TypeKind} because - * creating a {@link TypeMirror} requires a {@link Types} object - * from the {@link javax.annotation.processing.ProcessingEnvironment}. + * Returns the widened numeric type for an arithmetic operation performed on a value of the left + * type and the right type. Defined in JLS 5.6.2. We return a {@link TypeKind} because creating + * a {@link TypeMirror} requires a {@link Types} object from the {@link + * javax.annotation.processing.ProcessingEnvironment}. * - * @return the result of widening numeric conversion, or NONE when - * the conversion cannot be performed + * @return the result of widening numeric conversion, or NONE when the conversion cannot be + * performed */ public static TypeKind widenedNumericType(TypeMirror left, TypeMirror right) { if (!isNumeric(left) || !isNumeric(right)) { @@ -246,13 +262,12 @@ public final class TypesUtils { } /** - * If the argument is a bounded TypeVariable or WildcardType, - * return its non-variable, non-wildcard upper bound. Otherwise, - * return the type itself. + * If the argument is a bounded TypeVariable or WildcardType, return its non-variable, + * non-wildcard upper bound. Otherwise, return the type itself. * - * @param type a type - * @return the non-variable, non-wildcard upper bound of a type, - * if it has one, or itself if it has no bounds + * @param type a type + * @return the non-variable, non-wildcard upper bound of a type, if it has one, or itself if it + * has no bounds */ public static TypeMirror upperBound(TypeMirror type) { do { @@ -277,8 +292,28 @@ public final class TypesUtils { return type; } - // Version of com.sun.tools.javac.code.Types.wildUpperBound(Type) - // that works with both jdk8 (called upperBound there) and jdk8u. + /** + * Get the type parameter for this wildcard from the underlying type's bound field This field is + * sometimes null, in that case this method will return null + * + * @return the TypeParameterElement the wildcard is an argument to + */ + public static TypeParameterElement wildcardToTypeParam(final Type.WildcardType wildcard) { + + final Element typeParamElement; + if (wildcard.bound != null) { + typeParamElement = wildcard.bound.asElement(); + } else { + typeParamElement = null; + } + + return (TypeParameterElement) typeParamElement; + } + + /** + * Version of com.sun.tools.javac.code.Types.wildUpperBound(Type) that works with both jdk8 + * (called upperBound there) and jdk8u. + */ // TODO: contrast to upperBound. public static Type wildUpperBound(ProcessingEnvironment env, TypeMirror tm) { Type t = (Type) tm; @@ -291,15 +326,27 @@ public final class TypesUtils { } else { return wildUpperBound(env, w.type); } - } - else { + } else { return TypeAnnotationUtils.unannotatedType(t); } } /** - * Returns the {@link TypeMirror} for a given {@link Class}. + * Version of com.sun.tools.javac.code.Types.wildLowerBound(Type) that works with both jdk8 + * (called upperBound there) and jdk8u. */ + public static Type wildLowerBound(ProcessingEnvironment env, TypeMirror tm) { + Type t = (Type) tm; + if (t.hasTag(WILDCARD)) { + Context context = ((JavacProcessingEnvironment) env).getContext(); + Symtab syms = Symtab.instance(context); + Type.WildcardType w = (Type.WildcardType) TypeAnnotationUtils.unannotatedType(t); + return w.isExtendsBound() ? syms.botType : wildLowerBound(env, w.type); + } else { + return TypeAnnotationUtils.unannotatedType(t); + } + } + /** Returns the {@link TypeMirror} for a given {@link Class}. */ public static TypeMirror typeFromClass(Types types, Elements elements, Class<?> clazz) { if (clazz == void.class) { return types.getNoType(TypeKind.VOID); @@ -320,11 +367,86 @@ public final class TypesUtils { } } - /** - * Returns an {@link ArrayType} with elements of type {@code componentType}. - */ + /** Returns an {@link ArrayType} with elements of type {@code componentType}. */ public static ArrayType createArrayType(Types types, TypeMirror componentType) { JavacTypes t = (JavacTypes) types; return t.getArrayType(componentType); } + + /** + * Returns true if declaredType is a Class that is used to box primitive type (e.g. + * declaredType=java.lang.Double and primitiveType=22.5d ) + */ + public static boolean isBoxOf(TypeMirror declaredType, TypeMirror primitiveType) { + if (declaredType.getKind() != TypeKind.DECLARED) { + return false; + } + + final String qualifiedName = getQualifiedName((DeclaredType) declaredType).toString(); + switch (primitiveType.getKind()) { + case BOOLEAN: + return qualifiedName.equals("java.lang.Boolean"); + case BYTE: + return qualifiedName.equals("java.lang.Byte"); + case CHAR: + return qualifiedName.equals("java.lang.Character"); + case DOUBLE: + return qualifiedName.equals("java.lang.Double"); + case FLOAT: + return qualifiedName.equals("java.lang.Float"); + case INT: + return qualifiedName.equals("java.lang.Integer"); + case LONG: + return qualifiedName.equals("java.lang.Long"); + case SHORT: + return qualifiedName.equals("java.lang.Short"); + + default: + return false; + } + } + + /** + * Given a bounded type (wildcard or typevar) get the concrete type of its upper bound. If the + * bounded type extends other bounded types, this method will iterate through their bounds until + * a class, interface, or intersection is found. + * + * @return a type that is not a wildcard or typevar, or null if this type is an unbounded + * wildcard + */ + public static TypeMirror findConcreteUpperBound(final TypeMirror boundedType) { + TypeMirror effectiveUpper = boundedType; + outerLoop: + while (true) { + switch (effectiveUpper.getKind()) { + case WILDCARD: + effectiveUpper = + ((javax.lang.model.type.WildcardType) effectiveUpper).getExtendsBound(); + if (effectiveUpper == null) { + return null; + } + break; + + case TYPEVAR: + effectiveUpper = ((TypeVariable) effectiveUpper).getUpperBound(); + break; + + default: + break outerLoop; + } + } + return effectiveUpper; + } + + /** + * Returns true if the erased type of subtype is a subtype of the erased type of supertype. + * + * @param types Types + * @param subtype possible subtype + * @param supertype possible supertype + * @return true if the erased type of subtype is a subtype of the erased type of supertype + */ + public static boolean isErasedSubtype(Types types, TypeMirror subtype, TypeMirror supertype) { + return types.isSubtype(types.erasure(subtype), types.erasure(supertype)); + } } |