AnalysisConsumer.cpp revision 239462
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.MaxNodes, Opts.MaxLoop, 259 Opts.VisualizeEGDot, Opts.VisualizeEGUbi, 260 Opts.AnalysisPurgeOpt, Opts.EagerlyAssume, 261 Opts.TrimGraph, 262 Opts.UnoptimizedCFG, Opts.CFGAddImplicitDtors, 263 Opts.EagerlyTrimEGraph, 264 Opts.IPAMode, 265 Opts.InlineMaxStackDepth, 266 Opts.InlineMaxFunctionSize, 267 Opts.InliningMode, 268 Opts.NoRetryExhausted)); 269 } 270 271 /// \brief Store the top level decls in the set to be processed later on. 272 /// (Doing this pre-processing avoids deserialization of data from PCH.) 273 virtual bool HandleTopLevelDecl(DeclGroupRef D); 274 virtual void HandleTopLevelDeclInObjCContainer(DeclGroupRef D); 275 276 virtual void HandleTranslationUnit(ASTContext &C); 277 278 /// \brief Build the call graph for all the top level decls of this TU and 279 /// use it to define the order in which the functions should be visited. 280 void HandleDeclsGallGraph(const unsigned LocalTUDeclsSize); 281 282 /// \brief Run analyzes(syntax or path sensitive) on the given function. 283 /// \param Mode - determines if we are requesting syntax only or path 284 /// sensitive only analysis. 285 /// \param VisitedCallees - The output parameter, which is populated with the 286 /// set of functions which should be considered analyzed after analyzing the 287 /// given root function. 288 void HandleCode(Decl *D, AnalysisMode Mode, 289 SetOfConstDecls *VisitedCallees = 0); 290 291 void RunPathSensitiveChecks(Decl *D, SetOfConstDecls *VisitedCallees); 292 void ActionExprEngine(Decl *D, bool ObjCGCEnabled, 293 SetOfConstDecls *VisitedCallees); 294 295 /// Visitors for the RecursiveASTVisitor. 296 bool shouldWalkTypesOfTypeLocs() const { return false; } 297 298 /// Handle callbacks for arbitrary Decls. 299 bool VisitDecl(Decl *D) { 300 checkerMgr->runCheckersOnASTDecl(D, *Mgr, *RecVisitorBR); 301 return true; 302 } 303 304 bool VisitFunctionDecl(FunctionDecl *FD) { 305 IdentifierInfo *II = FD->getIdentifier(); 306 if (II && II->getName().startswith("__inline")) 307 return true; 308 309 // We skip function template definitions, as their semantics is 310 // only determined when they are instantiated. 311 if (FD->isThisDeclarationADefinition() && 312 !FD->isDependentContext()) { 313 HandleCode(FD, RecVisitorMode); 314 } 315 return true; 316 } 317 318 bool VisitObjCMethodDecl(ObjCMethodDecl *MD) { 319 checkerMgr->runCheckersOnASTDecl(MD, *Mgr, *RecVisitorBR); 320 if (MD->isThisDeclarationADefinition()) 321 HandleCode(MD, RecVisitorMode); 322 return true; 323 } 324 325private: 326 void storeTopLevelDecls(DeclGroupRef DG); 327 328 /// \brief Check if we should skip (not analyze) the given function. 329 bool skipFunction(Decl *D); 330 331}; 332} // end anonymous namespace 333 334 335//===----------------------------------------------------------------------===// 336// AnalysisConsumer implementation. 337//===----------------------------------------------------------------------===// 338llvm::Timer* AnalysisConsumer::TUTotalTimer = 0; 339 340bool AnalysisConsumer::HandleTopLevelDecl(DeclGroupRef DG) { 341 storeTopLevelDecls(DG); 342 return true; 343} 344 345void AnalysisConsumer::HandleTopLevelDeclInObjCContainer(DeclGroupRef DG) { 346 storeTopLevelDecls(DG); 347} 348 349void AnalysisConsumer::storeTopLevelDecls(DeclGroupRef DG) { 350 for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I) { 351 352 // Skip ObjCMethodDecl, wait for the objc container to avoid 353 // analyzing twice. 354 if (isa<ObjCMethodDecl>(*I)) 355 continue; 356 357 LocalTUDecls.push_back(*I); 358 } 359} 360 361void AnalysisConsumer::HandleDeclsGallGraph(const unsigned LocalTUDeclsSize) { 362 // Otherwise, use the Callgraph to derive the order. 363 // Build the Call Graph. 364 CallGraph CG; 365 366 // Add all the top level declarations to the graph. 367 // Note: CallGraph can trigger deserialization of more items from a pch 368 // (though HandleInterestingDecl); triggering additions to LocalTUDecls. 369 // We rely on random access to add the initially processed Decls to CG. 370 for (unsigned i = 0 ; i < LocalTUDeclsSize ; ++i) { 371 CG.addToCallGraph(LocalTUDecls[i]); 372 } 373 374 // Find the top level nodes - children of root + the unreachable (parentless) 375 // nodes. 376 llvm::SmallVector<CallGraphNode*, 24> TopLevelFunctions; 377 for (CallGraph::nodes_iterator TI = CG.parentless_begin(), 378 TE = CG.parentless_end(); TI != TE; ++TI) { 379 TopLevelFunctions.push_back(*TI); 380 NumFunctionTopLevel++; 381 } 382 CallGraphNode *Entry = CG.getRoot(); 383 for (CallGraphNode::iterator I = Entry->begin(), 384 E = Entry->end(); I != E; ++I) { 385 TopLevelFunctions.push_back(*I); 386 NumFunctionTopLevel++; 387 } 388 389 // Make sure the nodes are sorted in order reverse of their definition in the 390 // translation unit. This step is very important for performance. It ensures 391 // that we analyze the root functions before the externally available 392 // subroutines. 393 std::deque<CallGraphNode*> BFSQueue; 394 for (llvm::SmallVector<CallGraphNode*, 24>::reverse_iterator 395 TI = TopLevelFunctions.rbegin(), TE = TopLevelFunctions.rend(); 396 TI != TE; ++TI) 397 BFSQueue.push_back(*TI); 398 399 // BFS over all of the functions, while skipping the ones inlined into 400 // the previously processed functions. Use external Visited set, which is 401 // also modified when we inline a function. 402 SmallPtrSet<CallGraphNode*,24> Visited; 403 while(!BFSQueue.empty()) { 404 CallGraphNode *N = BFSQueue.front(); 405 BFSQueue.pop_front(); 406 407 // Push the children into the queue. 408 for (CallGraphNode::const_iterator CI = N->begin(), 409 CE = N->end(); CI != CE; ++CI) { 410 if (!Visited.count(*CI)) 411 BFSQueue.push_back(*CI); 412 } 413 414 // Skip the functions which have been processed already or previously 415 // inlined. 416 if (Visited.count(N)) 417 continue; 418 419 // Analyze the function. 420 SetOfConstDecls VisitedCallees; 421 Decl *D = N->getDecl(); 422 assert(D); 423 HandleCode(D, ANALYSIS_PATH, 424 (Mgr->InliningMode == All ? 0 : &VisitedCallees)); 425 426 // Add the visited callees to the global visited set. 427 for (SetOfConstDecls::iterator I = VisitedCallees.begin(), 428 E = VisitedCallees.end(); I != E; ++I) { 429 CallGraphNode *VN = CG.getNode(*I); 430 if (VN) 431 Visited.insert(VN); 432 } 433 Visited.insert(N); 434 } 435} 436 437void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) { 438 // Don't run the actions if an error has occurred with parsing the file. 439 DiagnosticsEngine &Diags = PP.getDiagnostics(); 440 if (Diags.hasErrorOccurred() || Diags.hasFatalErrorOccurred()) 441 return; 442 443 { 444 if (TUTotalTimer) TUTotalTimer->startTimer(); 445 446 // Introduce a scope to destroy BR before Mgr. 447 BugReporter BR(*Mgr); 448 TranslationUnitDecl *TU = C.getTranslationUnitDecl(); 449 checkerMgr->runCheckersOnASTDecl(TU, *Mgr, BR); 450 451 // Run the AST-only checks using the order in which functions are defined. 452 // If inlining is not turned on, use the simplest function order for path 453 // sensitive analyzes as well. 454 RecVisitorMode = (Mgr->shouldInlineCall() ? ANALYSIS_SYNTAX : ANALYSIS_ALL); 455 RecVisitorBR = &BR; 456 457 // Process all the top level declarations. 458 // 459 // Note: TraverseDecl may modify LocalTUDecls, but only by appending more 460 // entries. Thus we don't use an iterator, but rely on LocalTUDecls 461 // random access. By doing so, we automatically compensate for iterators 462 // possibly being invalidated, although this is a bit slower. 463 const unsigned LocalTUDeclsSize = LocalTUDecls.size(); 464 for (unsigned i = 0 ; i < LocalTUDeclsSize ; ++i) { 465 TraverseDecl(LocalTUDecls[i]); 466 } 467 468 if (Mgr->shouldInlineCall()) 469 HandleDeclsGallGraph(LocalTUDeclsSize); 470 471 // After all decls handled, run checkers on the entire TranslationUnit. 472 checkerMgr->runCheckersOnEndOfTranslationUnit(TU, *Mgr, BR); 473 474 RecVisitorBR = 0; 475 } 476 477 // Explicitly destroy the PathDiagnosticConsumer. This will flush its output. 478 // FIXME: This should be replaced with something that doesn't rely on 479 // side-effects in PathDiagnosticConsumer's destructor. This is required when 480 // used with option -disable-free. 481 Mgr.reset(NULL); 482 483 if (TUTotalTimer) TUTotalTimer->stopTimer(); 484 485 // Count how many basic blocks we have not covered. 486 NumBlocksInAnalyzedFunctions = FunctionSummaries.getTotalNumBasicBlocks(); 487 if (NumBlocksInAnalyzedFunctions > 0) 488 PercentReachableBlocks = 489 (FunctionSummaries.getTotalNumVisitedBasicBlocks() * 100) / 490 NumBlocksInAnalyzedFunctions; 491 492} 493 494static void FindBlocks(DeclContext *D, SmallVectorImpl<Decl*> &WL) { 495 if (BlockDecl *BD = dyn_cast<BlockDecl>(D)) 496 WL.push_back(BD); 497 498 for (DeclContext::decl_iterator I = D->decls_begin(), E = D->decls_end(); 499 I!=E; ++I) 500 if (DeclContext *DC = dyn_cast<DeclContext>(*I)) 501 FindBlocks(DC, WL); 502} 503 504static std::string getFunctionName(const Decl *D) { 505 if (const ObjCMethodDecl *ID = dyn_cast<ObjCMethodDecl>(D)) { 506 return ID->getSelector().getAsString(); 507 } 508 if (const FunctionDecl *ND = dyn_cast<FunctionDecl>(D)) { 509 IdentifierInfo *II = ND->getIdentifier(); 510 if (II) 511 return II->getName(); 512 } 513 return ""; 514} 515 516bool AnalysisConsumer::skipFunction(Decl *D) { 517 if (!Opts.AnalyzeSpecificFunction.empty() && 518 getFunctionName(D) != Opts.AnalyzeSpecificFunction) 519 return true; 520 521 // Don't run the actions on declarations in header files unless 522 // otherwise specified. 523 SourceManager &SM = Ctx->getSourceManager(); 524 SourceLocation SL = SM.getExpansionLoc(D->getLocation()); 525 if (!Opts.AnalyzeAll && !SM.isFromMainFile(SL)) 526 return true; 527 528 return false; 529} 530 531void AnalysisConsumer::HandleCode(Decl *D, AnalysisMode Mode, 532 SetOfConstDecls *VisitedCallees) { 533 if (skipFunction(D)) 534 return; 535 536 DisplayFunction(D, Mode); 537 CFG *DeclCFG = Mgr->getCFG(D); 538 if (DeclCFG) { 539 unsigned CFGSize = DeclCFG->size(); 540 MaxCFGSize = MaxCFGSize < CFGSize ? CFGSize : MaxCFGSize; 541 } 542 543 544 // Clear the AnalysisManager of old AnalysisDeclContexts. 545 Mgr->ClearContexts(); 546 547 // Dispatch on the actions. 548 SmallVector<Decl*, 10> WL; 549 WL.push_back(D); 550 551 if (D->hasBody() && Opts.AnalyzeNestedBlocks) 552 FindBlocks(cast<DeclContext>(D), WL); 553 554 BugReporter BR(*Mgr); 555 for (SmallVectorImpl<Decl*>::iterator WI=WL.begin(), WE=WL.end(); 556 WI != WE; ++WI) 557 if ((*WI)->hasBody()) { 558 if (Mode != ANALYSIS_PATH) 559 checkerMgr->runCheckersOnASTBody(*WI, *Mgr, BR); 560 if (Mode != ANALYSIS_SYNTAX && checkerMgr->hasPathSensitiveCheckers()) { 561 RunPathSensitiveChecks(*WI, VisitedCallees); 562 NumFunctionsAnalyzed++; 563 } 564 } 565} 566 567//===----------------------------------------------------------------------===// 568// Path-sensitive checking. 569//===----------------------------------------------------------------------===// 570 571void AnalysisConsumer::ActionExprEngine(Decl *D, bool ObjCGCEnabled, 572 SetOfConstDecls *VisitedCallees) { 573 // Construct the analysis engine. First check if the CFG is valid. 574 // FIXME: Inter-procedural analysis will need to handle invalid CFGs. 575 if (!Mgr->getCFG(D)) 576 return; 577 578 // See if the LiveVariables analysis scales. 579 if (!Mgr->getAnalysisDeclContext(D)->getAnalysis<RelaxedLiveVariables>()) 580 return; 581 582 ExprEngine Eng(*Mgr, ObjCGCEnabled, VisitedCallees, &FunctionSummaries); 583 584 // Set the graph auditor. 585 OwningPtr<ExplodedNode::Auditor> Auditor; 586 if (Mgr->shouldVisualizeUbigraph()) { 587 Auditor.reset(CreateUbiViz()); 588 ExplodedNode::SetAuditor(Auditor.get()); 589 } 590 591 // Execute the worklist algorithm. 592 Eng.ExecuteWorkList(Mgr->getAnalysisDeclContextManager().getStackFrame(D), 593 Mgr->getMaxNodes()); 594 595 // Release the auditor (if any) so that it doesn't monitor the graph 596 // created BugReporter. 597 ExplodedNode::SetAuditor(0); 598 599 // Visualize the exploded graph. 600 if (Mgr->shouldVisualizeGraphviz()) 601 Eng.ViewGraph(Mgr->shouldTrimGraph()); 602 603 // Display warnings. 604 Eng.getBugReporter().FlushReports(); 605} 606 607void AnalysisConsumer::RunPathSensitiveChecks(Decl *D, 608 SetOfConstDecls *Visited) { 609 610 switch (Mgr->getLangOpts().getGC()) { 611 case LangOptions::NonGC: 612 ActionExprEngine(D, false, Visited); 613 break; 614 615 case LangOptions::GCOnly: 616 ActionExprEngine(D, true, Visited); 617 break; 618 619 case LangOptions::HybridGC: 620 ActionExprEngine(D, false, Visited); 621 ActionExprEngine(D, true, Visited); 622 break; 623 } 624} 625 626//===----------------------------------------------------------------------===// 627// AnalysisConsumer creation. 628//===----------------------------------------------------------------------===// 629 630ASTConsumer* ento::CreateAnalysisConsumer(const Preprocessor& pp, 631 const std::string& outDir, 632 const AnalyzerOptions& opts, 633 ArrayRef<std::string> plugins) { 634 // Disable the effects of '-Werror' when using the AnalysisConsumer. 635 pp.getDiagnostics().setWarningsAsErrors(false); 636 637 return new AnalysisConsumer(pp, outDir, opts, plugins); 638} 639 640//===----------------------------------------------------------------------===// 641// Ubigraph Visualization. FIXME: Move to separate file. 642//===----------------------------------------------------------------------===// 643 644namespace { 645 646class UbigraphViz : public ExplodedNode::Auditor { 647 OwningPtr<raw_ostream> Out; 648 llvm::sys::Path Dir, Filename; 649 unsigned Cntr; 650 651 typedef llvm::DenseMap<void*,unsigned> VMap; 652 VMap M; 653 654public: 655 UbigraphViz(raw_ostream *out, llvm::sys::Path& dir, 656 llvm::sys::Path& filename); 657 658 ~UbigraphViz(); 659 660 virtual void AddEdge(ExplodedNode *Src, ExplodedNode *Dst); 661}; 662 663} // end anonymous namespace 664 665static ExplodedNode::Auditor* CreateUbiViz() { 666 std::string ErrMsg; 667 668 llvm::sys::Path Dir = llvm::sys::Path::GetTemporaryDirectory(&ErrMsg); 669 if (!ErrMsg.empty()) 670 return 0; 671 672 llvm::sys::Path Filename = Dir; 673 Filename.appendComponent("llvm_ubi"); 674 Filename.makeUnique(true,&ErrMsg); 675 676 if (!ErrMsg.empty()) 677 return 0; 678 679 llvm::errs() << "Writing '" << Filename.str() << "'.\n"; 680 681 OwningPtr<llvm::raw_fd_ostream> Stream; 682 Stream.reset(new llvm::raw_fd_ostream(Filename.c_str(), ErrMsg)); 683 684 if (!ErrMsg.empty()) 685 return 0; 686 687 return new UbigraphViz(Stream.take(), Dir, Filename); 688} 689 690void UbigraphViz::AddEdge(ExplodedNode *Src, ExplodedNode *Dst) { 691 692 assert (Src != Dst && "Self-edges are not allowed."); 693 694 // Lookup the Src. If it is a new node, it's a root. 695 VMap::iterator SrcI= M.find(Src); 696 unsigned SrcID; 697 698 if (SrcI == M.end()) { 699 M[Src] = SrcID = Cntr++; 700 *Out << "('vertex', " << SrcID << ", ('color','#00ff00'))\n"; 701 } 702 else 703 SrcID = SrcI->second; 704 705 // Lookup the Dst. 706 VMap::iterator DstI= M.find(Dst); 707 unsigned DstID; 708 709 if (DstI == M.end()) { 710 M[Dst] = DstID = Cntr++; 711 *Out << "('vertex', " << DstID << ")\n"; 712 } 713 else { 714 // We have hit DstID before. Change its style to reflect a cache hit. 715 DstID = DstI->second; 716 *Out << "('change_vertex_style', " << DstID << ", 1)\n"; 717 } 718 719 // Add the edge. 720 *Out << "('edge', " << SrcID << ", " << DstID 721 << ", ('arrow','true'), ('oriented', 'true'))\n"; 722} 723 724UbigraphViz::UbigraphViz(raw_ostream *out, llvm::sys::Path& dir, 725 llvm::sys::Path& filename) 726 : Out(out), Dir(dir), Filename(filename), Cntr(0) { 727 728 *Out << "('vertex_style_attribute', 0, ('shape', 'icosahedron'))\n"; 729 *Out << "('vertex_style', 1, 0, ('shape', 'sphere'), ('color', '#ffcc66')," 730 " ('size', '1.5'))\n"; 731} 732 733UbigraphViz::~UbigraphViz() { 734 Out.reset(0); 735 llvm::errs() << "Running 'ubiviz' program... "; 736 std::string ErrMsg; 737 llvm::sys::Path Ubiviz = llvm::sys::Program::FindProgramByName("ubiviz"); 738 std::vector<const char*> args; 739 args.push_back(Ubiviz.c_str()); 740 args.push_back(Filename.c_str()); 741 args.push_back(0); 742 743 if (llvm::sys::Program::ExecuteAndWait(Ubiviz, &args[0],0,0,0,0,&ErrMsg)) { 744 llvm::errs() << "Error viewing graph: " << ErrMsg << "\n"; 745 } 746 747 // Delete the directory. 748 Dir.eraseFromDisk(true); 749} 750