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