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