blob: ea2418610ec58ebaed670d8a262c357d5039e1dc [file] [log] [blame]
Ted Kremenekf4381fd2008-07-02 00:03:09 +00001//===--- 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.
11//
12//===----------------------------------------------------------------------===//
13
14#include "ASTConsumers.h"
Ted Kremenekb35a74a2008-07-02 00:44:58 +000015#include "HTMLDiagnostics.h"
Ted Kremenekf4381fd2008-07-02 00:03:09 +000016#include "clang/AST/ASTConsumer.h"
17#include "clang/AST/Decl.h"
18#include "clang/AST/DeclObjC.h"
19#include "llvm/Support/Compiler.h"
20#include "llvm/ADT/ImmutableList.h"
21#include "llvm/ADT/OwningPtr.h"
22#include "clang/AST/CFG.h"
23#include "clang/Analysis/Analyses/LiveVariables.h"
24#include "clang/Analysis/PathDiagnostic.h"
25#include "clang/Basic/SourceManager.h"
26#include "clang/Basic/FileManager.h"
27#include "clang/AST/ParentMap.h"
28#include "clang/Analysis/Analyses/LiveVariables.h"
29#include "clang/Analysis/LocalCheckers.h"
30#include "clang/Analysis/PathSensitive/GRTransferFuncs.h"
31#include "clang/Analysis/PathSensitive/GRExprEngine.h"
32
33using namespace clang;
34
35
36//===----------------------------------------------------------------------===//
37// Basic type definitions.
38//===----------------------------------------------------------------------===//
39
40namespace {
41
42 class AnalysisManager;
43 typedef void (*CodeAction)(AnalysisManager& Mgr);
44
45} // end anonymous namespace
46
47//===----------------------------------------------------------------------===//
48// AnalysisConsumer declaration.
49//===----------------------------------------------------------------------===//
50
51namespace {
52
53 class VISIBILITY_HIDDEN AnalysisConsumer : public ASTConsumer {
54 typedef llvm::ImmutableList<CodeAction> Actions;
55 Actions FunctionActions;
56 Actions ObjCMethodActions;
57
58 Actions::Factory F;
59
60 public:
61 const bool Visualize;
62 const bool TrimGraph;
63 const LangOptions& LOpts;
64 Diagnostic &Diags;
65 ASTContext* Ctx;
66 Preprocessor* PP;
67 PreprocessorFactory* PPF;
68 const std::string HTMLDir;
69 const std::string FName;
70 llvm::OwningPtr<PathDiagnosticClient> PD;
71 bool AnalyzeAll;
72
73 AnalysisConsumer(Diagnostic &diags, Preprocessor* pp,
74 PreprocessorFactory* ppf,
75 const LangOptions& lopts,
76 const std::string& fname,
77 const std::string& htmldir,
78 bool visualize, bool trim, bool analyzeAll)
79 : FunctionActions(F.GetEmptyList()), ObjCMethodActions(F.GetEmptyList()),
80 Visualize(visualize), TrimGraph(trim), LOpts(lopts), Diags(diags),
81 Ctx(0), PP(pp), PPF(ppf),
82 HTMLDir(htmldir),
83 FName(fname),
84 AnalyzeAll(analyzeAll) {}
85
86 void addCodeAction(CodeAction action) {
87 FunctionActions = F.Concat(action, FunctionActions);
88 ObjCMethodActions = F.Concat(action, ObjCMethodActions);
89 }
90
91 virtual void Initialize(ASTContext &Context) {
92 Ctx = &Context;
93 }
94
95 virtual void HandleTopLevelDecl(Decl *D);
96 void HandleCode(Decl* D, Stmt* Body, Actions actions);
97 };
98
99
100 class VISIBILITY_HIDDEN AnalysisManager {
101 Decl* D;
102 Stmt* Body;
103 AnalysisConsumer& C;
104
105 llvm::OwningPtr<CFG> cfg;
106 llvm::OwningPtr<LiveVariables> liveness;
107 llvm::OwningPtr<ParentMap> PM;
Ted Kremenekb35a74a2008-07-02 00:44:58 +0000108 llvm::OwningPtr<PathDiagnosticClient> PD;
Ted Kremenekf4381fd2008-07-02 00:03:09 +0000109
110 public:
111 AnalysisManager(AnalysisConsumer& c, Decl* d, Stmt* b)
112 : D(d), Body(b), C(c) {}
113
114
115 Decl* getCodeDecl() const { return D; }
116 Stmt* getBody() const { return Body; }
117
118 CFG* getCFG() {
119 if (!cfg) cfg.reset(CFG::buildCFG(getBody()));
120 return cfg.get();
121 }
122
123 ParentMap* getParentMap() {
124 if (!PM) PM.reset(new ParentMap(getBody()));
125 return PM.get();
126 }
127
128 ASTContext& getContext() {
129 return *C.Ctx;
130 }
131
132 Diagnostic& getDiagnostic() {
133 return C.Diags;
134 }
Ted Kremenekb35a74a2008-07-02 00:44:58 +0000135
136 const LangOptions& getLangOptions() const {
137 return C.LOpts;
138 }
139
140 PathDiagnosticClient* getPathDiagnosticClient() {
141 if (PD.get() == 0 && !C.HTMLDir.empty())
142 PD.reset(CreateHTMLDiagnosticClient(C.HTMLDir, C.PP, C.PPF));
143
144 return PD.get();
145 }
Ted Kremenekf4381fd2008-07-02 00:03:09 +0000146
147 LiveVariables* getLiveVariables() {
148 if (!liveness) liveness.reset(new LiveVariables(*getCFG()));
149 return liveness.get();
150 }
151 };
152
153} // end anonymous namespace
154
155namespace llvm {
156 template <> struct FoldingSetTrait<CodeAction> {
157 static inline void Profile(CodeAction X, FoldingSetNodeID& ID) {
158 ID.AddPointer(reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(X)));
159 }
160 };
161}
162
163//===----------------------------------------------------------------------===//
164// AnalysisConsumer implementation.
165//===----------------------------------------------------------------------===//
166
167void AnalysisConsumer::HandleTopLevelDecl(Decl *D) {
168 switch (D->getKind()) {
169 case Decl::Function: {
170 FunctionDecl* FD = cast<FunctionDecl>(D);
171 Stmt* Body = FD->getBody();
172 if (Body) HandleCode(FD, Body, FunctionActions);
173 break;
174 }
175
176 case Decl::ObjCMethod: {
177 ObjCMethodDecl* MD = cast<ObjCMethodDecl>(D);
178 Stmt* Body = MD->getBody();
179 if (Body) HandleCode(MD, Body, ObjCMethodActions);
180 break;
181 }
182
183 default:
184 break;
185 }
186}
187
188void AnalysisConsumer::HandleCode(Decl* D, Stmt* Body, Actions actions) {
189
190 // Don't run the actions if an error has occured with parsing the file.
191 if (Diags.hasErrorOccurred())
192 return;
193
194 SourceLocation Loc = D->getLocation();
195
196 // Only run actions on declarations defined in actual source.
197 if (!Loc.isFileID())
198 return;
199
200 // Don't run the actions on declarations in header files unless
201 // otherwise specified.
202 if (!AnalyzeAll && !Ctx->getSourceManager().isFromMainFile(Loc))
203 return;
204
205 // Create an AnalysisManager that will manage the state for analyzing
206 // this method/function.
207 AnalysisManager mgr(*this, D, Body);
208
209 // Dispatch on the actions.
210 for (Actions::iterator I = actions.begin(),
211 E = actions.end(); I != E; ++I)
212 ((*I).getHead())(mgr);
213}
214
215//===----------------------------------------------------------------------===//
216// Analyses
217//===----------------------------------------------------------------------===//
218
219static void ActionDeadStores(AnalysisManager& mgr) {
220 CheckDeadStores(*mgr.getCFG(), mgr.getContext(), *mgr.getParentMap(),
221 mgr.getDiagnostic());
222}
223
224static void ActionUninitVals(AnalysisManager& mgr) {
225 CheckUninitializedValues(*mgr.getCFG(), mgr.getContext(),
226 mgr.getDiagnostic());
227}
228
Ted Kremenekb35a74a2008-07-02 00:44:58 +0000229
Ted Kremenekbc46f342008-07-02 16:35:50 +0000230static void ActionGRExprEngine(AnalysisManager& mgr, GRTransferFuncs* tf) {
Ted Kremenekb35a74a2008-07-02 00:44:58 +0000231
Ted Kremenekbc46f342008-07-02 16:35:50 +0000232 llvm::OwningPtr<GRTransferFuncs> TF(tf);
233
234 // Construct the analysis engine.
235 GRExprEngine Eng(*mgr.getCFG(), *mgr.getCodeDecl(), mgr.getContext());
236 Eng.setTransferFunctions(tf);
237
Ted Kremenekb35a74a2008-07-02 00:44:58 +0000238 // Execute the worklist algorithm.
239 Eng.ExecuteWorkList();
Ted Kremenekbc46f342008-07-02 16:35:50 +0000240
Ted Kremenekb35a74a2008-07-02 00:44:58 +0000241 // Display warnings.
Ted Kremenekbc46f342008-07-02 16:35:50 +0000242 Eng.EmitWarnings(mgr.getDiagnostic(), mgr.getPathDiagnosticClient());
243}
244
245static void ActionRefLeakCheckerAux(AnalysisManager& mgr, bool GCEnabled,
246 bool StandardWarnings) {
247
248 GRTransferFuncs* TF = MakeCFRefCountTF(mgr.getContext(),
249 GCEnabled,
250 StandardWarnings,
251 mgr.getLangOptions());
252
253 ActionGRExprEngine(mgr, TF);
Ted Kremenekb35a74a2008-07-02 00:44:58 +0000254}
255
256static void ActionRefLeakChecker(AnalysisManager& mgr) {
257
258 switch (mgr.getLangOptions().getGCMode()) {
259 default:
260 assert (false && "Invalid GC mode.");
261 case LangOptions::NonGC:
262 ActionRefLeakCheckerAux(mgr, false, true);
263 break;
264
265 case LangOptions::GCOnly:
266 ActionRefLeakCheckerAux(mgr, true, true);
267 break;
268
269 case LangOptions::HybridGC:
270 ActionRefLeakCheckerAux(mgr, false, true);
271 ActionRefLeakCheckerAux(mgr, true, false);
272 break;
273 }
274}
275
Ted Kremenekbc46f342008-07-02 16:35:50 +0000276static void ActionSimpleChecks(AnalysisManager& mgr) {
277 ActionGRExprEngine(mgr, MakeGRSimpleValsTF());
278}
279
Ted Kremenekf4381fd2008-07-02 00:03:09 +0000280//===----------------------------------------------------------------------===//
281// AnalysisConsumer creation.
282//===----------------------------------------------------------------------===//
283
284ASTConsumer* clang::CreateAnalysisConsumer(Analyses* Beg, Analyses* End,
285 Diagnostic &diags, Preprocessor* pp,
286 PreprocessorFactory* ppf,
287 const LangOptions& lopts,
288 const std::string& fname,
289 const std::string& htmldir,
290 bool visualize, bool trim,
291 bool analyzeAll) {
292
293 llvm::OwningPtr<AnalysisConsumer>
294 C(new AnalysisConsumer(diags, pp, ppf, lopts, fname, htmldir,
295 visualize, trim, analyzeAll));
296
297 for ( ; Beg != End ; ++Beg)
298 switch (*Beg) {
299 case WarnDeadStores:
300 C->addCodeAction(&ActionDeadStores);
301 break;
302
303 case WarnUninitVals:
304 C->addCodeAction(&ActionUninitVals);
305 break;
306
Ted Kremenekb35a74a2008-07-02 00:44:58 +0000307 case CheckerCFRef:
308 C->addCodeAction(&ActionRefLeakChecker);
309 break;
310
Ted Kremenekbc46f342008-07-02 16:35:50 +0000311 case CheckerSimple:
312 C->addCodeAction(&ActionSimpleChecks);
313 break;
314
Ted Kremenekf4381fd2008-07-02 00:03:09 +0000315 default: break;
316 }
317
318 return C.take();
319}
320