• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/StaticAnalyzer/Frontend/CheckerRegistration.h"
26 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
27 #include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
28 #include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
29 #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
30 #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
31 #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
32 #include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h"
33 
34 #include "clang/Basic/FileManager.h"
35 #include "clang/Basic/SourceManager.h"
36 #include "clang/Frontend/AnalyzerOptions.h"
37 #include "clang/Lex/Preprocessor.h"
38 #include "llvm/Support/raw_ostream.h"
39 #include "llvm/Support/Path.h"
40 #include "llvm/Support/Program.h"
41 #include "llvm/Support/Timer.h"
42 #include "llvm/ADT/DepthFirstIterator.h"
43 #include "llvm/ADT/OwningPtr.h"
44 #include "llvm/ADT/SmallPtrSet.h"
45 #include "llvm/ADT/Statistic.h"
46 
47 #include <queue>
48 
49 using namespace clang;
50 using namespace ento;
51 using llvm::SmallPtrSet;
52 
53 static ExplodedNode::Auditor* CreateUbiViz();
54 
55 STATISTIC(NumFunctionTopLevel, "The # of functions at top level.");
56 STATISTIC(NumFunctionsAnalyzed, "The # of functions analysed (as top level).");
57 STATISTIC(NumBlocksInAnalyzedFunctions,
58                      "The # of basic blocks in the analyzed functions.");
59 STATISTIC(PercentReachableBlocks, "The % of reachable basic blocks.");
60 
61 //===----------------------------------------------------------------------===//
62 // Special PathDiagnosticConsumers.
63 //===----------------------------------------------------------------------===//
64 
65 static PathDiagnosticConsumer*
createPlistHTMLDiagnosticConsumer(const std::string & prefix,const Preprocessor & PP)66 createPlistHTMLDiagnosticConsumer(const std::string& prefix,
67                                 const Preprocessor &PP) {
68   PathDiagnosticConsumer *PD =
69     createHTMLDiagnosticConsumer(llvm::sys::path::parent_path(prefix), PP);
70   return createPlistDiagnosticConsumer(prefix, PP, PD);
71 }
72 
73 //===----------------------------------------------------------------------===//
74 // AnalysisConsumer declaration.
75 //===----------------------------------------------------------------------===//
76 
77 namespace {
78 
79 class AnalysisConsumer : public ASTConsumer,
80                          public RecursiveASTVisitor<AnalysisConsumer> {
81   enum AnalysisMode {
82     ANALYSIS_SYNTAX,
83     ANALYSIS_PATH,
84     ANALYSIS_ALL
85   };
86 
87   /// Mode of the analyzes while recursively visiting Decls.
88   AnalysisMode RecVisitorMode;
89   /// Bug Reporter to use while recursively visiting Decls.
90   BugReporter *RecVisitorBR;
91 
92 public:
93   ASTContext *Ctx;
94   const Preprocessor &PP;
95   const std::string OutDir;
96   AnalyzerOptions Opts;
97   ArrayRef<std::string> Plugins;
98 
99   /// \brief Stores the declarations from the local translation unit.
100   /// Note, we pre-compute the local declarations at parse time as an
101   /// optimization to make sure we do not deserialize everything from disk.
102   /// The local declaration to all declarations ratio might be very small when
103   /// working with a PCH file.
104   SetOfDecls LocalTUDecls;
105 
106   // PD is owned by AnalysisManager.
107   PathDiagnosticConsumer *PD;
108 
109   StoreManagerCreator CreateStoreMgr;
110   ConstraintManagerCreator CreateConstraintMgr;
111 
112   OwningPtr<CheckerManager> checkerMgr;
113   OwningPtr<AnalysisManager> Mgr;
114 
115   /// Time the analyzes time of each translation unit.
116   static llvm::Timer* TUTotalTimer;
117 
118   /// The information about analyzed functions shared throughout the
119   /// translation unit.
120   FunctionSummariesTy FunctionSummaries;
121 
AnalysisConsumer(const Preprocessor & pp,const std::string & outdir,const AnalyzerOptions & opts,ArrayRef<std::string> plugins)122   AnalysisConsumer(const Preprocessor& pp,
123                    const std::string& outdir,
124                    const AnalyzerOptions& opts,
125                    ArrayRef<std::string> plugins)
126     : RecVisitorMode(ANALYSIS_ALL), RecVisitorBR(0),
127       Ctx(0), PP(pp), OutDir(outdir), Opts(opts), Plugins(plugins), PD(0) {
128     DigestAnalyzerOptions();
129     if (Opts.PrintStats) {
130       llvm::EnableStatistics();
131       TUTotalTimer = new llvm::Timer("Analyzer Total Time");
132     }
133   }
134 
~AnalysisConsumer()135   ~AnalysisConsumer() {
136     if (Opts.PrintStats)
137       delete TUTotalTimer;
138   }
139 
DigestAnalyzerOptions()140   void DigestAnalyzerOptions() {
141     // Create the PathDiagnosticConsumer.
142     if (!OutDir.empty()) {
143       switch (Opts.AnalysisDiagOpt) {
144       default:
145 #define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN, AUTOCREATE) \
146         case PD_##NAME: PD = CREATEFN(OutDir, PP); break;
147 #include "clang/Frontend/Analyses.def"
148       }
149     } else if (Opts.AnalysisDiagOpt == PD_TEXT) {
150       // Create the text client even without a specified output file since
151       // it just uses diagnostic notes.
152       PD = createTextPathDiagnosticConsumer("", PP);
153     }
154 
155     // Create the analyzer component creators.
156     switch (Opts.AnalysisStoreOpt) {
157     default:
158       llvm_unreachable("Unknown store manager.");
159 #define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATEFN)           \
160       case NAME##Model: CreateStoreMgr = CREATEFN; break;
161 #include "clang/Frontend/Analyses.def"
162     }
163 
164     switch (Opts.AnalysisConstraintsOpt) {
165     default:
166       llvm_unreachable("Unknown store manager.");
167 #define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATEFN)     \
168       case NAME##Model: CreateConstraintMgr = CREATEFN; break;
169 #include "clang/Frontend/Analyses.def"
170     }
171   }
172 
DisplayFunction(const Decl * D,AnalysisMode Mode)173   void DisplayFunction(const Decl *D, AnalysisMode Mode) {
174     if (!Opts.AnalyzerDisplayProgress)
175       return;
176 
177     SourceManager &SM = Mgr->getASTContext().getSourceManager();
178     PresumedLoc Loc = SM.getPresumedLoc(D->getLocation());
179     if (Loc.isValid()) {
180       llvm::errs() << "ANALYZE";
181       switch (Mode) {
182         case ANALYSIS_SYNTAX: llvm::errs() << "(Syntax)"; break;
183         case ANALYSIS_PATH: llvm::errs() << "(Path Sensitive)"; break;
184         case ANALYSIS_ALL: break;
185       };
186       llvm::errs() << ": " << Loc.getFilename();
187       if (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)) {
188         const NamedDecl *ND = cast<NamedDecl>(D);
189         llvm::errs() << ' ' << *ND << '\n';
190       }
191       else if (isa<BlockDecl>(D)) {
192         llvm::errs() << ' ' << "block(line:" << Loc.getLine() << ",col:"
193                      << Loc.getColumn() << '\n';
194       }
195       else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
196         Selector S = MD->getSelector();
197         llvm::errs() << ' ' << S.getAsString();
198       }
199     }
200   }
201 
Initialize(ASTContext & Context)202   virtual void Initialize(ASTContext &Context) {
203     Ctx = &Context;
204     checkerMgr.reset(createCheckerManager(Opts, PP.getLangOpts(), Plugins,
205                                           PP.getDiagnostics()));
206     Mgr.reset(new AnalysisManager(*Ctx, PP.getDiagnostics(),
207                                   PP.getLangOpts(), PD,
208                                   CreateStoreMgr, CreateConstraintMgr,
209                                   checkerMgr.get(),
210                                   Opts.MaxNodes, Opts.MaxLoop,
211                                   Opts.VisualizeEGDot, Opts.VisualizeEGUbi,
212                                   Opts.AnalysisPurgeOpt, Opts.EagerlyAssume,
213                                   Opts.TrimGraph,
214                                   Opts.UnoptimizedCFG, Opts.CFGAddImplicitDtors,
215                                   Opts.CFGAddInitializers,
216                                   Opts.EagerlyTrimEGraph,
217                                   Opts.IPAMode,
218                                   Opts.InlineMaxStackDepth,
219                                   Opts.InlineMaxFunctionSize,
220                                   Opts.InliningMode,
221                                   Opts.NoRetryExhausted));
222   }
223 
224   /// \brief Store the top level decls in the set to be processed later on.
225   /// (Doing this pre-processing avoids deserialization of data from PCH.)
226   virtual bool HandleTopLevelDecl(DeclGroupRef D);
227   virtual void HandleTopLevelDeclInObjCContainer(DeclGroupRef D);
228 
229   virtual void HandleTranslationUnit(ASTContext &C);
230 
231   /// \brief Build the call graph for all the top level decls of this TU and
232   /// use it to define the order in which the functions should be visited.
233   void HandleDeclsGallGraph();
234 
235   /// \brief Run analyzes(syntax or path sensitive) on the given function.
236   /// \param Mode - determines if we are requesting syntax only or path
237   /// sensitive only analysis.
238   /// \param VisitedCallees - The output parameter, which is populated with the
239   /// set of functions which should be considered analyzed after analyzing the
240   /// given root function.
241   void HandleCode(Decl *D, AnalysisMode Mode,
242                   SetOfConstDecls *VisitedCallees = 0);
243 
244   void RunPathSensitiveChecks(Decl *D, SetOfConstDecls *VisitedCallees);
245   void ActionExprEngine(Decl *D, bool ObjCGCEnabled,
246                         SetOfConstDecls *VisitedCallees);
247 
248   /// Visitors for the RecursiveASTVisitor.
249 
250   /// Handle callbacks for arbitrary Decls.
VisitDecl(Decl * D)251   bool VisitDecl(Decl *D) {
252     checkerMgr->runCheckersOnASTDecl(D, *Mgr, *RecVisitorBR);
253     return true;
254   }
255 
VisitFunctionDecl(FunctionDecl * FD)256   bool VisitFunctionDecl(FunctionDecl *FD) {
257     IdentifierInfo *II = FD->getIdentifier();
258     if (II && II->getName().startswith("__inline"))
259       return true;
260 
261     // We skip function template definitions, as their semantics is
262     // only determined when they are instantiated.
263     if (FD->isThisDeclarationADefinition() &&
264         !FD->isDependentContext()) {
265       HandleCode(FD, RecVisitorMode);
266     }
267     return true;
268   }
269 
VisitObjCMethodDecl(ObjCMethodDecl * MD)270   bool VisitObjCMethodDecl(ObjCMethodDecl *MD) {
271     checkerMgr->runCheckersOnASTDecl(MD, *Mgr, *RecVisitorBR);
272     if (MD->isThisDeclarationADefinition())
273       HandleCode(MD, RecVisitorMode);
274     return true;
275   }
276 
277 private:
278   void storeTopLevelDecls(DeclGroupRef DG);
279 
280   /// \brief Check if we should skip (not analyze) the given function.
281   bool skipFunction(Decl *D);
282 
283 };
284 } // end anonymous namespace
285 
286 
287 //===----------------------------------------------------------------------===//
288 // AnalysisConsumer implementation.
289 //===----------------------------------------------------------------------===//
290 llvm::Timer* AnalysisConsumer::TUTotalTimer = 0;
291 
HandleTopLevelDecl(DeclGroupRef DG)292 bool AnalysisConsumer::HandleTopLevelDecl(DeclGroupRef DG) {
293   storeTopLevelDecls(DG);
294   return true;
295 }
296 
HandleTopLevelDeclInObjCContainer(DeclGroupRef DG)297 void AnalysisConsumer::HandleTopLevelDeclInObjCContainer(DeclGroupRef DG) {
298   storeTopLevelDecls(DG);
299 }
300 
storeTopLevelDecls(DeclGroupRef DG)301 void AnalysisConsumer::storeTopLevelDecls(DeclGroupRef DG) {
302   for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I) {
303 
304     // Skip ObjCMethodDecl, wait for the objc container to avoid
305     // analyzing twice.
306     if (isa<ObjCMethodDecl>(*I))
307       continue;
308 
309     LocalTUDecls.insert(*I);
310   }
311 }
312 
HandleDeclsGallGraph()313 void AnalysisConsumer::HandleDeclsGallGraph() {
314   // Otherwise, use the Callgraph to derive the order.
315   // Build the Call Graph.
316   CallGraph CG;
317   // Add all the top level declarations to the graph.
318   for (SetOfDecls::iterator I = LocalTUDecls.begin(),
319                             E = LocalTUDecls.end(); I != E; ++I)
320     CG.addToCallGraph(*I);
321 
322   // Find the top level nodes - children of root + the unreachable (parentless)
323   // nodes.
324   llvm::SmallVector<CallGraphNode*, 24> TopLevelFunctions;
325   for (CallGraph::nodes_iterator TI = CG.parentless_begin(),
326                                  TE = CG.parentless_end(); TI != TE; ++TI) {
327     TopLevelFunctions.push_back(*TI);
328     NumFunctionTopLevel++;
329   }
330   CallGraphNode *Entry = CG.getRoot();
331   for (CallGraphNode::iterator I = Entry->begin(),
332                                E = Entry->end(); I != E; ++I) {
333     TopLevelFunctions.push_back(*I);
334     NumFunctionTopLevel++;
335   }
336 
337   // Make sure the nodes are sorted in order reverse of their definition in the
338   // translation unit. This step is very important for performance. It ensures
339   // that we analyze the root functions before the externally available
340   // subroutines.
341   std::queue<CallGraphNode*> BFSQueue;
342   for (llvm::SmallVector<CallGraphNode*, 24>::reverse_iterator
343          TI = TopLevelFunctions.rbegin(), TE = TopLevelFunctions.rend();
344          TI != TE; ++TI)
345     BFSQueue.push(*TI);
346 
347   // BFS over all of the functions, while skipping the ones inlined into
348   // the previously processed functions. Use external Visited set, which is
349   // also modified when we inline a function.
350   SmallPtrSet<CallGraphNode*,24> Visited;
351   while(!BFSQueue.empty()) {
352     CallGraphNode *N = BFSQueue.front();
353     BFSQueue.pop();
354 
355     // Skip the functions which have been processed already or previously
356     // inlined.
357     if (Visited.count(N))
358       continue;
359 
360     // Analyze the function.
361     SetOfConstDecls VisitedCallees;
362     Decl *D = N->getDecl();
363     assert(D);
364     HandleCode(D, ANALYSIS_PATH,
365                (Mgr->InliningMode == All ? 0 : &VisitedCallees));
366 
367     // Add the visited callees to the global visited set.
368     for (SetOfConstDecls::const_iterator I = VisitedCallees.begin(),
369                                          E = VisitedCallees.end(); I != E; ++I){
370       CallGraphNode *VN = CG.getNode(*I);
371       if (VN)
372         Visited.insert(VN);
373     }
374     Visited.insert(N);
375 
376     // Push the children into the queue.
377     for (CallGraphNode::const_iterator CI = N->begin(),
378                                        CE = N->end(); CI != CE; ++CI) {
379       BFSQueue.push(*CI);
380     }
381   }
382 }
383 
HandleTranslationUnit(ASTContext & C)384 void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) {
385   // Don't run the actions if an error has occurred with parsing the file.
386   DiagnosticsEngine &Diags = PP.getDiagnostics();
387   if (Diags.hasErrorOccurred() || Diags.hasFatalErrorOccurred())
388     return;
389 
390   {
391     if (TUTotalTimer) TUTotalTimer->startTimer();
392 
393     // Introduce a scope to destroy BR before Mgr.
394     BugReporter BR(*Mgr);
395     TranslationUnitDecl *TU = C.getTranslationUnitDecl();
396     checkerMgr->runCheckersOnASTDecl(TU, *Mgr, BR);
397 
398     // Run the AST-only checks using the order in which functions are defined.
399     // If inlining is not turned on, use the simplest function order for path
400     // sensitive analyzes as well.
401     RecVisitorMode = (Mgr->shouldInlineCall() ? ANALYSIS_SYNTAX : ANALYSIS_ALL);
402     RecVisitorBR = &BR;
403 
404     // Process all the top level declarations.
405     for (SetOfDecls::iterator I = LocalTUDecls.begin(),
406                               E = LocalTUDecls.end(); I != E; ++I)
407       TraverseDecl(*I);
408 
409     if (Mgr->shouldInlineCall())
410       HandleDeclsGallGraph();
411 
412     // After all decls handled, run checkers on the entire TranslationUnit.
413     checkerMgr->runCheckersOnEndOfTranslationUnit(TU, *Mgr, BR);
414 
415     RecVisitorBR = 0;
416   }
417 
418   // Explicitly destroy the PathDiagnosticConsumer.  This will flush its output.
419   // FIXME: This should be replaced with something that doesn't rely on
420   // side-effects in PathDiagnosticConsumer's destructor. This is required when
421   // used with option -disable-free.
422   Mgr.reset(NULL);
423 
424   if (TUTotalTimer) TUTotalTimer->stopTimer();
425 
426   // Count how many basic blocks we have not covered.
427   NumBlocksInAnalyzedFunctions = FunctionSummaries.getTotalNumBasicBlocks();
428   if (NumBlocksInAnalyzedFunctions > 0)
429     PercentReachableBlocks =
430       (FunctionSummaries.getTotalNumVisitedBasicBlocks() * 100) /
431         NumBlocksInAnalyzedFunctions;
432 
433 }
434 
FindBlocks(DeclContext * D,SmallVectorImpl<Decl * > & WL)435 static void FindBlocks(DeclContext *D, SmallVectorImpl<Decl*> &WL) {
436   if (BlockDecl *BD = dyn_cast<BlockDecl>(D))
437     WL.push_back(BD);
438 
439   for (DeclContext::decl_iterator I = D->decls_begin(), E = D->decls_end();
440        I!=E; ++I)
441     if (DeclContext *DC = dyn_cast<DeclContext>(*I))
442       FindBlocks(DC, WL);
443 }
444 
getFunctionName(const Decl * D)445 static std::string getFunctionName(const Decl *D) {
446   if (const ObjCMethodDecl *ID = dyn_cast<ObjCMethodDecl>(D)) {
447     return ID->getSelector().getAsString();
448   }
449   if (const FunctionDecl *ND = dyn_cast<FunctionDecl>(D)) {
450     IdentifierInfo *II = ND->getIdentifier();
451     if (II)
452       return II->getName();
453   }
454   return "";
455 }
456 
skipFunction(Decl * D)457 bool AnalysisConsumer::skipFunction(Decl *D) {
458   if (!Opts.AnalyzeSpecificFunction.empty() &&
459       getFunctionName(D) != Opts.AnalyzeSpecificFunction)
460     return true;
461 
462   // Don't run the actions on declarations in header files unless
463   // otherwise specified.
464   SourceManager &SM = Ctx->getSourceManager();
465   SourceLocation SL = SM.getExpansionLoc(D->getLocation());
466   if (!Opts.AnalyzeAll && !SM.isFromMainFile(SL))
467     return true;
468 
469   return false;
470 }
471 
HandleCode(Decl * D,AnalysisMode Mode,SetOfConstDecls * VisitedCallees)472 void AnalysisConsumer::HandleCode(Decl *D, AnalysisMode Mode,
473                                   SetOfConstDecls *VisitedCallees) {
474   if (skipFunction(D))
475     return;
476 
477   DisplayFunction(D, Mode);
478 
479   // Clear the AnalysisManager of old AnalysisDeclContexts.
480   Mgr->ClearContexts();
481 
482   // Dispatch on the actions.
483   SmallVector<Decl*, 10> WL;
484   WL.push_back(D);
485 
486   if (D->hasBody() && Opts.AnalyzeNestedBlocks)
487     FindBlocks(cast<DeclContext>(D), WL);
488 
489   BugReporter BR(*Mgr);
490   for (SmallVectorImpl<Decl*>::iterator WI=WL.begin(), WE=WL.end();
491        WI != WE; ++WI)
492     if ((*WI)->hasBody()) {
493       if (Mode != ANALYSIS_PATH)
494         checkerMgr->runCheckersOnASTBody(*WI, *Mgr, BR);
495       if (Mode != ANALYSIS_SYNTAX && checkerMgr->hasPathSensitiveCheckers()) {
496         RunPathSensitiveChecks(*WI, VisitedCallees);
497         NumFunctionsAnalyzed++;
498       }
499     }
500 }
501 
502 //===----------------------------------------------------------------------===//
503 // Path-sensitive checking.
504 //===----------------------------------------------------------------------===//
505 
ActionExprEngine(Decl * D,bool ObjCGCEnabled,SetOfConstDecls * VisitedCallees)506 void AnalysisConsumer::ActionExprEngine(Decl *D, bool ObjCGCEnabled,
507                                         SetOfConstDecls *VisitedCallees) {
508   // Construct the analysis engine.  First check if the CFG is valid.
509   // FIXME: Inter-procedural analysis will need to handle invalid CFGs.
510   if (!Mgr->getCFG(D))
511     return;
512 
513   ExprEngine Eng(*Mgr, ObjCGCEnabled, VisitedCallees, &FunctionSummaries);
514 
515   // Set the graph auditor.
516   OwningPtr<ExplodedNode::Auditor> Auditor;
517   if (Mgr->shouldVisualizeUbigraph()) {
518     Auditor.reset(CreateUbiViz());
519     ExplodedNode::SetAuditor(Auditor.get());
520   }
521 
522   // Execute the worklist algorithm.
523   Eng.ExecuteWorkList(Mgr->getAnalysisDeclContextManager().getStackFrame(D, 0),
524                       Mgr->getMaxNodes());
525 
526   // Release the auditor (if any) so that it doesn't monitor the graph
527   // created BugReporter.
528   ExplodedNode::SetAuditor(0);
529 
530   // Visualize the exploded graph.
531   if (Mgr->shouldVisualizeGraphviz())
532     Eng.ViewGraph(Mgr->shouldTrimGraph());
533 
534   // Display warnings.
535   Eng.getBugReporter().FlushReports();
536 }
537 
RunPathSensitiveChecks(Decl * D,SetOfConstDecls * Visited)538 void AnalysisConsumer::RunPathSensitiveChecks(Decl *D,
539                                               SetOfConstDecls *Visited) {
540 
541   switch (Mgr->getLangOpts().getGC()) {
542   case LangOptions::NonGC:
543     ActionExprEngine(D, false, Visited);
544     break;
545 
546   case LangOptions::GCOnly:
547     ActionExprEngine(D, true, Visited);
548     break;
549 
550   case LangOptions::HybridGC:
551     ActionExprEngine(D, false, Visited);
552     ActionExprEngine(D, true, Visited);
553     break;
554   }
555 }
556 
557 //===----------------------------------------------------------------------===//
558 // AnalysisConsumer creation.
559 //===----------------------------------------------------------------------===//
560 
CreateAnalysisConsumer(const Preprocessor & pp,const std::string & outDir,const AnalyzerOptions & opts,ArrayRef<std::string> plugins)561 ASTConsumer* ento::CreateAnalysisConsumer(const Preprocessor& pp,
562                                           const std::string& outDir,
563                                           const AnalyzerOptions& opts,
564                                           ArrayRef<std::string> plugins) {
565   // Disable the effects of '-Werror' when using the AnalysisConsumer.
566   pp.getDiagnostics().setWarningsAsErrors(false);
567 
568   return new AnalysisConsumer(pp, outDir, opts, plugins);
569 }
570 
571 //===----------------------------------------------------------------------===//
572 // Ubigraph Visualization.  FIXME: Move to separate file.
573 //===----------------------------------------------------------------------===//
574 
575 namespace {
576 
577 class UbigraphViz : public ExplodedNode::Auditor {
578   OwningPtr<raw_ostream> Out;
579   llvm::sys::Path Dir, Filename;
580   unsigned Cntr;
581 
582   typedef llvm::DenseMap<void*,unsigned> VMap;
583   VMap M;
584 
585 public:
586   UbigraphViz(raw_ostream *out, llvm::sys::Path& dir,
587               llvm::sys::Path& filename);
588 
589   ~UbigraphViz();
590 
591   virtual void AddEdge(ExplodedNode *Src, ExplodedNode *Dst);
592 };
593 
594 } // end anonymous namespace
595 
CreateUbiViz()596 static ExplodedNode::Auditor* CreateUbiViz() {
597   std::string ErrMsg;
598 
599   llvm::sys::Path Dir = llvm::sys::Path::GetTemporaryDirectory(&ErrMsg);
600   if (!ErrMsg.empty())
601     return 0;
602 
603   llvm::sys::Path Filename = Dir;
604   Filename.appendComponent("llvm_ubi");
605   Filename.makeUnique(true,&ErrMsg);
606 
607   if (!ErrMsg.empty())
608     return 0;
609 
610   llvm::errs() << "Writing '" << Filename.str() << "'.\n";
611 
612   OwningPtr<llvm::raw_fd_ostream> Stream;
613   Stream.reset(new llvm::raw_fd_ostream(Filename.c_str(), ErrMsg));
614 
615   if (!ErrMsg.empty())
616     return 0;
617 
618   return new UbigraphViz(Stream.take(), Dir, Filename);
619 }
620 
AddEdge(ExplodedNode * Src,ExplodedNode * Dst)621 void UbigraphViz::AddEdge(ExplodedNode *Src, ExplodedNode *Dst) {
622 
623   assert (Src != Dst && "Self-edges are not allowed.");
624 
625   // Lookup the Src.  If it is a new node, it's a root.
626   VMap::iterator SrcI= M.find(Src);
627   unsigned SrcID;
628 
629   if (SrcI == M.end()) {
630     M[Src] = SrcID = Cntr++;
631     *Out << "('vertex', " << SrcID << ", ('color','#00ff00'))\n";
632   }
633   else
634     SrcID = SrcI->second;
635 
636   // Lookup the Dst.
637   VMap::iterator DstI= M.find(Dst);
638   unsigned DstID;
639 
640   if (DstI == M.end()) {
641     M[Dst] = DstID = Cntr++;
642     *Out << "('vertex', " << DstID << ")\n";
643   }
644   else {
645     // We have hit DstID before.  Change its style to reflect a cache hit.
646     DstID = DstI->second;
647     *Out << "('change_vertex_style', " << DstID << ", 1)\n";
648   }
649 
650   // Add the edge.
651   *Out << "('edge', " << SrcID << ", " << DstID
652        << ", ('arrow','true'), ('oriented', 'true'))\n";
653 }
654 
UbigraphViz(raw_ostream * out,llvm::sys::Path & dir,llvm::sys::Path & filename)655 UbigraphViz::UbigraphViz(raw_ostream *out, llvm::sys::Path& dir,
656                          llvm::sys::Path& filename)
657   : Out(out), Dir(dir), Filename(filename), Cntr(0) {
658 
659   *Out << "('vertex_style_attribute', 0, ('shape', 'icosahedron'))\n";
660   *Out << "('vertex_style', 1, 0, ('shape', 'sphere'), ('color', '#ffcc66'),"
661           " ('size', '1.5'))\n";
662 }
663 
~UbigraphViz()664 UbigraphViz::~UbigraphViz() {
665   Out.reset(0);
666   llvm::errs() << "Running 'ubiviz' program... ";
667   std::string ErrMsg;
668   llvm::sys::Path Ubiviz = llvm::sys::Program::FindProgramByName("ubiviz");
669   std::vector<const char*> args;
670   args.push_back(Ubiviz.c_str());
671   args.push_back(Filename.c_str());
672   args.push_back(0);
673 
674   if (llvm::sys::Program::ExecuteAndWait(Ubiviz, &args[0],0,0,0,0,&ErrMsg)) {
675     llvm::errs() << "Error viewing graph: " << ErrMsg << "\n";
676   }
677 
678   // Delete the directory.
679   Dir.eraseFromDisk(true);
680 }
681