aboutsummaryrefslogtreecommitdiffhomepage
path: root/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/DOTCFGVisualizer.java
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/DOTCFGVisualizer.java')
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/DOTCFGVisualizer.java511
1 files changed, 0 insertions, 511 deletions
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/DOTCFGVisualizer.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/DOTCFGVisualizer.java
deleted file mode 100644
index 1eb1cb87a2..0000000000
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/DOTCFGVisualizer.java
+++ /dev/null
@@ -1,511 +0,0 @@
-package org.checkerframework.dataflow.cfg;
-
-/*>>>
-import org.checkerframework.checker.nullness.qual.Nullable;
-*/
-
-import com.sun.tools.javac.tree.JCTree;
-import java.io.BufferedWriter;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.IdentityHashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Queue;
-import java.util.Set;
-import javax.lang.model.type.TypeMirror;
-import org.checkerframework.dataflow.analysis.AbstractValue;
-import org.checkerframework.dataflow.analysis.Analysis;
-import org.checkerframework.dataflow.analysis.FlowExpressions;
-import org.checkerframework.dataflow.analysis.Store;
-import org.checkerframework.dataflow.analysis.TransferFunction;
-import org.checkerframework.dataflow.analysis.TransferInput;
-import org.checkerframework.dataflow.cfg.UnderlyingAST.CFGMethod;
-import org.checkerframework.dataflow.cfg.UnderlyingAST.CFGStatement;
-import org.checkerframework.dataflow.cfg.block.Block;
-import org.checkerframework.dataflow.cfg.block.Block.BlockType;
-import org.checkerframework.dataflow.cfg.block.ConditionalBlock;
-import org.checkerframework.dataflow.cfg.block.ExceptionBlock;
-import org.checkerframework.dataflow.cfg.block.RegularBlock;
-import org.checkerframework.dataflow.cfg.block.SingleSuccessorBlock;
-import org.checkerframework.dataflow.cfg.block.SpecialBlock;
-import org.checkerframework.dataflow.cfg.node.Node;
-import org.checkerframework.javacutil.ErrorReporter;
-
-/**
- * Generate a graph description in the DOT language of a control graph.
- *
- * @author Stefan Heule
- */
-public class DOTCFGVisualizer<
- A extends AbstractValue<A>, S extends Store<S>, T extends TransferFunction<A, S>>
- implements CFGVisualizer<A, S, T> {
-
- protected String outdir;
- protected boolean verbose;
- protected String checkerName;
-
- protected StringBuilder sbDigraph;
- protected StringBuilder sbStore;
- protected StringBuilder sbBlock;
-
- /** Mapping from class/method representation to generated dot file. */
- protected Map<String, String> generated;
-
- @Override
- public void init(Map<String, Object> args) {
- this.outdir = (String) args.get("outdir");
- {
- Object verb = args.get("verbose");
- this.verbose =
- verb == null
- ? false
- : verb instanceof String
- ? Boolean.getBoolean((String) verb)
- : (boolean) verb;
- }
- this.checkerName = (String) args.get("checkerName");
-
- this.generated = new HashMap<>();
-
- this.sbDigraph = new StringBuilder();
-
- this.sbStore = new StringBuilder();
-
- this.sbBlock = new StringBuilder();
- }
-
- /** {@inheritDoc} */
- @Override
- public /*@Nullable*/ Map<String, Object> visualize(
- ControlFlowGraph cfg, Block entry, /*@Nullable*/ Analysis<A, S, T> analysis) {
-
- String dotgraph = generateDotGraph(cfg, entry, analysis);
-
- String dotfilename = dotOutputFileName(cfg.underlyingAST);
- // System.err.println("Output to DOT file: " + dotfilename);
-
- try {
- FileWriter fstream = new FileWriter(dotfilename);
- BufferedWriter out = new BufferedWriter(fstream);
- out.write(dotgraph);
- out.close();
- } catch (IOException e) {
- ErrorReporter.errorAbort(
- "Error creating dot file: " + dotfilename + "; ensure the path is valid", e);
- }
-
- Map<String, Object> res = new HashMap<>();
- res.put("dotFileName", dotfilename);
-
- return res;
- }
-
- /** Generate the dot representation as String. */
- protected String generateDotGraph(
- ControlFlowGraph cfg, Block entry, /*@Nullable*/ Analysis<A, S, T> analysis) {
- this.sbDigraph.setLength(0);
- Set<Block> visited = new HashSet<>();
-
- // header
- this.sbDigraph.append("digraph {\n");
-
- Block cur = entry;
- Queue<Block> worklist = new LinkedList<>();
- visited.add(entry);
- // traverse control flow graph and define all arrows
- while (true) {
- if (cur == null) {
- break;
- }
-
- if (cur.getType() == BlockType.CONDITIONAL_BLOCK) {
- ConditionalBlock ccur = ((ConditionalBlock) cur);
- Block thenSuccessor = ccur.getThenSuccessor();
- addDotEdge(ccur.getId(), thenSuccessor.getId(), "then\\n" + ccur.getThenFlowRule());
- if (!visited.contains(thenSuccessor)) {
- visited.add(thenSuccessor);
- worklist.add(thenSuccessor);
- }
- Block elseSuccessor = ccur.getElseSuccessor();
- addDotEdge(ccur.getId(), elseSuccessor.getId(), "else\\n" + ccur.getElseFlowRule());
- if (!visited.contains(elseSuccessor)) {
- visited.add(elseSuccessor);
- worklist.add(elseSuccessor);
- }
- } else {
- assert cur instanceof SingleSuccessorBlock;
- Block b = ((SingleSuccessorBlock) cur).getSuccessor();
- if (b != null) {
- addDotEdge(
- cur.getId(),
- b.getId(),
- ((SingleSuccessorBlock) cur).getFlowRule().name());
- if (!visited.contains(b)) {
- visited.add(b);
- worklist.add(b);
- }
- }
- }
-
- // exceptional edges
- if (cur.getType() == BlockType.EXCEPTION_BLOCK) {
- ExceptionBlock ecur = (ExceptionBlock) cur;
- for (Entry<TypeMirror, Set<Block>> e : ecur.getExceptionalSuccessors().entrySet()) {
- Set<Block> blocks = e.getValue();
- TypeMirror cause = e.getKey();
- String exception = cause.toString();
- if (exception.startsWith("java.lang.")) {
- exception = exception.replace("java.lang.", "");
- }
-
- for (Block b : blocks) {
- addDotEdge(cur.getId(), b.getId(), exception);
- if (!visited.contains(b)) {
- visited.add(b);
- worklist.add(b);
- }
- }
- }
- }
-
- cur = worklist.poll();
- }
-
- generateDotNodes(visited, cfg, analysis);
-
- // footer
- this.sbDigraph.append("}\n");
-
- return this.sbDigraph.toString();
- }
-
- protected void generateDotNodes(
- Set<Block> visited, ControlFlowGraph cfg, /*@Nullable*/ Analysis<A, S, T> analysis) {
- IdentityHashMap<Block, List<Integer>> processOrder = getProcessOrder(cfg);
- this.sbDigraph.append(" node [shape=rectangle];\n\n");
- // definition of all nodes including their labels
- for (Block v : visited) {
- this.sbDigraph.append(" " + v.getId() + " [");
- if (v.getType() == BlockType.CONDITIONAL_BLOCK) {
- this.sbDigraph.append("shape=polygon sides=8 ");
- } else if (v.getType() == BlockType.SPECIAL_BLOCK) {
- this.sbDigraph.append("shape=oval ");
- }
- this.sbDigraph.append("label=\"");
- if (verbose) {
- this.sbDigraph.append(
- "Process order: "
- + processOrder.get(v).toString().replaceAll("[\\[\\]]", "")
- + "\\n");
- }
- visualizeBlock(v, analysis);
- }
-
- this.sbDigraph.append("\n");
- }
-
- /** @return the file name used for DOT output. */
- protected String dotOutputFileName(UnderlyingAST ast) {
- StringBuilder srcloc = new StringBuilder();
-
- StringBuilder outfile = new StringBuilder(outdir);
- outfile.append('/');
- if (ast.getKind() == UnderlyingAST.Kind.ARBITRARY_CODE) {
- CFGStatement cfgs = (CFGStatement) ast;
- String clsname = cfgs.getClassTree().getSimpleName().toString();
- outfile.append(clsname);
- outfile.append("-initializer-");
- outfile.append(ast.hashCode());
-
- srcloc.append('<');
- srcloc.append(clsname);
- srcloc.append("::initializer::");
- srcloc.append(((JCTree) cfgs.getCode()).pos);
- srcloc.append('>');
- } else if (ast.getKind() == UnderlyingAST.Kind.METHOD) {
- CFGMethod cfgm = (CFGMethod) ast;
- String clsname = cfgm.getClassTree().getSimpleName().toString();
- String methname = cfgm.getMethod().getName().toString();
- outfile.append(clsname);
- outfile.append('-');
- outfile.append(methname);
-
- srcloc.append('<');
- srcloc.append(clsname);
- srcloc.append("::");
- srcloc.append(methname);
- srcloc.append('(');
- srcloc.append(cfgm.getMethod().getParameters());
- srcloc.append(")::");
- srcloc.append(((JCTree) cfgm.getMethod()).pos);
- srcloc.append('>');
- } else {
- ErrorReporter.errorAbort(
- "Unexpected AST kind: " + ast.getKind() + " value: " + ast.toString());
- return null;
- }
- outfile.append('-');
- outfile.append(checkerName);
- outfile.append(".dot");
-
- // make path safe for Windows
- String out = outfile.toString().replace("<", "_").replace(">", "");
-
- generated.put(srcloc.toString(), out);
-
- return out;
- }
-
- protected IdentityHashMap<Block, List<Integer>> getProcessOrder(ControlFlowGraph cfg) {
- IdentityHashMap<Block, List<Integer>> depthFirstOrder = new IdentityHashMap<>();
- int count = 1;
- for (Block b : cfg.getDepthFirstOrderedBlocks()) {
- if (depthFirstOrder.get(b) == null) {
- depthFirstOrder.put(b, new ArrayList<Integer>());
- }
- depthFirstOrder.get(b).add(count++);
- }
- return depthFirstOrder;
- }
-
- /**
- * Produce a representation of the contests of a basic block.
- *
- * @param bb basic block to visualize
- */
- @Override
- public void visualizeBlock(Block bb, /*@Nullable*/ Analysis<A, S, T> analysis) {
-
- this.sbBlock.setLength(0);
-
- // loop over contents
- List<Node> contents = new LinkedList<>();
- switch (bb.getType()) {
- case REGULAR_BLOCK:
- contents.addAll(((RegularBlock) bb).getContents());
- break;
- case EXCEPTION_BLOCK:
- contents.add(((ExceptionBlock) bb).getNode());
- break;
- case CONDITIONAL_BLOCK:
- break;
- case SPECIAL_BLOCK:
- break;
- default:
- assert false : "All types of basic blocks covered";
- }
- boolean notFirst = false;
- for (Node t : contents) {
- if (notFirst) {
- this.sbBlock.append("\\n");
- }
- notFirst = true;
- visualizeBlockNode(t, analysis);
- }
-
- // handle case where no contents are present
- boolean centered = false;
- if (this.sbBlock.length() == 0) {
- centered = true;
- if (bb.getType() == BlockType.SPECIAL_BLOCK) {
- visualizeSpecialBlock((SpecialBlock) bb);
- } else if (bb.getType() == BlockType.CONDITIONAL_BLOCK) {
- this.sbDigraph.append(" \",];\n");
- return;
- } else {
- this.sbDigraph.append("?? empty ?? \",];\n");
- return;
- }
- }
-
- // visualize transfer input if necessary
- if (analysis != null) {
- visualizeBlockTransferInput(bb, analysis);
- }
-
- this.sbDigraph.append(
- (this.sbBlock.toString() + (centered ? "" : "\\n")).replace("\\n", "\\l")
- + " \",];\n");
- }
-
- @Override
- public void visualizeSpecialBlock(SpecialBlock sbb) {
- switch (sbb.getSpecialType()) {
- case ENTRY:
- this.sbBlock.append("<entry>");
- break;
- case EXIT:
- this.sbBlock.append("<exit>");
- break;
- case EXCEPTIONAL_EXIT:
- this.sbBlock.append("<exceptional-exit>");
- break;
- }
- }
-
- @Override
- public void visualizeBlockTransferInput(Block bb, Analysis<A, S, T> analysis) {
- assert analysis != null
- : "analysis should be non-null when visualizing the transfer input of a block.";
-
- TransferInput<A, S> input = analysis.getInput(bb);
- this.sbStore.setLength(0);
-
- // split input representation to two lines
- this.sbStore.append("Before:");
- S thenStore = input.getThenStore();
- if (!input.containsTwoStores()) {
- S regularStore = input.getRegularStore();
- this.sbStore.append('[');
- visualizeStore(regularStore);
- this.sbStore.append(']');
- } else {
- S elseStore = input.getElseStore();
- this.sbStore.append("[then=");
- visualizeStore(thenStore);
- this.sbStore.append(", else=");
- visualizeStore(elseStore);
- this.sbStore.append("]");
- }
- // separator
- this.sbStore.append("\\n~~~~~~~~~\\n");
-
- // the transfer input before this block is added before the block content
- this.sbBlock.insert(0, this.sbStore);
-
- if (verbose) {
- Node lastNode;
- switch (bb.getType()) {
- case REGULAR_BLOCK:
- List<Node> blockContents = ((RegularBlock) bb).getContents();
- lastNode = blockContents.get(blockContents.size() - 1);
- break;
- case EXCEPTION_BLOCK:
- lastNode = ((ExceptionBlock) bb).getNode();
- break;
- default:
- lastNode = null;
- }
- if (lastNode != null) {
- this.sbStore.setLength(0);
- this.sbStore.append("\\n~~~~~~~~~\\n");
- this.sbStore.append("After:");
- visualizeStore(analysis.getResult().getStoreAfter(lastNode));
- this.sbBlock.append(this.sbStore);
- }
- }
- }
-
- @Override
- public void visualizeBlockNode(Node t, /*@Nullable*/ Analysis<A, S, T> analysis) {
- this.sbBlock.append(prepareString(t.toString()) + " [ " + prepareNodeType(t) + " ]");
- if (analysis != null) {
- A value = analysis.getValue(t);
- if (value != null) {
- this.sbBlock.append(" > " + prepareString(value.toString()));
- }
- }
- }
-
- protected String prepareNodeType(Node t) {
- String name = t.getClass().getSimpleName();
- return name.replace("Node", "");
- }
-
- protected String prepareString(String s) {
- return s.replace("\"", "\\\"");
- }
-
- protected void addDotEdge(long sId, long eId, String labelContent) {
- this.sbDigraph.append(" " + sId + " -> " + eId + " [label=\"" + labelContent + "\"];\n");
- }
-
- @Override
- public void visualizeStore(S store) {
- store.visualize(this);
- }
-
- @Override
- public void visualizeStoreThisVal(A value) {
- this.sbStore.append(" this > " + value + "\\n");
- }
-
- @Override
- public void visualizeStoreLocalVar(FlowExpressions.LocalVariable localVar, A value) {
- this.sbStore.append(" " + localVar + " > " + toStringEscapeDoubleQuotes(value) + "\\n");
- }
-
- @Override
- public void visualizeStoreFieldVals(FlowExpressions.FieldAccess fieldAccess, A value) {
- this.sbStore.append(" " + fieldAccess + " > " + toStringEscapeDoubleQuotes(value) + "\\n");
- }
-
- @Override
- public void visualizeStoreArrayVal(FlowExpressions.ArrayAccess arrayValue, A value) {
- this.sbStore.append(" " + arrayValue + " > " + toStringEscapeDoubleQuotes(value) + "\\n");
- }
-
- @Override
- public void visualizeStoreMethodVals(FlowExpressions.MethodCall methodCall, A value) {
- this.sbStore.append(
- " " + methodCall.toString().replace("\"", "\\\"") + " > " + value + "\\n");
- }
-
- @Override
- public void visualizeStoreClassVals(FlowExpressions.ClassName className, A value) {
- this.sbStore.append(" " + className + " > " + toStringEscapeDoubleQuotes(value) + "\\n");
- }
-
- @Override
- public void visualizeStoreKeyVal(String keyName, Object value) {
- this.sbStore.append(" " + keyName + " = " + value + "\\n");
- }
-
- protected String escapeDoubleQuotes(final String str) {
- return str.replace("\"", "\\\"");
- }
-
- protected String toStringEscapeDoubleQuotes(final Object obj) {
- return escapeDoubleQuotes(String.valueOf(obj));
- }
-
- @Override
- public void visualizeStoreHeader(String classCanonicalName) {
- this.sbStore.append(classCanonicalName + " (\\n");
- }
-
- @Override
- public void visualizeStoreFooter() {
- this.sbStore.append(")");
- }
-
- /**
- * Write a file {@code methods.txt} that contains a mapping from source code location to
- * generated dot file.
- */
- @Override
- public void shutdown() {
- try {
- // Open for append, in case of multiple sub-checkers.
- FileWriter fstream = new FileWriter(outdir + "/methods.txt", true);
- BufferedWriter out = new BufferedWriter(fstream);
- for (Map.Entry<String, String> kv : generated.entrySet()) {
- out.write(kv.getKey());
- out.append('\t');
- out.write(kv.getValue());
- out.append('\n');
- }
- out.close();
- } catch (IOException e) {
- ErrorReporter.errorAbort(
- "Error creating methods.txt file in: " + outdir + "; ensure the path is valid",
- e);
- }
- }
-}