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

org.checkerframework.dataflow.cfg.visualize.CFGVisualizeLauncher 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.44.0
Show newest version
package org.checkerframework.dataflow.cfg.visualize;

import com.sun.tools.javac.file.JavacFileManager;
import com.sun.tools.javac.main.JavaCompiler;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.Options;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import javax.tools.JavaFileManager;
import javax.tools.JavaFileObject;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.checkerframework.dataflow.analysis.AbstractValue;
import org.checkerframework.dataflow.analysis.Analysis;
import org.checkerframework.dataflow.analysis.Store;
import org.checkerframework.dataflow.analysis.TransferFunction;
import org.checkerframework.dataflow.cfg.CFGProcessor;
import org.checkerframework.dataflow.cfg.CFGProcessor.CFGProcessResult;
import org.checkerframework.dataflow.cfg.ControlFlowGraph;

/**
 * Launcher to generate the DOT or String representation of the control flow graph of a given method
 * in a given class.
 *
 * 

Usage: Directly run it as the main class to generate the DOT representation of the control * flow graph of a given method in a given class. See {@link * org.checkerframework.dataflow.cfg.playground.ConstantPropagationPlayground} for another way to * use it. */ public class CFGVisualizeLauncher { /** * The main entry point of CFGVisualizeLauncher. * * @param args the passed arguments, see {@link #printUsage()} for the usage */ public static void main(String[] args) { CFGVisualizeLauncher cfgVisualizeLauncher = new CFGVisualizeLauncher(); if (args.length == 0) { cfgVisualizeLauncher.printUsage(); System.exit(1); } String input = args[0]; File file = new File(input); if (!file.canRead()) { cfgVisualizeLauncher.printError("Cannot read input file: " + file.getAbsolutePath()); cfgVisualizeLauncher.printUsage(); System.exit(1); } String method = "test"; String clas = "Test"; String output = "."; boolean pdf = false; boolean error = false; boolean verbose = false; boolean string = false; for (int i = 1; i < args.length; i++) { switch (args[i]) { case "--outputdir": if (i >= args.length - 1) { cfgVisualizeLauncher.printError("Did not find after --outputdir."); continue; } i++; output = args[i]; break; case "--pdf": pdf = true; break; case "--method": if (i >= args.length - 1) { cfgVisualizeLauncher.printError("Did not find after --method."); continue; } i++; method = args[i]; break; case "--class": if (i >= args.length - 1) { cfgVisualizeLauncher.printError("Did not find after --class."); continue; } i++; clas = args[i]; break; case "--verbose": verbose = true; break; case "--string": string = true; break; default: cfgVisualizeLauncher.printError("Unknown command line argument: " + args[i]); error = true; break; } } if (error) { System.exit(1); } if (!string) { cfgVisualizeLauncher.generateDOTofCFGWithoutAnalysis( input, output, method, clas, pdf, verbose); } else { String stringGraph = cfgVisualizeLauncher.generateStringOfCFGWithoutAnalysis(input, method, clas, verbose); System.out.println(stringGraph); } } /** * Generate the DOT representation of the CFG for a method, only. Does no dataflow analysis. * * @param inputFile a Java source file, used as input * @param outputDir output directory * @param method name of the method to generate the CFG for * @param clas name of the class which includes the method to generate the CFG for * @param pdf also generate a PDF * @param verbose show verbose information in CFG */ protected void generateDOTofCFGWithoutAnalysis( String inputFile, String outputDir, String method, String clas, boolean pdf, boolean verbose) { generateDOTofCFG(inputFile, outputDir, method, clas, pdf, verbose, null); } /** * Generate the String representation of the CFG for a method, only. Does no dataflow analysis. * * @param inputFile a Java source file, used as input * @param method name of the method to generate the CFG for * @param clas name of the class which includes the method to generate the CFG for * @param verbose show verbose information in CFG * @return the String representation of the CFG */ protected String generateStringOfCFGWithoutAnalysis( String inputFile, String method, String clas, boolean verbose) { @Nullable Map res = generateStringOfCFG(inputFile, method, clas, verbose, null); if (res != null) { String stringGraph = (String) res.get("stringGraph"); if (stringGraph == null) { return "Unexpected output from generating string control flow graph, shouldn't be null."; } return stringGraph; } else { return "Unexpected output from generating string control flow graph, shouldn't be null."; } } /** * Generate the DOT representation of the CFG for a method. * * @param the abstract value type to be tracked by the analysis * @param the store type used in the analysis * @param the transfer function type that is used to approximated runtime behavior * @param inputFile a Java source file, used as input * @param outputDir source output directory * @param method name of the method to generate the CFG for * @param clas name of the class which includes the method to generate the CFG for * @param pdf also generate a PDF * @param verbose show verbose information in CFG * @param analysis analysis to perform before the visualization (or {@code null} if no analysis is * to be performed) */ public , S extends Store, T extends TransferFunction> void generateDOTofCFG( String inputFile, String outputDir, String method, String clas, boolean pdf, boolean verbose, @Nullable Analysis analysis) { ControlFlowGraph cfg = generateMethodCFG(inputFile, clas, method); if (analysis != null) { analysis.performAnalysis(cfg); } Map args = new HashMap<>(2); args.put("outdir", outputDir); args.put("verbose", verbose); CFGVisualizer viz = new DOTCFGVisualizer<>(); viz.init(args); Map res = viz.visualize(cfg, cfg.getEntryBlock(), analysis); viz.shutdown(); if (pdf && res != null) { assert res.get("dotFileName") != null : "@AssumeAssertion(nullness): specification"; producePDF((String) res.get("dotFileName")); } } /** * Generate the control flow graph of a method in a class. * * @param file a Java source file, used as input * @param clas name of the class which includes the method to generate the CFG for * @param method name of the method to generate the CFG for * @return control flow graph of the specified method */ protected ControlFlowGraph generateMethodCFG(String file, String clas, final String method) { CFGProcessor cfgProcessor = new CFGProcessor(clas, method); Context context = new Context(); Options.instance(context).put("compilePolicy", "ATTR_ONLY"); JavaCompiler javac = new JavaCompiler(context); JavacFileManager fileManager = (JavacFileManager) context.get(JavaFileManager.class); JavaFileObject l = fileManager.getJavaFileObjectsFromStrings(List.of(file)).iterator().next(); PrintStream err = System.err; try { // redirect syserr to nothing (and prevent the compiler from issuing // warnings about our exception. System.setErr( new PrintStream( new OutputStream() { @Override public void write(int b) throws IOException {} })); javac.compile(List.of(l), List.of(clas), List.of(cfgProcessor), List.nil()); } catch (Throwable e) { // ok } finally { System.setErr(err); } CFGProcessResult res = cfgProcessor.getCFGProcessResult(); if (res == null) { printError("internal error in type processor! method typeProcessOver() doesn't get called."); System.exit(1); } if (!res.isSuccess()) { printError(res.getErrMsg()); System.exit(1); } return res.getCFG(); } /** * Invoke "dot" command to generate a PDF. * * @param file name of the dot file */ protected void producePDF(String file) { try { String command = "dot -Tpdf \"" + file + "\" -o \"" + file + ".pdf\""; Process child = Runtime.getRuntime().exec(new String[] {"/bin/sh", "-c", command}); child.waitFor(); } catch (InterruptedException | IOException e) { e.printStackTrace(); System.exit(1); } } /** * Generate the String representation of the CFG for a method. * * @param the abstract value type to be tracked by the analysis * @param the store type used in the analysis * @param the transfer function type that is used to approximated runtime behavior * @param inputFile a Java source file, used as input * @param method name of the method to generate the CFG for * @param clas name of the class which includes the method to generate the CFG for * @param verbose show verbose information in CFG * @param analysis analysis to perform before the visualization (or {@code null} if no analysis is * to be performed) * @return a map which includes a key "stringGraph" and the String representation of CFG as the * value */ public , S extends Store, T extends TransferFunction> @Nullable Map generateStringOfCFG( String inputFile, String method, String clas, boolean verbose, @Nullable Analysis analysis) { ControlFlowGraph cfg = generateMethodCFG(inputFile, clas, method); if (analysis != null) { analysis.performAnalysis(cfg); } Map args = Collections.singletonMap("verbose", verbose); CFGVisualizer viz = new StringCFGVisualizer<>(); viz.init(args); Map res = viz.visualize(cfg, cfg.getEntryBlock(), analysis); viz.shutdown(); return res; } /** Print usage information. */ protected void printUsage() { System.out.println( "Generate the control flow graph of a Java method, represented as a DOT or String graph."); System.out.println( "Parameters: [--outputdir ] [--method ] [--class ]" + " [--pdf] [--verbose] [--string]"); System.out.println( " --outputdir: The output directory for the generated files (defaults to '.')."); System.out.println(" --method: The method to generate the CFG for (defaults to 'test')."); System.out.println( " --class: The class in which to find the method (defaults to 'Test')."); System.out.println(" --pdf: Also generate the PDF by invoking 'dot'."); System.out.println(" --verbose: Show the verbose output (defaults to 'false')."); System.out.println( " --string: Print the string representation of the control flow graph (defaults to" + " 'false')."); } /** * Print error message. * * @param string error message */ protected void printError(@Nullable String string) { System.err.println("ERROR: " + string); } }