clang API Documentation

AnalysisConsumer.cpp
Go to the documentation of this file.
00001 //===--- AnalysisConsumer.cpp - ASTConsumer for running Analyses ----------===//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 //
00010 // "Meta" ASTConsumer for running different source analyses.
00011 //
00012 //===----------------------------------------------------------------------===//
00013 
00014 #define DEBUG_TYPE "AnalysisConsumer"
00015 
00016 #include "AnalysisConsumer.h"
00017 #include "clang/AST/ASTConsumer.h"
00018 #include "clang/AST/Decl.h"
00019 #include "clang/AST/DeclCXX.h"
00020 #include "clang/AST/DeclObjC.h"
00021 #include "clang/AST/ParentMap.h"
00022 #include "clang/AST/RecursiveASTVisitor.h"
00023 #include "clang/Analysis/CFG.h"
00024 #include "clang/Analysis/CallGraph.h"
00025 #include "clang/StaticAnalyzer/Frontend/CheckerRegistration.h"
00026 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
00027 #include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
00028 #include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
00029 #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
00030 #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
00031 #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
00032 #include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h"
00033 
00034 #include "clang/Basic/FileManager.h"
00035 #include "clang/Basic/SourceManager.h"
00036 #include "clang/Frontend/AnalyzerOptions.h"
00037 #include "clang/Lex/Preprocessor.h"
00038 #include "llvm/Support/raw_ostream.h"
00039 #include "llvm/Support/Path.h"
00040 #include "llvm/Support/Program.h"
00041 #include "llvm/Support/Timer.h"
00042 #include "llvm/ADT/DepthFirstIterator.h"
00043 #include "llvm/ADT/OwningPtr.h"
00044 #include "llvm/ADT/SmallPtrSet.h"
00045 #include "llvm/ADT/Statistic.h"
00046 
00047 #include <queue>
00048 
00049 using namespace clang;
00050 using namespace ento;
00051 using llvm::SmallPtrSet;
00052 
00053 static ExplodedNode::Auditor* CreateUbiViz();
00054 
00055 STATISTIC(NumFunctionTopLevel, "The # of functions at top level.");
00056 STATISTIC(NumFunctionsAnalyzed, "The # of functions analysed (as top level).");
00057 STATISTIC(NumBlocksInAnalyzedFunctions,
00058                      "The # of basic blocks in the analyzed functions.");
00059 STATISTIC(PercentReachableBlocks, "The % of reachable basic blocks.");
00060 
00061 //===----------------------------------------------------------------------===//
00062 // Special PathDiagnosticConsumers.
00063 //===----------------------------------------------------------------------===//
00064 
00065 static PathDiagnosticConsumer*
00066 createPlistHTMLDiagnosticConsumer(const std::string& prefix,
00067                                 const Preprocessor &PP) {
00068   PathDiagnosticConsumer *PD =
00069     createHTMLDiagnosticConsumer(llvm::sys::path::parent_path(prefix), PP);
00070   return createPlistDiagnosticConsumer(prefix, PP, PD);
00071 }
00072 
00073 //===----------------------------------------------------------------------===//
00074 // AnalysisConsumer declaration.
00075 //===----------------------------------------------------------------------===//
00076 
00077 namespace {
00078 
00079 class AnalysisConsumer : public ASTConsumer,
00080                          public RecursiveASTVisitor<AnalysisConsumer> {
00081   enum AnalysisMode {
00082     ANALYSIS_SYNTAX,
00083     ANALYSIS_PATH,
00084     ANALYSIS_ALL
00085   };
00086 
00087   /// Mode of the analyzes while recursively visiting Decls.
00088   AnalysisMode RecVisitorMode;
00089   /// Bug Reporter to use while recursively visiting Decls.
00090   BugReporter *RecVisitorBR;
00091 
00092 public:
00093   ASTContext *Ctx;
00094   const Preprocessor &PP;
00095   const std::string OutDir;
00096   AnalyzerOptions Opts;
00097   ArrayRef<std::string> Plugins;
00098 
00099   /// \brief Stores the declarations from the local translation unit.
00100   /// Note, we pre-compute the local declarations at parse time as an
00101   /// optimization to make sure we do not deserialize everything from disk.
00102   /// The local declaration to all declarations ratio might be very small when
00103   /// working with a PCH file.
00104   SetOfDecls LocalTUDecls;
00105                            
00106   // PD is owned by AnalysisManager.
00107   PathDiagnosticConsumer *PD;
00108 
00109   StoreManagerCreator CreateStoreMgr;
00110   ConstraintManagerCreator CreateConstraintMgr;
00111 
00112   OwningPtr<CheckerManager> checkerMgr;
00113   OwningPtr<AnalysisManager> Mgr;
00114 
00115   /// Time the analyzes time of each translation unit.
00116   static llvm::Timer* TUTotalTimer;
00117 
00118   /// The information about analyzed functions shared throughout the
00119   /// translation unit.
00120   FunctionSummariesTy FunctionSummaries;
00121 
00122   AnalysisConsumer(const Preprocessor& pp,
00123                    const std::string& outdir,
00124                    const AnalyzerOptions& opts,
00125                    ArrayRef<std::string> plugins)
00126     : RecVisitorMode(ANALYSIS_ALL), RecVisitorBR(0),
00127       Ctx(0), PP(pp), OutDir(outdir), Opts(opts), Plugins(plugins), PD(0) {
00128     DigestAnalyzerOptions();
00129     if (Opts.PrintStats) {
00130       llvm::EnableStatistics();
00131       TUTotalTimer = new llvm::Timer("Analyzer Total Time");
00132     }
00133   }
00134 
00135   ~AnalysisConsumer() {
00136     if (Opts.PrintStats)
00137       delete TUTotalTimer;
00138   }
00139 
00140   void DigestAnalyzerOptions() {
00141     // Create the PathDiagnosticConsumer.
00142     if (!OutDir.empty()) {
00143       switch (Opts.AnalysisDiagOpt) {
00144       default:
00145 #define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN, AUTOCREATE) \
00146         case PD_##NAME: PD = CREATEFN(OutDir, PP); break;
00147 #include "clang/Frontend/Analyses.def"
00148       }
00149     } else if (Opts.AnalysisDiagOpt == PD_TEXT) {
00150       // Create the text client even without a specified output file since
00151       // it just uses diagnostic notes.
00152       PD = createTextPathDiagnosticConsumer("", PP);
00153     }
00154 
00155     // Create the analyzer component creators.
00156     switch (Opts.AnalysisStoreOpt) {
00157     default:
00158       llvm_unreachable("Unknown store manager.");
00159 #define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATEFN)           \
00160       case NAME##Model: CreateStoreMgr = CREATEFN; break;
00161 #include "clang/Frontend/Analyses.def"
00162     }
00163 
00164     switch (Opts.AnalysisConstraintsOpt) {
00165     default:
00166       llvm_unreachable("Unknown store manager.");
00167 #define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATEFN)     \
00168       case NAME##Model: CreateConstraintMgr = CREATEFN; break;
00169 #include "clang/Frontend/Analyses.def"
00170     }
00171   }
00172 
00173   void DisplayFunction(const Decl *D, AnalysisMode Mode) {
00174     if (!Opts.AnalyzerDisplayProgress)
00175       return;
00176 
00177     SourceManager &SM = Mgr->getASTContext().getSourceManager();
00178     PresumedLoc Loc = SM.getPresumedLoc(D->getLocation());
00179     if (Loc.isValid()) {
00180       llvm::errs() << "ANALYZE";
00181       switch (Mode) {
00182         case ANALYSIS_SYNTAX: llvm::errs() << "(Syntax)"; break;
00183         case ANALYSIS_PATH: llvm::errs() << "(Path Sensitive)"; break;
00184         case ANALYSIS_ALL: break;
00185       };
00186       llvm::errs() << ": " << Loc.getFilename();
00187       if (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)) {
00188         const NamedDecl *ND = cast<NamedDecl>(D);
00189         llvm::errs() << ' ' << *ND << '\n';
00190       }
00191       else if (isa<BlockDecl>(D)) {
00192         llvm::errs() << ' ' << "block(line:" << Loc.getLine() << ",col:"
00193                      << Loc.getColumn() << '\n';
00194       }
00195       else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
00196         Selector S = MD->getSelector();
00197         llvm::errs() << ' ' << S.getAsString();
00198       }
00199     }
00200   }
00201 
00202   virtual void Initialize(ASTContext &Context) {
00203     Ctx = &Context;
00204     checkerMgr.reset(createCheckerManager(Opts, PP.getLangOpts(), Plugins,
00205                                           PP.getDiagnostics()));
00206     Mgr.reset(new AnalysisManager(*Ctx, PP.getDiagnostics(),
00207                                   PP.getLangOpts(), PD,
00208                                   CreateStoreMgr, CreateConstraintMgr,
00209                                   checkerMgr.get(),
00210                                   Opts.MaxNodes, Opts.MaxLoop,
00211                                   Opts.VisualizeEGDot, Opts.VisualizeEGUbi,
00212                                   Opts.AnalysisPurgeOpt, Opts.EagerlyAssume,
00213                                   Opts.TrimGraph,
00214                                   Opts.UnoptimizedCFG, Opts.CFGAddImplicitDtors,
00215                                   Opts.CFGAddInitializers,
00216                                   Opts.EagerlyTrimEGraph,
00217                                   Opts.IPAMode,
00218                                   Opts.InlineMaxStackDepth,
00219                                   Opts.InlineMaxFunctionSize,
00220                                   Opts.InliningMode,
00221                                   Opts.NoRetryExhausted));
00222   }
00223 
00224   /// \brief Store the top level decls in the set to be processed later on.
00225   /// (Doing this pre-processing avoids deserialization of data from PCH.)
00226   virtual bool HandleTopLevelDecl(DeclGroupRef D);
00227   virtual void HandleTopLevelDeclInObjCContainer(DeclGroupRef D);
00228 
00229   virtual void HandleTranslationUnit(ASTContext &C);
00230 
00231   /// \brief Build the call graph for all the top level decls of this TU and
00232   /// use it to define the order in which the functions should be visited.
00233   void HandleDeclsGallGraph();
00234 
00235   /// \brief Run analyzes(syntax or path sensitive) on the given function.
00236   /// \param Mode - determines if we are requesting syntax only or path
00237   /// sensitive only analysis.
00238   /// \param VisitedCallees - The output parameter, which is populated with the
00239   /// set of functions which should be considered analyzed after analyzing the
00240   /// given root function.
00241   void HandleCode(Decl *D, AnalysisMode Mode,
00242                   SetOfConstDecls *VisitedCallees = 0);
00243 
00244   void RunPathSensitiveChecks(Decl *D, SetOfConstDecls *VisitedCallees);
00245   void ActionExprEngine(Decl *D, bool ObjCGCEnabled,
00246                         SetOfConstDecls *VisitedCallees);
00247 
00248   /// Visitors for the RecursiveASTVisitor.
00249   bool shouldWalkTypesOfTypeLocs() const { return false; }
00250 
00251   /// Handle callbacks for arbitrary Decls.
00252   bool VisitDecl(Decl *D) {
00253     checkerMgr->runCheckersOnASTDecl(D, *Mgr, *RecVisitorBR);
00254     return true;
00255   }
00256 
00257   bool VisitFunctionDecl(FunctionDecl *FD) {
00258     IdentifierInfo *II = FD->getIdentifier();
00259     if (II && II->getName().startswith("__inline"))
00260       return true;
00261 
00262     // We skip function template definitions, as their semantics is
00263     // only determined when they are instantiated.
00264     if (FD->isThisDeclarationADefinition() &&
00265         !FD->isDependentContext()) {
00266       HandleCode(FD, RecVisitorMode);
00267     }
00268     return true;
00269   }
00270 
00271   bool VisitObjCMethodDecl(ObjCMethodDecl *MD) {
00272     checkerMgr->runCheckersOnASTDecl(MD, *Mgr, *RecVisitorBR);
00273     if (MD->isThisDeclarationADefinition())
00274       HandleCode(MD, RecVisitorMode);
00275     return true;
00276   }
00277 
00278 private:
00279   void storeTopLevelDecls(DeclGroupRef DG);
00280 
00281   /// \brief Check if we should skip (not analyze) the given function.
00282   bool skipFunction(Decl *D);
00283 
00284 };
00285 } // end anonymous namespace
00286 
00287 
00288 //===----------------------------------------------------------------------===//
00289 // AnalysisConsumer implementation.
00290 //===----------------------------------------------------------------------===//
00291 llvm::Timer* AnalysisConsumer::TUTotalTimer = 0;
00292 
00293 bool AnalysisConsumer::HandleTopLevelDecl(DeclGroupRef DG) {
00294   storeTopLevelDecls(DG);
00295   return true;
00296 }
00297 
00298 void AnalysisConsumer::HandleTopLevelDeclInObjCContainer(DeclGroupRef DG) {
00299   storeTopLevelDecls(DG);
00300 }
00301 
00302 void AnalysisConsumer::storeTopLevelDecls(DeclGroupRef DG) {
00303   for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I) {
00304 
00305     // Skip ObjCMethodDecl, wait for the objc container to avoid
00306     // analyzing twice.
00307     if (isa<ObjCMethodDecl>(*I))
00308       continue;
00309 
00310     LocalTUDecls.push_back(*I);
00311   }
00312 }
00313 
00314 void AnalysisConsumer::HandleDeclsGallGraph() {
00315   // Otherwise, use the Callgraph to derive the order.
00316   // Build the Call Graph.
00317   CallGraph CG;
00318   // Add all the top level declarations to the graph.
00319   for (SetOfDecls::iterator I = LocalTUDecls.begin(),
00320                             E = LocalTUDecls.end(); I != E; ++I)
00321     CG.addToCallGraph(*I);
00322 
00323   // Find the top level nodes - children of root + the unreachable (parentless)
00324   // nodes.
00325   llvm::SmallVector<CallGraphNode*, 24> TopLevelFunctions;
00326   for (CallGraph::nodes_iterator TI = CG.parentless_begin(),
00327                                  TE = CG.parentless_end(); TI != TE; ++TI) {
00328     TopLevelFunctions.push_back(*TI);
00329     NumFunctionTopLevel++;
00330   }
00331   CallGraphNode *Entry = CG.getRoot();
00332   for (CallGraphNode::iterator I = Entry->begin(),
00333                                E = Entry->end(); I != E; ++I) {
00334     TopLevelFunctions.push_back(*I);
00335     NumFunctionTopLevel++;
00336   }
00337 
00338   // Make sure the nodes are sorted in order reverse of their definition in the 
00339   // translation unit. This step is very important for performance. It ensures 
00340   // that we analyze the root functions before the externally available 
00341   // subroutines.
00342   std::deque<CallGraphNode*> BFSQueue;
00343   for (llvm::SmallVector<CallGraphNode*, 24>::reverse_iterator
00344          TI = TopLevelFunctions.rbegin(), TE = TopLevelFunctions.rend();
00345          TI != TE; ++TI)
00346     BFSQueue.push_front(*TI);
00347 
00348   // BFS over all of the functions, while skipping the ones inlined into
00349   // the previously processed functions. Use external Visited set, which is
00350   // also modified when we inline a function.
00351   SmallPtrSet<CallGraphNode*,24> Visited;
00352   while(!BFSQueue.empty()) {
00353     CallGraphNode *N = BFSQueue.front();
00354     BFSQueue.pop_front();
00355 
00356     // Skip the functions which have been processed already or previously
00357     // inlined.
00358     if (Visited.count(N))
00359       continue;
00360 
00361     // Analyze the function.
00362     SetOfConstDecls VisitedCallees;
00363     Decl *D = N->getDecl();
00364     assert(D);
00365     HandleCode(D, ANALYSIS_PATH,
00366                (Mgr->InliningMode == All ? 0 : &VisitedCallees));
00367 
00368     // Add the visited callees to the global visited set.
00369     for (SetOfConstDecls::iterator I = VisitedCallees.begin(),
00370                                    E = VisitedCallees.end(); I != E; ++I) {
00371       CallGraphNode *VN = CG.getNode(*I);
00372       if (VN)
00373         Visited.insert(VN);
00374     }
00375     Visited.insert(N);
00376 
00377     // Push the children into the queue.
00378     for (CallGraphNode::const_iterator CI = N->begin(),
00379                                        CE = N->end(); CI != CE; ++CI) {
00380       BFSQueue.push_front(*CI);
00381     }
00382   }
00383 }
00384 
00385 void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) {
00386   // Don't run the actions if an error has occurred with parsing the file.
00387   DiagnosticsEngine &Diags = PP.getDiagnostics();
00388   if (Diags.hasErrorOccurred() || Diags.hasFatalErrorOccurred())
00389     return;
00390 
00391   {
00392     if (TUTotalTimer) TUTotalTimer->startTimer();
00393 
00394     // Introduce a scope to destroy BR before Mgr.
00395     BugReporter BR(*Mgr);
00396     TranslationUnitDecl *TU = C.getTranslationUnitDecl();
00397     checkerMgr->runCheckersOnASTDecl(TU, *Mgr, BR);
00398 
00399     // Run the AST-only checks using the order in which functions are defined.
00400     // If inlining is not turned on, use the simplest function order for path
00401     // sensitive analyzes as well.
00402     RecVisitorMode = (Mgr->shouldInlineCall() ? ANALYSIS_SYNTAX : ANALYSIS_ALL);
00403     RecVisitorBR = &BR;
00404 
00405     // Process all the top level declarations.
00406     //
00407     // Note: TraverseDecl may modify LocalTUDecls, but only by appending more
00408     // entries.  Thus we don't use an iterator, but rely on LocalTUDecls
00409     // random access.  By doing so, we automatically compensate for iterators
00410     // possibly being invalidated, although this is a bit slower.
00411     const unsigned n = LocalTUDecls.size();
00412     for (unsigned i = 0 ; i < n ; ++i) {
00413       TraverseDecl(LocalTUDecls[i]);
00414     }
00415 
00416     if (Mgr->shouldInlineCall())
00417       HandleDeclsGallGraph();
00418 
00419     // After all decls handled, run checkers on the entire TranslationUnit.
00420     checkerMgr->runCheckersOnEndOfTranslationUnit(TU, *Mgr, BR);
00421 
00422     RecVisitorBR = 0;
00423   }
00424 
00425   // Explicitly destroy the PathDiagnosticConsumer.  This will flush its output.
00426   // FIXME: This should be replaced with something that doesn't rely on
00427   // side-effects in PathDiagnosticConsumer's destructor. This is required when
00428   // used with option -disable-free.
00429   Mgr.reset(NULL);
00430 
00431   if (TUTotalTimer) TUTotalTimer->stopTimer();
00432 
00433   // Count how many basic blocks we have not covered.
00434   NumBlocksInAnalyzedFunctions = FunctionSummaries.getTotalNumBasicBlocks();
00435   if (NumBlocksInAnalyzedFunctions > 0)
00436     PercentReachableBlocks =
00437       (FunctionSummaries.getTotalNumVisitedBasicBlocks() * 100) /
00438         NumBlocksInAnalyzedFunctions;
00439 
00440 }
00441 
00442 static void FindBlocks(DeclContext *D, SmallVectorImpl<Decl*> &WL) {
00443   if (BlockDecl *BD = dyn_cast<BlockDecl>(D))
00444     WL.push_back(BD);
00445 
00446   for (DeclContext::decl_iterator I = D->decls_begin(), E = D->decls_end();
00447        I!=E; ++I)
00448     if (DeclContext *DC = dyn_cast<DeclContext>(*I))
00449       FindBlocks(DC, WL);
00450 }
00451 
00452 static std::string getFunctionName(const Decl *D) {
00453   if (const ObjCMethodDecl *ID = dyn_cast<ObjCMethodDecl>(D)) {
00454     return ID->getSelector().getAsString();
00455   }
00456   if (const FunctionDecl *ND = dyn_cast<FunctionDecl>(D)) {
00457     IdentifierInfo *II = ND->getIdentifier();
00458     if (II)
00459       return II->getName();
00460   }
00461   return "";
00462 }
00463 
00464 bool AnalysisConsumer::skipFunction(Decl *D) {
00465   if (!Opts.AnalyzeSpecificFunction.empty() &&
00466       getFunctionName(D) != Opts.AnalyzeSpecificFunction)
00467     return true;
00468 
00469   // Don't run the actions on declarations in header files unless
00470   // otherwise specified.
00471   SourceManager &SM = Ctx->getSourceManager();
00472   SourceLocation SL = SM.getExpansionLoc(D->getLocation());
00473   if (!Opts.AnalyzeAll && !SM.isFromMainFile(SL))
00474     return true;
00475 
00476   return false;
00477 }
00478 
00479 void AnalysisConsumer::HandleCode(Decl *D, AnalysisMode Mode,
00480                                   SetOfConstDecls *VisitedCallees) {
00481   if (skipFunction(D))
00482     return;
00483 
00484   DisplayFunction(D, Mode);
00485 
00486   // Clear the AnalysisManager of old AnalysisDeclContexts.
00487   Mgr->ClearContexts();
00488 
00489   // Dispatch on the actions.
00490   SmallVector<Decl*, 10> WL;
00491   WL.push_back(D);
00492 
00493   if (D->hasBody() && Opts.AnalyzeNestedBlocks)
00494     FindBlocks(cast<DeclContext>(D), WL);
00495 
00496   BugReporter BR(*Mgr);
00497   for (SmallVectorImpl<Decl*>::iterator WI=WL.begin(), WE=WL.end();
00498        WI != WE; ++WI)
00499     if ((*WI)->hasBody()) {
00500       if (Mode != ANALYSIS_PATH)
00501         checkerMgr->runCheckersOnASTBody(*WI, *Mgr, BR);
00502       if (Mode != ANALYSIS_SYNTAX && checkerMgr->hasPathSensitiveCheckers()) {
00503         RunPathSensitiveChecks(*WI, VisitedCallees);
00504         NumFunctionsAnalyzed++;
00505       }
00506     }
00507 }
00508 
00509 //===----------------------------------------------------------------------===//
00510 // Path-sensitive checking.
00511 //===----------------------------------------------------------------------===//
00512 
00513 void AnalysisConsumer::ActionExprEngine(Decl *D, bool ObjCGCEnabled,
00514                                         SetOfConstDecls *VisitedCallees) {
00515   // Construct the analysis engine.  First check if the CFG is valid.
00516   // FIXME: Inter-procedural analysis will need to handle invalid CFGs.
00517   if (!Mgr->getCFG(D))
00518     return;
00519 
00520   ExprEngine Eng(*Mgr, ObjCGCEnabled, VisitedCallees, &FunctionSummaries);
00521 
00522   // Set the graph auditor.
00523   OwningPtr<ExplodedNode::Auditor> Auditor;
00524   if (Mgr->shouldVisualizeUbigraph()) {
00525     Auditor.reset(CreateUbiViz());
00526     ExplodedNode::SetAuditor(Auditor.get());
00527   }
00528 
00529   // Execute the worklist algorithm.
00530   Eng.ExecuteWorkList(Mgr->getAnalysisDeclContextManager().getStackFrame(D),
00531                       Mgr->getMaxNodes());
00532 
00533   // Release the auditor (if any) so that it doesn't monitor the graph
00534   // created BugReporter.
00535   ExplodedNode::SetAuditor(0);
00536 
00537   // Visualize the exploded graph.
00538   if (Mgr->shouldVisualizeGraphviz())
00539     Eng.ViewGraph(Mgr->shouldTrimGraph());
00540 
00541   // Display warnings.
00542   Eng.getBugReporter().FlushReports();
00543 }
00544 
00545 void AnalysisConsumer::RunPathSensitiveChecks(Decl *D,
00546                                               SetOfConstDecls *Visited) {
00547 
00548   switch (Mgr->getLangOpts().getGC()) {
00549   case LangOptions::NonGC:
00550     ActionExprEngine(D, false, Visited);
00551     break;
00552   
00553   case LangOptions::GCOnly:
00554     ActionExprEngine(D, true, Visited);
00555     break;
00556   
00557   case LangOptions::HybridGC:
00558     ActionExprEngine(D, false, Visited);
00559     ActionExprEngine(D, true, Visited);
00560     break;
00561   }
00562 }
00563 
00564 //===----------------------------------------------------------------------===//
00565 // AnalysisConsumer creation.
00566 //===----------------------------------------------------------------------===//
00567 
00568 ASTConsumer* ento::CreateAnalysisConsumer(const Preprocessor& pp,
00569                                           const std::string& outDir,
00570                                           const AnalyzerOptions& opts,
00571                                           ArrayRef<std::string> plugins) {
00572   // Disable the effects of '-Werror' when using the AnalysisConsumer.
00573   pp.getDiagnostics().setWarningsAsErrors(false);
00574 
00575   return new AnalysisConsumer(pp, outDir, opts, plugins);
00576 }
00577 
00578 //===----------------------------------------------------------------------===//
00579 // Ubigraph Visualization.  FIXME: Move to separate file.
00580 //===----------------------------------------------------------------------===//
00581 
00582 namespace {
00583 
00584 class UbigraphViz : public ExplodedNode::Auditor {
00585   OwningPtr<raw_ostream> Out;
00586   llvm::sys::Path Dir, Filename;
00587   unsigned Cntr;
00588 
00589   typedef llvm::DenseMap<void*,unsigned> VMap;
00590   VMap M;
00591 
00592 public:
00593   UbigraphViz(raw_ostream *out, llvm::sys::Path& dir,
00594               llvm::sys::Path& filename);
00595 
00596   ~UbigraphViz();
00597 
00598   virtual void AddEdge(ExplodedNode *Src, ExplodedNode *Dst);
00599 };
00600 
00601 } // end anonymous namespace
00602 
00603 static ExplodedNode::Auditor* CreateUbiViz() {
00604   std::string ErrMsg;
00605 
00606   llvm::sys::Path Dir = llvm::sys::Path::GetTemporaryDirectory(&ErrMsg);
00607   if (!ErrMsg.empty())
00608     return 0;
00609 
00610   llvm::sys::Path Filename = Dir;
00611   Filename.appendComponent("llvm_ubi");
00612   Filename.makeUnique(true,&ErrMsg);
00613 
00614   if (!ErrMsg.empty())
00615     return 0;
00616 
00617   llvm::errs() << "Writing '" << Filename.str() << "'.\n";
00618 
00619   OwningPtr<llvm::raw_fd_ostream> Stream;
00620   Stream.reset(new llvm::raw_fd_ostream(Filename.c_str(), ErrMsg));
00621 
00622   if (!ErrMsg.empty())
00623     return 0;
00624 
00625   return new UbigraphViz(Stream.take(), Dir, Filename);
00626 }
00627 
00628 void UbigraphViz::AddEdge(ExplodedNode *Src, ExplodedNode *Dst) {
00629 
00630   assert (Src != Dst && "Self-edges are not allowed.");
00631 
00632   // Lookup the Src.  If it is a new node, it's a root.
00633   VMap::iterator SrcI= M.find(Src);
00634   unsigned SrcID;
00635 
00636   if (SrcI == M.end()) {
00637     M[Src] = SrcID = Cntr++;
00638     *Out << "('vertex', " << SrcID << ", ('color','#00ff00'))\n";
00639   }
00640   else
00641     SrcID = SrcI->second;
00642 
00643   // Lookup the Dst.
00644   VMap::iterator DstI= M.find(Dst);
00645   unsigned DstID;
00646 
00647   if (DstI == M.end()) {
00648     M[Dst] = DstID = Cntr++;
00649     *Out << "('vertex', " << DstID << ")\n";
00650   }
00651   else {
00652     // We have hit DstID before.  Change its style to reflect a cache hit.
00653     DstID = DstI->second;
00654     *Out << "('change_vertex_style', " << DstID << ", 1)\n";
00655   }
00656 
00657   // Add the edge.
00658   *Out << "('edge', " << SrcID << ", " << DstID
00659        << ", ('arrow','true'), ('oriented', 'true'))\n";
00660 }
00661 
00662 UbigraphViz::UbigraphViz(raw_ostream *out, llvm::sys::Path& dir,
00663                          llvm::sys::Path& filename)
00664   : Out(out), Dir(dir), Filename(filename), Cntr(0) {
00665 
00666   *Out << "('vertex_style_attribute', 0, ('shape', 'icosahedron'))\n";
00667   *Out << "('vertex_style', 1, 0, ('shape', 'sphere'), ('color', '#ffcc66'),"
00668           " ('size', '1.5'))\n";
00669 }
00670 
00671 UbigraphViz::~UbigraphViz() {
00672   Out.reset(0);
00673   llvm::errs() << "Running 'ubiviz' program... ";
00674   std::string ErrMsg;
00675   llvm::sys::Path Ubiviz = llvm::sys::Program::FindProgramByName("ubiviz");
00676   std::vector<const char*> args;
00677   args.push_back(Ubiviz.c_str());
00678   args.push_back(Filename.c_str());
00679   args.push_back(0);
00680 
00681   if (llvm::sys::Program::ExecuteAndWait(Ubiviz, &args[0],0,0,0,0,&ErrMsg)) {
00682     llvm::errs() << "Error viewing graph: " << ErrMsg << "\n";
00683   }
00684 
00685   // Delete the directory.
00686   Dir.eraseFromDisk(true);
00687 }