blob: db5c7e0b5efa9e52d2500dac486a83a4ca46d105 [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"
Ted Kremenekc0959972008-07-02 21:24:01 +000028#include "clang/Analysis/PathSensitive/BugReporter.h"
Ted Kremenekf4381fd2008-07-02 00:03:09 +000029#include "clang/Analysis/Analyses/LiveVariables.h"
30#include "clang/Analysis/LocalCheckers.h"
31#include "clang/Analysis/PathSensitive/GRTransferFuncs.h"
32#include "clang/Analysis/PathSensitive/GRExprEngine.h"
Ted Kremenek34d77342008-07-02 16:49:11 +000033#include "llvm/Support/Streams.h"
Ted Kremenekf4381fd2008-07-02 00:03:09 +000034
35using namespace clang;
36
37
38//===----------------------------------------------------------------------===//
39// Basic type definitions.
40//===----------------------------------------------------------------------===//
41
42namespace {
43
44 class AnalysisManager;
45 typedef void (*CodeAction)(AnalysisManager& Mgr);
46
47} // end anonymous namespace
48
49//===----------------------------------------------------------------------===//
50// AnalysisConsumer declaration.
51//===----------------------------------------------------------------------===//
52
53namespace {
54
55 class VISIBILITY_HIDDEN AnalysisConsumer : public ASTConsumer {
56 typedef llvm::ImmutableList<CodeAction> Actions;
57 Actions FunctionActions;
58 Actions ObjCMethodActions;
59
60 Actions::Factory F;
61
62 public:
63 const bool Visualize;
64 const bool TrimGraph;
65 const LangOptions& LOpts;
66 Diagnostic &Diags;
67 ASTContext* Ctx;
68 Preprocessor* PP;
69 PreprocessorFactory* PPF;
70 const std::string HTMLDir;
71 const std::string FName;
72 llvm::OwningPtr<PathDiagnosticClient> PD;
73 bool AnalyzeAll;
74
75 AnalysisConsumer(Diagnostic &diags, Preprocessor* pp,
76 PreprocessorFactory* ppf,
77 const LangOptions& lopts,
78 const std::string& fname,
79 const std::string& htmldir,
80 bool visualize, bool trim, bool analyzeAll)
81 : FunctionActions(F.GetEmptyList()), ObjCMethodActions(F.GetEmptyList()),
82 Visualize(visualize), TrimGraph(trim), LOpts(lopts), Diags(diags),
83 Ctx(0), PP(pp), PPF(ppf),
84 HTMLDir(htmldir),
85 FName(fname),
86 AnalyzeAll(analyzeAll) {}
87
88 void addCodeAction(CodeAction action) {
89 FunctionActions = F.Concat(action, FunctionActions);
90 ObjCMethodActions = F.Concat(action, ObjCMethodActions);
91 }
92
93 virtual void Initialize(ASTContext &Context) {
94 Ctx = &Context;
95 }
96
97 virtual void HandleTopLevelDecl(Decl *D);
98 void HandleCode(Decl* D, Stmt* Body, Actions actions);
99 };
100
101
Ted Kremenekc0959972008-07-02 21:24:01 +0000102 class VISIBILITY_HIDDEN AnalysisManager : public BugReporterData {
Ted Kremenekf4381fd2008-07-02 00:03:09 +0000103 Decl* D;
104 Stmt* Body;
105 AnalysisConsumer& C;
Ted Kremenek34d77342008-07-02 16:49:11 +0000106 bool DisplayedFunction;
Ted Kremenekf4381fd2008-07-02 00:03:09 +0000107
108 llvm::OwningPtr<CFG> cfg;
109 llvm::OwningPtr<LiveVariables> liveness;
110 llvm::OwningPtr<ParentMap> PM;
Ted Kremenekb35a74a2008-07-02 00:44:58 +0000111 llvm::OwningPtr<PathDiagnosticClient> PD;
Ted Kremenekf4381fd2008-07-02 00:03:09 +0000112
113 public:
114 AnalysisManager(AnalysisConsumer& c, Decl* d, Stmt* b)
Ted Kremenek34d77342008-07-02 16:49:11 +0000115 : D(d), Body(b), C(c), DisplayedFunction(false) {}
Ted Kremenekf4381fd2008-07-02 00:03:09 +0000116
117
118 Decl* getCodeDecl() const { return D; }
119 Stmt* getBody() const { return Body; }
120
Ted Kremenekc0959972008-07-02 21:24:01 +0000121 virtual CFG& getCFG() {
Ted Kremenekf4381fd2008-07-02 00:03:09 +0000122 if (!cfg) cfg.reset(CFG::buildCFG(getBody()));
Ted Kremenekc0959972008-07-02 21:24:01 +0000123 return *cfg.get();
Ted Kremenekf4381fd2008-07-02 00:03:09 +0000124 }
125
Ted Kremenekc0959972008-07-02 21:24:01 +0000126 virtual ParentMap& getParentMap() {
Ted Kremenekf4381fd2008-07-02 00:03:09 +0000127 if (!PM) PM.reset(new ParentMap(getBody()));
Ted Kremenekc0959972008-07-02 21:24:01 +0000128 return *PM.get();
Ted Kremenekf4381fd2008-07-02 00:03:09 +0000129 }
130
Ted Kremenekc0959972008-07-02 21:24:01 +0000131 virtual ASTContext& getContext() {
Ted Kremenekf4381fd2008-07-02 00:03:09 +0000132 return *C.Ctx;
133 }
134
Ted Kremenekc0959972008-07-02 21:24:01 +0000135 virtual SourceManager& getSourceManager() {
Ted Kremenek235e0312008-07-02 18:11:29 +0000136 return getContext().getSourceManager();
137 }
138
Ted Kremenekc0959972008-07-02 21:24:01 +0000139 virtual Diagnostic& getDiagnostic() {
Ted Kremenekf4381fd2008-07-02 00:03:09 +0000140 return C.Diags;
141 }
Ted Kremenekb35a74a2008-07-02 00:44:58 +0000142
143 const LangOptions& getLangOptions() const {
144 return C.LOpts;
145 }
146
Ted Kremenekc0959972008-07-02 21:24:01 +0000147 virtual PathDiagnosticClient* getPathDiagnosticClient() {
Ted Kremenekb35a74a2008-07-02 00:44:58 +0000148 if (PD.get() == 0 && !C.HTMLDir.empty())
149 PD.reset(CreateHTMLDiagnosticClient(C.HTMLDir, C.PP, C.PPF));
150
151 return PD.get();
152 }
Ted Kremenekf4381fd2008-07-02 00:03:09 +0000153
Ted Kremenekc0959972008-07-02 21:24:01 +0000154 virtual LiveVariables& getLiveVariables() {
Ted Kremenek235e0312008-07-02 18:11:29 +0000155 if (!liveness) {
Ted Kremenekc0959972008-07-02 21:24:01 +0000156 liveness.reset(new LiveVariables(getCFG()));
157 liveness->runOnCFG(getCFG());
158 liveness->runOnAllBlocks(getCFG(), 0, true);
Ted Kremenek235e0312008-07-02 18:11:29 +0000159 }
Ted Kremenekc0959972008-07-02 21:24:01 +0000160
161 return *liveness.get();
Ted Kremenekf4381fd2008-07-02 00:03:09 +0000162 }
Ted Kremenek34d77342008-07-02 16:49:11 +0000163
164 bool shouldVisualize() const {
165 return C.Visualize;
166 }
167
168 bool shouldTrimGraph() const {
169 return C.TrimGraph;
170 }
171
172 void DisplayFunction() {
173
174 if (DisplayedFunction)
175 return;
176
177 DisplayedFunction = true;
178
179 if (FunctionDecl *FD = dyn_cast<FunctionDecl>(getCodeDecl())) {
180 llvm::cerr << "ANALYZE: "
181 << getContext().getSourceManager().getSourceName(FD->getLocation())
182 << ' '
183 << FD->getIdentifier()->getName()
184 << '\n';
185 }
186 else if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(getCodeDecl())) {
187 llvm::cerr << "ANALYZE (ObjC Method): "
188 << getContext().getSourceManager().getSourceName(MD->getLocation())
189 << " '"
190 << MD->getSelector().getName() << "'\n";
191 }
192 }
Ted Kremenekf4381fd2008-07-02 00:03:09 +0000193 };
194
195} // end anonymous namespace
196
197namespace llvm {
198 template <> struct FoldingSetTrait<CodeAction> {
199 static inline void Profile(CodeAction X, FoldingSetNodeID& ID) {
200 ID.AddPointer(reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(X)));
201 }
202 };
203}
204
205//===----------------------------------------------------------------------===//
206// AnalysisConsumer implementation.
207//===----------------------------------------------------------------------===//
208
209void AnalysisConsumer::HandleTopLevelDecl(Decl *D) {
210 switch (D->getKind()) {
211 case Decl::Function: {
212 FunctionDecl* FD = cast<FunctionDecl>(D);
Ted Kremenek235e0312008-07-02 18:11:29 +0000213
214 if (FName.size() > 0 && FName != FD->getIdentifier()->getName())
215 break;
216
Ted Kremenekf4381fd2008-07-02 00:03:09 +0000217 Stmt* Body = FD->getBody();
218 if (Body) HandleCode(FD, Body, FunctionActions);
219 break;
220 }
221
222 case Decl::ObjCMethod: {
223 ObjCMethodDecl* MD = cast<ObjCMethodDecl>(D);
Ted Kremenek235e0312008-07-02 18:11:29 +0000224
225 if (FName.size() > 0 && FName != MD->getSelector().getName())
226 return;
227
Ted Kremenekf4381fd2008-07-02 00:03:09 +0000228 Stmt* Body = MD->getBody();
229 if (Body) HandleCode(MD, Body, ObjCMethodActions);
230 break;
231 }
232
233 default:
234 break;
235 }
236}
237
238void AnalysisConsumer::HandleCode(Decl* D, Stmt* Body, Actions actions) {
239
240 // Don't run the actions if an error has occured with parsing the file.
241 if (Diags.hasErrorOccurred())
242 return;
243
244 SourceLocation Loc = D->getLocation();
245
246 // Only run actions on declarations defined in actual source.
247 if (!Loc.isFileID())
248 return;
249
250 // Don't run the actions on declarations in header files unless
251 // otherwise specified.
252 if (!AnalyzeAll && !Ctx->getSourceManager().isFromMainFile(Loc))
253 return;
254
255 // Create an AnalysisManager that will manage the state for analyzing
256 // this method/function.
257 AnalysisManager mgr(*this, D, Body);
258
259 // Dispatch on the actions.
Ted Kremenekc0959972008-07-02 21:24:01 +0000260 for (Actions::iterator I = actions.begin(),
Ted Kremenekf4381fd2008-07-02 00:03:09 +0000261 E = actions.end(); I != E; ++I)
262 ((*I).getHead())(mgr);
263}
264
265//===----------------------------------------------------------------------===//
266// Analyses
267//===----------------------------------------------------------------------===//
268
269static void ActionDeadStores(AnalysisManager& mgr) {
Ted Kremenekc0959972008-07-02 21:24:01 +0000270 CheckDeadStores(mgr.getCFG(), mgr.getContext(),
271 mgr.getLiveVariables(), mgr.getParentMap(),
Ted Kremenekf4381fd2008-07-02 00:03:09 +0000272 mgr.getDiagnostic());
273}
274
275static void ActionUninitVals(AnalysisManager& mgr) {
Ted Kremenekc0959972008-07-02 21:24:01 +0000276 CheckUninitializedValues(mgr.getCFG(), mgr.getContext(),
Ted Kremenekf4381fd2008-07-02 00:03:09 +0000277 mgr.getDiagnostic());
278}
279
Ted Kremenekb35a74a2008-07-02 00:44:58 +0000280
Ted Kremenekbc46f342008-07-02 16:35:50 +0000281static void ActionGRExprEngine(AnalysisManager& mgr, GRTransferFuncs* tf) {
Ted Kremenekb35a74a2008-07-02 00:44:58 +0000282
Ted Kremenekbc46f342008-07-02 16:35:50 +0000283 llvm::OwningPtr<GRTransferFuncs> TF(tf);
284
Ted Kremenek34d77342008-07-02 16:49:11 +0000285 // Display progress.
286 if (!mgr.shouldVisualize())
287 mgr.DisplayFunction();
288
Ted Kremenekbc46f342008-07-02 16:35:50 +0000289 // Construct the analysis engine.
Ted Kremenekc0959972008-07-02 21:24:01 +0000290 GRExprEngine Eng(mgr.getCFG(), *mgr.getCodeDecl(), mgr.getContext(),
291 mgr.getLiveVariables());
Ted Kremenekbc46f342008-07-02 16:35:50 +0000292 Eng.setTransferFunctions(tf);
293
Ted Kremenekb35a74a2008-07-02 00:44:58 +0000294 // Execute the worklist algorithm.
295 Eng.ExecuteWorkList();
Ted Kremenekbc46f342008-07-02 16:35:50 +0000296
Ted Kremenekb35a74a2008-07-02 00:44:58 +0000297 // Display warnings.
Ted Kremenekc0959972008-07-02 21:24:01 +0000298 Eng.EmitWarnings(mgr);
Ted Kremenek34d77342008-07-02 16:49:11 +0000299
300 // Visualize the exploded graph.
301 if (mgr.shouldVisualize())
302 Eng.ViewGraph(mgr.shouldTrimGraph());
Ted Kremenekbc46f342008-07-02 16:35:50 +0000303}
304
305static void ActionRefLeakCheckerAux(AnalysisManager& mgr, bool GCEnabled,
306 bool StandardWarnings) {
307
308 GRTransferFuncs* TF = MakeCFRefCountTF(mgr.getContext(),
309 GCEnabled,
310 StandardWarnings,
311 mgr.getLangOptions());
312
313 ActionGRExprEngine(mgr, TF);
Ted Kremenekb35a74a2008-07-02 00:44:58 +0000314}
315
316static void ActionRefLeakChecker(AnalysisManager& mgr) {
317
318 switch (mgr.getLangOptions().getGCMode()) {
319 default:
320 assert (false && "Invalid GC mode.");
321 case LangOptions::NonGC:
322 ActionRefLeakCheckerAux(mgr, false, true);
323 break;
324
325 case LangOptions::GCOnly:
326 ActionRefLeakCheckerAux(mgr, true, true);
327 break;
328
329 case LangOptions::HybridGC:
330 ActionRefLeakCheckerAux(mgr, false, true);
331 ActionRefLeakCheckerAux(mgr, true, false);
332 break;
333 }
334}
335
Ted Kremenekbc46f342008-07-02 16:35:50 +0000336static void ActionSimpleChecks(AnalysisManager& mgr) {
337 ActionGRExprEngine(mgr, MakeGRSimpleValsTF());
338}
339
Ted Kremenek235e0312008-07-02 18:11:29 +0000340static void ActionLiveness(AnalysisManager& mgr) {
341 mgr.DisplayFunction();
Ted Kremenekc0959972008-07-02 21:24:01 +0000342 mgr.getLiveVariables().dumpBlockLiveness(mgr.getSourceManager());
Ted Kremenek235e0312008-07-02 18:11:29 +0000343}
344
Ted Kremenek902141f2008-07-02 18:23:21 +0000345static void ActionCFGDump(AnalysisManager& mgr) {
346 mgr.DisplayFunction();
Ted Kremenekc0959972008-07-02 21:24:01 +0000347 mgr.getCFG().dump();
Ted Kremenek902141f2008-07-02 18:23:21 +0000348}
349
350static void ActionCFGView(AnalysisManager& mgr) {
351 mgr.DisplayFunction();
Ted Kremenekc0959972008-07-02 21:24:01 +0000352 mgr.getCFG().viewCFG();
Ted Kremenek902141f2008-07-02 18:23:21 +0000353}
354
Ted Kremenekf4381fd2008-07-02 00:03:09 +0000355//===----------------------------------------------------------------------===//
356// AnalysisConsumer creation.
357//===----------------------------------------------------------------------===//
358
359ASTConsumer* clang::CreateAnalysisConsumer(Analyses* Beg, Analyses* End,
360 Diagnostic &diags, Preprocessor* pp,
361 PreprocessorFactory* ppf,
362 const LangOptions& lopts,
363 const std::string& fname,
364 const std::string& htmldir,
365 bool visualize, bool trim,
366 bool analyzeAll) {
367
368 llvm::OwningPtr<AnalysisConsumer>
369 C(new AnalysisConsumer(diags, pp, ppf, lopts, fname, htmldir,
370 visualize, trim, analyzeAll));
371
372 for ( ; Beg != End ; ++Beg)
373 switch (*Beg) {
374 case WarnDeadStores:
375 C->addCodeAction(&ActionDeadStores);
376 break;
377
378 case WarnUninitVals:
379 C->addCodeAction(&ActionUninitVals);
380 break;
Ted Kremenek235e0312008-07-02 18:11:29 +0000381
382 case DisplayLiveVariables:
383 C->addCodeAction(&ActionLiveness);
384 break;
Ted Kremenekf4381fd2008-07-02 00:03:09 +0000385
Ted Kremenekb35a74a2008-07-02 00:44:58 +0000386 case CheckerCFRef:
387 C->addCodeAction(&ActionRefLeakChecker);
388 break;
389
Ted Kremenekbc46f342008-07-02 16:35:50 +0000390 case CheckerSimple:
391 C->addCodeAction(&ActionSimpleChecks);
392 break;
393
Ted Kremenek902141f2008-07-02 18:23:21 +0000394 case CFGDump:
395 C->addCodeAction(&ActionCFGDump);
396 break;
397
398 case CFGView:
399 C->addCodeAction(&ActionCFGView);
400 break;
401
Ted Kremenekf4381fd2008-07-02 00:03:09 +0000402 default: break;
403 }
404
405 return C.take();
406}
407