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

framework.src.org.checkerframework.framework.type.ElementAnnotationApplier 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.42.0
Show newest version
package org.checkerframework.framework.type;

import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedDeclaredType;
import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedTypeVariable;
import org.checkerframework.framework.util.element.ClassTypeParamApplier;
import org.checkerframework.framework.util.element.MethodApplier;
import org.checkerframework.framework.util.element.MethodTypeParamApplier;
import org.checkerframework.framework.util.element.ParamApplier;
import org.checkerframework.framework.util.element.SuperTypeApplier;
import org.checkerframework.framework.util.element.TypeDeclarationApplier;
import org.checkerframework.framework.util.element.TypeVarUseApplier;
import org.checkerframework.framework.util.element.VariableApplier;
import org.checkerframework.javacutil.ErrorReporter;
import org.checkerframework.javacutil.Pair;

import java.util.List;

import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;

import com.sun.source.tree.LambdaExpressionTree;
import com.sun.source.tree.Tree;
import com.sun.source.tree.Tree.Kind;
import com.sun.source.tree.VariableTree;
import com.sun.tools.javac.code.Symbol;


/**
 * Utility methods for adding the annotations that are stored in an Element to the
 * type that represents that element (or a use of that Element).
 *
 * In a way, this class is a hack: the Type representation for the Elements should
 * contain all annotations that we want.
 * However, due to javac bugs
 * http://mail.openjdk.java.net/pipermail/type-annotations-dev/2013-December/001449.html
 * decoding the type annotations from the Element is necessary.
 *
 * Even once these bugs are fixed, this class might be useful: in TypesIntoElements
 * it is easy to add additional annotations to the element and have them stored in the
 * bytecode by the compiler.
 * It would be more work (and might not work in the end) to instead modify the Type
 * directly.
 * The interaction between TypeFromElement and TypesIntoElements allows us to write
 * the defaulted annotations into the Element and have them read later by other parts.
 */
public class ElementAnnotationApplier {

    /**
     * Add all of the relevant annotations stored in Element to type. This includes both top-level primary
     * annotations and nested annotations.  For the most part the TypeAnnotationPosition of the
     * element annotations are used to locate the annotation in the right AnnotatedTypeMirror location
     * though the individual applier classes may have special rules (such as those for upper and lower bounds
     * and intersections).
     *
     * Note:  Element annotations come from two sources.
     *
     * 1) Annotations found on elements may represent those in source code or bytecode;
     * these are added to the element by the compiler.
     *
     * 2) The annotations may also represent those that were inferred or defaulted by the Checker
     * Framework after a previous call to this method.  The Checker Framework will store
     * any annotations on declarations back into the elements that represent them
     * (see {@link org.checkerframework.framework.type.TypesIntoElements}).  Subsequent, calls to apply will encounter
     * these annotations on the provided element.
     *
     * Note:  This is not the ONLY place that annotations are explicitly added to types.
     * See {@link org.checkerframework.framework.type.TypeFromTree}.
     *
     * @param type the type to which we wish to apply the element's annotations
     * @param element an element that possibly contains annotations
     * @param typeFactory the typeFactory used to create the given type
     */
    public static void apply(final AnnotatedTypeMirror type, final Element element,
                             final AnnotatedTypeFactory typeFactory) {
        if ( element == null ) {
            ErrorReporter.errorAbort("ElementAnnotationUtil.apply: element cannot be null");

        } else if ( TypeVarUseApplier.accepts(type, element) ) {
            TypeVarUseApplier.apply(type, element, typeFactory);

        } else if ( VariableApplier.accepts(type, element) ) {
            VariableApplier.apply(type, element);

        } else if ( MethodApplier.accepts(type, element) ) {
            MethodApplier.apply(type, element, typeFactory);

        } else if ( TypeDeclarationApplier.accepts(type, element) ) {
            TypeDeclarationApplier.apply(type, element, typeFactory);

        } else if ( ClassTypeParamApplier.accepts(type, element) ) {
            ClassTypeParamApplier.apply((AnnotatedTypeVariable) type, element, typeFactory);

        } else if ( MethodTypeParamApplier.accepts(type, element)) {
            MethodTypeParamApplier.apply((AnnotatedTypeVariable) type, element, typeFactory);

        } else if ( ParamApplier.accepts(type, element) ) {
            ParamApplier.apply(type, element, typeFactory);

        } else if ( isCaptureConvertedTypeVar(element) ) {
            // Types resulting from capture conversion cannot have explicit annotations

        } else {
            ErrorReporter.errorAbort("ElementAnnotationUtil.apply: illegal argument: " +
                    element + " [" + element.getKind() + "]" + " with type " + type);
        }
    }

    /**
     * Annotate the list of supertypes using the annotations on the TypeElement representing a class or interface
     * @param supertypes types representing supertype declarations of TypeElement
     * @param subtypeElement an element representing the declaration of the class which is a subtype of supertypes
     */
    public static void annotateSupers(List supertypes, TypeElement subtypeElement ) {
        SuperTypeApplier.annotateSupers(supertypes, subtypeElement);
    }

    /**
     * Helper method to get the lambda tree for ParamApplier.  Ideally, this method would be located in
     * ElementAnnotationUtil but since AnnotatedTypeFactory.declarationFromElement is protected, it has
     * been placed here.
     *
     * @param varEle the element that may represent a lambda's parameter
     * @return a LambdaExpressionTree if the varEle represents a parameter in a lambda expression, otherwise
     *         null
     */
    public static Pair getParamAndLambdaTree(VariableElement varEle,
                                                                        AnnotatedTypeFactory typeFactory) {
        VariableTree paramDecl = (VariableTree) typeFactory.declarationFromElement(varEle);

        if (paramDecl != null) {
            final Tree parentTree = typeFactory.getPath(paramDecl).getParentPath().getLeaf();
            if (parentTree != null && parentTree.getKind() == Kind.LAMBDA_EXPRESSION) {
                return Pair.of(paramDecl, (LambdaExpressionTree) parentTree);
            }
        }

        return null;
    }

    /**
     * Was the type passed in generated by capture conversion.
     * @param element the element which type represents
     * @return true if type was generated via capture conversion
     *         false otherwise
     */
    private static boolean isCaptureConvertedTypeVar(final Element element) {
        final Element enclosure = element.getEnclosingElement();
        return (((Symbol)enclosure).kind == com.sun.tools.javac.code.Kinds.NIL);
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy