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

dataflow.src.org.checkerframework.dataflow.analysis.AnalysisResult 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.dataflow.analysis;

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

import org.checkerframework.dataflow.cfg.block.Block;
import org.checkerframework.dataflow.cfg.block.ExceptionBlock;
import org.checkerframework.dataflow.cfg.block.RegularBlock;
import org.checkerframework.dataflow.cfg.node.Node;

import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.Map;
import java.util.Map.Entry;

import javax.lang.model.element.Element;

import com.sun.source.tree.Tree;

/**
 * An {@link AnalysisResult} represents the result of a org.checkerframework.dataflow analysis by
 * providing the abstract values given a node or a tree. Note that it does not
 * keep track of custom results computed by some analysis.
 *
 * @author Stefan Heule
 *
 * @param 
 *            type of the abstract value that is tracked.
 */
public class AnalysisResult, S extends Store> {

    /** Abstract values of nodes. */
    protected final IdentityHashMap nodeValues;

    /** Map from AST {@link Tree}s to {@link Node}s. */
    protected final IdentityHashMap treeLookup;

    /** Map from (effectively final) local variable elements to their abstract value. */
    protected final HashMap finalLocalValues;

    /**
     * The stores before every method call.
     */
    protected final IdentityHashMap> stores;

    /**
     * Initialize with a given node-value mapping.
     */
    public AnalysisResult(Map nodeValues,
            IdentityHashMap> stores,
            IdentityHashMap treeLookup, HashMap finalLocalValues) {
        this.nodeValues = new IdentityHashMap<>(nodeValues);
        this.treeLookup = new IdentityHashMap<>(treeLookup);
        this.stores = stores;
        this.finalLocalValues = finalLocalValues;
    }

    /**
     * Initialize empty result.
     */
    public AnalysisResult() {
        nodeValues = new IdentityHashMap<>();
        treeLookup = new IdentityHashMap<>();
        stores = new IdentityHashMap<>();
        finalLocalValues = new HashMap<>();
    }

    /**
     * Combine with another analysis result.
     */
    public void combine(AnalysisResult other) {
        for (Entry e : other.nodeValues.entrySet()) {
            nodeValues.put(e.getKey(), e.getValue());
        }
        for (Entry e : other.treeLookup.entrySet()) {
            treeLookup.put(e.getKey(), e.getValue());
        }
        for (Entry> e : other.stores.entrySet()) {
            stores.put(e.getKey(), e.getValue());
        }
        for (Entry e : other.finalLocalValues.entrySet()) {
            finalLocalValues.put(e.getKey(), e.getValue());
        }
    }

    /**
     * @return the value of effectively final local variables
     */
    public HashMap getFinalLocalValues() {
        return finalLocalValues;
    }

    /**
     * @return the abstract value for {@link Node} {@code n}, or {@code null} if
     *         no information is available.
     */
    public /*@Nullable*/ A getValue(Node n) {
        return nodeValues.get(n);
    }

    /**
     * @return the abstract value for {@link Tree} {@code t}, or {@code null} if
     *         no information is available.
     */
    public /*@Nullable*/ A getValue(Tree t) {
        A val = getValue(treeLookup.get(t));
        return val;
    }

    /**
     * @return the {@link Node} for a given {@link Tree}.
     */
    public /*@Nullable*/ Node getNodeForTree(Tree tree) {
        return treeLookup.get(tree);
    }

    /**
     * @return the store immediately before a given {@link Tree}.
     */
    public S getStoreBefore(Tree tree) {
        Node node = getNodeForTree(tree);
        if (node == null) {
            return null;
        }
        return getStoreBefore(node);
    }

    /**
     * @return the store immediately before a given {@link Node}.
     */
    public S getStoreBefore(Node node) {
        return runAnalysisFor(node, true);
    }

    /**
     * @return the store immediately after a given {@link Tree}.
     */
    public S getStoreAfter(Tree tree) {
        Node node = getNodeForTree(tree);
        if (node == null) {
            return null;
        }
        return runAnalysisFor(node, false);
    }

    /**
     * Runs the analysis again within the block of {@code node} and returns the
     * store at the location of {@code node}. If {@code before} is true, then
     * the store immediately before the {@link Node} {@code node} is returned.
     * Otherwise, the store after {@code node} is returned.
     *
     * 

* If the given {@link Node} cannot be reached (in the control flow graph), * then {@code null} is returned. */ protected S runAnalysisFor(Node node, boolean before) { Block block = node.getBlock(); TransferInput transferInput = stores.get(block); if (transferInput == null) { return null; } return runAnalysisFor(node, before, transferInput); } /** * Runs the analysis again within the block of {@code node} and returns the * store at the location of {@code node}. If {@code before} is true, then * the store immediately before the {@link Node} {@code node} is returned. * Otherwise, the store after {@code node} is returned. */ public static , S extends Store> S runAnalysisFor( Node node, boolean before, TransferInput transferInput) { assert node != null; Block block = node.getBlock(); assert transferInput != null; Analysis analysis = transferInput.analysis; Node oldCurrentNode = analysis.currentNode; if (analysis.isRunning) { return analysis.currentInput.getRegularStore(); } analysis.isRunning = true; try { switch (block.getType()) { case REGULAR_BLOCK: { RegularBlock rb = (RegularBlock) block; // Apply transfer function to contents until we found the node // we // are looking for. TransferInput store = transferInput; TransferResult transferResult = null; for (Node n : rb.getContents()) { analysis.currentNode = n; if (n == node && before) { return store.getRegularStore(); } transferResult = analysis.callTransferFunction(n, store); if (n == node) { return transferResult.getRegularStore(); } store = new TransferInput<>(n, analysis, transferResult); } // This point should never be reached. If the block of 'node' is // 'block', then 'node' must be part of the contents of 'block'. assert false; return null; } case EXCEPTION_BLOCK: { ExceptionBlock eb = (ExceptionBlock) block; // apply transfer function to content assert eb.getNode() == node; if (before) { return transferInput.getRegularStore(); } analysis.currentNode = node; TransferResult transferResult = analysis .callTransferFunction(node, transferInput); return transferResult.getRegularStore(); } default: // Only regular blocks and exceptional blocks can hold nodes. assert false; break; } return null; } finally { analysis.currentNode = oldCurrentNode; analysis.isRunning = false; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy