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

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

package org.checkerframework.framework.type;

import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedArrayType;
import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedDeclaredType;
import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedPrimitiveType;
import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedTypeVariable;
import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedWildcardType;
import org.checkerframework.framework.type.visitor.AnnotatedTypeScanner;
import org.checkerframework.framework.type.visitor.SimpleAnnotatedTypeVisitor;
import org.checkerframework.javacutil.ElementUtils;
import org.checkerframework.javacutil.ErrorReporter;
import org.checkerframework.javacutil.TreeUtils;

import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.lang.model.element.AnnotationMirror;
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.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;

import com.sun.source.tree.ClassTree;
import com.sun.source.tree.Tree;

/**
 * Finds the direct supertypes of an input AnnotatedTypeMirror.
 * See http://docs.oracle.com/javase/specs/jls/se8/html/jls-4.html#jls-4.10.2
 * @see Types#directSupertypes(TypeMirror)
 */
class SupertypeFinder {

    // Version of method below for declared types
    /** @see Types#directSupertypes(TypeMirror) */
    public static List directSuperTypes(AnnotatedDeclaredType type) {
        SupertypeFindingVisitor supertypeFindingVisitor = new SupertypeFindingVisitor(type.atypeFactory);
        List supertypes = supertypeFindingVisitor.visitDeclared(type, null);
        type.atypeFactory.postDirectSuperTypes(type, supertypes);
        return supertypes;
    }

    // Version of method above for all types
    /** @see Types#directSupertypes(TypeMirror) */
    public static final List directSuperTypes(AnnotatedTypeMirror type) {
        SupertypeFindingVisitor supertypeFindingVisitor = new SupertypeFindingVisitor(type.atypeFactory);
        List supertypes = supertypeFindingVisitor.visit(type, null);
        type.atypeFactory.postDirectSuperTypes(type, supertypes);
        return supertypes;
    }

    private static class SupertypeFindingVisitor extends SimpleAnnotatedTypeVisitor, Void> {
        private final Types types;
        private final AnnotatedTypeFactory atypeFactory;
        private final TypeParamReplacer typeParamReplacer;

        SupertypeFindingVisitor(AnnotatedTypeFactory atypeFactory) {
            this.atypeFactory = atypeFactory;
            this.types = atypeFactory.types;
            this.typeParamReplacer = new TypeParamReplacer(types);
        }

        @Override
        public List defaultAction(AnnotatedTypeMirror t, Void p) {
            return new ArrayList();
        }

        /**
         * Primitive Rules:
         *
         * 
{@code
         * double >1 float
         * float >1 long
         * long >1 int
         * int >1 char
         * int >1 short
         * short >1 byte
         * }
* * For easiness: *
{@code
         * boxed(primitiveType) >: primitiveType
         * }
*/ @Override public List visitPrimitive(AnnotatedPrimitiveType type, Void p) { List superTypes = new ArrayList(); Set annotations = type.getAnnotations(); // Find Boxed type TypeElement boxed = types.boxedClass(type.getUnderlyingType()); AnnotatedDeclaredType boxedType = atypeFactory.getAnnotatedType(boxed); boxedType.replaceAnnotations(annotations); superTypes.add(boxedType); TypeKind superPrimitiveType = null; if (type.getKind() == TypeKind.BOOLEAN) { // Nothing } else if (type.getKind() == TypeKind.BYTE) { superPrimitiveType = TypeKind.SHORT; } else if (type.getKind() == TypeKind.CHAR) { superPrimitiveType = TypeKind.INT; } else if (type.getKind() == TypeKind.DOUBLE) { // Nothing } else if (type.getKind() == TypeKind.FLOAT) { superPrimitiveType = TypeKind.DOUBLE; } else if (type.getKind() == TypeKind.INT) { superPrimitiveType = TypeKind.LONG; } else if (type.getKind() == TypeKind.LONG) { superPrimitiveType = TypeKind.FLOAT; } else if (type.getKind() == TypeKind.SHORT) { superPrimitiveType = TypeKind.INT; } else { assert false: "Forgot the primitive " + type; } if (superPrimitiveType != null) { AnnotatedPrimitiveType superPrimitive = (AnnotatedPrimitiveType) atypeFactory.toAnnotatedType(types.getPrimitiveType(superPrimitiveType), false); superPrimitive.addAnnotations(annotations); superTypes.add(superPrimitive); } return superTypes; } @Override public List visitDeclared(AnnotatedDeclaredType type, Void p) { List supertypes = new ArrayList(); // Set annotations = type.getAnnotations(); TypeElement typeElement = (TypeElement) type.getUnderlyingType().asElement(); // Mapping of type variable to actual types Map mapping = new HashMap<>(); if (type.getTypeArguments().size() != typeElement.getTypeParameters().size()) { if (!type.wasRaw()) { ErrorReporter.errorAbort( "AnnotatedDeclaredType's element has a different number of type parameters than type.\n" + "type=" + type + "\n" + "element=" + typeElement); } } for (int i = 0; i < type.getTypeArguments().size(); ++i) { mapping.put(typeElement.getTypeParameters().get(i), type.getTypeArguments().get(i)); } ClassTree classTree = atypeFactory.trees.getTree(typeElement); // Testing against enum and annotation. Ideally we can simply use element! if (classTree != null) { supertypes.addAll(supertypesFromTree(type, classTree)); } else { supertypes.addAll(supertypesFromElement(type, typeElement)); // final Element elem = type.getElement() == null ? typeElement : type.getElement(); } if (typeElement.getKind() == ElementKind.ANNOTATION_TYPE) { TypeElement jlaElement = atypeFactory.elements.getTypeElement(Annotation.class.getCanonicalName()); AnnotatedDeclaredType jlaAnnotation = atypeFactory.fromElement(jlaElement); jlaAnnotation.addAnnotations(type.getAnnotations()); supertypes.add(jlaAnnotation); } for (AnnotatedDeclaredType dt : supertypes) { typeParamReplacer.visit(dt, mapping); } return supertypes; } private List supertypesFromElement(AnnotatedDeclaredType type, TypeElement typeElement) { List supertypes = new ArrayList(); // Find the super types: Start with enums and superclass if (typeElement.getKind() == ElementKind.ENUM) { DeclaredType dt = (DeclaredType) typeElement.getSuperclass(); AnnotatedDeclaredType adt = (AnnotatedDeclaredType) atypeFactory.toAnnotatedType(dt, false); List tas = adt.getTypeArguments(); List newtas = new ArrayList(); for (AnnotatedTypeMirror t : tas) { // If the type argument of super is the same as the input type if (atypeFactory.types.isSameType(t.getUnderlyingType(), type.getUnderlyingType())) { t.addAnnotations(type.getAnnotations()); newtas.add(t); } } adt.setTypeArguments(newtas); supertypes.add(adt); } else if (typeElement.getSuperclass().getKind() != TypeKind.NONE) { DeclaredType superClass = (DeclaredType) typeElement.getSuperclass(); AnnotatedDeclaredType dt = (AnnotatedDeclaredType) atypeFactory.toAnnotatedType(superClass, false); supertypes.add(dt); } else if (!ElementUtils.isObject(typeElement)) { supertypes.add(AnnotatedTypeMirror.createTypeOfObject(atypeFactory)); } for (TypeMirror st : typeElement.getInterfaces()) { if (type.wasRaw()) { st = types.erasure(st); } AnnotatedDeclaredType ast = (AnnotatedDeclaredType) atypeFactory.toAnnotatedType(st, false); supertypes.add(ast); if (type.wasRaw()) { if (st.getKind() == TypeKind.DECLARED) { final List typeArgs = ((DeclaredType) st).getTypeArguments(); final List annotatedTypeArgs = ast.getTypeArguments(); for (int i = 0; i < typeArgs.size(); i++) { atypeFactory.annotateImplicit(types.asElement(typeArgs.get(i)), annotatedTypeArgs.get(i)); } } } } ElementAnnotationApplier.annotateSupers(supertypes, typeElement); if (type.wasRaw()) { for (AnnotatedDeclaredType adt : supertypes) { adt.setWasRaw(); } } return supertypes; } private List supertypesFromTree(AnnotatedDeclaredType type, ClassTree classTree) { List supertypes = new ArrayList(); if (classTree.getExtendsClause() != null) { AnnotatedDeclaredType adt = (AnnotatedDeclaredType) atypeFactory.getAnnotatedTypeFromTypeTree(classTree.getExtendsClause()); supertypes.add(adt); } else if (!ElementUtils.isObject(TreeUtils.elementFromDeclaration(classTree))) { supertypes.add(AnnotatedTypeMirror.createTypeOfObject(atypeFactory)); } for (Tree implemented : classTree.getImplementsClause()) { AnnotatedDeclaredType adt = (AnnotatedDeclaredType) atypeFactory.getAnnotatedTypeFromTypeTree(implemented); supertypes.add(adt); } TypeElement elem = TreeUtils.elementFromDeclaration(classTree); if (elem.getKind() == ElementKind.ENUM) { DeclaredType dt = (DeclaredType) elem.getSuperclass(); AnnotatedDeclaredType adt = (AnnotatedDeclaredType) atypeFactory.toAnnotatedType(dt, false); List tas = adt.getTypeArguments(); List newtas = new ArrayList(); for (AnnotatedTypeMirror t : tas) { // If the type argument of super is the same as the input type if (atypeFactory.types.isSameType(t.getUnderlyingType(), type.getUnderlyingType())) { t.addAnnotations(type.getAnnotations()); newtas.add(t); } } adt.setTypeArguments(newtas); supertypes.add(adt); } if (type.wasRaw()) { for (AnnotatedDeclaredType adt : supertypes) { adt.setWasRaw(); } } return supertypes; } /** *
{@code
         * For type = A[ ] ==>
         *  Object >: A[ ]
         *  Clonable >: A[ ]
         *  java.io.Serializable >: A[ ]
         *
         * if A is reference type, then also
         *  B[ ] >: A[ ] for any B[ ] >: A[ ]
         * }
*/ @Override public List visitArray(AnnotatedArrayType type, Void p) { List superTypes = new ArrayList(); Set annotations = type.getAnnotations(); Elements elements = atypeFactory.elements; final AnnotatedTypeMirror objectType = atypeFactory.getAnnotatedType(elements.getTypeElement("java.lang.Object")); objectType.addAnnotations(annotations); superTypes.add(objectType); final AnnotatedTypeMirror cloneableType = atypeFactory.getAnnotatedType(elements.getTypeElement("java.lang.Cloneable")); cloneableType.addAnnotations(annotations); superTypes.add(cloneableType); final AnnotatedTypeMirror serializableType = atypeFactory.getAnnotatedType(elements.getTypeElement("java.io.Serializable")); serializableType.addAnnotations(annotations); superTypes.add(serializableType); for (AnnotatedTypeMirror sup : type.getComponentType().directSuperTypes()) { ArrayType arrType = atypeFactory.types.getArrayType(sup.getUnderlyingType()); AnnotatedArrayType aarrType = (AnnotatedArrayType) atypeFactory.toAnnotatedType(arrType, false); aarrType.setComponentType(sup); aarrType.addAnnotations(annotations); superTypes.add(aarrType); } return superTypes; } @Override public List visitTypeVariable(AnnotatedTypeVariable type, Void p) { List superTypes = new ArrayList<>(); superTypes.add(type.getUpperBound().deepCopy()); return superTypes; } @Override public List visitWildcard(AnnotatedWildcardType type, Void p) { List superTypes = new ArrayList<>(); superTypes.add(type.getExtendsBound().deepCopy()); return superTypes; } /** * Note: The explanation below is my interpretation of why we have this code. I am not sure if this * was the author's original intent but I can see no other reasoning, exercise caution: * * Classes may have type parameters that are used in extends or implements clauses. * E.g. * {@code class MyList extends List} * * Direct supertypes will contain a type {@code List} but the type T may become out of sync with * the annotations on type {@code MyList}. To keep them in-sync, we substitute out the copy of T * with the same reference to T that is on {@code MyList} */ private class TypeParamReplacer extends AnnotatedTypeScanner> { private final Types types; public TypeParamReplacer(Types types) { this.types = types; } @Override public Void visitDeclared(AnnotatedDeclaredType type, Map mapping) { if (visitedNodes.containsKey(type)) { return visitedNodes.get(type); } visitedNodes.put(type, null); List args = new ArrayList(); for (AnnotatedTypeMirror arg : type.getTypeArguments()) { Element elem = types.asElement(arg.getUnderlyingType()); if ((elem != null) && (elem.getKind() == ElementKind.TYPE_PARAMETER) && (mapping.containsKey(elem))) { AnnotatedTypeMirror other = mapping.get(elem); other.replaceAnnotations(arg.getAnnotationsField()); args.add(other); } else { args.add(arg); scan(arg, mapping); } } type.setTypeArguments(args); return null; } @Override public Void visitArray(AnnotatedArrayType type, Map mapping) { AnnotatedTypeMirror comptype = type.getComponentType(); Element elem = types.asElement(comptype.getUnderlyingType()); AnnotatedTypeMirror other; if ((elem != null) && (elem.getKind() == ElementKind.TYPE_PARAMETER) && (mapping.containsKey(elem))) { other = mapping.get(elem); other.replaceAnnotations(comptype.getAnnotationsField()); type.setComponentType(other); } else { scan(type.getComponentType(), mapping); } return null; } } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy