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

org.checkerframework.framework.type.TypeFromTypeTreeVisitor Maven / Gradle / Ivy

Go to download

The Checker Framework enhances Java's type system to make it more powerful and useful. This lets software developers detect and prevent errors in their Java programs. The Checker Framework includes compiler plug-ins ("checkers") that find bugs or verify their absence. It also permits you to write your own compiler plug-ins.

There is a newer version: 3.43.0
Show newest version
package org.checkerframework.framework.type;

import com.sun.source.tree.AnnotatedTypeTree;
import com.sun.source.tree.ArrayTypeTree;
import com.sun.source.tree.ClassTree;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.IdentifierTree;
import com.sun.source.tree.IntersectionTypeTree;
import com.sun.source.tree.MemberSelectTree;
import com.sun.source.tree.MethodTree;
import com.sun.source.tree.ParameterizedTypeTree;
import com.sun.source.tree.PrimitiveTypeTree;
import com.sun.source.tree.Tree;
import com.sun.source.tree.Tree.Kind;
import com.sun.source.tree.TypeParameterTree;
import com.sun.source.tree.UnionTypeTree;
import com.sun.source.tree.WildcardTree;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
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.element.TypeParameterElement;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeVariable;
import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedArrayType;
import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedDeclaredType;
import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedIntersectionType;
import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedTypeVariable;
import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedWildcardType;
import org.checkerframework.javacutil.ErrorReporter;
import org.checkerframework.javacutil.TreeUtils;
import org.checkerframework.javacutil.TypesUtils;

/**
 * Converts type trees into AnnotatedTypeMirrors
 *
 * @see org.checkerframework.framework.type.TypeFromTree
 */
class TypeFromTypeTreeVisitor extends TypeFromTreeVisitor {

    private final Map visitedBounds = new HashMap<>();

    @Override
    public AnnotatedTypeMirror visitAnnotatedType(AnnotatedTypeTree node, AnnotatedTypeFactory f) {
        AnnotatedTypeMirror type = visit(node.getUnderlyingType(), f);
        if (type == null) // e.g., for receiver type
        type = f.toAnnotatedType(f.types.getNoType(TypeKind.NONE), false);
        assert AnnotatedTypeFactory.validAnnotatedType(type);
        List annos = TreeUtils.annotationsFromTree(node);

        if (type.getKind() == TypeKind.WILDCARD) {
            final ExpressionTree underlyingTree = node.getUnderlyingType();

            if (underlyingTree.getKind() == Kind.UNBOUNDED_WILDCARD) {
                // primary annotations on unbounded wildcard types apply to both bounds
                ((AnnotatedWildcardType) type).getExtendsBound().addMissingAnnotations(annos);
                ((AnnotatedWildcardType) type).getSuperBound().addMissingAnnotations(annos);

            } else if (underlyingTree.getKind() == Kind.EXTENDS_WILDCARD) {
                ((AnnotatedWildcardType) type).getSuperBound().addMissingAnnotations(annos);

            } else if (underlyingTree.getKind() == Kind.SUPER_WILDCARD) {
                ((AnnotatedWildcardType) type).getExtendsBound().addMissingAnnotations(annos);

            } else {
                ErrorReporter.errorAbort(
                        "Unexpected kind for type!  node=" + node + " type=" + type);
            }
        } else {
            type.addAnnotations(annos);
        }

        return type;
    }

    @Override
    public AnnotatedTypeMirror visitArrayType(ArrayTypeTree node, AnnotatedTypeFactory f) {
        AnnotatedTypeMirror component = visit(node.getType(), f);

        AnnotatedTypeMirror result = f.type(node);
        assert result instanceof AnnotatedArrayType;
        ((AnnotatedArrayType) result).setComponentType(component);
        return result;
    }

    @Override
    public AnnotatedTypeMirror visitParameterizedType(
            ParameterizedTypeTree node, AnnotatedTypeFactory f) {

        List args = new ArrayList<>(node.getTypeArguments().size());
        for (Tree t : node.getTypeArguments()) {
            args.add(visit(t, f));
        }

        AnnotatedTypeMirror result = f.type(node); // use creator?
        AnnotatedTypeMirror atype = visit(node.getType(), f);
        result.addAnnotations(atype.getAnnotations());
        // new ArrayList<>() type is AnnotatedExecutableType for some reason

        if (result instanceof AnnotatedDeclaredType) {
            assert result instanceof AnnotatedDeclaredType : node + " --> " + result;
            ((AnnotatedDeclaredType) result).setTypeArguments(args);
        }
        return result;
    }

    @Override
    public AnnotatedTypeMirror visitPrimitiveType(PrimitiveTypeTree node, AnnotatedTypeFactory f) {
        return f.type(node);
    }

    @Override
    public AnnotatedTypeMirror visitTypeParameter(TypeParameterTree node, AnnotatedTypeFactory f) {

        List bounds = new ArrayList<>(node.getBounds().size());
        for (Tree t : node.getBounds()) {
            AnnotatedTypeMirror bound;
            if (visitedBounds.containsKey(t) && f == visitedBounds.get(t).atypeFactory) {
                bound = visitedBounds.get(t);
            } else {
                visitedBounds.put(t, f.type(t));
                bound = visit(t, f);
                visitedBounds.remove(t);
            }
            bounds.add(bound);
        }

        AnnotatedTypeVariable result = (AnnotatedTypeVariable) f.type(node);
        List annotations = TreeUtils.annotationsFromTree(node);
        result.getLowerBound().addAnnotations(annotations);

        switch (bounds.size()) {
            case 0:
                break;
            case 1:
                result.setUpperBound(bounds.get(0));
                break;
            default:
                AnnotatedIntersectionType upperBound =
                        (AnnotatedIntersectionType) result.getUpperBound();

                List superBounds =
                        new ArrayList(bounds.size());
                for (AnnotatedTypeMirror b : bounds) {
                    superBounds.add((AnnotatedDeclaredType) b);
                }
                upperBound.setDirectSuperTypes(superBounds);
        }

        return result;
    }

    @Override
    public AnnotatedTypeMirror visitWildcard(WildcardTree node, AnnotatedTypeFactory f) {

        AnnotatedTypeMirror bound = visit(node.getBound(), f);

        AnnotatedTypeMirror result = f.type(node);
        assert result instanceof AnnotatedWildcardType;

        // for wildcards unlike type variables there are bounds that differ in type from
        // result.  These occur for RAW types.  In this case, use the newly created bound
        // rather than merging into result
        if (node.getKind() == Tree.Kind.SUPER_WILDCARD) {
            ((AnnotatedWildcardType) result).setSuperBound(bound);

        } else if (node.getKind() == Tree.Kind.EXTENDS_WILDCARD) {
            ((AnnotatedWildcardType) result).setExtendsBound(bound);
        }
        return result;
    }

    private AnnotatedTypeMirror forTypeVariable(AnnotatedTypeMirror type, AnnotatedTypeFactory f) {
        if (type.getKind() != TypeKind.TYPEVAR) {
            ErrorReporter.errorAbort(
                    "TypeFromTree.forTypeVariable: should only be called on type variables");
            return null; // dead code
        }

        TypeVariable typeVar = (TypeVariable) type.getUnderlyingType();
        TypeParameterElement tpe = (TypeParameterElement) typeVar.asElement();
        Element elt = tpe.getGenericElement();
        if (elt instanceof TypeElement) {
            TypeElement typeElt = (TypeElement) elt;
            int idx = typeElt.getTypeParameters().indexOf(tpe);
            ClassTree cls = (ClassTree) f.declarationFromElement(typeElt);
            if (cls != null) {
                // `forTypeVariable` is called for Identifier, MemberSelect and UnionType trees,
                // none of which are declarations.  But `cls.getTypeParameters()` returns a list
                // of type parameter declarations (`TypeParameterTree`), so this recursive call
                // to `visit` will return a declaration ATV.  So we must copy the result and set
                // its `isDeclaration` field to `false`.
                AnnotatedTypeMirror result =
                        visit(cls.getTypeParameters().get(idx), f).shallowCopy();
                ((AnnotatedTypeVariable) result).setDeclaration(false);
                return result;
            } else {
                // We already have all info from the element -> nothing to do.
                return type;
            }
        } else if (elt instanceof ExecutableElement) {
            ExecutableElement exElt = (ExecutableElement) elt;
            int idx = exElt.getTypeParameters().indexOf(tpe);
            MethodTree meth = (MethodTree) f.declarationFromElement(exElt);
            if (meth != null) {
                // This works the same as the case above.  Even though `meth` itself is not a
                // type declaration tree, the elements of `meth.getTypeParameters()` still are.
                AnnotatedTypeMirror result =
                        visit(meth.getTypeParameters().get(idx), f).shallowCopy();
                ((AnnotatedTypeVariable) result).setDeclaration(false);
                return result;
            } else {
                // ErrorReporter.errorAbort("TypeFromTree.forTypeVariable: did not find source for:
                // " + elt);
                return type;
            }
        } else {
            // Captured types can have a generic element (owner) that is
            // not an element at all, namely Symtab.noSymbol.
            if (TypesUtils.isCaptured(typeVar)) {
                return type;
            } else {
                ErrorReporter.errorAbort(
                        "TypeFromTree.forTypeVariable: not a supported element: " + elt);
                return null; // dead code
            }
        }
    }

    @Override
    public AnnotatedTypeMirror visitIdentifier(IdentifierTree node, AnnotatedTypeFactory f) {

        AnnotatedTypeMirror type = f.type(node);

        if (type.getKind() == TypeKind.TYPEVAR) {
            return forTypeVariable(type, f).asUse();
        }

        return type;
    }

    @Override
    public AnnotatedTypeMirror visitMemberSelect(MemberSelectTree node, AnnotatedTypeFactory f) {

        AnnotatedTypeMirror type = f.type(node);

        if (type.getKind() == TypeKind.TYPEVAR) {
            return forTypeVariable(type, f).asUse();
        }

        return type;
    }

    @Override
    public AnnotatedTypeMirror visitUnionType(UnionTypeTree node, AnnotatedTypeFactory f) {
        AnnotatedTypeMirror type = f.type(node);

        if (type.getKind() == TypeKind.TYPEVAR) {
            return forTypeVariable(type, f).asUse();
        }

        return type;
    }

    @Override
    public AnnotatedTypeMirror visitIntersectionType(
            IntersectionTypeTree node, AnnotatedTypeFactory f) {
        AnnotatedTypeMirror type = f.type(node);

        if (type.getKind() == TypeKind.TYPEVAR) {
            return forTypeVariable(type, f).asUse();
        }

        return type;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy