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