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