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

framework.src.org.checkerframework.framework.util.element.TargetedElementAnnotationApplier 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.util.element;

import org.checkerframework.framework.type.AnnotatedTypeMirror;
import org.checkerframework.framework.util.PluginUtil;
import org.checkerframework.javacutil.ErrorReporter;

import java.util.ArrayList;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;

import javax.lang.model.element.Element;

import com.sun.tools.javac.code.Attribute;
import com.sun.tools.javac.code.Attribute.TypeCompound;
import com.sun.tools.javac.code.TargetType;

/**
 * TargetedElementAnnotationApplier filters annotations for an element into 3 groups.
 * TARGETED annotations are those we wish to apply in this ElementAnnotationApplier. VALID annotations
 * are those that are valid on the current element (or its enclosure, see getRawTypeAttributes)
 * but should not be applied to the given type.  Invalid annotations are those that should NEVER appear
 * for the given element.  Invalid annotations are reported as errors by default in the handleInvalid method.
 * See method extractAndApply.  Please read getRawTypeAttributes for an idea of what types of annotations
 * may be encountered by this ElementAnnotationApplier.
 *
 * Note: Subtypes of this class likely want to implement the handleTargeted and handleValid methods though
 * they have default empty implementations for brevity.
 */
abstract class TargetedElementAnnotationApplier {
    /**
     * Three annotation types that may be encountered when calling getRawTypeAttributes. see sift().
     */
    static enum TargetClass {
        TARGETED, VALID, INVALID
    }

    /**
     * The type to which we wish to apply annotations.
     */
    protected final AnnotatedTypeMirror type;

    /**
     * An Element that type represents.
     */
    protected final Element element;

    /**
     * @return the TargetTypes that identify annotations we wish to apply with this object.  Any annotations
     * that have these target types will be passed to handleTargeted.
     */
    protected abstract TargetType[] annotatedTargets();

    /**
     * @return the TargetTypes that identify annotations that are valid but we wish to ignore.  Any annotations
     * that have these target types will be passed to handleValid, providing they aren't also in annotatedTargets.
     */
    protected abstract TargetType [] validTargets();

    /**
     * Annotations on elements are represented as Attribute.TypeCompounds ( a subtype of AnnotationMirror) that
     * are usually accessed through a getRawTypeAttributes method on the element.
     *
     * In Java 8 and later these annotations are generally contained by elements to which they apply.  However, in
     * earlier versions of Java many of these annotations are handled by either the enclosing method, e.g. parameters
     * and method type parameters, or enclosing class, e.g. class type parameters.  Therefore, many annotations are
     * addressed by first getting all annotations on a method or class and the picking out only the ones we wish to
     * target (see extractAndApply).
     *
     * @return the annotations that we MAY wish to apply to the given type
     */
    protected abstract Iterable getRawTypeAttributes();

    /**
     * Tests element/type fields to ensure that this TargetedElementAnnotationApplier is valid for
     * this element/type pair.
     * @return true if the type/element members are handled by this class
     *         false otherwise
     */
    protected abstract boolean isAccepted();

    /**
     * @param type the type to annotate
     * @param element an element identifying type
     */
    TargetedElementAnnotationApplier(final AnnotatedTypeMirror type, final Element element) {
        this.type = type;
        this.element = element;
    }

    /**
     * This method should apply all annotations that are handled by this object.
     * @param targeted the list of annotations that were returned by getRawTypeAttributes and had a TargetType
     *                 contained by annotatedTargets
     */
    protected abstract void handleTargeted(List targeted);

    /**
     * The default implementation of this method does nothing.
     * @param valid the list of annotations that were returned by getRawTypeAttributes and had a TargetType
     *              contained by valid and NOT annotatedTargets
     */
    protected void handleValid(List valid) { }

    /**
     * @param invalid the list of annotations that were returned by getRawTypeAttributes and were not
     *                handled by handleTargeted or handleValid
     */
    protected void handleInvalid(List invalid) {
        if (!invalid.isEmpty()) {
            ErrorReporter.errorAbort(this.getClass().getName() + ".handleInvalid: " +
                    "Invalid variable and element passed to extractAndApply; type: " + type + "," +
                            " element: " + element + " (kind: " + element.getKind() +
                    "), invalid annotations: " + PluginUtil.join(", ", invalid) + "\n" +
                    "Targeted annotations: " + PluginUtil.join(", ", annotatedTargets()) +
                    "; Valid annotations: " + PluginUtil.join(", ", validTargets()));
        }
    }

    /**
     * Separate the input annotations into a Map of TargetClass (TARGETED, VALID, INVALID) to the annotations
     * that fall into each of those categories.
     * @param typeCompounds annotations to sift through, should be those returned by getRawTypeAttributes
     * @return a {@literal Map Annotations>.}
     */
    protected Map> sift(final Iterable typeCompounds) {

        final Map> targetClassToCompound = new EnumMap<>(TargetClass.class);
        for (TargetClass targetClass : TargetClass.values()) {
            targetClassToCompound.put(targetClass, new ArrayList());
        }

        for (final Attribute.TypeCompound typeCompound : typeCompounds) {
            final TargetType typeCompoundTarget = typeCompound.position.type;
            final List destList;

            if (ElementAnnotationUtil.contains(typeCompoundTarget, annotatedTargets())) {
                destList = targetClassToCompound.get(TargetClass.TARGETED);

            } else if (ElementAnnotationUtil.contains(typeCompoundTarget, validTargets())) {
                destList = targetClassToCompound.get(TargetClass.VALID);

            } else {
                destList = targetClassToCompound.get(TargetClass.INVALID);
            }

            destList.add(typeCompound);
        }

        return targetClassToCompound;
    }

    /**
     * Reads the list of annotations that apply to this element (see getRawTypeAttributes).  Sifts them into
     * three groups (TARGETED, INVALID, VALID) and then calls the appropriate handle method on them.  The
     * handleTargeted method should apply all annotations that are handled by this object.
     *
     * This method will throw a runtime exception if isAccepted returns false.
     */
    public void extractAndApply( ) {
        if (!isAccepted()) {
            ErrorReporter.errorAbort("LocalVariableExtractor.extractAndApply: " +
                    "Invalid variable and element passed to " + this.getClass().getName() + "::extractAndApply (" +
                    type + ", " + element );
        }

        final Map> targetClassToAnno = sift(getRawTypeAttributes());

        handleInvalid(targetClassToAnno.get(TargetClass.INVALID));
        handleValid(targetClassToAnno.get(TargetClass.VALID));
        handleTargeted(targetClassToAnno.get(TargetClass.TARGETED));
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy