AnalysisConsumer.cpp revision e1ce783708b65eaa832ffad03d239264046dd0eb
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 PathDiagnosticConsumer*
68createPlistHTMLDiagnosticConsumer(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
79namespace {
80
81class 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
94public:
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
279private:
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//===----------------------------------------------------------------------===//
292llvm::Timer* AnalysisConsumer::TUTotalTimer = 0;
293
294bool AnalysisConsumer::HandleTopLevelDecl(DeclGroupRef DG) {
295  storeTopLevelDecls(DG);
296  return true;
297}
298
299void AnalysisConsumer::HandleTopLevelDeclInObjCContainer(DeclGroupRef DG) {
300  storeTopLevelDecls(DG);
301}
302
303void 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
315void 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
391void 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
448static 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
458static 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
470bool 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
485void 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
525void 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
561void 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
584ASTConsumer* 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
598namespace {
599
600class 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
608public:
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
619static 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
644void 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
678UbigraphViz::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
687UbigraphViz::~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}
704