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 "clang/GR/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/GR/Checkers/LocalCheckers.h"
24 #include "clang/GR/ManagerRegistry.h"
25 #include "clang/GR/BugReporter/PathDiagnostic.h"
26 #include "clang/GR/PathSensitive/AnalysisManager.h"
27 #include "clang/GR/BugReporter/BugReporter.h"
28 #include "clang/GR/PathSensitive/ExprEngine.h"
29 #include "clang/GR/PathSensitive/TransferFuncs.h"
30 #include "clang/GR/PathDiagnosticClients.h"
32 // FIXME: Restructure checker registration.
33 #include "Checkers/ExprEngineExperimentalChecks.h"
34 #include "Checkers/ExprEngineInternalChecks.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
));
200 virtual void HandleTranslationUnit(ASTContext
&C
);
201 void HandleCode(Decl
*D
, Actions
& actions
);
203 } // end anonymous namespace
205 //===----------------------------------------------------------------------===//
206 // AnalysisConsumer implementation.
207 //===----------------------------------------------------------------------===//
209 void AnalysisConsumer::HandleTranslationUnit(ASTContext
&C
) {
211 TranslationUnitDecl
*TU
= C
.getTranslationUnitDecl();
213 for (DeclContext::decl_iterator I
= TU
->decls_begin(), E
= TU
->decls_end();
217 switch (D
->getKind()) {
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
);
259 for (TUActions::iterator I
= TranslationUnitActions
.begin(),
260 E
= TranslationUnitActions
.end(); I
!= E
; ++I
) {
261 (*I
)(*this, *Mgr
, *TU
);
264 // Explicitly destroy the PathDiagnosticClient. This will flush its output.
265 // FIXME: This should be replaced with something that doesn't rely on
266 // side-effects in PathDiagnosticClient's destructor. This is required when
267 // used with option -disable-free.
271 static void FindBlocks(DeclContext
*D
, llvm::SmallVectorImpl
<Decl
*> &WL
) {
272 if (BlockDecl
*BD
= dyn_cast
<BlockDecl
>(D
))
275 for (DeclContext::decl_iterator I
= D
->decls_begin(), E
= D
->decls_end();
277 if (DeclContext
*DC
= dyn_cast
<DeclContext
>(*I
))
281 void AnalysisConsumer::HandleCode(Decl
*D
, Actions
& actions
) {
283 // Don't run the actions if an error has occured with parsing the file.
284 Diagnostic
&Diags
= PP
.getDiagnostics();
285 if (Diags
.hasErrorOccurred() || Diags
.hasFatalErrorOccurred())
288 // Don't run the actions on declarations in header files unless
289 // otherwise specified.
290 SourceManager
&SM
= Ctx
->getSourceManager();
291 SourceLocation SL
= SM
.getInstantiationLoc(D
->getLocation());
292 if (!Opts
.AnalyzeAll
&& !SM
.isFromMainFile(SL
))
295 // Clear the AnalysisManager of old AnalysisContexts.
296 Mgr
->ClearContexts();
298 // Dispatch on the actions.
299 llvm::SmallVector
<Decl
*, 10> WL
;
302 if (D
->hasBody() && Opts
.AnalyzeNestedBlocks
)
303 FindBlocks(cast
<DeclContext
>(D
), WL
);
305 for (Actions::iterator I
= actions
.begin(), E
= actions
.end(); I
!= E
; ++I
)
306 for (llvm::SmallVectorImpl
<Decl
*>::iterator WI
=WL
.begin(), WE
=WL
.end();
308 (*I
)(*this, *Mgr
, *WI
);
311 //===----------------------------------------------------------------------===//
313 //===----------------------------------------------------------------------===//
315 static void ActionWarnDeadStores(AnalysisConsumer
&C
, AnalysisManager
& mgr
,
317 if (LiveVariables
*L
= mgr
.getLiveVariables(D
)) {
319 CheckDeadStores(*mgr
.getCFG(D
), *L
, mgr
.getParentMap(D
), BR
);
323 static void ActionWarnUninitVals(AnalysisConsumer
&C
, AnalysisManager
& mgr
,
325 if (CFG
* c
= mgr
.getCFG(D
)) {
326 CheckUninitializedValues(*c
, mgr
.getASTContext(), mgr
.getDiagnostic());
331 static void ActionExprEngine(AnalysisConsumer
&C
, AnalysisManager
& mgr
,
335 llvm::OwningPtr
<TransferFuncs
> TF(tf
);
337 // Construct the analysis engine. We first query for the LiveVariables
338 // information to see if the CFG is valid.
339 // FIXME: Inter-procedural analysis will need to handle invalid CFGs.
340 if (!mgr
.getLiveVariables(D
))
342 ExprEngine
Eng(mgr
, TF
.take());
344 if (C
.Opts
.EnableExperimentalInternalChecks
)
345 RegisterExperimentalInternalChecks(Eng
);
347 RegisterAppleChecks(Eng
, *D
);
349 if (C
.Opts
.EnableExperimentalChecks
)
350 RegisterExperimentalChecks(Eng
);
352 // Enable idempotent operation checking if it was explicitly turned on, or if
353 // we are running experimental checks (i.e. everything)
354 if (C
.Opts
.IdempotentOps
|| C
.Opts
.EnableExperimentalChecks
355 || C
.Opts
.EnableExperimentalInternalChecks
)
356 RegisterIdempotentOperationChecker(Eng
);
358 // Enable AnalyzerStatsChecker if it was given as an argument
359 if (C
.Opts
.AnalyzerStats
)
360 RegisterAnalyzerStatsChecker(Eng
);
362 // Set the graph auditor.
363 llvm::OwningPtr
<ExplodedNode::Auditor
> Auditor
;
364 if (mgr
.shouldVisualizeUbigraph()) {
365 Auditor
.reset(CreateUbiViz());
366 ExplodedNode::SetAuditor(Auditor
.get());
369 // Execute the worklist algorithm.
370 Eng
.ExecuteWorkList(mgr
.getStackFrame(D
, 0), mgr
.getMaxNodes());
372 // Release the auditor (if any) so that it doesn't monitor the graph
373 // created BugReporter.
374 ExplodedNode::SetAuditor(0);
376 // Visualize the exploded graph.
377 if (mgr
.shouldVisualizeGraphviz())
378 Eng
.ViewGraph(mgr
.shouldTrimGraph());
381 Eng
.getBugReporter().FlushReports();
384 static void ActionObjCMemCheckerAux(AnalysisConsumer
&C
, AnalysisManager
& mgr
,
385 Decl
*D
, bool GCEnabled
) {
387 TransferFuncs
* TF
= MakeCFRefCountTF(mgr
.getASTContext(),
389 mgr
.getLangOptions());
391 ActionExprEngine(C
, mgr
, D
, TF
);
394 static void ActionObjCMemChecker(AnalysisConsumer
&C
, AnalysisManager
& mgr
,
397 switch (mgr
.getLangOptions().getGCMode()) {
399 assert (false && "Invalid GC mode.");
400 case LangOptions::NonGC
:
401 ActionObjCMemCheckerAux(C
, mgr
, D
, false);
404 case LangOptions::GCOnly
:
405 ActionObjCMemCheckerAux(C
, mgr
, D
, true);
408 case LangOptions::HybridGC
:
409 ActionObjCMemCheckerAux(C
, mgr
, D
, false);
410 ActionObjCMemCheckerAux(C
, mgr
, D
, true);
415 static void ActionDisplayLiveVariables(AnalysisConsumer
&C
,
416 AnalysisManager
& mgr
, Decl
*D
) {
417 if (LiveVariables
* L
= mgr
.getLiveVariables(D
)) {
418 L
->dumpBlockLiveness(mgr
.getSourceManager());
422 static void ActionCFGDump(AnalysisConsumer
&C
, AnalysisManager
& mgr
, Decl
*D
) {
423 if (CFG
*cfg
= mgr
.getCFG(D
)) {
424 cfg
->dump(mgr
.getLangOptions());
428 static void ActionCFGView(AnalysisConsumer
&C
, AnalysisManager
& mgr
, Decl
*D
) {
429 if (CFG
*cfg
= mgr
.getCFG(D
)) {
430 cfg
->viewCFG(mgr
.getLangOptions());
434 static void ActionSecuritySyntacticChecks(AnalysisConsumer
&C
,
435 AnalysisManager
&mgr
, Decl
*D
) {
437 CheckSecuritySyntaxOnly(D
, BR
);
440 static void ActionLLVMConventionChecker(AnalysisConsumer
&C
,
441 AnalysisManager
&mgr
,
442 TranslationUnitDecl
&TU
) {
444 CheckLLVMConventions(TU
, BR
);
447 static void ActionWarnObjCDealloc(AnalysisConsumer
&C
, AnalysisManager
& mgr
,
449 if (mgr
.getLangOptions().getGCMode() == LangOptions::GCOnly
)
452 CheckObjCDealloc(cast
<ObjCImplementationDecl
>(D
), mgr
.getLangOptions(), BR
);
455 static void ActionWarnObjCUnusedIvars(AnalysisConsumer
&C
, AnalysisManager
& mgr
,
458 CheckObjCUnusedIvar(cast
<ObjCImplementationDecl
>(D
), BR
);
461 static void ActionWarnObjCMethSigs(AnalysisConsumer
&C
, AnalysisManager
& mgr
,
464 CheckObjCInstMethSignature(cast
<ObjCImplementationDecl
>(D
), BR
);
467 static void ActionWarnSizeofPointer(AnalysisConsumer
&C
, AnalysisManager
&mgr
,
470 CheckSizeofPointer(D
, BR
);
473 //===----------------------------------------------------------------------===//
474 // AnalysisConsumer creation.
475 //===----------------------------------------------------------------------===//
477 ASTConsumer
* GR::CreateAnalysisConsumer(const Preprocessor
& pp
,
478 const std::string
& OutDir
,
479 const AnalyzerOptions
& Opts
) {
480 llvm::OwningPtr
<AnalysisConsumer
> C(new AnalysisConsumer(pp
, OutDir
, Opts
));
482 for (unsigned i
= 0; i
< Opts
.AnalysisList
.size(); ++i
)
483 switch (Opts
.AnalysisList
[i
]) {
484 #define ANALYSIS(NAME, CMD, DESC, SCOPE)\
486 C->add ## SCOPE ## Action(&Action ## NAME);\
488 #include "clang/Frontend/Analyses.def"
492 // Last, disable the effects of '-Werror' when using the AnalysisConsumer.
493 pp
.getDiagnostics().setWarningsAsErrors(false);
498 //===----------------------------------------------------------------------===//
499 // Ubigraph Visualization. FIXME: Move to separate file.
500 //===----------------------------------------------------------------------===//
504 class UbigraphViz
: public ExplodedNode::Auditor
{
505 llvm::OwningPtr
<llvm::raw_ostream
> Out
;
506 llvm::sys::Path Dir
, Filename
;
509 typedef llvm::DenseMap
<void*,unsigned> VMap
;
513 UbigraphViz(llvm::raw_ostream
* out
, llvm::sys::Path
& dir
,
514 llvm::sys::Path
& filename
);
518 virtual void AddEdge(ExplodedNode
* Src
, ExplodedNode
* Dst
);
521 } // end anonymous namespace
523 static ExplodedNode::Auditor
* CreateUbiViz() {
526 llvm::sys::Path Dir
= llvm::sys::Path::GetTemporaryDirectory(&ErrMsg
);
530 llvm::sys::Path Filename
= Dir
;
531 Filename
.appendComponent("llvm_ubi");
532 Filename
.makeUnique(true,&ErrMsg
);
537 llvm::errs() << "Writing '" << Filename
.str() << "'.\n";
539 llvm::OwningPtr
<llvm::raw_fd_ostream
> Stream
;
540 Stream
.reset(new llvm::raw_fd_ostream(Filename
.c_str(), ErrMsg
));
545 return new UbigraphViz(Stream
.take(), Dir
, Filename
);
548 void UbigraphViz::AddEdge(ExplodedNode
* Src
, ExplodedNode
* Dst
) {
550 assert (Src
!= Dst
&& "Self-edges are not allowed.");
552 // Lookup the Src. If it is a new node, it's a root.
553 VMap::iterator SrcI
= M
.find(Src
);
556 if (SrcI
== M
.end()) {
557 M
[Src
] = SrcID
= Cntr
++;
558 *Out
<< "('vertex', " << SrcID
<< ", ('color','#00ff00'))\n";
561 SrcID
= SrcI
->second
;
564 VMap::iterator DstI
= M
.find(Dst
);
567 if (DstI
== M
.end()) {
568 M
[Dst
] = DstID
= Cntr
++;
569 *Out
<< "('vertex', " << DstID
<< ")\n";
572 // We have hit DstID before. Change its style to reflect a cache hit.
573 DstID
= DstI
->second
;
574 *Out
<< "('change_vertex_style', " << DstID
<< ", 1)\n";
578 *Out
<< "('edge', " << SrcID
<< ", " << DstID
579 << ", ('arrow','true'), ('oriented', 'true'))\n";
582 UbigraphViz::UbigraphViz(llvm::raw_ostream
* out
, llvm::sys::Path
& dir
,
583 llvm::sys::Path
& filename
)
584 : Out(out
), Dir(dir
), Filename(filename
), Cntr(0) {
586 *Out
<< "('vertex_style_attribute', 0, ('shape', 'icosahedron'))\n";
587 *Out
<< "('vertex_style', 1, 0, ('shape', 'sphere'), ('color', '#ffcc66'),"
588 " ('size', '1.5'))\n";
591 UbigraphViz::~UbigraphViz() {
593 llvm::errs() << "Running 'ubiviz' program... ";
595 llvm::sys::Path Ubiviz
= llvm::sys::Program::FindProgramByName("ubiviz");
596 std::vector
<const char*> args
;
597 args
.push_back(Ubiviz
.c_str());
598 args
.push_back(Filename
.c_str());
601 if (llvm::sys::Program::ExecuteAndWait(Ubiviz
, &args
[0],0,0,0,0,&ErrMsg
)) {
602 llvm::errs() << "Error viewing graph: " << ErrMsg
<< "\n";
605 // Delete the directory.
606 Dir
.eraseFromDisk(true);