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

org.checkerframework.framework.flow.CFCFGBuilder 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-eisop4
Show newest version
package org.checkerframework.framework.flow;

import com.sun.source.tree.AssertTree;
import com.sun.source.tree.CompilationUnitTree;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.MethodInvocationTree;
import com.sun.source.tree.Tree;
import com.sun.source.tree.VariableTree;
import com.sun.source.util.TreePath;

import org.checkerframework.common.basetype.BaseTypeChecker;
import org.checkerframework.dataflow.cfg.ControlFlowGraph;
import org.checkerframework.dataflow.cfg.UnderlyingAST;
import org.checkerframework.dataflow.cfg.builder.CFGBuilder;
import org.checkerframework.dataflow.cfg.builder.CFGTranslationPhaseOne;
import org.checkerframework.dataflow.cfg.builder.CFGTranslationPhaseThree;
import org.checkerframework.dataflow.cfg.builder.CFGTranslationPhaseTwo;
import org.checkerframework.dataflow.cfg.builder.PhaseOneResult;
import org.checkerframework.framework.type.AnnotatedTypeFactory;
import org.checkerframework.framework.type.AnnotatedTypeMirror;
import org.checkerframework.framework.type.GenericAnnotatedTypeFactory;
import org.checkerframework.javacutil.ElementUtils;
import org.checkerframework.javacutil.TreeUtils;
import org.checkerframework.javacutil.UserError;

import java.util.Collection;

import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.Element;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.ArrayType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;

/**
 * A control-flow graph builder (see {@link CFGBuilder}) that knows about the Checker Framework
 * annotations and their representation as {@link AnnotatedTypeMirror}s.
 */
public class CFCFGBuilder extends CFGBuilder {
    /** This class should never be instantiated. Protected to still allow subclasses. */
    protected CFCFGBuilder() {}

    /** Build the control flow graph of some code. */
    public static ControlFlowGraph build(
            CompilationUnitTree root,
            UnderlyingAST underlyingAST,
            BaseTypeChecker checker,
            AnnotatedTypeFactory atypeFactory,
            ProcessingEnvironment env) {
        boolean assumeAssertionsEnabled = checker.hasOption("assumeAssertionsAreEnabled");
        boolean assumeAssertionsDisabled = checker.hasOption("assumeAssertionsAreDisabled");
        if (assumeAssertionsEnabled && assumeAssertionsDisabled) {
            throw new UserError(
                    "Assertions cannot be assumed to be enabled and disabled at the same time.");
        }

        // Subcheckers with dataflow share control-flow graph structure to
        // allow a super-checker to query the stores of a subchecker.
        if (atypeFactory instanceof GenericAnnotatedTypeFactory) {
            GenericAnnotatedTypeFactory asGATF =
                    (GenericAnnotatedTypeFactory) atypeFactory;
            if (asGATF.hasOrIsSubchecker) {
                ControlFlowGraph sharedCFG = asGATF.getSharedCFGForTree(underlyingAST.getCode());
                if (sharedCFG != null) {
                    return sharedCFG;
                }
            }
        }

        CFTreeBuilder builder = new CFTreeBuilder(env);
        PhaseOneResult phase1result =
                new CFCFGTranslationPhaseOne(
                                builder,
                                checker,
                                atypeFactory,
                                assumeAssertionsEnabled,
                                assumeAssertionsDisabled,
                                env)
                        .process(root, underlyingAST);
        ControlFlowGraph phase2result = CFGTranslationPhaseTwo.process(phase1result);
        ControlFlowGraph phase3result = CFGTranslationPhaseThree.process(phase2result);
        if (atypeFactory instanceof GenericAnnotatedTypeFactory) {
            GenericAnnotatedTypeFactory asGATF =
                    (GenericAnnotatedTypeFactory) atypeFactory;
            if (asGATF.hasOrIsSubchecker) {
                asGATF.addSharedCFGForTree(underlyingAST.getCode(), phase3result);
            }
        }
        return phase3result;
    }

    /**
     * Given a SourceChecker and an AssertTree, returns whether the AssertTree uses
     * an @AssumeAssertion string that is relevant to the SourceChecker.
     *
     * @param checker the checker
     * @param tree an assert tree
     * @return true if the assert tree contains an @AssumeAssertion(checker) message string for any
     *     subchecker of the given checker's ultimate parent checker
     */
    public static boolean assumeAssertionsActivatedForAssertTree(
            BaseTypeChecker checker, AssertTree tree) {
        ExpressionTree detail = tree.getDetail();
        if (detail != null) {
            String msg = detail.toString();
            BaseTypeChecker ultimateParent = checker.getUltimateParentChecker();
            Collection prefixes = ultimateParent.getSuppressWarningsPrefixesOfSubcheckers();
            for (String prefix : prefixes) {
                String assumeAssert = "@AssumeAssertion(" + prefix + ")";
                if (msg.contains(assumeAssert)) {
                    return true;
                }
            }
        }

        return false;
    }

    /**
     * A specialized phase-one CFG builder, with a few modifications that make use of the type
     * factory. It is responsible for: 1) translating foreach loops so that the declarations of
     * their iteration variables have the right annotations, 2) registering the containing elements
     * of artificial trees with the relevant type factories, and 3) generating appropriate assertion
     * CFG structure in the presence of @AssumeAssertion assertion strings which mention the checker
     * or its supercheckers.
     */
    protected static class CFCFGTranslationPhaseOne extends CFGTranslationPhaseOne {
        /** The associated checker. */
        protected final BaseTypeChecker checker;

        /** Type factory to provide types used during CFG building. */
        protected final AnnotatedTypeFactory atypeFactory;

        public CFCFGTranslationPhaseOne(
                CFTreeBuilder builder,
                BaseTypeChecker checker,
                AnnotatedTypeFactory atypeFactory,
                boolean assumeAssertionsEnabled,
                boolean assumeAssertionsDisabled,
                ProcessingEnvironment env) {
            super(builder, atypeFactory, assumeAssertionsEnabled, assumeAssertionsDisabled, env);
            this.checker = checker;
            this.atypeFactory = atypeFactory;
        }

        @Override
        protected boolean assumeAssertionsEnabledFor(AssertTree tree) {
            if (assumeAssertionsActivatedForAssertTree(checker, tree)) {
                return true;
            }
            return super.assumeAssertionsEnabledFor(tree);
        }

        /**
         * {@inheritDoc}
         *
         * 

Assigns a path to the artificial tree. * * @param tree the newly created Tree */ @Override public void handleArtificialTree(Tree tree) { // Create a new child of the current path and assign to the artificial tree. // Although intuitively, using the sibling of the current path as the artificial tree // path makes more sense, it has the risk of improperly changing the defaulting scope // of the artificial tree. TreePath artificialPath = new TreePath(getCurrentPath(), tree); atypeFactory.setPathForArtificialTree(tree, artificialPath); } @Override protected VariableTree createEnhancedForLoopIteratorVariable( MethodInvocationTree iteratorCall, VariableElement variableElement) { Tree annotatedIteratorTypeTree = ((CFTreeBuilder) treeBuilder) .buildAnnotatedType(TreeUtils.typeOf(iteratorCall)); handleArtificialTree(annotatedIteratorTypeTree); // Declare and initialize a new, unique iterator variable VariableTree iteratorVariable = treeBuilder.buildVariableDecl( annotatedIteratorTypeTree, uniqueName("iter"), variableElement.getEnclosingElement(), iteratorCall); return iteratorVariable; } @Override protected VariableTree createEnhancedForLoopArrayVariable( ExpressionTree expression, VariableElement variableElement) { TypeMirror type = null; if (TreeUtils.isLocalVariable(expression)) { // It is necessary to get the elt because just getting the type of expression // directly (via TreeUtils.typeOf) doesn't include annotations on the declarations // of local variables, for some reason. Element elt = TreeUtils.elementFromTree(expression); if (elt != null) { type = ElementUtils.getType(elt); } } // In all other cases, instead get the type of the expression. This case is // also triggered when the type from the element is not an array, which can occur // if the declaration of the local is a generic, such as in // framework/tests/all-systems/java8inference/Issue1775.java. // Getting the type from the expression itself guarantees the result will be an array. if (type == null || type.getKind() != TypeKind.ARRAY) { TypeMirror expressionType = TreeUtils.typeOf(expression); type = expressionType; } assert (type instanceof ArrayType) : "array types must be represented by ArrayType"; Tree annotatedArrayTypeTree = ((CFTreeBuilder) treeBuilder).buildAnnotatedType(type); handleArtificialTree(annotatedArrayTypeTree); // Declare and initialize a temporary array variable VariableTree arrayVariable = treeBuilder.buildVariableDecl( annotatedArrayTypeTree, uniqueName("array"), variableElement.getEnclosingElement(), expression); return arrayVariable; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy