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