]> granicus.if.org Git - clang/commitdiff
Added Ubigraph visualization for the static analyzer (this is pretty alpha quality).
authorTed Kremenek <kremenek@apple.com>
Wed, 27 Aug 2008 22:31:43 +0000 (22:31 +0000)
committerTed Kremenek <kremenek@apple.com>
Wed, 27 Aug 2008 22:31:43 +0000 (22:31 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@55442 91177308-0d34-0410-b5e6-96231b3b80d8

Driver/AnalysisConsumer.cpp
Driver/AnalysisConsumer.h
Driver/clang.cpp
utils/ubiviz [new file with mode: 0755]

index 9b84aa37a37054741176b34e88c6b46a97df9433..7142b7918185268036c4258957fb4350e0df74df 100644 (file)
 #include "clang/Analysis/PathSensitive/GRTransferFuncs.h"
 #include "clang/Analysis/PathSensitive/GRExprEngine.h"
 #include "llvm/Support/Streams.h"
-
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/System/Path.h"
 #include <vector>
 
 using namespace clang;
 
+static ExplodedNodeImpl::Auditor* CreateUbiViz();
   
 //===----------------------------------------------------------------------===//
 // Basic type definitions.
@@ -59,7 +61,8 @@ namespace {
     Actions ObjCImplementationActions;
     
   public:
-    const bool Visualize;
+    const bool VisGraphviz;
+    const bool VisUbigraph;
     const bool TrimGraph;
     const LangOptions& LOpts;
     Diagnostic &Diags;
@@ -76,8 +79,9 @@ namespace {
                      const LangOptions& lopts,
                      const std::string& fname,
                      const std::string& htmldir,
-                     bool visualize, bool trim, bool analyzeAll) 
-      : Visualize(visualize), TrimGraph(trim), LOpts(lopts), Diags(diags),
+                     bool visgraphviz, bool visubi, bool trim, bool analyzeAll) 
+      : VisGraphviz(visgraphviz), VisUbigraph(visubi), TrimGraph(trim),
+        LOpts(lopts), Diags(diags),
         Ctx(0), PP(pp), PPF(ppf),
         HTMLDir(htmldir),
         FName(fname),
@@ -168,8 +172,16 @@ namespace {
       return liveness.get();
     }
     
+    bool shouldVisualizeGraphviz() const {
+      return C.VisGraphviz;
+    }
+\v    
+    bool shouldVisualizeUbigraph() const {
+      return C.VisUbigraph;
+    }
+    
     bool shouldVisualize() const {
-      return C.Visualize;
+      return C.VisGraphviz || C.VisUbigraph;
     }
     
     bool shouldTrimGraph() const {
@@ -319,15 +331,26 @@ static void ActionGRExprEngine(AnalysisManager& mgr, GRTransferFuncs* tf,
     Eng.RegisterInternalChecks();
     RegisterAppleChecks(Eng);
   }
+
+  // Set the graph auditor.
+  llvm::OwningPtr<ExplodedNodeImpl::Auditor> Auditor;
+  if (mgr.shouldVisualizeUbigraph()) {
+    Auditor.reset(CreateUbiViz());
+    ExplodedNodeImpl::SetAuditor(Auditor.get());
+  }
   
   // Execute the worklist algorithm.
   Eng.ExecuteWorkList();
   
+  // Release the auditor (if any) so that it doesn't monitor the graph
+  // created BugReporter.
+  ExplodedNodeImpl::SetAuditor(0);
+  
   // Display warnings.
   Eng.EmitWarnings(mgr);
   
   // Visualize the exploded graph.
-  if (mgr.shouldVisualize())
+  if (mgr.shouldVisualizeGraphviz())
     Eng.ViewGraph(mgr.shouldTrimGraph());
 }
 
@@ -418,12 +441,13 @@ ASTConsumer* clang::CreateAnalysisConsumer(Analyses* Beg, Analyses* End,
                                            const LangOptions& lopts,
                                            const std::string& fname,
                                            const std::string& htmldir,
-                                           bool visualize, bool trim,
+                                           bool VisGraphviz, bool VisUbi,
+                                           bool trim,
                                            bool analyzeAll) {
   
   llvm::OwningPtr<AnalysisConsumer>
   C(new AnalysisConsumer(diags, pp, ppf, lopts, fname, htmldir,
-                         visualize, trim, analyzeAll));
+                         VisGraphviz, VisUbi, trim, analyzeAll));
   
   for ( ; Beg != End ; ++Beg)
     switch (*Beg) {
@@ -438,3 +462,75 @@ ASTConsumer* clang::CreateAnalysisConsumer(Analyses* Beg, Analyses* End,
   return C.take();
 }
 
+//===----------------------------------------------------------------------===//
+// Ubigraph Visualization.  FIXME: Move to separate file.
+//===----------------------------------------------------------------------===//
+
+namespace {
+  
+class UbigraphViz : public ExplodedNodeImpl::Auditor {
+  llvm::OwningPtr<llvm::raw_ostream> Out;
+  unsigned Cntr;
+
+  typedef llvm::DenseMap<void*,unsigned> VMap;
+  VMap M;
+  
+public:
+  UbigraphViz(llvm::raw_ostream* out) : Out(out), Cntr(0) {}  
+  virtual void AddEdge(ExplodedNodeImpl* Src, ExplodedNodeImpl* Dst);  
+};
+  
+} // end anonymous namespace
+
+static ExplodedNodeImpl::Auditor* CreateUbiViz() {
+  std::string ErrMsg;
+  
+  llvm::sys::Path Filename = llvm::sys::Path::GetTemporaryDirectory(&ErrMsg);
+  if (!ErrMsg.empty())
+    return 0;
+
+  Filename.appendComponent("llvm_ubi");
+  Filename.makeUnique(true,&ErrMsg);
+
+  if (!ErrMsg.empty())
+    return 0;
+
+  llvm::cerr << "Writing '" << Filename << "'.\n";
+  
+  llvm::OwningPtr<llvm::raw_fd_ostream> Stream;
+  std::string filename = Filename.toString();
+  Stream.reset(new llvm::raw_fd_ostream(filename.c_str(), ErrMsg));
+
+  if (!ErrMsg.empty())
+    return 0;
+  
+  return new UbigraphViz(Stream.take());
+}
+
+void UbigraphViz::AddEdge(ExplodedNodeImpl* Src, ExplodedNodeImpl* Dst) {
+  // Lookup the Src.  If it is a new node, it's a root.
+  VMap::iterator SrcI= M.find(Src);
+  unsigned SrcID;
+  
+  if (SrcI == M.end()) {
+    M[Src] = SrcID = Cntr++;
+    *Out << "('vertex', " << SrcID << ", ('color','#00ff00'))\n";
+  }
+  else
+    SrcID = SrcI->second;
+  
+  // Lookup the Dst.
+  VMap::iterator DstI= M.find(Dst);
+  unsigned DstID;
+
+  if (DstI == M.end()) {
+    M[Dst] = DstID = Cntr++;
+    *Out << "('vertex', " << DstID << ")\n";
+  }
+  else
+    DstID = DstI->second;
+
+  // Add the edge.
+  *Out << "('edge', " << SrcID << ", " << DstID << ")\n";
+}
+
index 5a2550da43c0a52d25f9d8eaa577b7a4c285bd5b..daec6f3441ba773df07f63706fb52ff06a099a54 100644 (file)
@@ -28,8 +28,10 @@ ASTConsumer* CreateAnalysisConsumer(Analyses* Beg, Analyses* End,
                                     const LangOptions& lopts,
                                     const std::string& fname,
                                     const std::string& htmldir,
-                                    bool visualize, bool trim,
-                                    bool analyzeAll);
+                                    bool VisualizeGraphViz,
+                                    bool VisualizeUbi,
+                                    bool VizTrimGraph,
+                                    bool AnalyzeAll);
 } // end clang namespace
 
 #endif
index fad1624ef2b6aff8fedb07d785838169e95c9ff5..8b24474681b82e2c1153fc5bd31d76ca0fabb502 100644 (file)
@@ -159,11 +159,15 @@ NoCaretDiagnostics("fno-caret-diagnostics",
 //===----------------------------------------------------------------------===//
 
 static llvm::cl::opt<bool>
-VisualizeEG("visualize-egraph",
-            llvm::cl::desc("Display static analysis Exploded Graph"));
+VisualizeEGDot("analyzer-viz-egraph-graphviz",
+               llvm::cl::desc("Display exploded graph using GraphViz"));
 
 static llvm::cl::opt<bool>
-AnalyzeAll("checker-opt-analyze-headers",
+VisualizeEGUbi("analyzer-viz-egraph-ubigraph",
+               llvm::cl::desc("Display exploded graph using Ubigraph"));
+
+static llvm::cl::opt<bool>
+AnalyzeAll("analyzer-opt-analyze-headers",
     llvm::cl::desc("Force the static analyzer to analyze "
                    "functions defined in header files"));
 
@@ -964,8 +968,8 @@ static ASTConsumer* CreateASTConsumer(const std::string& InFile,
                                     &AnalysisList[0]+AnalysisList.size(),
                                     Diag, PP, PPF, LangOpts,
                                     AnalyzeSpecificFunction,
-                                    OutputFile, VisualizeEG, TrimGraph,
-                                    AnalyzeAll);
+                                    OutputFile, VisualizeEGDot, VisualizeEGUbi,
+                                    TrimGraph, AnalyzeAll);
   }
 }
 
diff --git a/utils/ubiviz b/utils/ubiviz
new file mode 100755 (executable)
index 0000000..1a8f742
--- /dev/null
@@ -0,0 +1,57 @@
+#!/usr/bin/env python
+#
+#                     The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+#
+# This script reads visualization data emitted by the static analyzer for
+# display in Ubigraph.
+#
+##===----------------------------------------------------------------------===##
+
+import xmlrpclib
+import sys
+
+def Error(message):
+    print >> sys.stderr, 'ubiviz: ' + message
+    sys.exit(1)
+    
+def StreamData(filename):
+  file = open(filename)
+  for ln in file:
+    yield eval(ln)
+  file.close()
+
+def Display(G, data):
+  action = data[0]
+  if action == 'vertex':
+    vertex = data[1]
+    G.new_vertex_w_id(vertex)
+    for attribute in data[2:]:
+      G.set_vertex_attribute(vertex, attribute[0], attribute[1])
+  elif action == 'edge':
+    src = data[1]
+    dst = data[2]
+    edge = G.new_edge(src,dst)
+    for attribute in data[3:]:
+      G.set_edge_attribute(edge, attribute[0], attribute[1])
+
+def main(args):
+  if len(args) == 0:
+    Error('no input files')    
+
+  server = xmlrpclib.Server('http://127.0.0.1:20738/RPC2')
+  G = server.ubigraph
+            
+  for arg in args:
+    G.clear()
+    for x in StreamData(arg):
+      Display(G,x)
+
+if __name__ == '__main__':
+    main(sys.argv[1:])
+    
+    
\ No newline at end of file