blob: 65a3dae507d4fe3210db4110d496b7d9faf1bdff [file] [log] [blame]
Ted Kremenek81ea7992008-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 Kremenek1c6cd212008-07-02 00:44:58 +000015#include "HTMLDiagnostics.h"
Ted Kremenek81ea7992008-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"
Ted Kremeneked80d002008-07-02 16:49:11 +000032#include "llvm/Support/Streams.h"
Ted Kremenek81ea7992008-07-02 00:03:09 +000033
34using namespace clang;
35
36
37//===----------------------------------------------------------------------===//
38// Basic type definitions.
39//===----------------------------------------------------------------------===//
40
41namespace {
42
43 class AnalysisManager;
44 typedef void (*CodeAction)(AnalysisManager& Mgr);
45
46} // end anonymous namespace
47
48//===----------------------------------------------------------------------===//
49// AnalysisConsumer declaration.
50//===----------------------------------------------------------------------===//
51
52namespace {
53
54 class VISIBILITY_HIDDEN AnalysisConsumer : public ASTConsumer {
55 typedef llvm::ImmutableList<CodeAction> Actions;
56 Actions FunctionActions;
57 Actions ObjCMethodActions;
58
59 Actions::Factory F;
60
61 public:
62 const bool Visualize;
63 const bool TrimGraph;
64 const LangOptions& LOpts;
65 Diagnostic &Diags;
66 ASTContext* Ctx;
67 Preprocessor* PP;
68 PreprocessorFactory* PPF;
69 const std::string HTMLDir;
70 const std::string FName;
71 llvm::OwningPtr<PathDiagnosticClient> PD;
72 bool AnalyzeAll;
73
74 AnalysisConsumer(Diagnostic &diags, Preprocessor* pp,
75 PreprocessorFactory* ppf,
76 const LangOptions& lopts,
77 const std::string& fname,
78 const std::string& htmldir,
79 bool visualize, bool trim, bool analyzeAll)
80 : FunctionActions(F.GetEmptyList()), ObjCMethodActions(F.GetEmptyList()),
81 Visualize(visualize), TrimGraph(trim), LOpts(lopts), Diags(diags),
82 Ctx(0), PP(pp), PPF(ppf),
83 HTMLDir(htmldir),
84 FName(fname),
85 AnalyzeAll(analyzeAll) {}
86
87 void addCodeAction(CodeAction action) {
88 FunctionActions = F.Concat(action, FunctionActions);
89 ObjCMethodActions = F.Concat(action, ObjCMethodActions);
90 }
91
92 virtual void Initialize(ASTContext &Context) {
93 Ctx = &Context;
94 }
95
96 virtual void HandleTopLevelDecl(Decl *D);
97 void HandleCode(Decl* D, Stmt* Body, Actions actions);
98 };
99
100
101 class VISIBILITY_HIDDEN AnalysisManager {
102 Decl* D;
103 Stmt* Body;
104 AnalysisConsumer& C;
Ted Kremeneked80d002008-07-02 16:49:11 +0000105 bool DisplayedFunction;
Ted Kremenek81ea7992008-07-02 00:03:09 +0000106
107 llvm::OwningPtr<CFG> cfg;
108 llvm::OwningPtr<LiveVariables> liveness;
109 llvm::OwningPtr<ParentMap> PM;
Ted Kremenek1c6cd212008-07-02 00:44:58 +0000110 llvm::OwningPtr<PathDiagnosticClient> PD;
Ted Kremenek81ea7992008-07-02 00:03:09 +0000111
112 public:
113 AnalysisManager(AnalysisConsumer& c, Decl* d, Stmt* b)
Ted Kremeneked80d002008-07-02 16:49:11 +0000114 : D(d), Body(b), C(c), DisplayedFunction(false) {}
Ted Kremenek81ea7992008-07-02 00:03:09 +0000115
116
117 Decl* getCodeDecl() const { return D; }
118 Stmt* getBody() const { return Body; }
119
120 CFG* getCFG() {
121 if (!cfg) cfg.reset(CFG::buildCFG(getBody()));
122 return cfg.get();
123 }
124
125 ParentMap* getParentMap() {
126 if (!PM) PM.reset(new ParentMap(getBody()));
127 return PM.get();
128 }
129
130 ASTContext& getContext() {
131 return *C.Ctx;
132 }
133
Ted Kremenekd899b0f2008-07-02 18:11:29 +0000134 SourceManager& getSourceManager() {
135 return getContext().getSourceManager();
136 }
137
Ted Kremenek81ea7992008-07-02 00:03:09 +0000138 Diagnostic& getDiagnostic() {
139 return C.Diags;
140 }
Ted Kremenek1c6cd212008-07-02 00:44:58 +0000141
142 const LangOptions& getLangOptions() const {
143 return C.LOpts;
144 }
145
146 PathDiagnosticClient* getPathDiagnosticClient() {
147 if (PD.get() == 0 && !C.HTMLDir.empty())
148 PD.reset(CreateHTMLDiagnosticClient(C.HTMLDir, C.PP, C.PPF));
149
150 return PD.get();
151 }
Ted Kremenek81ea7992008-07-02 00:03:09 +0000152
153 LiveVariables* getLiveVariables() {
Ted Kremenekd899b0f2008-07-02 18:11:29 +0000154 if (!liveness) {
155 liveness.reset(new LiveVariables(*getCFG()));
156 liveness->runOnCFG(*getCFG());
Ted Kremenek1607f512008-07-02 20:13:38 +0000157 liveness->runOnAllBlocks(*getCFG(), 0, true);
Ted Kremenekd899b0f2008-07-02 18:11:29 +0000158 }
Ted Kremenek81ea7992008-07-02 00:03:09 +0000159 return liveness.get();
160 }
Ted Kremeneked80d002008-07-02 16:49:11 +0000161
162 bool shouldVisualize() const {
163 return C.Visualize;
164 }
165
166 bool shouldTrimGraph() const {
167 return C.TrimGraph;
168 }
169
170 void DisplayFunction() {
171
172 if (DisplayedFunction)
173 return;
174
175 DisplayedFunction = true;
176
177 if (FunctionDecl *FD = dyn_cast<FunctionDecl>(getCodeDecl())) {
178 llvm::cerr << "ANALYZE: "
179 << getContext().getSourceManager().getSourceName(FD->getLocation())
180 << ' '
181 << FD->getIdentifier()->getName()
182 << '\n';
183 }
184 else if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(getCodeDecl())) {
185 llvm::cerr << "ANALYZE (ObjC Method): "
186 << getContext().getSourceManager().getSourceName(MD->getLocation())
187 << " '"
188 << MD->getSelector().getName() << "'\n";
189 }
190 }
Ted Kremenek81ea7992008-07-02 00:03:09 +0000191 };
192
193} // end anonymous namespace
194
195namespace llvm {
196 template <> struct FoldingSetTrait<CodeAction> {
197 static inline void Profile(CodeAction X, FoldingSetNodeID& ID) {
198 ID.AddPointer(reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(X)));
199 }
200 };
201}
202
203//===----------------------------------------------------------------------===//
204// AnalysisConsumer implementation.
205//===----------------------------------------------------------------------===//
206
207void AnalysisConsumer::HandleTopLevelDecl(Decl *D) {
208 switch (D->getKind()) {
209 case Decl::Function: {
210 FunctionDecl* FD = cast<FunctionDecl>(D);
Ted Kremenekd899b0f2008-07-02 18:11:29 +0000211
212 if (FName.size() > 0 && FName != FD->getIdentifier()->getName())
213 break;
214
Ted Kremenek81ea7992008-07-02 00:03:09 +0000215 Stmt* Body = FD->getBody();
216 if (Body) HandleCode(FD, Body, FunctionActions);
217 break;
218 }
219
220 case Decl::ObjCMethod: {
221 ObjCMethodDecl* MD = cast<ObjCMethodDecl>(D);
Ted Kremenekd899b0f2008-07-02 18:11:29 +0000222
223 if (FName.size() > 0 && FName != MD->getSelector().getName())
224 return;
225
Ted Kremenek81ea7992008-07-02 00:03:09 +0000226 Stmt* Body = MD->getBody();
227 if (Body) HandleCode(MD, Body, ObjCMethodActions);
228 break;
229 }
230
231 default:
232 break;
233 }
234}
235
236void AnalysisConsumer::HandleCode(Decl* D, Stmt* Body, Actions actions) {
237
238 // Don't run the actions if an error has occured with parsing the file.
239 if (Diags.hasErrorOccurred())
240 return;
241
242 SourceLocation Loc = D->getLocation();
243
244 // Only run actions on declarations defined in actual source.
245 if (!Loc.isFileID())
246 return;
247
248 // Don't run the actions on declarations in header files unless
249 // otherwise specified.
250 if (!AnalyzeAll && !Ctx->getSourceManager().isFromMainFile(Loc))
251 return;
252
253 // Create an AnalysisManager that will manage the state for analyzing
254 // this method/function.
255 AnalysisManager mgr(*this, D, Body);
256
257 // Dispatch on the actions.
258 for (Actions::iterator I = actions.begin(),
259 E = actions.end(); I != E; ++I)
260 ((*I).getHead())(mgr);
261}
262
263//===----------------------------------------------------------------------===//
264// Analyses
265//===----------------------------------------------------------------------===//
266
267static void ActionDeadStores(AnalysisManager& mgr) {
Ted Kremenek3349aa12008-07-02 18:39:20 +0000268 CheckDeadStores(*mgr.getCFG(), mgr.getContext(),
269 *mgr.getLiveVariables(), *mgr.getParentMap(),
Ted Kremenek81ea7992008-07-02 00:03:09 +0000270 mgr.getDiagnostic());
271}
272
273static void ActionUninitVals(AnalysisManager& mgr) {
274 CheckUninitializedValues(*mgr.getCFG(), mgr.getContext(),
275 mgr.getDiagnostic());
276}
277
Ted Kremenek1c6cd212008-07-02 00:44:58 +0000278
Ted Kremenekc8a5fd42008-07-02 16:35:50 +0000279static void ActionGRExprEngine(AnalysisManager& mgr, GRTransferFuncs* tf) {
Ted Kremenek1c6cd212008-07-02 00:44:58 +0000280
Ted Kremenekc8a5fd42008-07-02 16:35:50 +0000281 llvm::OwningPtr<GRTransferFuncs> TF(tf);
282
Ted Kremeneked80d002008-07-02 16:49:11 +0000283 // Display progress.
284 if (!mgr.shouldVisualize())
285 mgr.DisplayFunction();
286
Ted Kremenekc8a5fd42008-07-02 16:35:50 +0000287 // Construct the analysis engine.
Ted Kremenek1607f512008-07-02 20:13:38 +0000288 GRExprEngine Eng(*mgr.getCFG(), *mgr.getCodeDecl(), mgr.getContext(),
289 *mgr.getLiveVariables());
Ted Kremenekc8a5fd42008-07-02 16:35:50 +0000290 Eng.setTransferFunctions(tf);
291
Ted Kremenek1c6cd212008-07-02 00:44:58 +0000292 // Execute the worklist algorithm.
293 Eng.ExecuteWorkList();
Ted Kremenekc8a5fd42008-07-02 16:35:50 +0000294
Ted Kremenek1c6cd212008-07-02 00:44:58 +0000295 // Display warnings.
Ted Kremeneked80d002008-07-02 16:49:11 +0000296 Eng.EmitWarnings(mgr.getDiagnostic(), mgr.getPathDiagnosticClient());
297
298 // Visualize the exploded graph.
299 if (mgr.shouldVisualize())
300 Eng.ViewGraph(mgr.shouldTrimGraph());
Ted Kremenekc8a5fd42008-07-02 16:35:50 +0000301}
302
303static void ActionRefLeakCheckerAux(AnalysisManager& mgr, bool GCEnabled,
304 bool StandardWarnings) {
305
306 GRTransferFuncs* TF = MakeCFRefCountTF(mgr.getContext(),
307 GCEnabled,
308 StandardWarnings,
309 mgr.getLangOptions());
310
311 ActionGRExprEngine(mgr, TF);
Ted Kremenek1c6cd212008-07-02 00:44:58 +0000312}
313
314static void ActionRefLeakChecker(AnalysisManager& mgr) {
315
316 switch (mgr.getLangOptions().getGCMode()) {
317 default:
318 assert (false && "Invalid GC mode.");
319 case LangOptions::NonGC:
320 ActionRefLeakCheckerAux(mgr, false, true);
321 break;
322
323 case LangOptions::GCOnly:
324 ActionRefLeakCheckerAux(mgr, true, true);
325 break;
326
327 case LangOptions::HybridGC:
328 ActionRefLeakCheckerAux(mgr, false, true);
329 ActionRefLeakCheckerAux(mgr, true, false);
330 break;
331 }
332}
333
Ted Kremenekc8a5fd42008-07-02 16:35:50 +0000334static void ActionSimpleChecks(AnalysisManager& mgr) {
335 ActionGRExprEngine(mgr, MakeGRSimpleValsTF());
336}
337
Ted Kremenekd899b0f2008-07-02 18:11:29 +0000338static void ActionLiveness(AnalysisManager& mgr) {
339 mgr.DisplayFunction();
340 mgr.getLiveVariables()->dumpBlockLiveness(mgr.getSourceManager());
341}
342
Ted Kremeneke972d852008-07-02 18:23:21 +0000343static void ActionCFGDump(AnalysisManager& mgr) {
344 mgr.DisplayFunction();
345 mgr.getCFG()->dump();
346}
347
348static void ActionCFGView(AnalysisManager& mgr) {
349 mgr.DisplayFunction();
350 mgr.getCFG()->viewCFG();
351}
352
Ted Kremenek81ea7992008-07-02 00:03:09 +0000353//===----------------------------------------------------------------------===//
354// AnalysisConsumer creation.
355//===----------------------------------------------------------------------===//
356
357ASTConsumer* clang::CreateAnalysisConsumer(Analyses* Beg, Analyses* End,
358 Diagnostic &diags, Preprocessor* pp,
359 PreprocessorFactory* ppf,
360 const LangOptions& lopts,
361 const std::string& fname,
362 const std::string& htmldir,
363 bool visualize, bool trim,
364 bool analyzeAll) {
365
366 llvm::OwningPtr<AnalysisConsumer>
367 C(new AnalysisConsumer(diags, pp, ppf, lopts, fname, htmldir,
368 visualize, trim, analyzeAll));
369
370 for ( ; Beg != End ; ++Beg)
371 switch (*Beg) {
372 case WarnDeadStores:
373 C->addCodeAction(&ActionDeadStores);
374 break;
375
376 case WarnUninitVals:
377 C->addCodeAction(&ActionUninitVals);
378 break;
Ted Kremenekd899b0f2008-07-02 18:11:29 +0000379
380 case DisplayLiveVariables:
381 C->addCodeAction(&ActionLiveness);
382 break;
Ted Kremenek81ea7992008-07-02 00:03:09 +0000383
Ted Kremenek1c6cd212008-07-02 00:44:58 +0000384 case CheckerCFRef:
385 C->addCodeAction(&ActionRefLeakChecker);
386 break;
387
Ted Kremenekc8a5fd42008-07-02 16:35:50 +0000388 case CheckerSimple:
389 C->addCodeAction(&ActionSimpleChecks);
390 break;
391
Ted Kremeneke972d852008-07-02 18:23:21 +0000392 case CFGDump:
393 C->addCodeAction(&ActionCFGDump);
394 break;
395
396 case CFGView:
397 C->addCodeAction(&ActionCFGView);
398 break;
399
Ted Kremenek81ea7992008-07-02 00:03:09 +0000400 default: break;
401 }
402
403 return C.take();
404}
405