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