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