[analyzer] Move include/clang/StaticAnalyzer/AnalysisConsumer.h -> lib/StaticAnalyzer...
[clang.git] / lib / StaticAnalyzer / Frontend / AnalysisConsumer.cpp
blob75f475a5bcbfc220c1567d326b463aac545f5508
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.
12 //===----------------------------------------------------------------------===//
14 #include "AnalysisConsumer.h"
15 #include "clang/AST/ASTConsumer.h"
16 #include "clang/AST/Decl.h"
17 #include "clang/AST/DeclCXX.h"
18 #include "clang/AST/DeclObjC.h"
19 #include "clang/AST/ParentMap.h"
20 #include "clang/Analysis/Analyses/LiveVariables.h"
21 #include "clang/Analysis/Analyses/UninitializedValues.h"
22 #include "clang/Analysis/CFG.h"
23 #include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
24 #include "clang/StaticAnalyzer/Core/ManagerRegistry.h"
25 #include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
26 #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
27 #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
28 #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
29 #include "clang/StaticAnalyzer/Core/PathSensitive/TransferFuncs.h"
30 #include "clang/StaticAnalyzer/Core/PathDiagnosticClients.h"
32 // FIXME: Restructure checker registration.
33 #include "../Checkers/ExperimentalChecks.h"
34 #include "../Checkers/InternalChecks.h"
36 #include "clang/Basic/FileManager.h"
37 #include "clang/Basic/SourceManager.h"
38 #include "clang/Frontend/AnalyzerOptions.h"
39 #include "clang/Lex/Preprocessor.h"
40 #include "llvm/Support/raw_ostream.h"
41 #include "llvm/Support/Path.h"
42 #include "llvm/Support/Program.h"
43 #include "llvm/ADT/OwningPtr.h"
45 using namespace clang;
46 using namespace ento;
48 static ExplodedNode::Auditor* CreateUbiViz();
50 //===----------------------------------------------------------------------===//
51 // Special PathDiagnosticClients.
52 //===----------------------------------------------------------------------===//
54 static PathDiagnosticClient*
55 createPlistHTMLDiagnosticClient(const std::string& prefix,
56 const Preprocessor &PP) {
57 PathDiagnosticClient *PD =
58 createHTMLDiagnosticClient(llvm::sys::path::parent_path(prefix), PP);
59 return createPlistDiagnosticClient(prefix, PP, PD);
62 //===----------------------------------------------------------------------===//
63 // AnalysisConsumer declaration.
64 //===----------------------------------------------------------------------===//
66 namespace {
68 class AnalysisConsumer : public ASTConsumer {
69 public:
70 typedef void (*CodeAction)(AnalysisConsumer &C, AnalysisManager &M, Decl *D);
71 typedef void (*TUAction)(AnalysisConsumer &C, AnalysisManager &M,
72 TranslationUnitDecl &TU);
74 private:
75 typedef std::vector<CodeAction> Actions;
76 typedef std::vector<TUAction> TUActions;
78 Actions FunctionActions;
79 Actions ObjCMethodActions;
80 Actions ObjCImplementationActions;
81 Actions CXXMethodActions;
82 TUActions TranslationUnitActions; // Remove this.
84 public:
85 ASTContext* Ctx;
86 const Preprocessor &PP;
87 const std::string OutDir;
88 AnalyzerOptions Opts;
90 // PD is owned by AnalysisManager.
91 PathDiagnosticClient *PD;
93 StoreManagerCreator CreateStoreMgr;
94 ConstraintManagerCreator CreateConstraintMgr;
96 llvm::OwningPtr<AnalysisManager> Mgr;
98 AnalysisConsumer(const Preprocessor& pp,
99 const std::string& outdir,
100 const AnalyzerOptions& opts)
101 : Ctx(0), PP(pp), OutDir(outdir),
102 Opts(opts), PD(0) {
103 DigestAnalyzerOptions();
106 void DigestAnalyzerOptions() {
107 // Create the PathDiagnosticClient.
108 if (!OutDir.empty()) {
109 switch (Opts.AnalysisDiagOpt) {
110 default:
111 #define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN, AUTOCREATE) \
112 case PD_##NAME: PD = CREATEFN(OutDir, PP); break;
113 #include "clang/Frontend/Analyses.def"
115 } else if (Opts.AnalysisDiagOpt == PD_TEXT) {
116 // Create the text client even without a specified output file since
117 // it just uses diagnostic notes.
118 PD = createTextPathDiagnosticClient("", PP);
121 // Create the analyzer component creators.
122 if (ManagerRegistry::StoreMgrCreator != 0) {
123 CreateStoreMgr = ManagerRegistry::StoreMgrCreator;
125 else {
126 switch (Opts.AnalysisStoreOpt) {
127 default:
128 assert(0 && "Unknown store manager.");
129 #define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATEFN) \
130 case NAME##Model: CreateStoreMgr = CREATEFN; break;
131 #include "clang/Frontend/Analyses.def"
135 if (ManagerRegistry::ConstraintMgrCreator != 0)
136 CreateConstraintMgr = ManagerRegistry::ConstraintMgrCreator;
137 else {
138 switch (Opts.AnalysisConstraintsOpt) {
139 default:
140 assert(0 && "Unknown store manager.");
141 #define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATEFN) \
142 case NAME##Model: CreateConstraintMgr = CREATEFN; break;
143 #include "clang/Frontend/Analyses.def"
148 void DisplayFunction(const Decl *D) {
149 if (!Opts.AnalyzerDisplayProgress)
150 return;
152 SourceManager &SM = Mgr->getASTContext().getSourceManager();
153 PresumedLoc Loc = SM.getPresumedLoc(D->getLocation());
154 if (Loc.isValid()) {
155 llvm::errs() << "ANALYZE: " << Loc.getFilename();
157 if (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)) {
158 const NamedDecl *ND = cast<NamedDecl>(D);
159 llvm::errs() << ' ' << ND << '\n';
161 else if (isa<BlockDecl>(D)) {
162 llvm::errs() << ' ' << "block(line:" << Loc.getLine() << ",col:"
163 << Loc.getColumn() << '\n';
165 else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
166 Selector S = MD->getSelector();
167 llvm::errs() << ' ' << S.getAsString();
172 void addCodeAction(CodeAction action) {
173 FunctionActions.push_back(action);
174 ObjCMethodActions.push_back(action);
175 CXXMethodActions.push_back(action);
178 void addTranslationUnitAction(TUAction action) {
179 TranslationUnitActions.push_back(action);
182 void addObjCImplementationAction(CodeAction action) {
183 ObjCImplementationActions.push_back(action);
186 virtual void Initialize(ASTContext &Context) {
187 Ctx = &Context;
188 Mgr.reset(new AnalysisManager(*Ctx, PP.getDiagnostics(),
189 PP.getLangOptions(), PD,
190 CreateStoreMgr, CreateConstraintMgr,
191 /* Indexer */ 0,
192 Opts.MaxNodes, Opts.MaxLoop,
193 Opts.VisualizeEGDot, Opts.VisualizeEGUbi,
194 Opts.PurgeDead, Opts.EagerlyAssume,
195 Opts.TrimGraph, Opts.InlineCall,
196 Opts.UnoptimizedCFG, Opts.CFGAddImplicitDtors,
197 Opts.CFGAddInitializers,
198 Opts.EagerlyTrimEGraph));
201 virtual void HandleTranslationUnit(ASTContext &C);
202 void HandleDeclContext(ASTContext &C, DeclContext *dc);
204 void HandleCode(Decl *D, Actions& actions);
206 } // end anonymous namespace
208 //===----------------------------------------------------------------------===//
209 // AnalysisConsumer implementation.
210 //===----------------------------------------------------------------------===//
212 void AnalysisConsumer::HandleDeclContext(ASTContext &C, DeclContext *dc) {
213 for (DeclContext::decl_iterator I = dc->decls_begin(), E = dc->decls_end();
214 I != E; ++I) {
215 Decl *D = *I;
217 switch (D->getKind()) {
218 case Decl::Namespace: {
219 HandleDeclContext(C, cast<NamespaceDecl>(D));
220 break;
222 case Decl::CXXConstructor:
223 case Decl::CXXDestructor:
224 case Decl::CXXConversion:
225 case Decl::CXXMethod:
226 case Decl::Function: {
227 FunctionDecl* FD = cast<FunctionDecl>(D);
228 // We skip function template definitions, as their semantics is
229 // only determined when they are instantiated.
230 if (FD->isThisDeclarationADefinition() &&
231 !FD->isDependentContext()) {
232 if (!Opts.AnalyzeSpecificFunction.empty() &&
233 FD->getDeclName().getAsString() != Opts.AnalyzeSpecificFunction)
234 break;
235 DisplayFunction(FD);
236 HandleCode(FD, FunctionActions);
238 break;
241 case Decl::ObjCImplementation: {
242 ObjCImplementationDecl* ID = cast<ObjCImplementationDecl>(*I);
243 HandleCode(ID, ObjCImplementationActions);
245 for (ObjCImplementationDecl::method_iterator MI = ID->meth_begin(),
246 ME = ID->meth_end(); MI != ME; ++MI) {
247 if ((*MI)->isThisDeclarationADefinition()) {
248 if (!Opts.AnalyzeSpecificFunction.empty() &&
249 Opts.AnalyzeSpecificFunction != (*MI)->getSelector().getAsString())
250 break;
251 DisplayFunction(*MI);
252 HandleCode(*MI, ObjCMethodActions);
255 break;
258 default:
259 break;
264 void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) {
265 TranslationUnitDecl *TU = C.getTranslationUnitDecl();
266 HandleDeclContext(C, TU);
268 for (TUActions::iterator I = TranslationUnitActions.begin(),
269 E = TranslationUnitActions.end(); I != E; ++I) {
270 (*I)(*this, *Mgr, *TU);
273 // Explicitly destroy the PathDiagnosticClient. This will flush its output.
274 // FIXME: This should be replaced with something that doesn't rely on
275 // side-effects in PathDiagnosticClient's destructor. This is required when
276 // used with option -disable-free.
277 Mgr.reset(NULL);
280 static void FindBlocks(DeclContext *D, llvm::SmallVectorImpl<Decl*> &WL) {
281 if (BlockDecl *BD = dyn_cast<BlockDecl>(D))
282 WL.push_back(BD);
284 for (DeclContext::decl_iterator I = D->decls_begin(), E = D->decls_end();
285 I!=E; ++I)
286 if (DeclContext *DC = dyn_cast<DeclContext>(*I))
287 FindBlocks(DC, WL);
290 void AnalysisConsumer::HandleCode(Decl *D, Actions& actions) {
292 // Don't run the actions if an error has occured with parsing the file.
293 Diagnostic &Diags = PP.getDiagnostics();
294 if (Diags.hasErrorOccurred() || Diags.hasFatalErrorOccurred())
295 return;
297 // Don't run the actions on declarations in header files unless
298 // otherwise specified.
299 SourceManager &SM = Ctx->getSourceManager();
300 SourceLocation SL = SM.getInstantiationLoc(D->getLocation());
301 if (!Opts.AnalyzeAll && !SM.isFromMainFile(SL))
302 return;
304 // Clear the AnalysisManager of old AnalysisContexts.
305 Mgr->ClearContexts();
307 // Dispatch on the actions.
308 llvm::SmallVector<Decl*, 10> WL;
309 WL.push_back(D);
311 if (D->hasBody() && Opts.AnalyzeNestedBlocks)
312 FindBlocks(cast<DeclContext>(D), WL);
314 for (Actions::iterator I = actions.begin(), E = actions.end(); I != E; ++I)
315 for (llvm::SmallVectorImpl<Decl*>::iterator WI=WL.begin(), WE=WL.end();
316 WI != WE; ++WI)
317 (*I)(*this, *Mgr, *WI);
320 //===----------------------------------------------------------------------===//
321 // Analyses
322 //===----------------------------------------------------------------------===//
324 static void ActionWarnDeadStores(AnalysisConsumer &C, AnalysisManager& mgr,
325 Decl *D) {
326 if (LiveVariables *L = mgr.getLiveVariables(D)) {
327 BugReporter BR(mgr);
328 CheckDeadStores(*mgr.getCFG(D), *L, mgr.getParentMap(D), BR);
332 static void ActionWarnUninitVals(AnalysisConsumer &C, AnalysisManager& mgr,
333 Decl *D) {
334 if (CFG* c = mgr.getCFG(D)) {
335 CheckUninitializedValues(*c, mgr.getASTContext(), mgr.getDiagnostic());
340 static void ActionExprEngine(AnalysisConsumer &C, AnalysisManager& mgr,
341 Decl *D,
342 TransferFuncs* tf) {
344 llvm::OwningPtr<TransferFuncs> TF(tf);
346 // Construct the analysis engine. We first query for the LiveVariables
347 // information to see if the CFG is valid.
348 // FIXME: Inter-procedural analysis will need to handle invalid CFGs.
349 if (!mgr.getLiveVariables(D))
350 return;
351 ExprEngine Eng(mgr, TF.take());
353 if (C.Opts.EnableExperimentalInternalChecks)
354 RegisterExperimentalInternalChecks(Eng);
356 RegisterAppleChecks(Eng, *D);
358 if (C.Opts.EnableExperimentalChecks)
359 RegisterExperimentalChecks(Eng);
361 if (C.Opts.ObjCSelfInitCheck && isa<ObjCMethodDecl>(D))
362 registerObjCSelfInitChecker(Eng);
364 // Enable idempotent operation checking if it was explicitly turned on, or if
365 // we are running experimental checks (i.e. everything)
366 if (C.Opts.IdempotentOps || C.Opts.EnableExperimentalChecks
367 || C.Opts.EnableExperimentalInternalChecks)
368 RegisterIdempotentOperationChecker(Eng);
370 if (C.Opts.BufferOverflows)
371 RegisterArrayBoundCheckerV2(Eng);
373 // Enable AnalyzerStatsChecker if it was given as an argument
374 if (C.Opts.AnalyzerStats)
375 RegisterAnalyzerStatsChecker(Eng);
377 // Set the graph auditor.
378 llvm::OwningPtr<ExplodedNode::Auditor> Auditor;
379 if (mgr.shouldVisualizeUbigraph()) {
380 Auditor.reset(CreateUbiViz());
381 ExplodedNode::SetAuditor(Auditor.get());
384 // Execute the worklist algorithm.
385 Eng.ExecuteWorkList(mgr.getStackFrame(D, 0), mgr.getMaxNodes());
387 // Release the auditor (if any) so that it doesn't monitor the graph
388 // created BugReporter.
389 ExplodedNode::SetAuditor(0);
391 // Visualize the exploded graph.
392 if (mgr.shouldVisualizeGraphviz())
393 Eng.ViewGraph(mgr.shouldTrimGraph());
395 // Display warnings.
396 Eng.getBugReporter().FlushReports();
399 static void ActionObjCMemCheckerAux(AnalysisConsumer &C, AnalysisManager& mgr,
400 Decl *D, bool GCEnabled) {
402 TransferFuncs* TF = MakeCFRefCountTF(mgr.getASTContext(),
403 GCEnabled,
404 mgr.getLangOptions());
406 ActionExprEngine(C, mgr, D, TF);
409 static void ActionObjCMemChecker(AnalysisConsumer &C, AnalysisManager& mgr,
410 Decl *D) {
412 switch (mgr.getLangOptions().getGCMode()) {
413 default:
414 assert (false && "Invalid GC mode.");
415 case LangOptions::NonGC:
416 ActionObjCMemCheckerAux(C, mgr, D, false);
417 break;
419 case LangOptions::GCOnly:
420 ActionObjCMemCheckerAux(C, mgr, D, true);
421 break;
423 case LangOptions::HybridGC:
424 ActionObjCMemCheckerAux(C, mgr, D, false);
425 ActionObjCMemCheckerAux(C, mgr, D, true);
426 break;
430 static void ActionDisplayLiveVariables(AnalysisConsumer &C,
431 AnalysisManager& mgr, Decl *D) {
432 if (LiveVariables* L = mgr.getLiveVariables(D)) {
433 L->dumpBlockLiveness(mgr.getSourceManager());
437 static void ActionCFGDump(AnalysisConsumer &C, AnalysisManager& mgr, Decl *D) {
438 if (CFG *cfg = mgr.getCFG(D)) {
439 cfg->dump(mgr.getLangOptions());
443 static void ActionCFGView(AnalysisConsumer &C, AnalysisManager& mgr, Decl *D) {
444 if (CFG *cfg = mgr.getCFG(D)) {
445 cfg->viewCFG(mgr.getLangOptions());
449 static void ActionSecuritySyntacticChecks(AnalysisConsumer &C,
450 AnalysisManager &mgr, Decl *D) {
451 BugReporter BR(mgr);
452 CheckSecuritySyntaxOnly(D, BR);
455 static void ActionLLVMConventionChecker(AnalysisConsumer &C,
456 AnalysisManager &mgr,
457 TranslationUnitDecl &TU) {
458 BugReporter BR(mgr);
459 CheckLLVMConventions(TU, BR);
462 static void ActionWarnObjCDealloc(AnalysisConsumer &C, AnalysisManager& mgr,
463 Decl *D) {
464 if (mgr.getLangOptions().getGCMode() == LangOptions::GCOnly)
465 return;
466 BugReporter BR(mgr);
467 CheckObjCDealloc(cast<ObjCImplementationDecl>(D), mgr.getLangOptions(), BR);
470 static void ActionWarnObjCUnusedIvars(AnalysisConsumer &C, AnalysisManager& mgr,
471 Decl *D) {
472 BugReporter BR(mgr);
473 CheckObjCUnusedIvar(cast<ObjCImplementationDecl>(D), BR);
476 static void ActionWarnObjCMethSigs(AnalysisConsumer &C, AnalysisManager& mgr,
477 Decl *D) {
478 BugReporter BR(mgr);
479 CheckObjCInstMethSignature(cast<ObjCImplementationDecl>(D), BR);
482 static void ActionWarnSizeofPointer(AnalysisConsumer &C, AnalysisManager &mgr,
483 Decl *D) {
484 BugReporter BR(mgr);
485 CheckSizeofPointer(D, BR);
488 //===----------------------------------------------------------------------===//
489 // AnalysisConsumer creation.
490 //===----------------------------------------------------------------------===//
492 ASTConsumer* ento::CreateAnalysisConsumer(const Preprocessor& pp,
493 const std::string& OutDir,
494 const AnalyzerOptions& Opts) {
495 llvm::OwningPtr<AnalysisConsumer> C(new AnalysisConsumer(pp, OutDir, Opts));
497 for (unsigned i = 0; i < Opts.AnalysisList.size(); ++i)
498 switch (Opts.AnalysisList[i]) {
499 #define ANALYSIS(NAME, CMD, DESC, SCOPE)\
500 case NAME:\
501 C->add ## SCOPE ## Action(&Action ## NAME);\
502 break;
503 #include "clang/Frontend/Analyses.def"
504 default: break;
507 // Last, disable the effects of '-Werror' when using the AnalysisConsumer.
508 pp.getDiagnostics().setWarningsAsErrors(false);
510 return C.take();
513 //===----------------------------------------------------------------------===//
514 // Ubigraph Visualization. FIXME: Move to separate file.
515 //===----------------------------------------------------------------------===//
517 namespace {
519 class UbigraphViz : public ExplodedNode::Auditor {
520 llvm::OwningPtr<llvm::raw_ostream> Out;
521 llvm::sys::Path Dir, Filename;
522 unsigned Cntr;
524 typedef llvm::DenseMap<void*,unsigned> VMap;
525 VMap M;
527 public:
528 UbigraphViz(llvm::raw_ostream* out, llvm::sys::Path& dir,
529 llvm::sys::Path& filename);
531 ~UbigraphViz();
533 virtual void AddEdge(ExplodedNode* Src, ExplodedNode* Dst);
536 } // end anonymous namespace
538 static ExplodedNode::Auditor* CreateUbiViz() {
539 std::string ErrMsg;
541 llvm::sys::Path Dir = llvm::sys::Path::GetTemporaryDirectory(&ErrMsg);
542 if (!ErrMsg.empty())
543 return 0;
545 llvm::sys::Path Filename = Dir;
546 Filename.appendComponent("llvm_ubi");
547 Filename.makeUnique(true,&ErrMsg);
549 if (!ErrMsg.empty())
550 return 0;
552 llvm::errs() << "Writing '" << Filename.str() << "'.\n";
554 llvm::OwningPtr<llvm::raw_fd_ostream> Stream;
555 Stream.reset(new llvm::raw_fd_ostream(Filename.c_str(), ErrMsg));
557 if (!ErrMsg.empty())
558 return 0;
560 return new UbigraphViz(Stream.take(), Dir, Filename);
563 void UbigraphViz::AddEdge(ExplodedNode* Src, ExplodedNode* Dst) {
565 assert (Src != Dst && "Self-edges are not allowed.");
567 // Lookup the Src. If it is a new node, it's a root.
568 VMap::iterator SrcI= M.find(Src);
569 unsigned SrcID;
571 if (SrcI == M.end()) {
572 M[Src] = SrcID = Cntr++;
573 *Out << "('vertex', " << SrcID << ", ('color','#00ff00'))\n";
575 else
576 SrcID = SrcI->second;
578 // Lookup the Dst.
579 VMap::iterator DstI= M.find(Dst);
580 unsigned DstID;
582 if (DstI == M.end()) {
583 M[Dst] = DstID = Cntr++;
584 *Out << "('vertex', " << DstID << ")\n";
586 else {
587 // We have hit DstID before. Change its style to reflect a cache hit.
588 DstID = DstI->second;
589 *Out << "('change_vertex_style', " << DstID << ", 1)\n";
592 // Add the edge.
593 *Out << "('edge', " << SrcID << ", " << DstID
594 << ", ('arrow','true'), ('oriented', 'true'))\n";
597 UbigraphViz::UbigraphViz(llvm::raw_ostream* out, llvm::sys::Path& dir,
598 llvm::sys::Path& filename)
599 : Out(out), Dir(dir), Filename(filename), Cntr(0) {
601 *Out << "('vertex_style_attribute', 0, ('shape', 'icosahedron'))\n";
602 *Out << "('vertex_style', 1, 0, ('shape', 'sphere'), ('color', '#ffcc66'),"
603 " ('size', '1.5'))\n";
606 UbigraphViz::~UbigraphViz() {
607 Out.reset(0);
608 llvm::errs() << "Running 'ubiviz' program... ";
609 std::string ErrMsg;
610 llvm::sys::Path Ubiviz = llvm::sys::Program::FindProgramByName("ubiviz");
611 std::vector<const char*> args;
612 args.push_back(Ubiviz.c_str());
613 args.push_back(Filename.c_str());
614 args.push_back(0);
616 if (llvm::sys::Program::ExecuteAndWait(Ubiviz, &args[0],0,0,0,0,&ErrMsg)) {
617 llvm::errs() << "Error viewing graph: " << ErrMsg << "\n";
620 // Delete the directory.
621 Dir.eraseFromDisk(true);