clang API Documentation
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 }