Added Ubigraph visualization for the static analyzer (this is pretty alpha quality).
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@55442 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/Driver/AnalysisConsumer.cpp b/Driver/AnalysisConsumer.cpp
index 9b84aa3..7142b79 100644
--- a/Driver/AnalysisConsumer.cpp
+++ b/Driver/AnalysisConsumer.cpp
@@ -31,11 +31,13 @@
#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 @@
Actions ObjCImplementationActions;
public:
- const bool Visualize;
+ const bool VisGraphviz;
+ const bool VisUbigraph;
const bool TrimGraph;
const LangOptions& LOpts;
Diagnostic &Diags;
@@ -76,8 +79,9 @@
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 @@
return liveness.get();
}
+ bool shouldVisualizeGraphviz() const {
+ return C.VisGraphviz;
+ }
+
+ bool shouldVisualizeUbigraph() const {
+ return C.VisUbigraph;
+ }
+
bool shouldVisualize() const {
- return C.Visualize;
+ return C.VisGraphviz || C.VisUbigraph;
}
bool shouldTrimGraph() const {
@@ -319,15 +331,26 @@
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 @@
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 @@
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";
+}
+