r368766 - [analyzer] exploded-graph-rewriter: Open the converted graph immediately.

Artem Dergachev via cfe-commits cfe-commits at lists.llvm.org
Tue Aug 13 16:04:47 PDT 2019


Author: dergachev
Date: Tue Aug 13 16:04:47 2019
New Revision: 368766

URL: http://llvm.org/viewvc/llvm-project?rev=368766&view=rev
Log:
[analyzer] exploded-graph-rewriter: Open the converted graph immediately.

Change the default behavior: the tool no longer dumps the rewritten .dot file
to stdout, but instead it automatically converts it into an .html file
(which essentially wraps an .svg file) and immediately opens it with
the default web browser.

This means that the tool should now be fairly easy to use:

  $ exploded-graph-rewriter.py /tmp/ExprEngine.dot

The benefits of wrapping the .svg file into an .html file are:

    - It'll open in a web browser, which is the intended behavior.
      An .svg file would be open with an image viewer/editor instead.
    - It avoids the white background around the otherwise dark svg area
      in dark mode.

The feature can be turned off by passing a flag '--rewrite-only'.
The LIT substitution is updated to enforce the old mode because
we don't want web browsers opening on our buildbots.

Differential Revision: https://reviews.llvm.org/D65250

Modified:
    cfe/trunk/test/Analysis/exploded-graph-rewriter/lit.local.cfg
    cfe/trunk/utils/analyzer/exploded-graph-rewriter.py

Modified: cfe/trunk/test/Analysis/exploded-graph-rewriter/lit.local.cfg
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/exploded-graph-rewriter/lit.local.cfg?rev=368766&r1=368765&r2=368766&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/exploded-graph-rewriter/lit.local.cfg (original)
+++ cfe/trunk/test/Analysis/exploded-graph-rewriter/lit.local.cfg Tue Aug 13 16:04:47 2019
@@ -8,7 +8,7 @@ use_lit_shell = os.environ.get("LIT_USE_
 config.test_format = lit.formats.ShTest(use_lit_shell == "0")
 
 config.substitutions.append(('%exploded_graph_rewriter',
-                             '\'%s\' %s' % (
+                             '\'%s\' %s --dump-dot-only' % (
                                  config.python_executable,
                                  lit.util.which('exploded-graph-rewriter.py',
                                                 os.path.join(

Modified: cfe/trunk/utils/analyzer/exploded-graph-rewriter.py
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/utils/analyzer/exploded-graph-rewriter.py?rev=368766&r1=368765&r2=368766&view=diff
==============================================================================
--- cfe/trunk/utils/analyzer/exploded-graph-rewriter.py (original)
+++ cfe/trunk/utils/analyzer/exploded-graph-rewriter.py Tue Aug 13 16:04:47 2019
@@ -394,16 +394,25 @@ class ExplodedGraph(object):
 # A visitor that dumps the ExplodedGraph into a DOT file with fancy HTML-based
 # syntax highlighing.
 class DotDumpVisitor(object):
-    def __init__(self, do_diffs, dark_mode, gray_mode, topo_mode):
+    def __init__(self, do_diffs, dark_mode, gray_mode,
+                 topo_mode, dump_dot_only):
         super(DotDumpVisitor, self).__init__()
         self._do_diffs = do_diffs
         self._dark_mode = dark_mode
         self._gray_mode = gray_mode
         self._topo_mode = topo_mode
+        self._dump_dot_only = dump_dot_only
+        self._output = []
 
-    @staticmethod
-    def _dump_raw(s):
-        print(s, end='')
+    def _dump_raw(self, s):
+        if self._dump_dot_only:
+            print(s, end='')
+        else:
+            self._output.append(s)
+
+    def output(self):
+        assert not self._dump_dot_only
+        return ''.join(self._output)
 
     def _dump(self, s):
         s = s.replace('&', '&') \
@@ -812,6 +821,44 @@ class DotDumpVisitor(object):
     def visit_end_of_graph(self):
         self._dump_raw('}\n')
 
+        if not self._dump_dot_only:
+            import sys
+            import tempfile
+
+            def write_temp_file(suffix, data):
+                fd, filename = tempfile.mkstemp(suffix=suffix)
+                print('Writing "%s"...' % filename)
+                with os.fdopen(fd, 'w') as fp:
+                    fp.write(data)
+                print('Done! Please remember to remove the file.')
+                return filename
+
+            try:
+                import graphviz
+            except ImportError:
+                # The fallback behavior if graphviz is not installed!
+                print('Python graphviz not found. Please invoke')
+                print('  $ pip install graphviz')
+                print('in order to enable automatic conversion to HTML.')
+                print()
+                print('You may also convert DOT to SVG manually via')
+                print('  $ dot -Tsvg input.dot -o output.svg')
+                print()
+                write_temp_file('.dot', self.output())
+                return
+
+            svg = graphviz.pipe('dot', 'svg', self.output())
+
+            filename = write_temp_file(
+                '.html', '<html><body bgcolor="%s">%s</body></html>' % (
+                             '#1a1a1a' if self._dark_mode else 'white', svg))
+            if sys.platform == 'win32':
+                os.startfile(filename)
+            elif sys.platform == 'darwin':
+                os.system('open "%s"' % filename)
+            else:
+                os.system('xdg-open "%s"' % filename)
+
 
 #===-----------------------------------------------------------------------===#
 # Explorers know how to traverse the ExplodedGraph in a certain order.
@@ -874,8 +921,10 @@ class SinglePathExplorer(object):
 
 
 def main():
-    parser = argparse.ArgumentParser()
-    parser.add_argument('filename', type=str)
+    parser = argparse.ArgumentParser(
+        description='Display and manipulate Exploded Graph dumps.')
+    parser.add_argument('filename', type=str,
+                        help='the .dot file produced by the Static Analyzer')
     parser.add_argument('-v', '--verbose', action='store_const',
                         dest='loglevel', const=logging.DEBUG,
                         default=logging.WARNING,
@@ -897,6 +946,11 @@ def main():
     parser.add_argument('--gray', action='store_const', dest='gray',
                         const=True, default=False,
                         help='black-and-white mode')
+    parser.add_argument('--dump-dot-only', action='store_const',
+                        dest='dump_dot_only', const=True, default=False,
+                        help='instead of writing an HTML file and immediately '
+                             'displaying it, dump the rewritten dot file '
+                             'to stdout')
     args = parser.parse_args()
     logging.basicConfig(level=args.loglevel)
 
@@ -907,7 +961,8 @@ def main():
             graph.add_raw_line(raw_line)
 
     explorer = SinglePathExplorer() if args.single_path else BasicExplorer()
-    visitor = DotDumpVisitor(args.diff, args.dark, args.gray, args.topology)
+    visitor = DotDumpVisitor(args.diff, args.dark, args.gray, args.topology,
+                             args.dump_dot_only)
 
     explorer.explore(graph, visitor)
 




More information about the cfe-commits mailing list