Home | History | Annotate | Download | only in Frontend
      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*
     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 
    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 
    135   ~AnalysisConsumer() {
    136     if (Opts.PrintStats)
    137       delete TUTotalTimer;
    138   }
    139 
    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 
    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 
    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.
    251   bool VisitDecl(Decl *D) {
    252     checkerMgr->runCheckersOnASTDecl(D, *Mgr, *RecVisitorBR);
    253     return true;
    254   }
    255 
    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 
    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 
    292 bool AnalysisConsumer::HandleTopLevelDecl(DeclGroupRef DG) {
    293   storeTopLevelDecls(DG);
    294   return true;
    295 }
    296 
    297 void AnalysisConsumer::HandleTopLevelDeclInObjCContainer(DeclGroupRef DG) {
    298   storeTopLevelDecls(DG);
    299 }
    300 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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