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

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

import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;

import org.checkerframework.framework.qual.ConditionalPostconditionAnnotation;
import org.checkerframework.framework.qual.EnsuresQualifier;
import org.checkerframework.framework.qual.EnsuresQualifierIf;
import org.checkerframework.framework.qual.EnsuresQualifiers;
import org.checkerframework.framework.qual.EnsuresQualifiersIf;
import org.checkerframework.framework.qual.PostconditionAnnotation;
import org.checkerframework.framework.qual.PreconditionAnnotation;
import org.checkerframework.framework.qual.RequiresQualifier;
import org.checkerframework.framework.qual.RequiresQualifiers;
import org.checkerframework.framework.type.GenericAnnotatedTypeFactory;
import org.checkerframework.javacutil.AnnotationUtils;
import org.checkerframework.javacutil.Pair;

/**
 * A utility class to handle pre- and postconditions.
 *
 * @see PreconditionAnnotation
 * @see RequiresQualifier
 * @see PostconditionAnnotation
 * @see EnsuresQualifier
 * @see EnsuresQualifierIf
 * @author Stefan Heule
 */
public class ContractsUtils {

    protected static ContractsUtils instance;
    protected GenericAnnotatedTypeFactory factory;

    /**
     * Returns an instance of the {@link ContractsUtils} class.
     */
    public static ContractsUtils getInstance(
            GenericAnnotatedTypeFactory factory) {
        if (instance == null || instance.factory != factory) {
            instance = new ContractsUtils(factory);
        }
        return instance;
    }

    /**
     * Returns a set of pairs {@code (expr, annotation)} of preconditions on the
     * element {@code element}.
     */
    public Set> getPreconditions(
            Element element) {
        Set> result = new HashSet<>();
        // Check for a single contract.
        AnnotationMirror requiresAnnotation = factory.getDeclAnnotation(
                element, RequiresQualifier.class);
        result.addAll(getPrecondition(requiresAnnotation));

        // Check for multiple contracts.
        AnnotationMirror requiresAnnotations = factory.getDeclAnnotation(
                element, RequiresQualifiers.class);
        if (requiresAnnotations != null) {
            List annotations = AnnotationUtils
                    .getElementValueArray(requiresAnnotations, "value", AnnotationMirror.class, false);
            for (AnnotationMirror a : annotations) {
                result.addAll(getPrecondition(a));
            }
        }

        // Check type-system specific annotations.
        Class metaAnnotation = PreconditionAnnotation.class;
        List> declAnnotations = factory
                .getDeclAnnotationWithMetaAnnotation(element,
                        metaAnnotation);
        for (Pair r : declAnnotations) {
            AnnotationMirror anno = r.first;
            AnnotationMirror metaAnno = r.second;
            List expressions = AnnotationUtils.getElementValueArray(anno,
                    "value", String.class, false);
            String annotationString = AnnotationUtils.getElementValueClassName(
                    metaAnno, "qualifier", false).toString();
            for (String expr : expressions) {
                result.add(Pair.of(expr, annotationString));
            }
        }
        return result;
    }

    /**
     * Returns a set of pairs {@code (expr, annotation)} of preconditions
     * according to the given {@link RequiresQualifier}.
     */
    private Set> getPrecondition(
            AnnotationMirror requiresAnnotation) {
        if (requiresAnnotation == null) {
            return Collections.emptySet();
        }
        Set> result = new HashSet<>();
        List expressions = AnnotationUtils.getElementValueArray(
                requiresAnnotation, "expression", String.class, false);
        String annotation = AnnotationUtils.getElementValueClassName(
                requiresAnnotation, "qualifier", false).toString();
        for (String expr : expressions) {
            result.add(Pair.of(expr, annotation));
        }
        return result;
    }

    /**
     * Returns a set of pairs {@code (expr, annotation)} of postconditions on
     * the method {@code methodElement}.
     */
    public Set> getPostconditions(
            ExecutableElement methodElement) {
        Set> result = new HashSet<>();
        // Check for a single contract.
        AnnotationMirror ensuresAnnotation = factory.getDeclAnnotation(
                methodElement, EnsuresQualifier.class);
        result.addAll(getPostcondition(ensuresAnnotation));

        // Check for multiple contracts.
        AnnotationMirror ensuresAnnotations = factory.getDeclAnnotation(
                methodElement, EnsuresQualifiers.class);
        if (ensuresAnnotations != null) {
            List annotations = AnnotationUtils
                    .getElementValueArray(ensuresAnnotations, "value", AnnotationMirror.class, false);
            for (AnnotationMirror a : annotations) {
                result.addAll(getPostcondition(a));
            }
        }

        // Check type-system specific annotations.
        Class metaAnnotation = PostconditionAnnotation.class;
        List> declAnnotations = factory
                .getDeclAnnotationWithMetaAnnotation(methodElement,
                        metaAnnotation);
        for (Pair r : declAnnotations) {
            AnnotationMirror anno = r.first;
            AnnotationMirror metaAnno = r.second;
            List expressions = AnnotationUtils.getElementValueArray(anno,
                    "value", String.class, false);
            String annotationString = AnnotationUtils.getElementValueClassName(
                    metaAnno, "qualifier", false).toString();
            for (String expr : expressions) {
                result.add(Pair.of(expr, annotationString));
            }
        }
        return result;
    }

    /**
     * Returns a set of pairs {@code (expr, annotation)} of postconditions
     * according to the given {@link EnsuresQualifier}.
     */
    private Set> getPostcondition(
            AnnotationMirror ensuresAnnotation) {
        if (ensuresAnnotation == null) {
            return Collections.emptySet();
        }
        Set> result = new HashSet<>();
        List expressions = AnnotationUtils.getElementValueArray(
                ensuresAnnotation, "expression", String.class, false);
        String annotation = AnnotationUtils.getElementValueClassName(
                ensuresAnnotation, "qualifier", false).toString();
        for (String expr : expressions) {
            result.add(Pair.of(expr, annotation));
        }
        return result;
    }

    /**
     * Returns a set of triples {@code (expr, (result, annotation))} of
     * conditional postconditions on the method {@code methodElement}.
     */
    public Set>> getConditionalPostconditions(
            ExecutableElement methodElement) {
        Set>> result = new HashSet<>();
        // Check for a single contract.
        AnnotationMirror ensuresAnnotationIf = factory.getDeclAnnotation(
                methodElement, EnsuresQualifierIf.class);
        result.addAll(getConditionalPostcondition(ensuresAnnotationIf));

        // Check for multiple contracts.
        AnnotationMirror ensuresAnnotationsIf = factory.getDeclAnnotation(
                methodElement, EnsuresQualifiersIf.class);
        if (ensuresAnnotationsIf != null) {
            List annotations = AnnotationUtils
                    .getElementValueArray(ensuresAnnotationsIf, "value", AnnotationMirror.class, false);
            for (AnnotationMirror a : annotations) {
                result.addAll(getConditionalPostcondition(a));
            }
        }

        // Check type-system specific annotations.
        Class metaAnnotation = ConditionalPostconditionAnnotation.class;
        List> declAnnotations = factory
                .getDeclAnnotationWithMetaAnnotation(methodElement,
                        metaAnnotation);
        for (Pair r : declAnnotations) {
            AnnotationMirror anno = r.first;
            AnnotationMirror metaAnno = r.second;
            List expressions = AnnotationUtils.getElementValueArray(anno,
                    "expression", String.class, false);
            String annotationString = AnnotationUtils.getElementValueClassName(
                    metaAnno, "qualifier", false).toString();
            boolean annoResult = AnnotationUtils.getElementValue(anno,
                    "result", Boolean.class, false);
            for (String expr : expressions) {
                result.add(Pair.of(expr, Pair.of(annoResult, annotationString)));
            }
        }
        return result;
    }

    /**
     * Returns a set of triples {@code (expr, (result, annotation))} of
     * conditional postconditions according to the given
     * {@link EnsuresQualifierIf}.
     */
    private Set>> getConditionalPostcondition(
            AnnotationMirror ensuresAnnotationIf) {
        if (ensuresAnnotationIf == null) {
            return Collections.emptySet();
        }
        Set>> result = new HashSet<>();
        List expressions = AnnotationUtils.getElementValueArray(
                ensuresAnnotationIf, "expression", String.class, false);
        String annotation = AnnotationUtils.getElementValueClassName(
                ensuresAnnotationIf, "qualifier", false).toString();
        boolean annoResult = AnnotationUtils.getElementValue(ensuresAnnotationIf,
                "result", Boolean.class, false);
        for (String expr : expressions) {
            result.add(Pair.of(expr, Pair.of(annoResult, annotation)));
        }
        return result;
    }

    // private constructor
    private ContractsUtils(GenericAnnotatedTypeFactory factory) {
        this.factory = factory;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy