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