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(const unsigned LocalTUDeclsSize);
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   bool shouldWalkTypesOfTypeLocs() const { return false; }
250 
251   /// Handle callbacks for arbitrary Decls.
252   bool VisitDecl(Decl *D) {
253     checkerMgr->runCheckersOnASTDecl(D, *Mgr, *RecVisitorBR);
254     return true;
255   }
256 
257   bool VisitFunctionDecl(FunctionDecl *FD) {
258     IdentifierInfo *II = FD->getIdentifier();
259     if (II && II->getName().startswith("__inline"))
260       return true;
261 
262     // We skip function template definitions, as their semantics is
263     // only determined when they are instantiated.
264     if (FD->isThisDeclarationADefinition() &&
265         !FD->isDependentContext()) {
266       HandleCode(FD, RecVisitorMode);
267     }
268     return true;
269   }
270 
271   bool VisitObjCMethodDecl(ObjCMethodDecl *MD) {
272     checkerMgr->runCheckersOnASTDecl(MD, *Mgr, *RecVisitorBR);
273     if (MD->isThisDeclarationADefinition())
274       HandleCode(MD, RecVisitorMode);
275     return true;
276   }
277 
278 private:
279   void storeTopLevelDecls(DeclGroupRef DG);
280 
281   /// \brief Check if we should skip (not analyze) the given function.
282   bool skipFunction(Decl *D);
283 
284 };
285 } // end anonymous namespace
286 
287 
288 //===----------------------------------------------------------------------===//
289 // AnalysisConsumer implementation.
290 //===----------------------------------------------------------------------===//
291 llvm::Timer* AnalysisConsumer::TUTotalTimer = 0;
292 
293 bool AnalysisConsumer::HandleTopLevelDecl(DeclGroupRef DG) {
294   storeTopLevelDecls(DG);
295   return true;
296 }
297 
298 void AnalysisConsumer::HandleTopLevelDeclInObjCContainer(DeclGroupRef DG) {
299   storeTopLevelDecls(DG);
300 }
301 
302 void AnalysisConsumer::storeTopLevelDecls(DeclGroupRef DG) {
303   for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I) {
304 
305     // Skip ObjCMethodDecl, wait for the objc container to avoid
306     // analyzing twice.
307     if (isa<ObjCMethodDecl>(*I))
308       continue;
309 
310     LocalTUDecls.push_back(*I);
311   }
312 }
313 
314 void AnalysisConsumer::HandleDeclsGallGraph(const unsigned LocalTUDeclsSize) {
315   // Otherwise, use the Callgraph to derive the order.
316   // Build the Call Graph.
317   CallGraph CG;
318 
319   // Add all the top level declarations to the graph.
320   // Note: CallGraph can trigger deserialization of more items from a pch
321   // (though HandleInterestingDecl); triggering additions to LocalTUDecls.
322   // We rely on random access to add the initially processed Decls to CG.
323   for (unsigned i = 0 ; i < LocalTUDeclsSize ; ++i) {
324     CG.addToCallGraph(LocalTUDecls[i]);
325   }
326 
327   // Find the top level nodes - children of root + the unreachable (parentless)
328   // nodes.
329   llvm::SmallVector<CallGraphNode*, 24> TopLevelFunctions;
330   for (CallGraph::nodes_iterator TI = CG.parentless_begin(),
331                                  TE = CG.parentless_end(); TI != TE; ++TI) {
332     TopLevelFunctions.push_back(*TI);
333     NumFunctionTopLevel++;
334   }
335   CallGraphNode *Entry = CG.getRoot();
336   for (CallGraphNode::iterator I = Entry->begin(),
337                                E = Entry->end(); I != E; ++I) {
338     TopLevelFunctions.push_back(*I);
339     NumFunctionTopLevel++;
340   }
341 
342   // Make sure the nodes are sorted in order reverse of their definition in the
343   // translation unit. This step is very important for performance. It ensures
344   // that we analyze the root functions before the externally available
345   // subroutines.
346   std::deque<CallGraphNode*> BFSQueue;
347   for (llvm::SmallVector<CallGraphNode*, 24>::reverse_iterator
348          TI = TopLevelFunctions.rbegin(), TE = TopLevelFunctions.rend();
349          TI != TE; ++TI)
350     BFSQueue.push_front(*TI);
351 
352   // BFS over all of the functions, while skipping the ones inlined into
353   // the previously processed functions. Use external Visited set, which is
354   // also modified when we inline a function.
355   SmallPtrSet<CallGraphNode*,24> Visited;
356   while(!BFSQueue.empty()) {
357     CallGraphNode *N = BFSQueue.front();
358     BFSQueue.pop_front();
359 
360     // Skip the functions which have been processed already or previously
361     // inlined.
362     if (Visited.count(N))
363       continue;
364 
365     // Analyze the function.
366     SetOfConstDecls VisitedCallees;
367     Decl *D = N->getDecl();
368     assert(D);
369     HandleCode(D, ANALYSIS_PATH,
370                (Mgr->InliningMode == All ? 0 : &VisitedCallees));
371 
372     // Add the visited callees to the global visited set.
373     for (SetOfConstDecls::iterator I = VisitedCallees.begin(),
374                                    E = VisitedCallees.end(); I != E; ++I) {
375       CallGraphNode *VN = CG.getNode(*I);
376       if (VN)
377         Visited.insert(VN);
378     }
379     Visited.insert(N);
380 
381     // Push the children into the queue.
382     for (CallGraphNode::const_iterator CI = N->begin(),
383                                        CE = N->end(); CI != CE; ++CI) {
384       BFSQueue.push_front(*CI);
385     }
386   }
387 }
388 
389 void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) {
390   // Don't run the actions if an error has occurred with parsing the file.
391   DiagnosticsEngine &Diags = PP.getDiagnostics();
392   if (Diags.hasErrorOccurred() || Diags.hasFatalErrorOccurred())
393     return;
394 
395   {
396     if (TUTotalTimer) TUTotalTimer->startTimer();
397 
398     // Introduce a scope to destroy BR before Mgr.
399     BugReporter BR(*Mgr);
400     TranslationUnitDecl *TU = C.getTranslationUnitDecl();
401     checkerMgr->runCheckersOnASTDecl(TU, *Mgr, BR);
402 
403     // Run the AST-only checks using the order in which functions are defined.
404     // If inlining is not turned on, use the simplest function order for path
405     // sensitive analyzes as well.
406     RecVisitorMode = (Mgr->shouldInlineCall() ? ANALYSIS_SYNTAX : ANALYSIS_ALL);
407     RecVisitorBR = &BR;
408 
409     // Process all the top level declarations.
410     //
411     // Note: TraverseDecl may modify LocalTUDecls, but only by appending more
412     // entries.  Thus we don't use an iterator, but rely on LocalTUDecls
413     // random access.  By doing so, we automatically compensate for iterators
414     // possibly being invalidated, although this is a bit slower.
415     const unsigned LocalTUDeclsSize = LocalTUDecls.size();
416     for (unsigned i = 0 ; i < LocalTUDeclsSize ; ++i) {
417       TraverseDecl(LocalTUDecls[i]);
418     }
419 
420     if (Mgr->shouldInlineCall())
421       HandleDeclsGallGraph(LocalTUDeclsSize);
422 
423     // After all decls handled, run checkers on the entire TranslationUnit.
424     checkerMgr->runCheckersOnEndOfTranslationUnit(TU, *Mgr, BR);
425 
426     RecVisitorBR = 0;
427   }
428 
429   // Explicitly destroy the PathDiagnosticConsumer.  This will flush its output.
430   // FIXME: This should be replaced with something that doesn't rely on
431   // side-effects in PathDiagnosticConsumer's destructor. This is required when
432   // used with option -disable-free.
433   Mgr.reset(NULL);
434 
435   if (TUTotalTimer) TUTotalTimer->stopTimer();
436 
437   // Count how many basic blocks we have not covered.
438   NumBlocksInAnalyzedFunctions = FunctionSummaries.getTotalNumBasicBlocks();
439   if (NumBlocksInAnalyzedFunctions > 0)
440     PercentReachableBlocks =
441       (FunctionSummaries.getTotalNumVisitedBasicBlocks() * 100) /
442         NumBlocksInAnalyzedFunctions;
443 
444 }
445 
446 static void FindBlocks(DeclContext *D, SmallVectorImpl<Decl*> &WL) {
447   if (BlockDecl *BD = dyn_cast<BlockDecl>(D))
448     WL.push_back(BD);
449 
450   for (DeclContext::decl_iterator I = D->decls_begin(), E = D->decls_end();
451        I!=E; ++I)
452     if (DeclContext *DC = dyn_cast<DeclContext>(*I))
453       FindBlocks(DC, WL);
454 }
455 
456 static std::string getFunctionName(const Decl *D) {
457   if (const ObjCMethodDecl *ID = dyn_cast<ObjCMethodDecl>(D)) {
458     return ID->getSelector().getAsString();
459   }
460   if (const FunctionDecl *ND = dyn_cast<FunctionDecl>(D)) {
461     IdentifierInfo *II = ND->getIdentifier();
462     if (II)
463       return II->getName();
464   }
465   return "";
466 }
467 
468 bool AnalysisConsumer::skipFunction(Decl *D) {
469   if (!Opts.AnalyzeSpecificFunction.empty() &&
470       getFunctionName(D) != Opts.AnalyzeSpecificFunction)
471     return true;
472 
473   // Don't run the actions on declarations in header files unless
474   // otherwise specified.
475   SourceManager &SM = Ctx->getSourceManager();
476   SourceLocation SL = SM.getExpansionLoc(D->getLocation());
477   if (!Opts.AnalyzeAll && !SM.isFromMainFile(SL))
478     return true;
479 
480   return false;
481 }
482 
483 void AnalysisConsumer::HandleCode(Decl *D, AnalysisMode Mode,
484                                   SetOfConstDecls *VisitedCallees) {
485   if (skipFunction(D))
486     return;
487 
488   DisplayFunction(D, Mode);
489 
490   // Clear the AnalysisManager of old AnalysisDeclContexts.
491   Mgr->ClearContexts();
492 
493   // Dispatch on the actions.
494   SmallVector<Decl*, 10> WL;
495   WL.push_back(D);
496 
497   if (D->hasBody() && Opts.AnalyzeNestedBlocks)
498     FindBlocks(cast<DeclContext>(D), WL);
499 
500   BugReporter BR(*Mgr);
501   for (SmallVectorImpl<Decl*>::iterator WI=WL.begin(), WE=WL.end();
502        WI != WE; ++WI)
503     if ((*WI)->hasBody()) {
504       if (Mode != ANALYSIS_PATH)
505         checkerMgr->runCheckersOnASTBody(*WI, *Mgr, BR);
506       if (Mode != ANALYSIS_SYNTAX && checkerMgr->hasPathSensitiveCheckers()) {
507         RunPathSensitiveChecks(*WI, VisitedCallees);
508         NumFunctionsAnalyzed++;
509       }
510     }
511 }
512 
513 //===----------------------------------------------------------------------===//
514 // Path-sensitive checking.
515 //===----------------------------------------------------------------------===//
516 
517 void AnalysisConsumer::ActionExprEngine(Decl *D, bool ObjCGCEnabled,
518                                         SetOfConstDecls *VisitedCallees) {
519   // Construct the analysis engine.  First check if the CFG is valid.
520   // FIXME: Inter-procedural analysis will need to handle invalid CFGs.
521   if (!Mgr->getCFG(D))
522     return;
523 
524   ExprEngine Eng(*Mgr, ObjCGCEnabled, VisitedCallees, &FunctionSummaries);
525 
526   // Set the graph auditor.
527   OwningPtr<ExplodedNode::Auditor> Auditor;
528   if (Mgr->shouldVisualizeUbigraph()) {
529     Auditor.reset(CreateUbiViz());
530     ExplodedNode::SetAuditor(Auditor.get());
531   }
532 
533   // Execute the worklist algorithm.
534   Eng.ExecuteWorkList(Mgr->getAnalysisDeclContextManager().getStackFrame(D),
535                       Mgr->getMaxNodes());
536 
537   // Release the auditor (if any) so that it doesn't monitor the graph
538   // created BugReporter.
539   ExplodedNode::SetAuditor(0);
540 
541   // Visualize the exploded graph.
542   if (Mgr->shouldVisualizeGraphviz())
543     Eng.ViewGraph(Mgr->shouldTrimGraph());
544 
545   // Display warnings.
546   Eng.getBugReporter().FlushReports();
547 }
548 
549 void AnalysisConsumer::RunPathSensitiveChecks(Decl *D,
550                                               SetOfConstDecls *Visited) {
551 
552   switch (Mgr->getLangOpts().getGC()) {
553   case LangOptions::NonGC:
554     ActionExprEngine(D, false, Visited);
555     break;
556 
557   case LangOptions::GCOnly:
558     ActionExprEngine(D, true, Visited);
559     break;
560 
561   case LangOptions::HybridGC:
562     ActionExprEngine(D, false, Visited);
563     ActionExprEngine(D, true, Visited);
564     break;
565   }
566 }
567 
568 //===----------------------------------------------------------------------===//
569 // AnalysisConsumer creation.
570 //===----------------------------------------------------------------------===//
571 
572 ASTConsumer* ento::CreateAnalysisConsumer(const Preprocessor& pp,
573                                           const std::string& outDir,
574                                           const AnalyzerOptions& opts,
575                                           ArrayRef<std::string> plugins) {
576   // Disable the effects of '-Werror' when using the AnalysisConsumer.
577   pp.getDiagnostics().setWarningsAsErrors(false);
578 
579   return new AnalysisConsumer(pp, outDir, opts, plugins);
580 }
581 
582 //===----------------------------------------------------------------------===//
583 // Ubigraph Visualization.  FIXME: Move to separate file.
584 //===----------------------------------------------------------------------===//
585 
586 namespace {
587 
588 class UbigraphViz : public ExplodedNode::Auditor {
589   OwningPtr<raw_ostream> Out;
590   llvm::sys::Path Dir, Filename;
591   unsigned Cntr;
592 
593   typedef llvm::DenseMap<void*,unsigned> VMap;
594   VMap M;
595 
596 public:
597   UbigraphViz(raw_ostream *out, llvm::sys::Path& dir,
598               llvm::sys::Path& filename);
599 
600   ~UbigraphViz();
601 
602   virtual void AddEdge(ExplodedNode *Src, ExplodedNode *Dst);
603 };
604 
605 } // end anonymous namespace
606 
607 static ExplodedNode::Auditor* CreateUbiViz() {
608   std::string ErrMsg;
609 
610   llvm::sys::Path Dir = llvm::sys::Path::GetTemporaryDirectory(&ErrMsg);
611   if (!ErrMsg.empty())
612     return 0;
613 
614   llvm::sys::Path Filename = Dir;
615   Filename.appendComponent("llvm_ubi");
616   Filename.makeUnique(true,&ErrMsg);
617 
618   if (!ErrMsg.empty())
619     return 0;
620 
621   llvm::errs() << "Writing '" << Filename.str() << "'.\n";
622 
623   OwningPtr<llvm::raw_fd_ostream> Stream;
624   Stream.reset(new llvm::raw_fd_ostream(Filename.c_str(), ErrMsg));
625 
626   if (!ErrMsg.empty())
627     return 0;
628 
629   return new UbigraphViz(Stream.take(), Dir, Filename);
630 }
631 
632 void UbigraphViz::AddEdge(ExplodedNode *Src, ExplodedNode *Dst) {
633 
634   assert (Src != Dst && "Self-edges are not allowed.");
635 
636   // Lookup the Src.  If it is a new node, it's a root.
637   VMap::iterator SrcI= M.find(Src);
638   unsigned SrcID;
639 
640   if (SrcI == M.end()) {
641     M[Src] = SrcID = Cntr++;
642     *Out << "('vertex', " << SrcID << ", ('color','#00ff00'))\n";
643   }
644   else
645     SrcID = SrcI->second;
646 
647   // Lookup the Dst.
648   VMap::iterator DstI= M.find(Dst);
649   unsigned DstID;
650 
651   if (DstI == M.end()) {
652     M[Dst] = DstID = Cntr++;
653     *Out << "('vertex', " << DstID << ")\n";
654   }
655   else {
656     // We have hit DstID before.  Change its style to reflect a cache hit.
657     DstID = DstI->second;
658     *Out << "('change_vertex_style', " << DstID << ", 1)\n";
659   }
660 
661   // Add the edge.
662   *Out << "('edge', " << SrcID << ", " << DstID
663        << ", ('arrow','true'), ('oriented', 'true'))\n";
664 }
665 
666 UbigraphViz::UbigraphViz(raw_ostream *out, llvm::sys::Path& dir,
667                          llvm::sys::Path& filename)
668   : Out(out), Dir(dir), Filename(filename), Cntr(0) {
669 
670   *Out << "('vertex_style_attribute', 0, ('shape', 'icosahedron'))\n";
671   *Out << "('vertex_style', 1, 0, ('shape', 'sphere'), ('color', '#ffcc66'),"
672           " ('size', '1.5'))\n";
673 }
674 
675 UbigraphViz::~UbigraphViz() {
676   Out.reset(0);
677   llvm::errs() << "Running 'ubiviz' program... ";
678   std::string ErrMsg;
679   llvm::sys::Path Ubiviz = llvm::sys::Program::FindProgramByName("ubiviz");
680   std::vector<const char*> args;
681   args.push_back(Ubiviz.c_str());
682   args.push_back(Filename.c_str());
683   args.push_back(0);
684 
685   if (llvm::sys::Program::ExecuteAndWait(Ubiviz, &args[0],0,0,0,0,&ErrMsg)) {
686     llvm::errs() << "Error viewing graph: " << ErrMsg << "\n";
687   }
688 
689   // Delete the directory.
690   Dir.eraseFromDisk(true);
691 }
692