]> CyberLeo.Net >> Repos - FreeBSD/stable/9.git/blob - contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
MFC r234353:
[FreeBSD/stable/9.git] / contrib / llvm / tools / clang / lib / StaticAnalyzer / Frontend / AnalysisConsumer.cpp
1 //===--- AnalysisConsumer.cpp - ASTConsumer for running Analyses ----------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // "Meta" ASTConsumer for running different source analyses.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #define DEBUG_TYPE "AnalysisConsumer"
15
16 #include "AnalysisConsumer.h"
17 #include "clang/AST/ASTConsumer.h"
18 #include "clang/AST/Decl.h"
19 #include "clang/AST/DeclCXX.h"
20 #include "clang/AST/DeclObjC.h"
21 #include "clang/AST/ParentMap.h"
22 #include "clang/AST/RecursiveASTVisitor.h"
23 #include "clang/Analysis/CFG.h"
24 #include "clang/Analysis/CallGraph.h"
25 #include "clang/StaticAnalyzer/Frontend/CheckerRegistration.h"
26 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
27 #include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
28 #include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
29 #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
30 #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
31 #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
32 #include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h"
33
34 #include "clang/Basic/FileManager.h"
35 #include "clang/Basic/SourceManager.h"
36 #include "clang/Frontend/AnalyzerOptions.h"
37 #include "clang/Lex/Preprocessor.h"
38 #include "llvm/Support/raw_ostream.h"
39 #include "llvm/Support/Path.h"
40 #include "llvm/Support/Program.h"
41 #include "llvm/Support/Timer.h"
42 #include "llvm/ADT/DepthFirstIterator.h"
43 #include "llvm/ADT/OwningPtr.h"
44 #include "llvm/ADT/SmallPtrSet.h"
45 #include "llvm/ADT/Statistic.h"
46
47 #include <queue>
48
49 using namespace clang;
50 using namespace ento;
51 using llvm::SmallPtrSet;
52
53 static ExplodedNode::Auditor* CreateUbiViz();
54
55 STATISTIC(NumFunctionTopLevel, "The # of functions at top level.");
56 STATISTIC(NumFunctionsAnalyzed, "The # of functions analysed (as top level).");
57 STATISTIC(NumBlocksInAnalyzedFunctions,
58                      "The # of basic blocks in the analyzed functions.");
59 STATISTIC(PercentReachableBlocks, "The % of reachable basic blocks.");
60
61 //===----------------------------------------------------------------------===//
62 // Special PathDiagnosticConsumers.
63 //===----------------------------------------------------------------------===//
64
65 static PathDiagnosticConsumer*
66 createPlistHTMLDiagnosticConsumer(const std::string& prefix,
67                                 const Preprocessor &PP) {
68   PathDiagnosticConsumer *PD =
69     createHTMLDiagnosticConsumer(llvm::sys::path::parent_path(prefix), PP);
70   return createPlistDiagnosticConsumer(prefix, PP, PD);
71 }
72
73 //===----------------------------------------------------------------------===//
74 // AnalysisConsumer declaration.
75 //===----------------------------------------------------------------------===//
76
77 namespace {
78
79 class AnalysisConsumer : public ASTConsumer,
80                          public RecursiveASTVisitor<AnalysisConsumer> {
81   enum AnalysisMode {
82     ANALYSIS_SYNTAX,
83     ANALYSIS_PATH,
84     ANALYSIS_ALL
85   };
86
87   /// Mode of the analyzes while recursively visiting Decls.
88   AnalysisMode RecVisitorMode;
89   /// Bug Reporter to use while recursively visiting Decls.
90   BugReporter *RecVisitorBR;
91
92 public:
93   ASTContext *Ctx;
94   const Preprocessor &PP;
95   const std::string OutDir;
96   AnalyzerOptions Opts;
97   ArrayRef<std::string> Plugins;
98
99   /// \brief Stores the declarations from the local translation unit.
100   /// Note, we pre-compute the local declarations at parse time as an
101   /// optimization to make sure we do not deserialize everything from disk.
102   /// The local declaration to all declarations ratio might be very small when
103   /// working with a PCH file.
104   SetOfDecls LocalTUDecls;
105
106   // PD is owned by AnalysisManager.
107   PathDiagnosticConsumer *PD;
108
109   StoreManagerCreator CreateStoreMgr;
110   ConstraintManagerCreator CreateConstraintMgr;
111
112   OwningPtr<CheckerManager> checkerMgr;
113   OwningPtr<AnalysisManager> Mgr;
114
115   /// Time the analyzes time of each translation unit.
116   static llvm::Timer* TUTotalTimer;
117
118   /// The information about analyzed functions shared throughout the
119   /// translation unit.
120   FunctionSummariesTy FunctionSummaries;
121
122   AnalysisConsumer(const Preprocessor& pp,
123                    const std::string& outdir,
124                    const AnalyzerOptions& opts,
125                    ArrayRef<std::string> plugins)
126     : RecVisitorMode(ANALYSIS_ALL), RecVisitorBR(0),
127       Ctx(0), PP(pp), OutDir(outdir), Opts(opts), Plugins(plugins), PD(0) {
128     DigestAnalyzerOptions();
129     if (Opts.PrintStats) {
130       llvm::EnableStatistics();
131       TUTotalTimer = new llvm::Timer("Analyzer Total Time");
132     }
133   }
134
135   ~AnalysisConsumer() {
136     if (Opts.PrintStats)
137       delete TUTotalTimer;
138   }
139
140   void DigestAnalyzerOptions() {
141     // Create the PathDiagnosticConsumer.
142     if (!OutDir.empty()) {
143       switch (Opts.AnalysisDiagOpt) {
144       default:
145 #define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN, AUTOCREATE) \
146         case PD_##NAME: PD = CREATEFN(OutDir, PP); break;
147 #include "clang/Frontend/Analyses.def"
148       }
149     } else if (Opts.AnalysisDiagOpt == PD_TEXT) {
150       // Create the text client even without a specified output file since
151       // it just uses diagnostic notes.
152       PD = createTextPathDiagnosticConsumer("", PP);
153     }
154
155     // Create the analyzer component creators.
156     switch (Opts.AnalysisStoreOpt) {
157     default:
158       llvm_unreachable("Unknown store manager.");
159 #define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATEFN)           \
160       case NAME##Model: CreateStoreMgr = CREATEFN; break;
161 #include "clang/Frontend/Analyses.def"
162     }
163
164     switch (Opts.AnalysisConstraintsOpt) {
165     default:
166       llvm_unreachable("Unknown store manager.");
167 #define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATEFN)     \
168       case NAME##Model: CreateConstraintMgr = CREATEFN; break;
169 #include "clang/Frontend/Analyses.def"
170     }
171   }
172
173   void DisplayFunction(const Decl *D, AnalysisMode Mode) {
174     if (!Opts.AnalyzerDisplayProgress)
175       return;
176
177     SourceManager &SM = Mgr->getASTContext().getSourceManager();
178     PresumedLoc Loc = SM.getPresumedLoc(D->getLocation());
179     if (Loc.isValid()) {
180       llvm::errs() << "ANALYZE";
181       switch (Mode) {
182         case ANALYSIS_SYNTAX: llvm::errs() << "(Syntax)"; break;
183         case ANALYSIS_PATH: llvm::errs() << "(Path Sensitive)"; break;
184         case ANALYSIS_ALL: break;
185       };
186       llvm::errs() << ": " << Loc.getFilename();
187       if (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)) {
188         const NamedDecl *ND = cast<NamedDecl>(D);
189         llvm::errs() << ' ' << *ND << '\n';
190       }
191       else if (isa<BlockDecl>(D)) {
192         llvm::errs() << ' ' << "block(line:" << Loc.getLine() << ",col:"
193                      << Loc.getColumn() << '\n';
194       }
195       else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
196         Selector S = MD->getSelector();
197         llvm::errs() << ' ' << S.getAsString();
198       }
199     }
200   }
201
202   virtual void Initialize(ASTContext &Context) {
203     Ctx = &Context;
204     checkerMgr.reset(createCheckerManager(Opts, PP.getLangOpts(), Plugins,
205                                           PP.getDiagnostics()));
206     Mgr.reset(new AnalysisManager(*Ctx, PP.getDiagnostics(),
207                                   PP.getLangOpts(), PD,
208                                   CreateStoreMgr, CreateConstraintMgr,
209                                   checkerMgr.get(),
210                                   Opts.MaxNodes, Opts.MaxLoop,
211                                   Opts.VisualizeEGDot, Opts.VisualizeEGUbi,
212                                   Opts.AnalysisPurgeOpt, Opts.EagerlyAssume,
213                                   Opts.TrimGraph,
214                                   Opts.UnoptimizedCFG, Opts.CFGAddImplicitDtors,
215                                   Opts.CFGAddInitializers,
216                                   Opts.EagerlyTrimEGraph,
217                                   Opts.IPAMode,
218                                   Opts.InlineMaxStackDepth,
219                                   Opts.InlineMaxFunctionSize,
220                                   Opts.InliningMode,
221                                   Opts.NoRetryExhausted));
222   }
223
224   /// \brief Store the top level decls in the set to be processed later on.
225   /// (Doing this pre-processing avoids deserialization of data from PCH.)
226   virtual bool HandleTopLevelDecl(DeclGroupRef D);
227   virtual void HandleTopLevelDeclInObjCContainer(DeclGroupRef D);
228
229   virtual void HandleTranslationUnit(ASTContext &C);
230
231   /// \brief Build the call graph for all the top level decls of this TU and
232   /// use it to define the order in which the functions should be visited.
233   void HandleDeclsGallGraph();
234
235   /// \brief Run analyzes(syntax or path sensitive) on the given function.
236   /// \param Mode - determines if we are requesting syntax only or path
237   /// sensitive only analysis.
238   /// \param VisitedCallees - The output parameter, which is populated with the
239   /// set of functions which should be considered analyzed after analyzing the
240   /// given root function.
241   void HandleCode(Decl *D, AnalysisMode Mode,
242                   SetOfConstDecls *VisitedCallees = 0);
243
244   void RunPathSensitiveChecks(Decl *D, SetOfConstDecls *VisitedCallees);
245   void ActionExprEngine(Decl *D, bool ObjCGCEnabled,
246                         SetOfConstDecls *VisitedCallees);
247
248   /// Visitors for the RecursiveASTVisitor.
249
250   /// Handle callbacks for arbitrary Decls.
251   bool VisitDecl(Decl *D) {
252     checkerMgr->runCheckersOnASTDecl(D, *Mgr, *RecVisitorBR);
253     return true;
254   }
255
256   bool VisitFunctionDecl(FunctionDecl *FD) {
257     IdentifierInfo *II = FD->getIdentifier();
258     if (II && II->getName().startswith("__inline"))
259       return true;
260
261     // We skip function template definitions, as their semantics is
262     // only determined when they are instantiated.
263     if (FD->isThisDeclarationADefinition() &&
264         !FD->isDependentContext()) {
265       HandleCode(FD, RecVisitorMode);
266     }
267     return true;
268   }
269
270   bool VisitObjCMethodDecl(ObjCMethodDecl *MD) {
271     checkerMgr->runCheckersOnASTDecl(MD, *Mgr, *RecVisitorBR);
272     if (MD->isThisDeclarationADefinition())
273       HandleCode(MD, RecVisitorMode);
274     return true;
275   }
276
277 private:
278   void storeTopLevelDecls(DeclGroupRef DG);
279
280   /// \brief Check if we should skip (not analyze) the given function.
281   bool skipFunction(Decl *D);
282
283 };
284 } // end anonymous namespace
285
286
287 //===----------------------------------------------------------------------===//
288 // AnalysisConsumer implementation.
289 //===----------------------------------------------------------------------===//
290 llvm::Timer* AnalysisConsumer::TUTotalTimer = 0;
291
292 bool AnalysisConsumer::HandleTopLevelDecl(DeclGroupRef DG) {
293   storeTopLevelDecls(DG);
294   return true;
295 }
296
297 void AnalysisConsumer::HandleTopLevelDeclInObjCContainer(DeclGroupRef DG) {
298   storeTopLevelDecls(DG);
299 }
300
301 void AnalysisConsumer::storeTopLevelDecls(DeclGroupRef DG) {
302   for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I) {
303
304     // Skip ObjCMethodDecl, wait for the objc container to avoid
305     // analyzing twice.
306     if (isa<ObjCMethodDecl>(*I))
307       continue;
308
309     LocalTUDecls.insert(*I);
310   }
311 }
312
313 void AnalysisConsumer::HandleDeclsGallGraph() {
314   // Otherwise, use the Callgraph to derive the order.
315   // Build the Call Graph.
316   CallGraph CG;
317   // Add all the top level declarations to the graph.
318   for (SetOfDecls::iterator I = LocalTUDecls.begin(),
319                             E = LocalTUDecls.end(); I != E; ++I)
320     CG.addToCallGraph(*I);
321
322   // Find the top level nodes - children of root + the unreachable (parentless)
323   // nodes.
324   llvm::SmallVector<CallGraphNode*, 24> TopLevelFunctions;
325   for (CallGraph::nodes_iterator TI = CG.parentless_begin(),
326                                  TE = CG.parentless_end(); TI != TE; ++TI) {
327     TopLevelFunctions.push_back(*TI);
328     NumFunctionTopLevel++;
329   }
330   CallGraphNode *Entry = CG.getRoot();
331   for (CallGraphNode::iterator I = Entry->begin(),
332                                E = Entry->end(); I != E; ++I) {
333     TopLevelFunctions.push_back(*I);
334     NumFunctionTopLevel++;
335   }
336
337   // Make sure the nodes are sorted in order reverse of their definition in the 
338   // translation unit. This step is very important for performance. It ensures 
339   // that we analyze the root functions before the externally available 
340   // subroutines.
341   std::queue<CallGraphNode*> BFSQueue;
342   for (llvm::SmallVector<CallGraphNode*, 24>::reverse_iterator
343          TI = TopLevelFunctions.rbegin(), TE = TopLevelFunctions.rend();
344          TI != TE; ++TI)
345     BFSQueue.push(*TI);
346
347   // BFS over all of the functions, while skipping the ones inlined into
348   // the previously processed functions. Use external Visited set, which is
349   // also modified when we inline a function.
350   SmallPtrSet<CallGraphNode*,24> Visited;
351   while(!BFSQueue.empty()) {
352     CallGraphNode *N = BFSQueue.front();
353     BFSQueue.pop();
354
355     // Skip the functions which have been processed already or previously
356     // inlined.
357     if (Visited.count(N))
358       continue;
359
360     // Analyze the function.
361     SetOfConstDecls VisitedCallees;
362     Decl *D = N->getDecl();
363     assert(D);
364     HandleCode(D, ANALYSIS_PATH,
365                (Mgr->InliningMode == All ? 0 : &VisitedCallees));
366
367     // Add the visited callees to the global visited set.
368     for (SetOfConstDecls::const_iterator I = VisitedCallees.begin(),
369                                          E = VisitedCallees.end(); I != E; ++I){
370       CallGraphNode *VN = CG.getNode(*I);
371       if (VN)
372         Visited.insert(VN);
373     }
374     Visited.insert(N);
375
376     // Push the children into the queue.
377     for (CallGraphNode::const_iterator CI = N->begin(),
378                                        CE = N->end(); CI != CE; ++CI) {
379       BFSQueue.push(*CI);
380     }
381   }
382 }
383
384 void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) {
385   // Don't run the actions if an error has occurred with parsing the file.
386   DiagnosticsEngine &Diags = PP.getDiagnostics();
387   if (Diags.hasErrorOccurred() || Diags.hasFatalErrorOccurred())
388     return;
389
390   {
391     if (TUTotalTimer) TUTotalTimer->startTimer();
392
393     // Introduce a scope to destroy BR before Mgr.
394     BugReporter BR(*Mgr);
395     TranslationUnitDecl *TU = C.getTranslationUnitDecl();
396     checkerMgr->runCheckersOnASTDecl(TU, *Mgr, BR);
397
398     // Run the AST-only checks using the order in which functions are defined.
399     // If inlining is not turned on, use the simplest function order for path
400     // sensitive analyzes as well.
401     RecVisitorMode = (Mgr->shouldInlineCall() ? ANALYSIS_SYNTAX : ANALYSIS_ALL);
402     RecVisitorBR = &BR;
403
404     // Process all the top level declarations.
405     for (SetOfDecls::iterator I = LocalTUDecls.begin(),
406                               E = LocalTUDecls.end(); I != E; ++I)
407       TraverseDecl(*I);
408
409     if (Mgr->shouldInlineCall())
410       HandleDeclsGallGraph();
411
412     // After all decls handled, run checkers on the entire TranslationUnit.
413     checkerMgr->runCheckersOnEndOfTranslationUnit(TU, *Mgr, BR);
414
415     RecVisitorBR = 0;
416   }
417
418   // Explicitly destroy the PathDiagnosticConsumer.  This will flush its output.
419   // FIXME: This should be replaced with something that doesn't rely on
420   // side-effects in PathDiagnosticConsumer's destructor. This is required when
421   // used with option -disable-free.
422   Mgr.reset(NULL);
423
424   if (TUTotalTimer) TUTotalTimer->stopTimer();
425
426   // Count how many basic blocks we have not covered.
427   NumBlocksInAnalyzedFunctions = FunctionSummaries.getTotalNumBasicBlocks();
428   if (NumBlocksInAnalyzedFunctions > 0)
429     PercentReachableBlocks =
430       (FunctionSummaries.getTotalNumVisitedBasicBlocks() * 100) /
431         NumBlocksInAnalyzedFunctions;
432
433 }
434
435 static void FindBlocks(DeclContext *D, SmallVectorImpl<Decl*> &WL) {
436   if (BlockDecl *BD = dyn_cast<BlockDecl>(D))
437     WL.push_back(BD);
438
439   for (DeclContext::decl_iterator I = D->decls_begin(), E = D->decls_end();
440        I!=E; ++I)
441     if (DeclContext *DC = dyn_cast<DeclContext>(*I))
442       FindBlocks(DC, WL);
443 }
444
445 static std::string getFunctionName(const Decl *D) {
446   if (const ObjCMethodDecl *ID = dyn_cast<ObjCMethodDecl>(D)) {
447     return ID->getSelector().getAsString();
448   }
449   if (const FunctionDecl *ND = dyn_cast<FunctionDecl>(D)) {
450     IdentifierInfo *II = ND->getIdentifier();
451     if (II)
452       return II->getName();
453   }
454   return "";
455 }
456
457 bool AnalysisConsumer::skipFunction(Decl *D) {
458   if (!Opts.AnalyzeSpecificFunction.empty() &&
459       getFunctionName(D) != Opts.AnalyzeSpecificFunction)
460     return true;
461
462   // Don't run the actions on declarations in header files unless
463   // otherwise specified.
464   SourceManager &SM = Ctx->getSourceManager();
465   SourceLocation SL = SM.getExpansionLoc(D->getLocation());
466   if (!Opts.AnalyzeAll && !SM.isFromMainFile(SL))
467     return true;
468
469   return false;
470 }
471
472 void AnalysisConsumer::HandleCode(Decl *D, AnalysisMode Mode,
473                                   SetOfConstDecls *VisitedCallees) {
474   if (skipFunction(D))
475     return;
476
477   DisplayFunction(D, Mode);
478
479   // Clear the AnalysisManager of old AnalysisDeclContexts.
480   Mgr->ClearContexts();
481
482   // Dispatch on the actions.
483   SmallVector<Decl*, 10> WL;
484   WL.push_back(D);
485
486   if (D->hasBody() && Opts.AnalyzeNestedBlocks)
487     FindBlocks(cast<DeclContext>(D), WL);
488
489   BugReporter BR(*Mgr);
490   for (SmallVectorImpl<Decl*>::iterator WI=WL.begin(), WE=WL.end();
491        WI != WE; ++WI)
492     if ((*WI)->hasBody()) {
493       if (Mode != ANALYSIS_PATH)
494         checkerMgr->runCheckersOnASTBody(*WI, *Mgr, BR);
495       if (Mode != ANALYSIS_SYNTAX && checkerMgr->hasPathSensitiveCheckers()) {
496         RunPathSensitiveChecks(*WI, VisitedCallees);
497         NumFunctionsAnalyzed++;
498       }
499     }
500 }
501
502 //===----------------------------------------------------------------------===//
503 // Path-sensitive checking.
504 //===----------------------------------------------------------------------===//
505
506 void AnalysisConsumer::ActionExprEngine(Decl *D, bool ObjCGCEnabled,
507                                         SetOfConstDecls *VisitedCallees) {
508   // Construct the analysis engine.  First check if the CFG is valid.
509   // FIXME: Inter-procedural analysis will need to handle invalid CFGs.
510   if (!Mgr->getCFG(D))
511     return;
512
513   ExprEngine Eng(*Mgr, ObjCGCEnabled, VisitedCallees, &FunctionSummaries);
514
515   // Set the graph auditor.
516   OwningPtr<ExplodedNode::Auditor> Auditor;
517   if (Mgr->shouldVisualizeUbigraph()) {
518     Auditor.reset(CreateUbiViz());
519     ExplodedNode::SetAuditor(Auditor.get());
520   }
521
522   // Execute the worklist algorithm.
523   Eng.ExecuteWorkList(Mgr->getAnalysisDeclContextManager().getStackFrame(D, 0),
524                       Mgr->getMaxNodes());
525
526   // Release the auditor (if any) so that it doesn't monitor the graph
527   // created BugReporter.
528   ExplodedNode::SetAuditor(0);
529
530   // Visualize the exploded graph.
531   if (Mgr->shouldVisualizeGraphviz())
532     Eng.ViewGraph(Mgr->shouldTrimGraph());
533
534   // Display warnings.
535   Eng.getBugReporter().FlushReports();
536 }
537
538 void AnalysisConsumer::RunPathSensitiveChecks(Decl *D,
539                                               SetOfConstDecls *Visited) {
540
541   switch (Mgr->getLangOpts().getGC()) {
542   case LangOptions::NonGC:
543     ActionExprEngine(D, false, Visited);
544     break;
545   
546   case LangOptions::GCOnly:
547     ActionExprEngine(D, true, Visited);
548     break;
549   
550   case LangOptions::HybridGC:
551     ActionExprEngine(D, false, Visited);
552     ActionExprEngine(D, true, Visited);
553     break;
554   }
555 }
556
557 //===----------------------------------------------------------------------===//
558 // AnalysisConsumer creation.
559 //===----------------------------------------------------------------------===//
560
561 ASTConsumer* ento::CreateAnalysisConsumer(const Preprocessor& pp,
562                                           const std::string& outDir,
563                                           const AnalyzerOptions& opts,
564                                           ArrayRef<std::string> plugins) {
565   // Disable the effects of '-Werror' when using the AnalysisConsumer.
566   pp.getDiagnostics().setWarningsAsErrors(false);
567
568   return new AnalysisConsumer(pp, outDir, opts, plugins);
569 }
570
571 //===----------------------------------------------------------------------===//
572 // Ubigraph Visualization.  FIXME: Move to separate file.
573 //===----------------------------------------------------------------------===//
574
575 namespace {
576
577 class UbigraphViz : public ExplodedNode::Auditor {
578   OwningPtr<raw_ostream> Out;
579   llvm::sys::Path Dir, Filename;
580   unsigned Cntr;
581
582   typedef llvm::DenseMap<void*,unsigned> VMap;
583   VMap M;
584
585 public:
586   UbigraphViz(raw_ostream *out, llvm::sys::Path& dir,
587               llvm::sys::Path& filename);
588
589   ~UbigraphViz();
590
591   virtual void AddEdge(ExplodedNode *Src, ExplodedNode *Dst);
592 };
593
594 } // end anonymous namespace
595
596 static ExplodedNode::Auditor* CreateUbiViz() {
597   std::string ErrMsg;
598
599   llvm::sys::Path Dir = llvm::sys::Path::GetTemporaryDirectory(&ErrMsg);
600   if (!ErrMsg.empty())
601     return 0;
602
603   llvm::sys::Path Filename = Dir;
604   Filename.appendComponent("llvm_ubi");
605   Filename.makeUnique(true,&ErrMsg);
606
607   if (!ErrMsg.empty())
608     return 0;
609
610   llvm::errs() << "Writing '" << Filename.str() << "'.\n";
611
612   OwningPtr<llvm::raw_fd_ostream> Stream;
613   Stream.reset(new llvm::raw_fd_ostream(Filename.c_str(), ErrMsg));
614
615   if (!ErrMsg.empty())
616     return 0;
617
618   return new UbigraphViz(Stream.take(), Dir, Filename);
619 }
620
621 void UbigraphViz::AddEdge(ExplodedNode *Src, ExplodedNode *Dst) {
622
623   assert (Src != Dst && "Self-edges are not allowed.");
624
625   // Lookup the Src.  If it is a new node, it's a root.
626   VMap::iterator SrcI= M.find(Src);
627   unsigned SrcID;
628
629   if (SrcI == M.end()) {
630     M[Src] = SrcID = Cntr++;
631     *Out << "('vertex', " << SrcID << ", ('color','#00ff00'))\n";
632   }
633   else
634     SrcID = SrcI->second;
635
636   // Lookup the Dst.
637   VMap::iterator DstI= M.find(Dst);
638   unsigned DstID;
639
640   if (DstI == M.end()) {
641     M[Dst] = DstID = Cntr++;
642     *Out << "('vertex', " << DstID << ")\n";
643   }
644   else {
645     // We have hit DstID before.  Change its style to reflect a cache hit.
646     DstID = DstI->second;
647     *Out << "('change_vertex_style', " << DstID << ", 1)\n";
648   }
649
650   // Add the edge.
651   *Out << "('edge', " << SrcID << ", " << DstID
652        << ", ('arrow','true'), ('oriented', 'true'))\n";
653 }
654
655 UbigraphViz::UbigraphViz(raw_ostream *out, llvm::sys::Path& dir,
656                          llvm::sys::Path& filename)
657   : Out(out), Dir(dir), Filename(filename), Cntr(0) {
658
659   *Out << "('vertex_style_attribute', 0, ('shape', 'icosahedron'))\n";
660   *Out << "('vertex_style', 1, 0, ('shape', 'sphere'), ('color', '#ffcc66'),"
661           " ('size', '1.5'))\n";
662 }
663
664 UbigraphViz::~UbigraphViz() {
665   Out.reset(0);
666   llvm::errs() << "Running 'ubiviz' program... ";
667   std::string ErrMsg;
668   llvm::sys::Path Ubiviz = llvm::sys::Program::FindProgramByName("ubiviz");
669   std::vector<const char*> args;
670   args.push_back(Ubiviz.c_str());
671   args.push_back(Filename.c_str());
672   args.push_back(0);
673
674   if (llvm::sys::Program::ExecuteAndWait(Ubiviz, &args[0],0,0,0,0,&ErrMsg)) {
675     llvm::errs() << "Error viewing graph: " << ErrMsg << "\n";
676   }
677
678   // Delete the directory.
679   Dir.eraseFromDisk(true);
680 }