blob: 44d96a00501b7638fa2d24f740514a055f1c609e [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"
Ted Kremenekf4381fd2008-07-02 00:03:09 +000020#include "llvm/ADT/OwningPtr.h"
21#include "clang/AST/CFG.h"
22#include "clang/Analysis/Analyses/LiveVariables.h"
23#include "clang/Analysis/PathDiagnostic.h"
24#include "clang/Basic/SourceManager.h"
25#include "clang/Basic/FileManager.h"
26#include "clang/AST/ParentMap.h"
Ted Kremenekdb09a4d2008-07-03 04:29:21 +000027#include "clang/AST/TranslationUnit.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
Ted Kremenekdb09a4d2008-07-03 04:29:21 +000035#include <vector>
36
Ted Kremenekf4381fd2008-07-02 00:03:09 +000037using namespace clang;
38
39
40//===----------------------------------------------------------------------===//
41// Basic type definitions.
42//===----------------------------------------------------------------------===//
43
44namespace {
45
46 class AnalysisManager;
47 typedef void (*CodeAction)(AnalysisManager& Mgr);
48
49} // end anonymous namespace
50
51//===----------------------------------------------------------------------===//
52// AnalysisConsumer declaration.
53//===----------------------------------------------------------------------===//
54
55namespace {
56
57 class VISIBILITY_HIDDEN AnalysisConsumer : public ASTConsumer {
Ted Kremenekdb09a4d2008-07-03 04:29:21 +000058 typedef std::vector<CodeAction> Actions;
Ted Kremenekf4381fd2008-07-02 00:03:09 +000059 Actions FunctionActions;
60 Actions ObjCMethodActions;
Ted Kremenekdb09a4d2008-07-03 04:29:21 +000061 Actions ObjCImplementationActions;
Ted Kremenekf4381fd2008-07-02 00:03:09 +000062
63 public:
64 const bool Visualize;
65 const bool TrimGraph;
66 const LangOptions& LOpts;
67 Diagnostic &Diags;
68 ASTContext* Ctx;
69 Preprocessor* PP;
70 PreprocessorFactory* PPF;
71 const std::string HTMLDir;
72 const std::string FName;
73 llvm::OwningPtr<PathDiagnosticClient> PD;
74 bool AnalyzeAll;
75
76 AnalysisConsumer(Diagnostic &diags, Preprocessor* pp,
77 PreprocessorFactory* ppf,
78 const LangOptions& lopts,
79 const std::string& fname,
80 const std::string& htmldir,
81 bool visualize, bool trim, bool analyzeAll)
Ted Kremenekdb09a4d2008-07-03 04:29:21 +000082 : Visualize(visualize), TrimGraph(trim), LOpts(lopts), Diags(diags),
Ted Kremenekf4381fd2008-07-02 00:03:09 +000083 Ctx(0), PP(pp), PPF(ppf),
84 HTMLDir(htmldir),
85 FName(fname),
86 AnalyzeAll(analyzeAll) {}
87
88 void addCodeAction(CodeAction action) {
Ted Kremenekdb09a4d2008-07-03 04:29:21 +000089 FunctionActions.push_back(action);
90 ObjCMethodActions.push_back(action);
91 }
92
93 void addObjCImplementationAction(CodeAction action) {
94 ObjCImplementationActions.push_back(action);
Ted Kremenekf4381fd2008-07-02 00:03:09 +000095 }
96
97 virtual void Initialize(ASTContext &Context) {
98 Ctx = &Context;
99 }
100
101 virtual void HandleTopLevelDecl(Decl *D);
Ted Kremenekdb09a4d2008-07-03 04:29:21 +0000102 virtual void HandleTranslationUnit(TranslationUnit &TU);
103
Ted Kremenekf4381fd2008-07-02 00:03:09 +0000104 void HandleCode(Decl* D, Stmt* Body, Actions actions);
105 };
106
107
Ted Kremenekc0959972008-07-02 21:24:01 +0000108 class VISIBILITY_HIDDEN AnalysisManager : public BugReporterData {
Ted Kremenekf4381fd2008-07-02 00:03:09 +0000109 Decl* D;
110 Stmt* Body;
111 AnalysisConsumer& C;
Ted Kremenek34d77342008-07-02 16:49:11 +0000112 bool DisplayedFunction;
Ted Kremenekf4381fd2008-07-02 00:03:09 +0000113
114 llvm::OwningPtr<CFG> cfg;
115 llvm::OwningPtr<LiveVariables> liveness;
116 llvm::OwningPtr<ParentMap> PM;
117
118 public:
119 AnalysisManager(AnalysisConsumer& c, Decl* d, Stmt* b)
Ted Kremenek34d77342008-07-02 16:49:11 +0000120 : D(d), Body(b), C(c), DisplayedFunction(false) {}
Ted Kremenekf4381fd2008-07-02 00:03:09 +0000121
122
123 Decl* getCodeDecl() const { return D; }
124 Stmt* getBody() const { return Body; }
125
Ted Kremenek7032f462008-07-03 05:26:14 +0000126 virtual CFG* getCFG() {
Ted Kremenekf4381fd2008-07-02 00:03:09 +0000127 if (!cfg) cfg.reset(CFG::buildCFG(getBody()));
Ted Kremenek7032f462008-07-03 05:26:14 +0000128 return cfg.get();
Ted Kremenekf4381fd2008-07-02 00:03:09 +0000129 }
130
Ted Kremenekc0959972008-07-02 21:24:01 +0000131 virtual ParentMap& getParentMap() {
Ted Kremeneke2075582008-07-02 23:16:33 +0000132 if (!PM)
133 PM.reset(new ParentMap(getBody()));
Ted Kremenekc0959972008-07-02 21:24:01 +0000134 return *PM.get();
Ted Kremenekf4381fd2008-07-02 00:03:09 +0000135 }
136
Ted Kremenekc0959972008-07-02 21:24:01 +0000137 virtual ASTContext& getContext() {
Ted Kremenekf4381fd2008-07-02 00:03:09 +0000138 return *C.Ctx;
139 }
140
Ted Kremenekc0959972008-07-02 21:24:01 +0000141 virtual SourceManager& getSourceManager() {
Ted Kremenek235e0312008-07-02 18:11:29 +0000142 return getContext().getSourceManager();
143 }
144
Ted Kremenekc0959972008-07-02 21:24:01 +0000145 virtual Diagnostic& getDiagnostic() {
Ted Kremenekf4381fd2008-07-02 00:03:09 +0000146 return C.Diags;
147 }
Ted Kremenekb35a74a2008-07-02 00:44:58 +0000148
149 const LangOptions& getLangOptions() const {
150 return C.LOpts;
151 }
152
Ted Kremenekc0959972008-07-02 21:24:01 +0000153 virtual PathDiagnosticClient* getPathDiagnosticClient() {
Ted Kremeneke2075582008-07-02 23:16:33 +0000154 if (C.PD.get() == 0 && !C.HTMLDir.empty())
155 C.PD.reset(CreateHTMLDiagnosticClient(C.HTMLDir, C.PP, C.PPF));
Ted Kremenekb35a74a2008-07-02 00:44:58 +0000156
Ted Kremeneke2075582008-07-02 23:16:33 +0000157 return C.PD.get();
Ted Kremenekb35a74a2008-07-02 00:44:58 +0000158 }
Ted Kremenekf4381fd2008-07-02 00:03:09 +0000159
Ted Kremenek7032f462008-07-03 05:26:14 +0000160 virtual LiveVariables* getLiveVariables() {
Ted Kremenek235e0312008-07-02 18:11:29 +0000161 if (!liveness) {
Ted Kremenek7032f462008-07-03 05:26:14 +0000162 CFG* c = getCFG();
163 if (!c) return 0;
164
165 liveness.reset(new LiveVariables(*c));
166 liveness->runOnCFG(*c);
167 liveness->runOnAllBlocks(*c, 0, true);
Ted Kremenek235e0312008-07-02 18:11:29 +0000168 }
Ted Kremenekc0959972008-07-02 21:24:01 +0000169
Ted Kremenek7032f462008-07-03 05:26:14 +0000170 return liveness.get();
Ted Kremenekf4381fd2008-07-02 00:03:09 +0000171 }
Ted Kremenek34d77342008-07-02 16:49:11 +0000172
173 bool shouldVisualize() const {
174 return C.Visualize;
175 }
176
177 bool shouldTrimGraph() const {
178 return C.TrimGraph;
179 }
180
181 void DisplayFunction() {
182
183 if (DisplayedFunction)
184 return;
185
186 DisplayedFunction = true;
187
188 if (FunctionDecl *FD = dyn_cast<FunctionDecl>(getCodeDecl())) {
189 llvm::cerr << "ANALYZE: "
190 << getContext().getSourceManager().getSourceName(FD->getLocation())
191 << ' '
192 << FD->getIdentifier()->getName()
193 << '\n';
194 }
195 else if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(getCodeDecl())) {
196 llvm::cerr << "ANALYZE (ObjC Method): "
197 << getContext().getSourceManager().getSourceName(MD->getLocation())
198 << " '"
199 << MD->getSelector().getName() << "'\n";
200 }
201 }
Ted Kremenekf4381fd2008-07-02 00:03:09 +0000202 };
203
204} // end anonymous namespace
205
206namespace llvm {
207 template <> struct FoldingSetTrait<CodeAction> {
208 static inline void Profile(CodeAction X, FoldingSetNodeID& ID) {
209 ID.AddPointer(reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(X)));
210 }
211 };
212}
213
214//===----------------------------------------------------------------------===//
215// AnalysisConsumer implementation.
216//===----------------------------------------------------------------------===//
217
218void AnalysisConsumer::HandleTopLevelDecl(Decl *D) {
219 switch (D->getKind()) {
220 case Decl::Function: {
221 FunctionDecl* FD = cast<FunctionDecl>(D);
Ted Kremenek235e0312008-07-02 18:11:29 +0000222
223 if (FName.size() > 0 && FName != FD->getIdentifier()->getName())
224 break;
225
Ted Kremenekf4381fd2008-07-02 00:03:09 +0000226 Stmt* Body = FD->getBody();
227 if (Body) HandleCode(FD, Body, FunctionActions);
228 break;
229 }
230
231 case Decl::ObjCMethod: {
232 ObjCMethodDecl* MD = cast<ObjCMethodDecl>(D);
Ted Kremenek235e0312008-07-02 18:11:29 +0000233
234 if (FName.size() > 0 && FName != MD->getSelector().getName())
235 return;
236
Ted Kremenekf4381fd2008-07-02 00:03:09 +0000237 Stmt* Body = MD->getBody();
238 if (Body) HandleCode(MD, Body, ObjCMethodActions);
239 break;
240 }
241
242 default:
243 break;
244 }
245}
246
Ted Kremenekdb09a4d2008-07-03 04:29:21 +0000247void AnalysisConsumer::HandleTranslationUnit(TranslationUnit& TU) {
248
249 if (ObjCImplementationActions.empty())
250 return;
251
252 for (TranslationUnit::iterator I = TU.begin(), E = TU.end(); I!=E; ++I) {
253
254 if (ObjCImplementationDecl* ID = dyn_cast<ObjCImplementationDecl>(*I))
255 HandleCode(ID, 0, ObjCImplementationActions);
256 }
257}
258
Ted Kremenekf4381fd2008-07-02 00:03:09 +0000259void AnalysisConsumer::HandleCode(Decl* D, Stmt* Body, Actions actions) {
260
261 // Don't run the actions if an error has occured with parsing the file.
262 if (Diags.hasErrorOccurred())
263 return;
264
265 SourceLocation Loc = D->getLocation();
266
267 // Only run actions on declarations defined in actual source.
268 if (!Loc.isFileID())
269 return;
270
271 // Don't run the actions on declarations in header files unless
272 // otherwise specified.
273 if (!AnalyzeAll && !Ctx->getSourceManager().isFromMainFile(Loc))
274 return;
275
276 // Create an AnalysisManager that will manage the state for analyzing
277 // this method/function.
278 AnalysisManager mgr(*this, D, Body);
279
280 // Dispatch on the actions.
Ted Kremenekc0959972008-07-02 21:24:01 +0000281 for (Actions::iterator I = actions.begin(),
Ted Kremenekf4381fd2008-07-02 00:03:09 +0000282 E = actions.end(); I != E; ++I)
Ted Kremenekdb09a4d2008-07-03 04:29:21 +0000283 (*I)(mgr);
Ted Kremenekf4381fd2008-07-02 00:03:09 +0000284}
285
286//===----------------------------------------------------------------------===//
287// Analyses
288//===----------------------------------------------------------------------===//
289
290static void ActionDeadStores(AnalysisManager& mgr) {
Ted Kremenek7032f462008-07-03 05:26:14 +0000291 if (LiveVariables* L = mgr.getLiveVariables()) {
292 BugReporter BR(mgr);
293 CheckDeadStores(*L, BR);
294 }
Ted Kremenekf4381fd2008-07-02 00:03:09 +0000295}
296
297static void ActionUninitVals(AnalysisManager& mgr) {
Ted Kremenek7032f462008-07-03 05:26:14 +0000298 if (CFG* c = mgr.getCFG())
299 CheckUninitializedValues(*c, mgr.getContext(), mgr.getDiagnostic());
Ted Kremenekf4381fd2008-07-02 00:03:09 +0000300}
301
Ted Kremenekb35a74a2008-07-02 00:44:58 +0000302
Ted Kremenekbc46f342008-07-02 16:35:50 +0000303static void ActionGRExprEngine(AnalysisManager& mgr, GRTransferFuncs* tf) {
Ted Kremenekb35a74a2008-07-02 00:44:58 +0000304
Ted Kremenek7032f462008-07-03 05:26:14 +0000305
Ted Kremenekbc46f342008-07-02 16:35:50 +0000306 llvm::OwningPtr<GRTransferFuncs> TF(tf);
Ted Kremenek7032f462008-07-03 05:26:14 +0000307
308 // Construct the analysis engine.
309 LiveVariables* L = mgr.getLiveVariables();
310 if (!L) return;
Ted Kremenekbc46f342008-07-02 16:35:50 +0000311
Ted Kremenek34d77342008-07-02 16:49:11 +0000312 // Display progress.
313 if (!mgr.shouldVisualize())
314 mgr.DisplayFunction();
315
Ted Kremenek7032f462008-07-03 05:26:14 +0000316 GRExprEngine Eng(*mgr.getCFG(), *mgr.getCodeDecl(), mgr.getContext(), *L);
Ted Kremenekbc46f342008-07-02 16:35:50 +0000317 Eng.setTransferFunctions(tf);
318
Ted Kremenekb35a74a2008-07-02 00:44:58 +0000319 // Execute the worklist algorithm.
320 Eng.ExecuteWorkList();
Ted Kremenekbc46f342008-07-02 16:35:50 +0000321
Ted Kremenekb35a74a2008-07-02 00:44:58 +0000322 // Display warnings.
Ted Kremenekc0959972008-07-02 21:24:01 +0000323 Eng.EmitWarnings(mgr);
Ted Kremenek34d77342008-07-02 16:49:11 +0000324
325 // Visualize the exploded graph.
326 if (mgr.shouldVisualize())
327 Eng.ViewGraph(mgr.shouldTrimGraph());
Ted Kremenekbc46f342008-07-02 16:35:50 +0000328}
329
330static void ActionRefLeakCheckerAux(AnalysisManager& mgr, bool GCEnabled,
331 bool StandardWarnings) {
332
333 GRTransferFuncs* TF = MakeCFRefCountTF(mgr.getContext(),
334 GCEnabled,
335 StandardWarnings,
336 mgr.getLangOptions());
337
338 ActionGRExprEngine(mgr, TF);
Ted Kremenekb35a74a2008-07-02 00:44:58 +0000339}
340
341static void ActionRefLeakChecker(AnalysisManager& mgr) {
342
343 switch (mgr.getLangOptions().getGCMode()) {
344 default:
345 assert (false && "Invalid GC mode.");
346 case LangOptions::NonGC:
347 ActionRefLeakCheckerAux(mgr, false, true);
348 break;
349
350 case LangOptions::GCOnly:
351 ActionRefLeakCheckerAux(mgr, true, true);
352 break;
353
354 case LangOptions::HybridGC:
355 ActionRefLeakCheckerAux(mgr, false, true);
356 ActionRefLeakCheckerAux(mgr, true, false);
357 break;
358 }
359}
360
Ted Kremenekbc46f342008-07-02 16:35:50 +0000361static void ActionSimpleChecks(AnalysisManager& mgr) {
362 ActionGRExprEngine(mgr, MakeGRSimpleValsTF());
363}
364
Ted Kremenek235e0312008-07-02 18:11:29 +0000365static void ActionLiveness(AnalysisManager& mgr) {
Ted Kremenek7032f462008-07-03 05:26:14 +0000366 if (LiveVariables* L = mgr.getLiveVariables()) {
367 mgr.DisplayFunction();
368 L->dumpBlockLiveness(mgr.getSourceManager());
369 }
Ted Kremenek235e0312008-07-02 18:11:29 +0000370}
371
Ted Kremenek902141f2008-07-02 18:23:21 +0000372static void ActionCFGDump(AnalysisManager& mgr) {
Ted Kremenek7032f462008-07-03 05:26:14 +0000373 if (CFG* c = mgr.getCFG()) {
374 mgr.DisplayFunction();
375 c->dump();
376 }
Ted Kremenek902141f2008-07-02 18:23:21 +0000377}
378
379static void ActionCFGView(AnalysisManager& mgr) {
Ted Kremenek7032f462008-07-03 05:26:14 +0000380 if (CFG* c = mgr.getCFG()) {
381 mgr.DisplayFunction();
382 c->viewCFG();
383 }
Ted Kremenek902141f2008-07-02 18:23:21 +0000384}
385
Ted Kremenekdb09a4d2008-07-03 04:29:21 +0000386static void ActionCheckObjCDealloc(AnalysisManager& mgr) {
387 BugReporter BR(mgr);
Ted Kremenek3cd483c2008-07-03 14:35:01 +0000388
389 CheckObjCDealloc(cast<ObjCImplementationDecl>(mgr.getCodeDecl()),
390 mgr.getLangOptions(), BR);
Ted Kremenekdb09a4d2008-07-03 04:29:21 +0000391}
392
Ted Kremenekf4381fd2008-07-02 00:03:09 +0000393//===----------------------------------------------------------------------===//
394// AnalysisConsumer creation.
395//===----------------------------------------------------------------------===//
396
397ASTConsumer* clang::CreateAnalysisConsumer(Analyses* Beg, Analyses* End,
398 Diagnostic &diags, Preprocessor* pp,
399 PreprocessorFactory* ppf,
400 const LangOptions& lopts,
401 const std::string& fname,
402 const std::string& htmldir,
403 bool visualize, bool trim,
404 bool analyzeAll) {
405
406 llvm::OwningPtr<AnalysisConsumer>
407 C(new AnalysisConsumer(diags, pp, ppf, lopts, fname, htmldir,
408 visualize, trim, analyzeAll));
409
410 for ( ; Beg != End ; ++Beg)
411 switch (*Beg) {
412 case WarnDeadStores:
413 C->addCodeAction(&ActionDeadStores);
414 break;
415
416 case WarnUninitVals:
417 C->addCodeAction(&ActionUninitVals);
418 break;
Ted Kremenek235e0312008-07-02 18:11:29 +0000419
420 case DisplayLiveVariables:
421 C->addCodeAction(&ActionLiveness);
422 break;
Ted Kremenekf4381fd2008-07-02 00:03:09 +0000423
Ted Kremenekb35a74a2008-07-02 00:44:58 +0000424 case CheckerCFRef:
425 C->addCodeAction(&ActionRefLeakChecker);
426 break;
427
Ted Kremenekbc46f342008-07-02 16:35:50 +0000428 case CheckerSimple:
429 C->addCodeAction(&ActionSimpleChecks);
430 break;
431
Ted Kremenek902141f2008-07-02 18:23:21 +0000432 case CFGDump:
433 C->addCodeAction(&ActionCFGDump);
434 break;
435
436 case CFGView:
437 C->addCodeAction(&ActionCFGView);
438 break;
439
Ted Kremenekf4381fd2008-07-02 00:03:09 +0000440 default: break;
441 }
442
Ted Kremenekdb09a4d2008-07-03 04:29:21 +0000443 // Checks we always perform:
Ted Kremenek3cd483c2008-07-03 14:35:01 +0000444 if (lopts.getGCMode() != LangOptions::GCOnly)
445 C->addObjCImplementationAction(&ActionCheckObjCDealloc);
Ted Kremenekdb09a4d2008-07-03 04:29:21 +0000446
Ted Kremenekf4381fd2008-07-02 00:03:09 +0000447 return C.take();
448}
449