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"
37 #include "../Checkers/BasicObjCFoundationChecks.h"
39 #include "clang/Basic/FileManager.h"
40 #include "clang/Basic/SourceManager.h"
41 #include "clang/Frontend/AnalyzerOptions.h"
42 #include "clang/Lex/Preprocessor.h"
43 #include "llvm/Support/raw_ostream.h"
44 #include "llvm/Support/Path.h"
45 #include "llvm/Support/Program.h"
46 #include "llvm/ADT/OwningPtr.h"
48 using namespace clang
;
51 static ExplodedNode::Auditor
* CreateUbiViz();
53 //===----------------------------------------------------------------------===//
54 // Special PathDiagnosticClients.
55 //===----------------------------------------------------------------------===//
57 static PathDiagnosticClient
*
58 createPlistHTMLDiagnosticClient(const std::string
& prefix
,
59 const Preprocessor
&PP
) {
60 PathDiagnosticClient
*PD
=
61 createHTMLDiagnosticClient(llvm::sys::path::parent_path(prefix
), PP
);
62 return createPlistDiagnosticClient(prefix
, PP
, PD
);
65 //===----------------------------------------------------------------------===//
66 // AnalysisConsumer declaration.
67 //===----------------------------------------------------------------------===//
71 class AnalysisConsumer
: public ASTConsumer
{
73 typedef void (*CodeAction
)(AnalysisConsumer
&C
, AnalysisManager
&M
, Decl
*D
);
74 typedef void (*TUAction
)(AnalysisConsumer
&C
, AnalysisManager
&M
,
75 TranslationUnitDecl
&TU
);
78 typedef std::vector
<CodeAction
> Actions
;
79 typedef std::vector
<TUAction
> TUActions
;
81 Actions FunctionActions
;
82 Actions ObjCMethodActions
;
83 Actions ObjCImplementationActions
;
84 Actions CXXMethodActions
;
85 TUActions TranslationUnitActions
; // Remove this.
89 const Preprocessor
&PP
;
90 const std::string OutDir
;
93 // PD is owned by AnalysisManager.
94 PathDiagnosticClient
*PD
;
96 StoreManagerCreator CreateStoreMgr
;
97 ConstraintManagerCreator CreateConstraintMgr
;
99 llvm::OwningPtr
<CheckerManager
> checkerMgr
;
100 llvm::OwningPtr
<AnalysisManager
> Mgr
;
102 AnalysisConsumer(const Preprocessor
& pp
,
103 const std::string
& outdir
,
104 const AnalyzerOptions
& opts
)
105 : Ctx(0), PP(pp
), OutDir(outdir
),
107 DigestAnalyzerOptions();
110 void DigestAnalyzerOptions() {
111 // Create the PathDiagnosticClient.
112 if (!OutDir
.empty()) {
113 switch (Opts
.AnalysisDiagOpt
) {
115 #define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN, AUTOCREATE) \
116 case PD_##NAME: PD = CREATEFN(OutDir, PP); break;
117 #include "clang/Frontend/Analyses.def"
119 } else if (Opts
.AnalysisDiagOpt
== PD_TEXT
) {
120 // Create the text client even without a specified output file since
121 // it just uses diagnostic notes.
122 PD
= createTextPathDiagnosticClient("", PP
);
125 // Create the analyzer component creators.
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"
134 switch (Opts
.AnalysisConstraintsOpt
) {
136 assert(0 && "Unknown store manager.");
137 #define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATEFN) \
138 case NAME##Model: CreateConstraintMgr = CREATEFN; break;
139 #include "clang/Frontend/Analyses.def"
143 void DisplayFunction(const Decl
*D
) {
144 if (!Opts
.AnalyzerDisplayProgress
)
147 SourceManager
&SM
= Mgr
->getASTContext().getSourceManager();
148 PresumedLoc Loc
= SM
.getPresumedLoc(D
->getLocation());
150 llvm::errs() << "ANALYZE: " << Loc
.getFilename();
152 if (isa
<FunctionDecl
>(D
) || isa
<ObjCMethodDecl
>(D
)) {
153 const NamedDecl
*ND
= cast
<NamedDecl
>(D
);
154 llvm::errs() << ' ' << ND
<< '\n';
156 else if (isa
<BlockDecl
>(D
)) {
157 llvm::errs() << ' ' << "block(line:" << Loc
.getLine() << ",col:"
158 << Loc
.getColumn() << '\n';
160 else if (const ObjCMethodDecl
*MD
= dyn_cast
<ObjCMethodDecl
>(D
)) {
161 Selector S
= MD
->getSelector();
162 llvm::errs() << ' ' << S
.getAsString();
167 void addCodeAction(CodeAction action
) {
168 FunctionActions
.push_back(action
);
169 ObjCMethodActions
.push_back(action
);
170 CXXMethodActions
.push_back(action
);
173 void addTranslationUnitAction(TUAction action
) {
174 TranslationUnitActions
.push_back(action
);
177 void addObjCImplementationAction(CodeAction action
) {
178 ObjCImplementationActions
.push_back(action
);
181 virtual void Initialize(ASTContext
&Context
) {
183 checkerMgr
.reset(registerCheckers(Opts
, PP
.getDiagnostics()));
184 Mgr
.reset(new AnalysisManager(*Ctx
, PP
.getDiagnostics(),
185 PP
.getLangOptions(), PD
,
186 CreateStoreMgr
, CreateConstraintMgr
,
189 Opts
.MaxNodes
, Opts
.MaxLoop
,
190 Opts
.VisualizeEGDot
, Opts
.VisualizeEGUbi
,
191 Opts
.PurgeDead
, Opts
.EagerlyAssume
,
192 Opts
.TrimGraph
, Opts
.InlineCall
,
193 Opts
.UnoptimizedCFG
, Opts
.CFGAddImplicitDtors
,
194 Opts
.CFGAddInitializers
,
195 Opts
.EagerlyTrimEGraph
));
198 virtual void HandleTranslationUnit(ASTContext
&C
);
199 void HandleDeclContext(ASTContext
&C
, DeclContext
*dc
);
201 void HandleCode(Decl
*D
, Actions
& actions
);
203 } // end anonymous namespace
205 //===----------------------------------------------------------------------===//
206 // AnalysisConsumer implementation.
207 //===----------------------------------------------------------------------===//
209 void AnalysisConsumer::HandleDeclContext(ASTContext
&C
, DeclContext
*dc
) {
210 for (DeclContext::decl_iterator I
= dc
->decls_begin(), E
= dc
->decls_end();
214 switch (D
->getKind()) {
215 case Decl::Namespace
: {
216 HandleDeclContext(C
, cast
<NamespaceDecl
>(D
));
219 case Decl::CXXConstructor
:
220 case Decl::CXXDestructor
:
221 case Decl::CXXConversion
:
222 case Decl::CXXMethod
:
223 case Decl::Function
: {
224 FunctionDecl
* FD
= cast
<FunctionDecl
>(D
);
225 // We skip function template definitions, as their semantics is
226 // only determined when they are instantiated.
227 if (FD
->isThisDeclarationADefinition() &&
228 !FD
->isDependentContext()) {
229 if (!Opts
.AnalyzeSpecificFunction
.empty() &&
230 FD
->getDeclName().getAsString() != Opts
.AnalyzeSpecificFunction
)
233 HandleCode(FD
, FunctionActions
);
238 case Decl::ObjCImplementation
: {
239 ObjCImplementationDecl
* ID
= cast
<ObjCImplementationDecl
>(*I
);
240 HandleCode(ID
, ObjCImplementationActions
);
242 for (ObjCImplementationDecl::method_iterator MI
= ID
->meth_begin(),
243 ME
= ID
->meth_end(); MI
!= ME
; ++MI
) {
244 if ((*MI
)->isThisDeclarationADefinition()) {
245 if (!Opts
.AnalyzeSpecificFunction
.empty() &&
246 Opts
.AnalyzeSpecificFunction
!= (*MI
)->getSelector().getAsString())
248 DisplayFunction(*MI
);
249 HandleCode(*MI
, ObjCMethodActions
);
261 void AnalysisConsumer::HandleTranslationUnit(ASTContext
&C
) {
262 TranslationUnitDecl
*TU
= C
.getTranslationUnitDecl();
263 HandleDeclContext(C
, TU
);
265 for (TUActions::iterator I
= TranslationUnitActions
.begin(),
266 E
= TranslationUnitActions
.end(); I
!= E
; ++I
) {
267 (*I
)(*this, *Mgr
, *TU
);
270 // Explicitly destroy the PathDiagnosticClient. This will flush its output.
271 // FIXME: This should be replaced with something that doesn't rely on
272 // side-effects in PathDiagnosticClient's destructor. This is required when
273 // used with option -disable-free.
277 static void FindBlocks(DeclContext
*D
, llvm::SmallVectorImpl
<Decl
*> &WL
) {
278 if (BlockDecl
*BD
= dyn_cast
<BlockDecl
>(D
))
281 for (DeclContext::decl_iterator I
= D
->decls_begin(), E
= D
->decls_end();
283 if (DeclContext
*DC
= dyn_cast
<DeclContext
>(*I
))
287 void AnalysisConsumer::HandleCode(Decl
*D
, Actions
& actions
) {
289 // Don't run the actions if an error has occured with parsing the file.
290 Diagnostic
&Diags
= PP
.getDiagnostics();
291 if (Diags
.hasErrorOccurred() || Diags
.hasFatalErrorOccurred())
294 // Don't run the actions on declarations in header files unless
295 // otherwise specified.
296 SourceManager
&SM
= Ctx
->getSourceManager();
297 SourceLocation SL
= SM
.getInstantiationLoc(D
->getLocation());
298 if (!Opts
.AnalyzeAll
&& !SM
.isFromMainFile(SL
))
301 // Clear the AnalysisManager of old AnalysisContexts.
302 Mgr
->ClearContexts();
304 // Dispatch on the actions.
305 llvm::SmallVector
<Decl
*, 10> WL
;
308 if (D
->hasBody() && Opts
.AnalyzeNestedBlocks
)
309 FindBlocks(cast
<DeclContext
>(D
), WL
);
311 for (Actions::iterator I
= actions
.begin(), E
= actions
.end(); I
!= E
; ++I
)
312 for (llvm::SmallVectorImpl
<Decl
*>::iterator WI
=WL
.begin(), WE
=WL
.end();
314 (*I
)(*this, *Mgr
, *WI
);
317 //===----------------------------------------------------------------------===//
319 //===----------------------------------------------------------------------===//
321 static void ActionWarnDeadStores(AnalysisConsumer
&C
, AnalysisManager
& mgr
,
323 if (LiveVariables
*L
= mgr
.getLiveVariables(D
)) {
325 CheckDeadStores(*mgr
.getCFG(D
), *L
, mgr
.getParentMap(D
), BR
);
329 static void ActionWarnUninitVals(AnalysisConsumer
&C
, AnalysisManager
& mgr
,
331 if (CFG
* c
= mgr
.getCFG(D
)) {
332 CheckUninitializedValues(*c
, mgr
.getASTContext(), mgr
.getDiagnostic());
337 static void ActionExprEngine(AnalysisConsumer
&C
, AnalysisManager
& mgr
,
341 llvm::OwningPtr
<TransferFuncs
> TF(tf
);
343 // Construct the analysis engine. We first query for the LiveVariables
344 // information to see if the CFG is valid.
345 // FIXME: Inter-procedural analysis will need to handle invalid CFGs.
346 if (!mgr
.getLiveVariables(D
))
348 ExprEngine
Eng(mgr
, TF
.take());
350 if (C
.Opts
.EnableExperimentalInternalChecks
)
351 RegisterExperimentalInternalChecks(Eng
);
353 RegisterNSErrorChecks(Eng
.getBugReporter(), Eng
, *D
);
355 if (C
.Opts
.EnableExperimentalChecks
)
356 RegisterExperimentalChecks(Eng
);
358 if (C
.Opts
.BufferOverflows
)
359 RegisterArrayBoundCheckerV2(Eng
);
361 // Enable AnalyzerStatsChecker if it was given as an argument
362 if (C
.Opts
.AnalyzerStats
)
363 RegisterAnalyzerStatsChecker(Eng
);
365 // Set the graph auditor.
366 llvm::OwningPtr
<ExplodedNode::Auditor
> Auditor
;
367 if (mgr
.shouldVisualizeUbigraph()) {
368 Auditor
.reset(CreateUbiViz());
369 ExplodedNode::SetAuditor(Auditor
.get());
372 // Execute the worklist algorithm.
373 Eng
.ExecuteWorkList(mgr
.getStackFrame(D
, 0), mgr
.getMaxNodes());
375 // Release the auditor (if any) so that it doesn't monitor the graph
376 // created BugReporter.
377 ExplodedNode::SetAuditor(0);
379 // Visualize the exploded graph.
380 if (mgr
.shouldVisualizeGraphviz())
381 Eng
.ViewGraph(mgr
.shouldTrimGraph());
384 Eng
.getBugReporter().FlushReports();
387 static void ActionObjCMemCheckerAux(AnalysisConsumer
&C
, AnalysisManager
& mgr
,
388 Decl
*D
, bool GCEnabled
) {
390 TransferFuncs
* TF
= MakeCFRefCountTF(mgr
.getASTContext(),
392 mgr
.getLangOptions());
394 ActionExprEngine(C
, mgr
, D
, TF
);
397 static void ActionObjCMemChecker(AnalysisConsumer
&C
, AnalysisManager
& mgr
,
400 switch (mgr
.getLangOptions().getGCMode()) {
402 assert (false && "Invalid GC mode.");
403 case LangOptions::NonGC
:
404 ActionObjCMemCheckerAux(C
, mgr
, D
, false);
407 case LangOptions::GCOnly
:
408 ActionObjCMemCheckerAux(C
, mgr
, D
, true);
411 case LangOptions::HybridGC
:
412 ActionObjCMemCheckerAux(C
, mgr
, D
, false);
413 ActionObjCMemCheckerAux(C
, mgr
, D
, true);
418 static void ActionDisplayLiveVariables(AnalysisConsumer
&C
,
419 AnalysisManager
& mgr
, Decl
*D
) {
420 if (LiveVariables
* L
= mgr
.getLiveVariables(D
)) {
421 L
->dumpBlockLiveness(mgr
.getSourceManager());
425 static void ActionCFGDump(AnalysisConsumer
&C
, AnalysisManager
& mgr
, Decl
*D
) {
426 if (CFG
*cfg
= mgr
.getCFG(D
)) {
427 cfg
->dump(mgr
.getLangOptions());
431 static void ActionCFGView(AnalysisConsumer
&C
, AnalysisManager
& mgr
, Decl
*D
) {
432 if (CFG
*cfg
= mgr
.getCFG(D
)) {
433 cfg
->viewCFG(mgr
.getLangOptions());
437 static void ActionSecuritySyntacticChecks(AnalysisConsumer
&C
,
438 AnalysisManager
&mgr
, Decl
*D
) {
440 CheckSecuritySyntaxOnly(D
, BR
);
443 static void ActionLLVMConventionChecker(AnalysisConsumer
&C
,
444 AnalysisManager
&mgr
,
445 TranslationUnitDecl
&TU
) {
447 CheckLLVMConventions(TU
, BR
);
450 static void ActionWarnObjCDealloc(AnalysisConsumer
&C
, AnalysisManager
& mgr
,
452 if (mgr
.getLangOptions().getGCMode() == LangOptions::GCOnly
)
455 CheckObjCDealloc(cast
<ObjCImplementationDecl
>(D
), mgr
.getLangOptions(), BR
);
458 static void ActionWarnObjCUnusedIvars(AnalysisConsumer
&C
, AnalysisManager
& mgr
,
461 CheckObjCUnusedIvar(cast
<ObjCImplementationDecl
>(D
), BR
);
464 static void ActionWarnObjCMethSigs(AnalysisConsumer
&C
, AnalysisManager
& mgr
,
467 CheckObjCInstMethSignature(cast
<ObjCImplementationDecl
>(D
), BR
);
470 static void ActionWarnSizeofPointer(AnalysisConsumer
&C
, AnalysisManager
&mgr
,
473 CheckSizeofPointer(D
, BR
);
476 //===----------------------------------------------------------------------===//
477 // AnalysisConsumer creation.
478 //===----------------------------------------------------------------------===//
480 ASTConsumer
* ento::CreateAnalysisConsumer(const Preprocessor
& pp
,
481 const std::string
& OutDir
,
482 const AnalyzerOptions
& Opts
) {
483 llvm::OwningPtr
<AnalysisConsumer
> C(new AnalysisConsumer(pp
, OutDir
, Opts
));
485 for (unsigned i
= 0; i
< Opts
.AnalysisList
.size(); ++i
)
486 switch (Opts
.AnalysisList
[i
]) {
487 #define ANALYSIS(NAME, CMD, DESC, SCOPE)\
489 C->add ## SCOPE ## Action(&Action ## NAME);\
491 #include "clang/Frontend/Analyses.def"
495 // Last, disable the effects of '-Werror' when using the AnalysisConsumer.
496 pp
.getDiagnostics().setWarningsAsErrors(false);
501 //===----------------------------------------------------------------------===//
502 // Ubigraph Visualization. FIXME: Move to separate file.
503 //===----------------------------------------------------------------------===//
507 class UbigraphViz
: public ExplodedNode::Auditor
{
508 llvm::OwningPtr
<llvm::raw_ostream
> Out
;
509 llvm::sys::Path Dir
, Filename
;
512 typedef llvm::DenseMap
<void*,unsigned> VMap
;
516 UbigraphViz(llvm::raw_ostream
* out
, llvm::sys::Path
& dir
,
517 llvm::sys::Path
& filename
);
521 virtual void AddEdge(ExplodedNode
* Src
, ExplodedNode
* Dst
);
524 } // end anonymous namespace
526 static ExplodedNode::Auditor
* CreateUbiViz() {
529 llvm::sys::Path Dir
= llvm::sys::Path::GetTemporaryDirectory(&ErrMsg
);
533 llvm::sys::Path Filename
= Dir
;
534 Filename
.appendComponent("llvm_ubi");
535 Filename
.makeUnique(true,&ErrMsg
);
540 llvm::errs() << "Writing '" << Filename
.str() << "'.\n";
542 llvm::OwningPtr
<llvm::raw_fd_ostream
> Stream
;
543 Stream
.reset(new llvm::raw_fd_ostream(Filename
.c_str(), ErrMsg
));
548 return new UbigraphViz(Stream
.take(), Dir
, Filename
);
551 void UbigraphViz::AddEdge(ExplodedNode
* Src
, ExplodedNode
* Dst
) {
553 assert (Src
!= Dst
&& "Self-edges are not allowed.");
555 // Lookup the Src. If it is a new node, it's a root.
556 VMap::iterator SrcI
= M
.find(Src
);
559 if (SrcI
== M
.end()) {
560 M
[Src
] = SrcID
= Cntr
++;
561 *Out
<< "('vertex', " << SrcID
<< ", ('color','#00ff00'))\n";
564 SrcID
= SrcI
->second
;
567 VMap::iterator DstI
= M
.find(Dst
);
570 if (DstI
== M
.end()) {
571 M
[Dst
] = DstID
= Cntr
++;
572 *Out
<< "('vertex', " << DstID
<< ")\n";
575 // We have hit DstID before. Change its style to reflect a cache hit.
576 DstID
= DstI
->second
;
577 *Out
<< "('change_vertex_style', " << DstID
<< ", 1)\n";
581 *Out
<< "('edge', " << SrcID
<< ", " << DstID
582 << ", ('arrow','true'), ('oriented', 'true'))\n";
585 UbigraphViz::UbigraphViz(llvm::raw_ostream
* out
, llvm::sys::Path
& dir
,
586 llvm::sys::Path
& filename
)
587 : Out(out
), Dir(dir
), Filename(filename
), Cntr(0) {
589 *Out
<< "('vertex_style_attribute', 0, ('shape', 'icosahedron'))\n";
590 *Out
<< "('vertex_style', 1, 0, ('shape', 'sphere'), ('color', '#ffcc66'),"
591 " ('size', '1.5'))\n";
594 UbigraphViz::~UbigraphViz() {
596 llvm::errs() << "Running 'ubiviz' program... ";
598 llvm::sys::Path Ubiviz
= llvm::sys::Program::FindProgramByName("ubiviz");
599 std::vector
<const char*> args
;
600 args
.push_back(Ubiviz
.c_str());
601 args
.push_back(Filename
.c_str());
604 if (llvm::sys::Program::ExecuteAndWait(Ubiviz
, &args
[0],0,0,0,0,&ErrMsg
)) {
605 llvm::errs() << "Error viewing graph: " << ErrMsg
<< "\n";
608 // Delete the directory.
609 Dir
.eraseFromDisk(true);