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

checker.src.org.checkerframework.checker.units.UnitsRelationsTools 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.checker.units;

import java.lang.annotation.Annotation;
import java.util.Map;
import java.util.Set;

import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.AnnotationValue;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.util.Elements;

import org.checkerframework.checker.units.qual.Prefix;
import org.checkerframework.checker.units.qual.UnknownUnits;
import org.checkerframework.framework.type.AnnotatedTypeMirror;
import org.checkerframework.framework.util.AnnotationBuilder;
import org.checkerframework.javacutil.AnnotationUtils;

/*>>>
import org.checkerframework.checker.nullness.qual.Nullable;
 */

/**
 * A helper class for UnitsRelations, providing numerous methods which help process Annotations and Annotated Types representing various units
 */
public class UnitsRelationsTools {

    /**
     * Creates an AnnotationMirror representing a unit defined by annoClass, with the default Prefix of Prefix.one
     * @param env the Checker Processing Environment, provided as a parameter in init() of a UnitsRelations implementation
     * @param annoClass the Class of an Annotation representing a Unit (eg m.class for meters)
     * @return an AnnotationMirror of the Unit with Prefix.one, or null if it cannot be constructed
     */
    public static /*@Nullable*/ AnnotationMirror buildAnnoMirrorWithDefaultPrefix(final ProcessingEnvironment env, final Class annoClass) {
        if (env == null || annoClass == null) {
            return null;
        }

        return buildAnnoMirrorWithSpecificPrefix(env, annoClass, Prefix.one);
    }

    /**
     * Creates an AnnotationMirror representing a unit defined by annoClass, with the specific Prefix p
     * @param env the Checker Processing Environment, provided as a parameter in init() of a UnitsRelations implementation
     * @param annoClass the Class of an Annotation representing a Unit (eg m.class for meters)
     * @param p a Prefix value
     * @return an AnnotationMirror of the Unit with the Prefix p, or null if it cannot be constructed
     */
    public static /*@Nullable*/ AnnotationMirror buildAnnoMirrorWithSpecificPrefix(final ProcessingEnvironment env, final Class annoClass, final Prefix p) {
        if (env == null || annoClass == null || p == null) {
            return null;
        }

        AnnotationBuilder builder = new AnnotationBuilder(env, annoClass);
        builder.setValue("value", p);
        return builder.build();
    }

    /**
     * Creates an AnnotationMirror representing a unit defined by annoClass, with no prefix
     * @param env checker Processing Environment, provided as a parameter in init() of a UnitsRelations implementation
     * @param annoClass the Class of an Annotation representing a Unit (eg m.class for meters)
     * @return an AnnotationMirror of the Unit with no prefix, or null if it cannot be constructed
     */
    public static /*@Nullable*/ AnnotationMirror buildAnnoMirrorWithNoPrefix(final ProcessingEnvironment env, final Class annoClass) {
        if (env == null || annoClass == null) {
            return null;
        }

        return AnnotationUtils.fromClass(env.getElementUtils(), annoClass);
    }

    /**
     * Retrieves the SI Prefix of an Annotated Type
     * @param annoType an AnnotatedTypeMirror representing a Units Annotated Type
     * @return a Prefix value (including Prefix.one), or null if it has none
     */
    public static /*@Nullable*/ Prefix getPrefix(final AnnotatedTypeMirror annoType) {
        if (annoType == null) {
            return null;
        }

        Prefix result = null;

        // go through each Annotation of an Annotated Type, find the prefix and return it
        for (AnnotationMirror mirror : annoType.getAnnotations()) {
            // try to get a prefix
            result = getPrefix(mirror);
            // if it is not null, then return the retrieved prefix immediately
            if (result != null) {
                return result;
            }
        }

        // if it can't find any prefix at all, then return null
        return result;
    }

    /**
     * Retrieves the SI Prefix of an Annotation
     * @param unitsAnnotation an AnnotationMirror representing a Units Annotation
     * @return a Prefix value (including Prefix.one), or null if it has none
     */
    public static /*@Nullable*/ Prefix getPrefix(/*@Nullable*/final AnnotationMirror unitsAnnotation) {
        AnnotationValue annotationValue = getAnnotationMirrorPrefix(unitsAnnotation);

        // if this Annotation has no prefix, return null
        if (hasNoPrefix(annotationValue)) {
            return null;
        }

        // if the Annotation has a value, then detect and match the string name of the prefix, and return the matching Prefix
        String prefixString = annotationValue.getValue().toString();
        for (Prefix prefix : Prefix.values()) {
            if (prefixString.equals(prefix.toString())) {
                return prefix;
            }
        }

        // if none of the strings match, then return null
        return null;
    }

    /**
     * Checks to see if an Annotated Type has no prefix
     * @param annoType an AnnotatedTypeMirror representing a Units Annotated Type
     * @return true if it has no prefix, false otherwise
     */
    public static boolean hasNoPrefix(/*@Nullable*/ final AnnotatedTypeMirror annoType) {
        if (annoType == null) {
            return true;
        }

        for (AnnotationMirror mirror : annoType.getAnnotations()) {
            // if any Annotation has a prefix, return false
            if (!hasNoPrefix(mirror)) {
                return false;
            }
        }

        return true;
    }

    /**
     * Checks to see if an Annotation has no prefix
     * @param unitsAnnotation an AnnotationMirror representing a Units Annotation
     * @return true if it has no prefix, false otherwise
     */
    public static boolean hasNoPrefix(/*@Nullable*/ final AnnotationMirror unitsAnnotation) {
        AnnotationValue annotationValue = getAnnotationMirrorPrefix(unitsAnnotation);
        return hasNoPrefix(annotationValue);
    }

    private static boolean hasNoPrefix(/*@Nullable*/ final AnnotationValue annotationValue) {
        // Annotation has no element value (ie no SI prefix)
        if (annotationValue == null) {
            return true;
        } else {
            return false;
        }
    }

    /** Given an Annotation, returns the prefix (eg kilo) as an AnnotationValue if there is any, otherwise returns null. */
    private static /*@Nullable*/ AnnotationValue getAnnotationMirrorPrefix(/*@Nullable*/ final AnnotationMirror unitsAnnotation) {
        if (unitsAnnotation == null) {
            return null;
        }

        Map elementValues = unitsAnnotation.getElementValues();

        for (Map.Entry entry : elementValues.entrySet()) {
            if (entry.getKey().getSimpleName().toString().equals("value")) {
                return entry.getValue();
            }
        }

        return null;
    }

    /**
     * Removes the Prefix value from an Annotation, by constructing and returning a copy of its base SI unit's Annotation
     * @param elements
     *            Element Utilities from a checker's processing environment,
     *            typically obtained by calling env.getElementUtils() in init()
     *            of a Units Relations implementation
     * @param unitsAnnotation an AnnotationMirror representing a Units Annotation
     * @return the base SI Unit's AnnotationMirror, or null if the base SI Unit cannot
     *         be constructed
     */
    public static /*@Nullable*/ AnnotationMirror removePrefix(/*@Nullable*/ final Elements elements, /*@Nullable*/ final AnnotationMirror unitsAnnotation) {
        if (elements == null) {
            return null;
        }

        if (hasNoPrefix(unitsAnnotation)) {
            return unitsAnnotation;
        } else {
            // the only value is the prefix value in Units Checker
            // TODO: refine sensitivity of removal for extension units, in case extension Annotations have more than just Prefix in its values.
            return AnnotationUtils.fromName(elements, unitsAnnotation.getAnnotationType().toString());
        }
    }

    /**
     * Removes the Prefix value from an Annotated Type, by constructing and returning a copy of the Annotated Type without the prefix
     * @param elements
     *            Element Utilities from a checker's processing environment,
     *            typically obtained by calling env.getElementUtils() in init()
     *            of a Units Relations implementation
     * @param annoType an AnnotatedTypeMirror representing a Units Annotated Type
     * @return a copy of the Annotated Type without the prefix
     */
    public static AnnotatedTypeMirror removePrefix(/*@Nullable*/ final Elements elements, /*@Nullable*/ final AnnotatedTypeMirror annoType) {
        // deep copy the Annotated Type Mirror without any of the Annotations
        AnnotatedTypeMirror result = annoType.deepCopy(false);

        // get all of the original Annotations in the Annotated Type
        Set annos = annoType.getAnnotations();

        // loop through all the Annotations to see if they use Prefix.one, remove Prefix.one if it does
        for (AnnotationMirror anno : annos) {
            // try to clean the Annotation Mirror of the Prefix
            AnnotationMirror cleanedMirror = removePrefix(elements, anno);
            // if successful, add the cleaned annotation to the deep copy
            if (cleanedMirror != null) {
                result.addAnnotation(cleanedMirror);
            }
            // if unsuccessful, add the original annotation
            else {
                result.addAnnotation(anno);
            }
        }

        return result;
    }

    /**
     * Checks to see if a particular Annotated Type has no units, such as scalar constants in calculations.
     *
     * Any number that isn't assigned a unit will automatically get the Annotation UnknownUnits.
     * eg: int x = 5; // x has @UnknownUnits
     *
     * @param annoType an AnnotatedTypeMirror representing a Units Annotated Type
     * @return true if the Type has no units, false otherwise
     */
    public static boolean hasNoUnits(/*@Nullable*/ final AnnotatedTypeMirror annoType) {
        if (annoType == null) {
            return false;
        }

        return (annoType.getAnnotation(UnknownUnits.class) != null);
    }

    /**
     * Checks to see if a particular Annotated Type has a specific unit (represented by its Annotation)
     * @param annoType an AnnotatedTypeMirror representing a Units Annotated Type
     * @param unitsAnnotation an AnnotationMirror representing a Units Annotation of a specific unit
     * @return true if the Type has the specific unit, false otherwise
     */
    public static boolean hasSpecificUnit(/*@Nullable*/ final AnnotatedTypeMirror annoType, /*@Nullable*/ final AnnotationMirror unitsAnnotation) {
        if (annoType == null || unitsAnnotation == null) {
            return false;
        }

        return AnnotationUtils.containsSame(annoType.getAnnotations(), unitsAnnotation);
    }

    /**
     * Checks to see if a particular Annotated Type has a particular base unit (represented by its Annotation)
     * @param annoType an AnnotatedTypeMirror representing a Units Annotated Type
     * @param unitsAnnotation an AnnotationMirror representing a Units Annotation of the base unit
     * @return true if the Type has the specific unit, false otherwise
     */
    public static boolean hasSpecificUnitIgnoringPrefix(/*@Nullable*/ final AnnotatedTypeMirror annoType, /*@Nullable*/ final AnnotationMirror unitsAnnotation) {
        if (annoType == null || unitsAnnotation == null) {
            return false;
        }

        return AnnotationUtils.containsSameIgnoringValues(annoType.getAnnotations(), unitsAnnotation);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy