diff options
Diffstat (limited to 'third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/InternalUtils.java')
-rw-r--r-- | third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/InternalUtils.java | 291 |
1 files changed, 195 insertions, 96 deletions
diff --git a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/InternalUtils.java b/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/InternalUtils.java index 40cb4747f5..10a48cd719 100644 --- a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/InternalUtils.java +++ b/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/InternalUtils.java @@ -1,19 +1,5 @@ package org.checkerframework.javacutil; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import javax.annotation.processing.ProcessingEnvironment; -import javax.lang.model.element.AnnotationMirror; -import javax.lang.model.element.Element; -import javax.lang.model.element.ExecutableElement; -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.Elements; - import com.sun.source.tree.AnnotatedTypeTree; import com.sun.source.tree.AnnotationTree; import com.sun.source.tree.ArrayAccessTree; @@ -29,6 +15,7 @@ import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.code.Symbol; import com.sun.tools.javac.code.Symbol.TypeSymbol; import com.sun.tools.javac.code.Type; +import com.sun.tools.javac.code.Type.CapturedType; import com.sun.tools.javac.code.Types; import com.sun.tools.javac.processing.JavacProcessingEnvironment; import com.sun.tools.javac.tree.JCTree; @@ -43,15 +30,29 @@ import com.sun.tools.javac.tree.JCTree.JCNewClass; import com.sun.tools.javac.tree.JCTree.JCTypeParameter; import com.sun.tools.javac.tree.TreeInfo; import com.sun.tools.javac.util.Context; +import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +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.Elements; /*>>> - import org.checkerframework.checker.nullness.qual.*; - */ +import org.checkerframework.checker.nullness.qual.*; +*/ /** - * Static utility methods used by annotation abstractions in this package. Some - * methods in this class depend on the use of Sun javac internals; any procedure - * in the Checker Framework that uses a non-public API should be placed here. + * Static utility methods used by annotation abstractions in this package. Some methods in this + * class depend on the use of Sun javac internals; any procedure in the Checker Framework that uses + * a non-public API should be placed here. */ public class InternalUtils { @@ -64,11 +65,9 @@ public class InternalUtils { * Gets the {@link Element} ("symbol") for the given Tree API node. * * @param tree the {@link Tree} node to get the symbol for - * @throws IllegalArgumentException - * if {@code tree} is null or is not a valid javac-internal tree - * (JCTree) - * @return the {@code {@link Symbol}} for the given tree, or null if one - * could not be found + * @throws IllegalArgumentException if {@code tree} is null or is not a valid javac-internal + * tree (JCTree) + * @return the {@link Symbol} for the given tree, or null if one could not be found */ public static /*@Nullable*/ Element symbol(Tree tree) { if (tree == null) { @@ -95,19 +94,19 @@ public class InternalUtils { case TYPE_PARAMETER: return TreeInfo.symbolFor((JCTree) tree); - // symbol() only works on MethodSelects, so we need to get it manually - // for method invocations. + // symbol() only works on MethodSelects, so we need to get it manually + // for method invocations. case METHOD_INVOCATION: return TreeInfo.symbol(((JCMethodInvocation) tree).getMethodSelect()); case ASSIGNMENT: - return TreeInfo.symbol((JCTree)((AssignmentTree)tree).getVariable()); + return TreeInfo.symbol((JCTree) ((AssignmentTree) tree).getVariable()); case ARRAY_ACCESS: - return symbol(((ArrayAccessTree)tree).getExpression()); + return symbol(((ArrayAccessTree) tree).getExpression()); case NEW_CLASS: - return ((JCNewClass)tree).constructor; + return ((JCNewClass) tree).constructor; case MEMBER_REFERENCE: // TreeInfo.symbol, which is used in the default case, didn't handle @@ -120,43 +119,40 @@ public class InternalUtils { } /** - * Determines whether or not the node referred to by the given - * {@link TreePath} is an anonymous constructor (the constructor for an - * anonymous class. + * Determines whether or not the node referred to by the given {@link TreePath} is an anonymous + * constructor (the constructor for an anonymous class. * - * @param method the {@link TreePath} for a node that may be an anonymous - * constructor - * @return true if the given path points to an anonymous constructor, false - * if it does not + * @param method the {@link TreePath} for a node that may be an anonymous constructor + * @return true if the given path points to an anonymous constructor, false if it does not */ public static boolean isAnonymousConstructor(final MethodTree method) { /*@Nullable*/ Element e = InternalUtils.symbol(method); - if (e == null || !(e instanceof Symbol)) + if (e == null || !(e instanceof Symbol)) { return false; + } - if ((((/*@NonNull*/ Symbol)e).flags() & Flags.ANONCONSTR) != 0) + if ((((/*@NonNull*/ Symbol) e).flags() & Flags.ANONCONSTR) != 0) { return true; + } return false; } /** - * indicates whether it should return the constructor that gets invoked - * in cases of anonymous classes + * indicates whether it should return the constructor that gets invoked in cases of anonymous + * classes */ private static final boolean RETURN_INVOKE_CONSTRUCTOR = true; /** - * Determines the symbol for a constructor given an invocation via - * {@code new}. + * Determines the symbol for a constructor given an invocation via {@code new}. * - * If the tree is a declaration of an anonymous class, then method returns - * constructor that gets invoked in the extended class, rather than the - * anonymous constructor implicitly added by the constructor (JLS 15.9.5.1) + * <p>If the tree is a declaration of an anonymous class, then method returns constructor that + * gets invoked in the extended class, rather than the anonymous constructor implicitly added by + * the constructor (JLS 15.9.5.1) * * @param tree the constructor invocation - * @return the {@link ExecutableElement} corresponding to the constructor - * call in {@code tree} + * @return the {@link ExecutableElement} corresponding to the constructor call in {@code tree} */ public static ExecutableElement constructor(NewClassTree tree) { @@ -178,7 +174,7 @@ public class InternalUtils { // the method call is guaranteed to return nonnull JCMethodDecl anonConstructor = - (JCMethodDecl) TreeInfo.declarationFor(newClassTree.constructor, newClassTree); + (JCMethodDecl) TreeInfo.declarationFor(newClassTree.constructor, newClassTree); assert anonConstructor != null; assert anonConstructor.body.stats.size() == 1; JCExpressionStatement stmt = (JCExpressionStatement) anonConstructor.body.stats.head; @@ -193,22 +189,31 @@ public class InternalUtils { return (ExecutableElement) e; } - public final static List<AnnotationMirror> annotationsFromTypeAnnotationTrees(List<? extends AnnotationTree> annos) { + public static final List<AnnotationMirror> annotationsFromTypeAnnotationTrees( + List<? extends AnnotationTree> annos) { List<AnnotationMirror> annotations = new ArrayList<AnnotationMirror>(annos.size()); - for (AnnotationTree anno : annos) - annotations.add(((JCAnnotation)anno).attribute); + for (AnnotationTree anno : annos) { + annotations.add(annotationFromAnnotationTree(anno)); + } return annotations; } - public final static List<? extends AnnotationMirror> annotationsFromTree(AnnotatedTypeTree node) { - return annotationsFromTypeAnnotationTrees(((JCAnnotatedType)node).annotations); + public static AnnotationMirror annotationFromAnnotationTree(AnnotationTree tree) { + return ((JCAnnotation) tree).attribute; + } + + public static final List<? extends AnnotationMirror> annotationsFromTree( + AnnotatedTypeTree node) { + return annotationsFromTypeAnnotationTrees(((JCAnnotatedType) node).annotations); } - public final static List<? extends AnnotationMirror> annotationsFromTree(TypeParameterTree node) { - return annotationsFromTypeAnnotationTrees(((JCTypeParameter)node).annotations); + public static final List<? extends AnnotationMirror> annotationsFromTree( + TypeParameterTree node) { + return annotationsFromTypeAnnotationTrees(((JCTypeParameter) node).annotations); } - public final static List<? extends AnnotationMirror> annotationsFromArrayCreation(NewArrayTree node, int level) { + public static final List<? extends AnnotationMirror> annotationsFromArrayCreation( + NewArrayTree node, int level) { assert node instanceof JCNewArray; final JCNewArray newArray = ((JCNewArray) node); @@ -229,32 +234,40 @@ public class InternalUtils { return ((JCTree) tree).type; } - /** - * Returns whether a TypeVariable represents a captured type. - */ + /** Returns whether a TypeVariable represents a captured type. */ public static boolean isCaptured(TypeVariable typeVar) { - return ((Type.TypeVar) typeVar).isCaptured(); + return ((Type.TypeVar) TypeAnnotationUtils.unannotatedType(typeVar)).isCaptured(); } - /** - * Returns whether a TypeMirror represents a class type. - */ + /** If typeVar is a captured wildcard, returns that wildcard; otherwise returns null. */ + public static WildcardType getCapturedWildcard(TypeVariable typeVar) { + if (isCaptured(typeVar)) { + return ((CapturedType) TypeAnnotationUtils.unannotatedType(typeVar)).wildcard; + } + return null; + } + + /** Returns whether a TypeMirror represents a class type. */ public static boolean isClassType(TypeMirror type) { return (type instanceof Type.ClassType); } /** - * Returns the least upper bound of two {@link TypeMirror}s. + * Returns the least upper bound of two {@link TypeMirror}s, ignoring any annotations on the + * types. * - * @param processingEnv The {@link ProcessingEnvironment} to use. - * @param tm1 A {@link TypeMirror}. - * @param tm2 A {@link TypeMirror}. - * @return The least upper bound of {@code tm1} and {@code tm2}. + * <p>Wrapper around Types.lub to add special handling for null types, primitives, and + * wildcards. + * + * @param processingEnv the {@link ProcessingEnvironment} to use + * @param tm1 a {@link TypeMirror} + * @param tm2 a {@link TypeMirror} + * @return the least upper bound of {@code tm1} and {@code tm2}. */ public static TypeMirror leastUpperBound( ProcessingEnvironment processingEnv, TypeMirror tm1, TypeMirror tm2) { - Type t1 = (Type) tm1; - Type t2 = (Type) tm2; + Type t1 = TypeAnnotationUtils.unannotatedType(tm1); + Type t2 = TypeAnnotationUtils.unannotatedType(tm2); JavacProcessingEnvironment javacEnv = (JavacProcessingEnvironment) processingEnv; Types types = Types.instance(javacEnv.getContext()); if (types.isSameType(t1, t2)) { @@ -268,16 +281,6 @@ public class InternalUtils { if (t2.getKind() == TypeKind.NULL) { return t1; } - // Special case for primitives. - if (TypesUtils.isPrimitive(t1) || TypesUtils.isPrimitive(t2)) { - if (types.isAssignable(t1, t2)) { - return t2; - } else if (types.isAssignable(t2, t1)) { - return t1; - } else { - return processingEnv.getTypeUtils().getNoType(TypeKind.NONE); - } - } if (t1.getKind() == TypeKind.WILDCARD) { WildcardType wc1 = (WildcardType) t1; Type bound = (Type) wc1.getExtendsBound(); @@ -298,21 +301,36 @@ public class InternalUtils { } t2 = bound; } + // Special case for primitives. + if (TypesUtils.isPrimitive(t1) || TypesUtils.isPrimitive(t2)) { + if (types.isAssignable(t1, t2)) { + return t2; + } else if (types.isAssignable(t2, t1)) { + return t1; + } else { + Elements elements = processingEnv.getElementUtils(); + return elements.getTypeElement("java.lang.Object").asType(); + } + } return types.lub(t1, t2); } /** - * Returns the greatest lower bound of two {@link TypeMirror}s. + * Returns the greatest lower bound of two {@link TypeMirror}s, ignoring any annotations on the + * types. * - * @param processingEnv The {@link ProcessingEnvironment} to use. - * @param tm1 A {@link TypeMirror}. - * @param tm2 A {@link TypeMirror}. - * @return The greatest lower bound of {@code tm1} and {@code tm2}. + * <p>Wrapper around Types.glb to add special handling for null types, primitives, and + * wildcards. + * + * @param processingEnv the {@link ProcessingEnvironment} to use + * @param tm1 a {@link TypeMirror} + * @param tm2 a {@link TypeMirror} + * @return the greatest lower bound of {@code tm1} and {@code tm2}. */ public static TypeMirror greatestLowerBound( ProcessingEnvironment processingEnv, TypeMirror tm1, TypeMirror tm2) { - Type t1 = (Type) tm1; - Type t2 = (Type) tm2; + Type t1 = TypeAnnotationUtils.unannotatedType(tm1); + Type t2 = TypeAnnotationUtils.unannotatedType(tm2); JavacProcessingEnvironment javacEnv = (JavacProcessingEnvironment) processingEnv; Types types = Types.instance(javacEnv.getContext()); if (types.isSameType(t1, t2)) { @@ -345,21 +363,24 @@ public class InternalUtils { if (t2.getKind() == TypeKind.WILDCARD) { return t1; } + + // If neither type is a primitive type, null type, or wildcard + // and if the types are not the same, use javac types.glb return types.glb(t1, t2); } /** - * Returns the return type of a method, where the "raw" return type of that - * method is given (i.e., the return type might still contain unsubstituted - * type variables), given the receiver of the method call. + * Returns the return type of a method, where the "raw" return type of that method is given + * (i.e., the return type might still contain unsubstituted type variables), given the receiver + * of the method call. */ - public static TypeMirror substituteMethodReturnType(TypeMirror methodType, - TypeMirror substitutedReceiverType) { + public static TypeMirror substituteMethodReturnType( + TypeMirror methodType, TypeMirror substitutedReceiverType) { if (methodType.getKind() != TypeKind.TYPEVAR) { return methodType; } // TODO: find a nicer way to substitute type variables - String t = methodType.toString(); + String t = TypeAnnotationUtils.unannotatedType(methodType).toString(); Type finalReceiverType = (Type) substitutedReceiverType; int i = 0; for (TypeSymbol typeParam : finalReceiverType.tsym.getTypeParameters()) { @@ -372,13 +393,91 @@ public class InternalUtils { return null; } - /** Helper function to extract the javac Context from the - * javac processing environment. + /** + * Helper function to extract the javac Context from the javac processing environment. * * @param env the processing environment * @return the javac Context */ public static Context getJavacContext(ProcessingEnvironment env) { - return ((JavacProcessingEnvironment)env).getContext(); + return ((JavacProcessingEnvironment) env).getContext(); + } + + /** + * Returns the type element for {@code type} if {@code type} is a class, interface, annotation + * type, or enum. Otherwise, returns null. + * + * @param type whose element is returned + * @return the type element for {@code type} if {@code type} is a class, interface, annotation + * type, or enum; otherwise, returns null + */ + public static TypeElement getTypeElement(TypeMirror type) { + Element element = ((Type) type).asElement(); + switch (element.getKind()) { + case ANNOTATION_TYPE: + case CLASS: + case ENUM: + case INTERFACE: + return (TypeElement) element; + default: + return null; + } + } + + /** + * Obtain the class loader for {@code clazz}. If that is not available, return the system class + * loader. + * + * @param clazz the class whose class loader to find + * @return the class loader used to {@code clazz}, or the system class loader, or null if both + * are unavailable + */ + public static ClassLoader getClassLoaderForClass(Class<? extends Object> clazz) { + ClassLoader classLoader = clazz.getClassLoader(); + return classLoader == null ? ClassLoader.getSystemClassLoader() : classLoader; + } + + /** + * Compares tree1 to tree2 by the position at which a diagnostic (e.g., an error message) for + * the tree should be printed. + */ + public static int compareDiagnosticPosition(Tree tree1, Tree tree2) { + DiagnosticPosition pos1 = (DiagnosticPosition) tree1; + DiagnosticPosition pos2 = (DiagnosticPosition) tree2; + + int preferred = Integer.compare(pos1.getPreferredPosition(), pos2.getPreferredPosition()); + if (preferred != 0) { + return preferred; + } + + return Integer.compare(pos1.getStartPosition(), pos2.getStartPosition()); + } + + /** + * Returns whether or not {@code type} is a functional interface type (as defined in JLS 9.8). + * + * @param type possible functional interface type + * @param env ProcessingEnvironment + * @return whether or not {@code type} is a functional interface type (as defined in JLS 9.8) + */ + public static boolean isFunctionalInterface(TypeMirror type, ProcessingEnvironment env) { + Context ctx = ((JavacProcessingEnvironment) env).getContext(); + com.sun.tools.javac.code.Types javacTypes = com.sun.tools.javac.code.Types.instance(ctx); + return javacTypes.isFunctionalInterface((Type) type); + } + + /** + * The type of the lambda or method reference tree is a functional interface type. This method + * returns the single abstract method declared by that functional interface. (The type of this + * method is referred to as the function type.) + * + * @param tree lambda or member reference tree + * @param env ProcessingEnvironment + * @return the single abstract method declared by the type of the tree + */ + public static Symbol findFunction(Tree tree, ProcessingEnvironment env) { + Context ctx = ((JavacProcessingEnvironment) env).getContext(); + com.sun.tools.javac.code.Types javacTypes = com.sun.tools.javac.code.Types.instance(ctx); + return javacTypes.findDescriptorSymbol(((Type) typeOf(tree)).asElement()); } } |