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