1 //===--- AnalysisConsumer.cpp - ASTConsumer for running Analyses ----------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
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
;
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 //===----------------------------------------------------------------------===//
68 class AnalysisConsumer
: public ASTConsumer
{
70 typedef void (*CodeAction
)(AnalysisConsumer
&C
, AnalysisManager
&M
, Decl
*D
);
71 typedef void (*TUAction
)(AnalysisConsumer
&C
, AnalysisManager
&M
,
72 TranslationUnitDecl
&TU
);
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.
86 const Preprocessor
&PP
;
87 const std::string OutDir
;
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
),
103 DigestAnalyzerOptions();
106 void DigestAnalyzerOptions() {
107 // Create the PathDiagnosticClient.
108 if (!OutDir
.empty()) {
109 switch (Opts
.AnalysisDiagOpt
) {
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
;
126 switch (Opts
.AnalysisStoreOpt
) {
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
;
138 switch (Opts
.AnalysisConstraintsOpt
) {
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
)
152 SourceManager
&SM
= Mgr
->getASTContext().getSourceManager();
153 PresumedLoc Loc
= SM
.getPresumedLoc(D
->getLocation());
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
) {
188 Mgr
.reset(new AnalysisManager(*Ctx
, PP
.getDiagnostics(),
189 PP
.getLangOptions(), PD
,
190 CreateStoreMgr
, CreateConstraintMgr
,
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();
217 switch (D
->getKind()) {
218 case Decl::Namespace
: {
219 HandleDeclContext(C
, cast
<NamespaceDecl
>(D
));
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
)
236 HandleCode(FD
, FunctionActions
);
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())
251 DisplayFunction(*MI
);
252 HandleCode(*MI
, ObjCMethodActions
);
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.
280 static void FindBlocks(DeclContext
*D
, llvm::SmallVectorImpl
<Decl
*> &WL
) {
281 if (BlockDecl
*BD
= dyn_cast
<BlockDecl
>(D
))
284 for (DeclContext::decl_iterator I
= D
->decls_begin(), E
= D
->decls_end();
286 if (DeclContext
*DC
= dyn_cast
<DeclContext
>(*I
))
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())
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
))
304 // Clear the AnalysisManager of old AnalysisContexts.
305 Mgr
->ClearContexts();
307 // Dispatch on the actions.
308 llvm::SmallVector
<Decl
*, 10> WL
;
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();
317 (*I
)(*this, *Mgr
, *WI
);
320 //===----------------------------------------------------------------------===//
322 //===----------------------------------------------------------------------===//
324 static void ActionWarnDeadStores(AnalysisConsumer
&C
, AnalysisManager
& mgr
,
326 if (LiveVariables
*L
= mgr
.getLiveVariables(D
)) {
328 CheckDeadStores(*mgr
.getCFG(D
), *L
, mgr
.getParentMap(D
), BR
);
332 static void ActionWarnUninitVals(AnalysisConsumer
&C
, AnalysisManager
& mgr
,
334 if (CFG
* c
= mgr
.getCFG(D
)) {
335 CheckUninitializedValues(*c
, mgr
.getASTContext(), mgr
.getDiagnostic());
340 static void ActionExprEngine(AnalysisConsumer
&C
, AnalysisManager
& mgr
,
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
))
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());
396 Eng
.getBugReporter().FlushReports();
399 static void ActionObjCMemCheckerAux(AnalysisConsumer
&C
, AnalysisManager
& mgr
,
400 Decl
*D
, bool GCEnabled
) {
402 TransferFuncs
* TF
= MakeCFRefCountTF(mgr
.getASTContext(),
404 mgr
.getLangOptions());
406 ActionExprEngine(C
, mgr
, D
, TF
);
409 static void ActionObjCMemChecker(AnalysisConsumer
&C
, AnalysisManager
& mgr
,
412 switch (mgr
.getLangOptions().getGCMode()) {
414 assert (false && "Invalid GC mode.");
415 case LangOptions::NonGC
:
416 ActionObjCMemCheckerAux(C
, mgr
, D
, false);
419 case LangOptions::GCOnly
:
420 ActionObjCMemCheckerAux(C
, mgr
, D
, true);
423 case LangOptions::HybridGC
:
424 ActionObjCMemCheckerAux(C
, mgr
, D
, false);
425 ActionObjCMemCheckerAux(C
, mgr
, D
, true);
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
) {
452 CheckSecuritySyntaxOnly(D
, BR
);
455 static void ActionLLVMConventionChecker(AnalysisConsumer
&C
,
456 AnalysisManager
&mgr
,
457 TranslationUnitDecl
&TU
) {
459 CheckLLVMConventions(TU
, BR
);
462 static void ActionWarnObjCDealloc(AnalysisConsumer
&C
, AnalysisManager
& mgr
,
464 if (mgr
.getLangOptions().getGCMode() == LangOptions::GCOnly
)
467 CheckObjCDealloc(cast
<ObjCImplementationDecl
>(D
), mgr
.getLangOptions(), BR
);
470 static void ActionWarnObjCUnusedIvars(AnalysisConsumer
&C
, AnalysisManager
& mgr
,
473 CheckObjCUnusedIvar(cast
<ObjCImplementationDecl
>(D
), BR
);
476 static void ActionWarnObjCMethSigs(AnalysisConsumer
&C
, AnalysisManager
& mgr
,
479 CheckObjCInstMethSignature(cast
<ObjCImplementationDecl
>(D
), BR
);
482 static void ActionWarnSizeofPointer(AnalysisConsumer
&C
, AnalysisManager
&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)\
501 C->add ## SCOPE ## Action(&Action ## NAME);\
503 #include "clang/Frontend/Analyses.def"
507 // Last, disable the effects of '-Werror' when using the AnalysisConsumer.
508 pp
.getDiagnostics().setWarningsAsErrors(false);
513 //===----------------------------------------------------------------------===//
514 // Ubigraph Visualization. FIXME: Move to separate file.
515 //===----------------------------------------------------------------------===//
519 class UbigraphViz
: public ExplodedNode::Auditor
{
520 llvm::OwningPtr
<llvm::raw_ostream
> Out
;
521 llvm::sys::Path Dir
, Filename
;
524 typedef llvm::DenseMap
<void*,unsigned> VMap
;
528 UbigraphViz(llvm::raw_ostream
* out
, llvm::sys::Path
& dir
,
529 llvm::sys::Path
& filename
);
533 virtual void AddEdge(ExplodedNode
* Src
, ExplodedNode
* Dst
);
536 } // end anonymous namespace
538 static ExplodedNode::Auditor
* CreateUbiViz() {
541 llvm::sys::Path Dir
= llvm::sys::Path::GetTemporaryDirectory(&ErrMsg
);
545 llvm::sys::Path Filename
= Dir
;
546 Filename
.appendComponent("llvm_ubi");
547 Filename
.makeUnique(true,&ErrMsg
);
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
));
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
);
571 if (SrcI
== M
.end()) {
572 M
[Src
] = SrcID
= Cntr
++;
573 *Out
<< "('vertex', " << SrcID
<< ", ('color','#00ff00'))\n";
576 SrcID
= SrcI
->second
;
579 VMap::iterator DstI
= M
.find(Dst
);
582 if (DstI
== M
.end()) {
583 M
[Dst
] = DstID
= Cntr
++;
584 *Out
<< "('vertex', " << DstID
<< ")\n";
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";
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() {
608 llvm::errs() << "Running 'ubiviz' program... ";
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());
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);