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/Frontend/CheckerRegistration.h"
24 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
25 #include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
26 #include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
27 #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
28 #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
29 #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
30 #include "clang/StaticAnalyzer/Core/PathSensitive/TransferFuncs.h"
31 #include "clang/StaticAnalyzer/Core/PathDiagnosticClients.h"
33 // FIXME: Restructure checker registration.
34 #include "../Checkers/ClangSACheckers.h"
35 #include "../Checkers/ExperimentalChecks.h"
36 #include "../Checkers/InternalChecks.h"
38 #include "clang/Basic/FileManager.h"
39 #include "clang/Basic/SourceManager.h"
40 #include "clang/Frontend/AnalyzerOptions.h"
41 #include "clang/Lex/Preprocessor.h"
42 #include "llvm/Support/raw_ostream.h"
43 #include "llvm/Support/Path.h"
44 #include "llvm/Support/Program.h"
45 #include "llvm/ADT/OwningPtr.h"
47 using namespace clang
;
50 static ExplodedNode::Auditor
* CreateUbiViz();
52 //===----------------------------------------------------------------------===//
53 // Special PathDiagnosticClients.
54 //===----------------------------------------------------------------------===//
56 static PathDiagnosticClient
*
57 createPlistHTMLDiagnosticClient(const std::string
& prefix
,
58 const Preprocessor
&PP
) {
59 PathDiagnosticClient
*PD
=
60 createHTMLDiagnosticClient(llvm::sys::path::parent_path(prefix
), PP
);
61 return createPlistDiagnosticClient(prefix
, PP
, PD
);
64 //===----------------------------------------------------------------------===//
65 // AnalysisConsumer declaration.
66 //===----------------------------------------------------------------------===//
70 class AnalysisConsumer
: public ASTConsumer
{
72 typedef void (*CodeAction
)(AnalysisConsumer
&C
, AnalysisManager
&M
, Decl
*D
);
73 typedef void (*TUAction
)(AnalysisConsumer
&C
, AnalysisManager
&M
,
74 TranslationUnitDecl
&TU
);
77 typedef std::vector
<CodeAction
> Actions
;
78 typedef std::vector
<TUAction
> TUActions
;
80 Actions FunctionActions
;
81 Actions ObjCMethodActions
;
82 Actions ObjCImplementationActions
;
83 Actions CXXMethodActions
;
84 TUActions TranslationUnitActions
; // Remove this.
88 const Preprocessor
&PP
;
89 const std::string OutDir
;
92 // PD is owned by AnalysisManager.
93 PathDiagnosticClient
*PD
;
95 StoreManagerCreator CreateStoreMgr
;
96 ConstraintManagerCreator CreateConstraintMgr
;
98 llvm::OwningPtr
<CheckerManager
> checkerMgr
;
99 llvm::OwningPtr
<AnalysisManager
> Mgr
;
101 AnalysisConsumer(const Preprocessor
& pp
,
102 const std::string
& outdir
,
103 const AnalyzerOptions
& opts
)
104 : Ctx(0), PP(pp
), OutDir(outdir
),
106 DigestAnalyzerOptions();
109 void DigestAnalyzerOptions() {
110 // Create the PathDiagnosticClient.
111 if (!OutDir
.empty()) {
112 switch (Opts
.AnalysisDiagOpt
) {
114 #define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN, AUTOCREATE) \
115 case PD_##NAME: PD = CREATEFN(OutDir, PP); break;
116 #include "clang/Frontend/Analyses.def"
118 } else if (Opts
.AnalysisDiagOpt
== PD_TEXT
) {
119 // Create the text client even without a specified output file since
120 // it just uses diagnostic notes.
121 PD
= createTextPathDiagnosticClient("", PP
);
124 // Create the analyzer component creators.
125 switch (Opts
.AnalysisStoreOpt
) {
127 assert(0 && "Unknown store manager.");
128 #define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATEFN) \
129 case NAME##Model: CreateStoreMgr = CREATEFN; break;
130 #include "clang/Frontend/Analyses.def"
133 switch (Opts
.AnalysisConstraintsOpt
) {
135 assert(0 && "Unknown store manager.");
136 #define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATEFN) \
137 case NAME##Model: CreateConstraintMgr = CREATEFN; break;
138 #include "clang/Frontend/Analyses.def"
142 void DisplayFunction(const Decl
*D
) {
143 if (!Opts
.AnalyzerDisplayProgress
)
146 SourceManager
&SM
= Mgr
->getASTContext().getSourceManager();
147 PresumedLoc Loc
= SM
.getPresumedLoc(D
->getLocation());
149 llvm::errs() << "ANALYZE: " << Loc
.getFilename();
151 if (isa
<FunctionDecl
>(D
) || isa
<ObjCMethodDecl
>(D
)) {
152 const NamedDecl
*ND
= cast
<NamedDecl
>(D
);
153 llvm::errs() << ' ' << ND
<< '\n';
155 else if (isa
<BlockDecl
>(D
)) {
156 llvm::errs() << ' ' << "block(line:" << Loc
.getLine() << ",col:"
157 << Loc
.getColumn() << '\n';
159 else if (const ObjCMethodDecl
*MD
= dyn_cast
<ObjCMethodDecl
>(D
)) {
160 Selector S
= MD
->getSelector();
161 llvm::errs() << ' ' << S
.getAsString();
166 void addCodeAction(CodeAction action
) {
167 FunctionActions
.push_back(action
);
168 ObjCMethodActions
.push_back(action
);
169 CXXMethodActions
.push_back(action
);
172 void addTranslationUnitAction(TUAction action
) {
173 TranslationUnitActions
.push_back(action
);
176 void addObjCImplementationAction(CodeAction action
) {
177 ObjCImplementationActions
.push_back(action
);
180 virtual void Initialize(ASTContext
&Context
) {
182 checkerMgr
.reset(registerCheckers(Opts
, PP
.getDiagnostics()));
183 Mgr
.reset(new AnalysisManager(*Ctx
, PP
.getDiagnostics(),
184 PP
.getLangOptions(), PD
,
185 CreateStoreMgr
, CreateConstraintMgr
,
188 Opts
.MaxNodes
, Opts
.MaxLoop
,
189 Opts
.VisualizeEGDot
, Opts
.VisualizeEGUbi
,
190 Opts
.PurgeDead
, Opts
.EagerlyAssume
,
191 Opts
.TrimGraph
, Opts
.InlineCall
,
192 Opts
.UnoptimizedCFG
, Opts
.CFGAddImplicitDtors
,
193 Opts
.CFGAddInitializers
,
194 Opts
.EagerlyTrimEGraph
));
197 virtual void HandleTranslationUnit(ASTContext
&C
);
198 void HandleDeclContext(ASTContext
&C
, DeclContext
*dc
);
200 void HandleCode(Decl
*D
, Actions
& actions
);
202 } // end anonymous namespace
204 //===----------------------------------------------------------------------===//
205 // AnalysisConsumer implementation.
206 //===----------------------------------------------------------------------===//
208 void AnalysisConsumer::HandleDeclContext(ASTContext
&C
, DeclContext
*dc
) {
209 for (DeclContext::decl_iterator I
= dc
->decls_begin(), E
= dc
->decls_end();
213 switch (D
->getKind()) {
214 case Decl::Namespace
: {
215 HandleDeclContext(C
, cast
<NamespaceDecl
>(D
));
218 case Decl::CXXConstructor
:
219 case Decl::CXXDestructor
:
220 case Decl::CXXConversion
:
221 case Decl::CXXMethod
:
222 case Decl::Function
: {
223 FunctionDecl
* FD
= cast
<FunctionDecl
>(D
);
224 // We skip function template definitions, as their semantics is
225 // only determined when they are instantiated.
226 if (FD
->isThisDeclarationADefinition() &&
227 !FD
->isDependentContext()) {
228 if (!Opts
.AnalyzeSpecificFunction
.empty() &&
229 FD
->getDeclName().getAsString() != Opts
.AnalyzeSpecificFunction
)
232 HandleCode(FD
, FunctionActions
);
237 case Decl::ObjCImplementation
: {
238 ObjCImplementationDecl
* ID
= cast
<ObjCImplementationDecl
>(*I
);
239 HandleCode(ID
, ObjCImplementationActions
);
241 for (ObjCImplementationDecl::method_iterator MI
= ID
->meth_begin(),
242 ME
= ID
->meth_end(); MI
!= ME
; ++MI
) {
243 if ((*MI
)->isThisDeclarationADefinition()) {
244 if (!Opts
.AnalyzeSpecificFunction
.empty() &&
245 Opts
.AnalyzeSpecificFunction
!= (*MI
)->getSelector().getAsString())
247 DisplayFunction(*MI
);
248 HandleCode(*MI
, ObjCMethodActions
);
260 void AnalysisConsumer::HandleTranslationUnit(ASTContext
&C
) {
261 TranslationUnitDecl
*TU
= C
.getTranslationUnitDecl();
262 HandleDeclContext(C
, TU
);
264 for (TUActions::iterator I
= TranslationUnitActions
.begin(),
265 E
= TranslationUnitActions
.end(); I
!= E
; ++I
) {
266 (*I
)(*this, *Mgr
, *TU
);
269 // Explicitly destroy the PathDiagnosticClient. This will flush its output.
270 // FIXME: This should be replaced with something that doesn't rely on
271 // side-effects in PathDiagnosticClient's destructor. This is required when
272 // used with option -disable-free.
276 static void FindBlocks(DeclContext
*D
, llvm::SmallVectorImpl
<Decl
*> &WL
) {
277 if (BlockDecl
*BD
= dyn_cast
<BlockDecl
>(D
))
280 for (DeclContext::decl_iterator I
= D
->decls_begin(), E
= D
->decls_end();
282 if (DeclContext
*DC
= dyn_cast
<DeclContext
>(*I
))
286 void AnalysisConsumer::HandleCode(Decl
*D
, Actions
& actions
) {
288 // Don't run the actions if an error has occured with parsing the file.
289 Diagnostic
&Diags
= PP
.getDiagnostics();
290 if (Diags
.hasErrorOccurred() || Diags
.hasFatalErrorOccurred())
293 // Don't run the actions on declarations in header files unless
294 // otherwise specified.
295 SourceManager
&SM
= Ctx
->getSourceManager();
296 SourceLocation SL
= SM
.getInstantiationLoc(D
->getLocation());
297 if (!Opts
.AnalyzeAll
&& !SM
.isFromMainFile(SL
))
300 // Clear the AnalysisManager of old AnalysisContexts.
301 Mgr
->ClearContexts();
303 // Dispatch on the actions.
304 llvm::SmallVector
<Decl
*, 10> WL
;
307 if (D
->hasBody() && Opts
.AnalyzeNestedBlocks
)
308 FindBlocks(cast
<DeclContext
>(D
), WL
);
310 for (Actions::iterator I
= actions
.begin(), E
= actions
.end(); I
!= E
; ++I
)
311 for (llvm::SmallVectorImpl
<Decl
*>::iterator WI
=WL
.begin(), WE
=WL
.end();
313 (*I
)(*this, *Mgr
, *WI
);
316 //===----------------------------------------------------------------------===//
318 //===----------------------------------------------------------------------===//
320 static void ActionWarnDeadStores(AnalysisConsumer
&C
, AnalysisManager
& mgr
,
322 if (LiveVariables
*L
= mgr
.getLiveVariables(D
)) {
324 CheckDeadStores(*mgr
.getCFG(D
), *L
, mgr
.getParentMap(D
), BR
);
328 static void ActionWarnUninitVals(AnalysisConsumer
&C
, AnalysisManager
& mgr
,
330 if (CFG
* c
= mgr
.getCFG(D
)) {
331 CheckUninitializedValues(*c
, mgr
.getASTContext(), mgr
.getDiagnostic());
336 static void ActionExprEngine(AnalysisConsumer
&C
, AnalysisManager
& mgr
,
340 llvm::OwningPtr
<TransferFuncs
> TF(tf
);
342 // Construct the analysis engine. We first query for the LiveVariables
343 // information to see if the CFG is valid.
344 // FIXME: Inter-procedural analysis will need to handle invalid CFGs.
345 if (!mgr
.getLiveVariables(D
))
347 ExprEngine
Eng(mgr
, TF
.take());
349 if (C
.Opts
.EnableExperimentalInternalChecks
)
350 RegisterExperimentalInternalChecks(Eng
);
352 RegisterAppleChecks(Eng
, *D
);
354 if (C
.Opts
.EnableExperimentalChecks
)
355 RegisterExperimentalChecks(Eng
);
357 if (C
.Opts
.ObjCSelfInitCheck
&& isa
<ObjCMethodDecl
>(D
))
358 registerObjCSelfInitChecker(Eng
);
360 // Enable idempotent operation checking if it was explicitly turned on, or if
361 // we are running experimental checks (i.e. everything)
362 if (C
.Opts
.IdempotentOps
|| C
.Opts
.EnableExperimentalChecks
363 || C
.Opts
.EnableExperimentalInternalChecks
)
364 RegisterIdempotentOperationChecker(Eng
);
366 if (C
.Opts
.BufferOverflows
)
367 RegisterArrayBoundCheckerV2(Eng
);
369 // Enable AnalyzerStatsChecker if it was given as an argument
370 if (C
.Opts
.AnalyzerStats
)
371 RegisterAnalyzerStatsChecker(Eng
);
373 // Set the graph auditor.
374 llvm::OwningPtr
<ExplodedNode::Auditor
> Auditor
;
375 if (mgr
.shouldVisualizeUbigraph()) {
376 Auditor
.reset(CreateUbiViz());
377 ExplodedNode::SetAuditor(Auditor
.get());
380 // Execute the worklist algorithm.
381 Eng
.ExecuteWorkList(mgr
.getStackFrame(D
, 0), mgr
.getMaxNodes());
383 // Release the auditor (if any) so that it doesn't monitor the graph
384 // created BugReporter.
385 ExplodedNode::SetAuditor(0);
387 // Visualize the exploded graph.
388 if (mgr
.shouldVisualizeGraphviz())
389 Eng
.ViewGraph(mgr
.shouldTrimGraph());
392 Eng
.getBugReporter().FlushReports();
395 static void ActionObjCMemCheckerAux(AnalysisConsumer
&C
, AnalysisManager
& mgr
,
396 Decl
*D
, bool GCEnabled
) {
398 TransferFuncs
* TF
= MakeCFRefCountTF(mgr
.getASTContext(),
400 mgr
.getLangOptions());
402 ActionExprEngine(C
, mgr
, D
, TF
);
405 static void ActionObjCMemChecker(AnalysisConsumer
&C
, AnalysisManager
& mgr
,
408 switch (mgr
.getLangOptions().getGCMode()) {
410 assert (false && "Invalid GC mode.");
411 case LangOptions::NonGC
:
412 ActionObjCMemCheckerAux(C
, mgr
, D
, false);
415 case LangOptions::GCOnly
:
416 ActionObjCMemCheckerAux(C
, mgr
, D
, true);
419 case LangOptions::HybridGC
:
420 ActionObjCMemCheckerAux(C
, mgr
, D
, false);
421 ActionObjCMemCheckerAux(C
, mgr
, D
, true);
426 static void ActionDisplayLiveVariables(AnalysisConsumer
&C
,
427 AnalysisManager
& mgr
, Decl
*D
) {
428 if (LiveVariables
* L
= mgr
.getLiveVariables(D
)) {
429 L
->dumpBlockLiveness(mgr
.getSourceManager());
433 static void ActionCFGDump(AnalysisConsumer
&C
, AnalysisManager
& mgr
, Decl
*D
) {
434 if (CFG
*cfg
= mgr
.getCFG(D
)) {
435 cfg
->dump(mgr
.getLangOptions());
439 static void ActionCFGView(AnalysisConsumer
&C
, AnalysisManager
& mgr
, Decl
*D
) {
440 if (CFG
*cfg
= mgr
.getCFG(D
)) {
441 cfg
->viewCFG(mgr
.getLangOptions());
445 static void ActionSecuritySyntacticChecks(AnalysisConsumer
&C
,
446 AnalysisManager
&mgr
, Decl
*D
) {
448 CheckSecuritySyntaxOnly(D
, BR
);
451 static void ActionLLVMConventionChecker(AnalysisConsumer
&C
,
452 AnalysisManager
&mgr
,
453 TranslationUnitDecl
&TU
) {
455 CheckLLVMConventions(TU
, BR
);
458 static void ActionWarnObjCDealloc(AnalysisConsumer
&C
, AnalysisManager
& mgr
,
460 if (mgr
.getLangOptions().getGCMode() == LangOptions::GCOnly
)
463 CheckObjCDealloc(cast
<ObjCImplementationDecl
>(D
), mgr
.getLangOptions(), BR
);
466 static void ActionWarnObjCUnusedIvars(AnalysisConsumer
&C
, AnalysisManager
& mgr
,
469 CheckObjCUnusedIvar(cast
<ObjCImplementationDecl
>(D
), BR
);
472 static void ActionWarnObjCMethSigs(AnalysisConsumer
&C
, AnalysisManager
& mgr
,
475 CheckObjCInstMethSignature(cast
<ObjCImplementationDecl
>(D
), BR
);
478 static void ActionWarnSizeofPointer(AnalysisConsumer
&C
, AnalysisManager
&mgr
,
481 CheckSizeofPointer(D
, BR
);
484 //===----------------------------------------------------------------------===//
485 // AnalysisConsumer creation.
486 //===----------------------------------------------------------------------===//
488 ASTConsumer
* ento::CreateAnalysisConsumer(const Preprocessor
& pp
,
489 const std::string
& OutDir
,
490 const AnalyzerOptions
& Opts
) {
491 llvm::OwningPtr
<AnalysisConsumer
> C(new AnalysisConsumer(pp
, OutDir
, Opts
));
493 for (unsigned i
= 0; i
< Opts
.AnalysisList
.size(); ++i
)
494 switch (Opts
.AnalysisList
[i
]) {
495 #define ANALYSIS(NAME, CMD, DESC, SCOPE)\
497 C->add ## SCOPE ## Action(&Action ## NAME);\
499 #include "clang/Frontend/Analyses.def"
503 // Last, disable the effects of '-Werror' when using the AnalysisConsumer.
504 pp
.getDiagnostics().setWarningsAsErrors(false);
509 //===----------------------------------------------------------------------===//
510 // Ubigraph Visualization. FIXME: Move to separate file.
511 //===----------------------------------------------------------------------===//
515 class UbigraphViz
: public ExplodedNode::Auditor
{
516 llvm::OwningPtr
<llvm::raw_ostream
> Out
;
517 llvm::sys::Path Dir
, Filename
;
520 typedef llvm::DenseMap
<void*,unsigned> VMap
;
524 UbigraphViz(llvm::raw_ostream
* out
, llvm::sys::Path
& dir
,
525 llvm::sys::Path
& filename
);
529 virtual void AddEdge(ExplodedNode
* Src
, ExplodedNode
* Dst
);
532 } // end anonymous namespace
534 static ExplodedNode::Auditor
* CreateUbiViz() {
537 llvm::sys::Path Dir
= llvm::sys::Path::GetTemporaryDirectory(&ErrMsg
);
541 llvm::sys::Path Filename
= Dir
;
542 Filename
.appendComponent("llvm_ubi");
543 Filename
.makeUnique(true,&ErrMsg
);
548 llvm::errs() << "Writing '" << Filename
.str() << "'.\n";
550 llvm::OwningPtr
<llvm::raw_fd_ostream
> Stream
;
551 Stream
.reset(new llvm::raw_fd_ostream(Filename
.c_str(), ErrMsg
));
556 return new UbigraphViz(Stream
.take(), Dir
, Filename
);
559 void UbigraphViz::AddEdge(ExplodedNode
* Src
, ExplodedNode
* Dst
) {
561 assert (Src
!= Dst
&& "Self-edges are not allowed.");
563 // Lookup the Src. If it is a new node, it's a root.
564 VMap::iterator SrcI
= M
.find(Src
);
567 if (SrcI
== M
.end()) {
568 M
[Src
] = SrcID
= Cntr
++;
569 *Out
<< "('vertex', " << SrcID
<< ", ('color','#00ff00'))\n";
572 SrcID
= SrcI
->second
;
575 VMap::iterator DstI
= M
.find(Dst
);
578 if (DstI
== M
.end()) {
579 M
[Dst
] = DstID
= Cntr
++;
580 *Out
<< "('vertex', " << DstID
<< ")\n";
583 // We have hit DstID before. Change its style to reflect a cache hit.
584 DstID
= DstI
->second
;
585 *Out
<< "('change_vertex_style', " << DstID
<< ", 1)\n";
589 *Out
<< "('edge', " << SrcID
<< ", " << DstID
590 << ", ('arrow','true'), ('oriented', 'true'))\n";
593 UbigraphViz::UbigraphViz(llvm::raw_ostream
* out
, llvm::sys::Path
& dir
,
594 llvm::sys::Path
& filename
)
595 : Out(out
), Dir(dir
), Filename(filename
), Cntr(0) {
597 *Out
<< "('vertex_style_attribute', 0, ('shape', 'icosahedron'))\n";
598 *Out
<< "('vertex_style', 1, 0, ('shape', 'sphere'), ('color', '#ffcc66'),"
599 " ('size', '1.5'))\n";
602 UbigraphViz::~UbigraphViz() {
604 llvm::errs() << "Running 'ubiviz' program... ";
606 llvm::sys::Path Ubiviz
= llvm::sys::Program::FindProgramByName("ubiviz");
607 std::vector
<const char*> args
;
608 args
.push_back(Ubiviz
.c_str());
609 args
.push_back(Filename
.c_str());
612 if (llvm::sys::Program::ExecuteAndWait(Ubiviz
, &args
[0],0,0,0,0,&ErrMsg
)) {
613 llvm::errs() << "Error viewing graph: " << ErrMsg
<< "\n";
616 // Delete the directory.
617 Dir
.eraseFromDisk(true);