blob: a52cd4511aa3c6044e654b4acbac22a20d5f5881 [file] [log] [blame]
Chris Lattnereb8c9632007-10-07 06:04:32 +00001//===--- ASTConsumers.cpp - ASTConsumer implementations -------------------===//
Chris Lattner4b009652007-07-25 00:24:17 +00002//
3// The LLVM Compiler Infrastructure
4//
Chris Lattnereb8c9632007-10-07 06:04:32 +00005// This file was developed by Chris Lattner and is distributed under the
Chris Lattner4b009652007-07-25 00:24:17 +00006// University of Illinois Open Source License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
Chris Lattnereb8c9632007-10-07 06:04:32 +000010// AST Consumer Implementations.
Chris Lattner4b009652007-07-25 00:24:17 +000011//
12//===----------------------------------------------------------------------===//
13
Chris Lattnereb8c9632007-10-07 06:04:32 +000014#include "ASTConsumers.h"
Chris Lattner4b009652007-07-25 00:24:17 +000015#include "clang/AST/AST.h"
Chris Lattnerb73abd52007-09-15 23:02:28 +000016#include "clang/AST/ASTConsumer.h"
Ted Kremenek97f75312007-08-21 21:42:03 +000017#include "clang/AST/CFG.h"
Ted Kremenekaa04c512007-09-06 00:17:54 +000018#include "clang/Analysis/LiveVariables.h"
Ted Kremeneke805c4a2007-09-06 23:00:42 +000019#include "clang/Analysis/LocalCheckers.h"
Chris Lattner95578782007-08-08 22:51:59 +000020using namespace clang;
Chris Lattner4b009652007-07-25 00:24:17 +000021
Chris Lattner95578782007-08-08 22:51:59 +000022
23static void PrintFunctionDeclStart(FunctionDecl *FD) {
Chris Lattner4b009652007-07-25 00:24:17 +000024 bool HasBody = FD->getBody();
25
Chris Lattner987058a2007-08-26 04:02:13 +000026 fprintf(stderr, "\n");
27
28 switch (FD->getStorageClass()) {
29 default: assert(0 && "Unknown storage class");
30 case FunctionDecl::None: break;
31 case FunctionDecl::Extern: fprintf(stderr, "extern "); break;
32 case FunctionDecl::Static: fprintf(stderr, "static "); break;
33 }
34
35 if (FD->isInline())
36 fprintf(stderr, "inline ");
37
Chris Lattner4b009652007-07-25 00:24:17 +000038 std::string Proto = FD->getName();
39 FunctionType *AFT = cast<FunctionType>(FD->getType());
40
41 if (FunctionTypeProto *FT = dyn_cast<FunctionTypeProto>(AFT)) {
42 Proto += "(";
43 for (unsigned i = 0, e = FD->getNumParams(); i != e; ++i) {
44 if (i) Proto += ", ";
45 std::string ParamStr;
46 if (HasBody) ParamStr = FD->getParamDecl(i)->getName();
47
48 FT->getArgType(i).getAsStringInternal(ParamStr);
49 Proto += ParamStr;
50 }
51
52 if (FT->isVariadic()) {
53 if (FD->getNumParams()) Proto += ", ";
54 Proto += "...";
55 }
56 Proto += ")";
57 } else {
58 assert(isa<FunctionTypeNoProto>(AFT));
59 Proto += "()";
60 }
61
62 AFT->getResultType().getAsStringInternal(Proto);
Chris Lattner987058a2007-08-26 04:02:13 +000063 fprintf(stderr, "%s", Proto.c_str());
Chris Lattner4b009652007-07-25 00:24:17 +000064
Chris Lattner95578782007-08-08 22:51:59 +000065 if (!FD->getBody())
Chris Lattner4b009652007-07-25 00:24:17 +000066 fprintf(stderr, ";\n");
Chris Lattner95578782007-08-08 22:51:59 +000067 // Doesn't print the body.
Chris Lattner4b009652007-07-25 00:24:17 +000068}
69
Chris Lattner95578782007-08-08 22:51:59 +000070static void PrintTypeDefDecl(TypedefDecl *TD) {
Chris Lattner4b009652007-07-25 00:24:17 +000071 std::string S = TD->getName();
72 TD->getUnderlyingType().getAsStringInternal(S);
73 fprintf(stderr, "typedef %s;\n", S.c_str());
74}
75
Steve Narofffaed3bf2007-09-10 20:51:04 +000076static void PrintObjcInterfaceDecl(ObjcInterfaceDecl *OID) {
77 std::string S = OID->getName();
78 fprintf(stderr, "@interface %s;\n", S.c_str());
79 // FIXME: implement the rest...
80}
81
Fariborz Jahanianac20be22007-10-08 18:53:38 +000082static void PrintObjcProtocolDecl(ObjcProtocolDecl *PID) {
83 std::string S = PID->getName();
84 fprintf(stderr, "@protocol %s;\n", S.c_str());
85 // FIXME: implement the rest...
86}
87
88static void PrintObjcCategoryImplDecl(ObjcCategoryImplDecl *PID) {
89 std::string S = PID->getName();
90 std::string I = PID->getClassInterface()->getName();
91 fprintf(stderr, "@implementation %s(%s);\n", I.c_str(), S.c_str());
92 // FIXME: implement the rest...
93}
94
95static void PrintObjcCategoryDecl(ObjcCategoryDecl *PID) {
96 std::string S = PID->getName();
97 std::string I = PID->getClassInterface()->getName();
98 fprintf(stderr, "@interface %s(%s);\n", I.c_str(), S.c_str());
99 // FIXME: implement the rest...
100}
101
Chris Lattnerb73abd52007-09-15 23:02:28 +0000102namespace {
103 class ASTPrinter : public ASTConsumer {
104 virtual void HandleTopLevelDecl(Decl *D) {
105 if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
106 PrintFunctionDeclStart(FD);
107
108 if (FD->getBody()) {
109 fprintf(stderr, " ");
110 FD->getBody()->dumpPretty();
111 fprintf(stderr, "\n");
112 }
113 } else if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) {
114 PrintTypeDefDecl(TD);
Chris Lattnerd5c9d3d2007-10-06 18:52:10 +0000115 } else if (ObjcInterfaceDecl *OID = dyn_cast<ObjcInterfaceDecl>(D)) {
116 PrintObjcInterfaceDecl(OID);
Fariborz Jahanianac20be22007-10-08 18:53:38 +0000117 } else if (ObjcProtocolDecl *PID = dyn_cast<ObjcProtocolDecl>(D)) {
118 PrintObjcProtocolDecl(PID);
Chris Lattnerd5c9d3d2007-10-06 18:52:10 +0000119 } else if (ObjcForwardProtocolDecl *OFPD =
120 dyn_cast<ObjcForwardProtocolDecl>(D)) {
121 fprintf(stderr, "@protocol ");
122 for (unsigned i = 0, e = OFPD->getNumForwardDecls(); i != e; ++i) {
123 const ObjcProtocolDecl *D = OFPD->getForwardProtocolDecl(i);
124 if (i) fprintf(stderr, ", ");
125 fprintf(stderr, "%s", D->getName());
126 }
Chris Lattnera845bbe2007-10-06 19:08:22 +0000127 fprintf(stderr, ";\n");
Chris Lattnerd5c9d3d2007-10-06 18:52:10 +0000128 } else if (ObjcImplementationDecl *OID =
129 dyn_cast<ObjcImplementationDecl>(D)) {
130 fprintf(stderr, "@implementation %s [printing todo]\n",
131 OID->getName());
Fariborz Jahanianac20be22007-10-08 18:53:38 +0000132 } else if (ObjcCategoryImplDecl *OID =
133 dyn_cast<ObjcCategoryImplDecl>(D)) {
134 PrintObjcCategoryImplDecl(OID);
135 } else if (ObjcCategoryDecl *OID =
136 dyn_cast<ObjcCategoryDecl>(D)) {
137 PrintObjcCategoryDecl(OID);
Chris Lattnerd5c9d3d2007-10-06 18:52:10 +0000138 } else if (isa<ObjcClassDecl>(D)) {
139 fprintf(stderr, "@class [printing todo]\n");
Fariborz Jahanianac20be22007-10-08 18:53:38 +0000140 } else if (ScopedDecl *SD = dyn_cast<ScopedDecl>(D)) {
141 fprintf(stderr, "Read top-level variable decl: '%s'\n", SD->getName());
Chris Lattnerd5c9d3d2007-10-06 18:52:10 +0000142 } else {
143 assert(0 && "Unknown decl type!");
Chris Lattner95578782007-08-08 22:51:59 +0000144 }
Chris Lattner4b009652007-07-25 00:24:17 +0000145 }
Chris Lattnerb73abd52007-09-15 23:02:28 +0000146 };
Chris Lattner4b009652007-07-25 00:24:17 +0000147}
Chris Lattner95578782007-08-08 22:51:59 +0000148
Chris Lattnerb73abd52007-09-15 23:02:28 +0000149ASTConsumer *clang::CreateASTPrinter() { return new ASTPrinter(); }
150
151namespace {
152 class ASTDumper : public ASTConsumer {
153 SourceManager *SM;
154 public:
155 void Initialize(ASTContext &Context, unsigned MainFileID) {
156 SM = &Context.SourceMgr;
Chris Lattner95578782007-08-08 22:51:59 +0000157 }
Chris Lattnerb73abd52007-09-15 23:02:28 +0000158
159 virtual void HandleTopLevelDecl(Decl *D) {
160 if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
161 PrintFunctionDeclStart(FD);
162
163 if (FD->getBody()) {
164 fprintf(stderr, "\n");
165 FD->getBody()->dumpAll(*SM);
166 fprintf(stderr, "\n");
167 }
168 } else if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) {
169 PrintTypeDefDecl(TD);
170 } else if (ScopedDecl *SD = dyn_cast<ScopedDecl>(D)) {
171 fprintf(stderr, "Read top-level variable decl: '%s'\n", SD->getName());
Chris Lattnerd5c9d3d2007-10-06 18:52:10 +0000172 } else if (ObjcInterfaceDecl *OID = dyn_cast<ObjcInterfaceDecl>(D)) {
173 fprintf(stderr, "Read objc interface '%s'\n", OID->getName());
174 } else if (isa<ObjcForwardProtocolDecl>(D)) {
175 fprintf(stderr, "Read objc fwd protocol decl\n");
176 } else {
177 assert(0 && "Unknown decl type!");
Chris Lattnerb73abd52007-09-15 23:02:28 +0000178 }
179 }
180 };
Chris Lattner95578782007-08-08 22:51:59 +0000181}
182
Chris Lattnerb73abd52007-09-15 23:02:28 +0000183ASTConsumer *clang::CreateASTDumper() { return new ASTDumper(); }
184
Ted Kremenekb6976a22007-09-19 21:29:43 +0000185namespace {
186 class ASTViewer : public ASTConsumer {
187 SourceManager *SM;
188 public:
189 void Initialize(ASTContext &Context, unsigned MainFileID) {
190 SM = &Context.SourceMgr;
191 }
192
193 virtual void HandleTopLevelDecl(Decl *D) {
194 if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
195 PrintFunctionDeclStart(FD);
196
197 if (FD->getBody()) {
198 fprintf(stderr, "\n");
199 FD->getBody()->viewAST();
200 fprintf(stderr, "\n");
201 }
202 }
203 }
204 };
205}
206
207ASTConsumer *clang::CreateASTViewer() { return new ASTViewer(); }
208
209
Ted Kremenek1e3c2022007-09-07 23:47:56 +0000210//===----------------------------------------------------------------------===//
211// CFGVisitor & VisitCFGs - Boilerplate interface and logic to visit
212// the CFGs for all function definitions.
213
214namespace {
215
Chris Lattner52332d02007-09-15 23:21:08 +0000216class CFGVisitor : public ASTConsumer {
Ted Kremenek1e3c2022007-09-07 23:47:56 +0000217public:
Chris Lattner52332d02007-09-15 23:21:08 +0000218 // CFG Visitor interface to be implemented by subclass.
Ted Kremenek1e3c2022007-09-07 23:47:56 +0000219 virtual void VisitCFG(CFG& C) = 0;
220 virtual bool printFuncDeclStart() { return true; }
Chris Lattner52332d02007-09-15 23:21:08 +0000221
222 virtual void HandleTopLevelDecl(Decl *D);
Ted Kremenek1e3c2022007-09-07 23:47:56 +0000223};
224
225} // end anonymous namespace
226
Chris Lattner52332d02007-09-15 23:21:08 +0000227void CFGVisitor::HandleTopLevelDecl(Decl *D) {
228 FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
229 if (!FD || !FD->getBody())
230 return;
231
232 if (printFuncDeclStart()) {
233 PrintFunctionDeclStart(FD);
234 fprintf(stderr,"\n");
Ted Kremenek1e3c2022007-09-07 23:47:56 +0000235 }
Chris Lattner52332d02007-09-15 23:21:08 +0000236
Ted Kremenek3e88d752007-09-17 17:10:02 +0000237 CFG *C = CFG::buildCFG(FD->getBody());
238 VisitCFG(*C);
239 delete C;
Ted Kremenek1e3c2022007-09-07 23:47:56 +0000240}
241
242//===----------------------------------------------------------------------===//
243// DumpCFGs - Dump CFGs to stderr or visualize with Graphviz
244
245namespace {
246 class CFGDumper : public CFGVisitor {
247 const bool UseGraphviz;
248 public:
249 CFGDumper(bool use_graphviz) : UseGraphviz(use_graphviz) {}
250
Chris Lattner52332d02007-09-15 23:21:08 +0000251 virtual void VisitCFG(CFG &C) {
252 if (UseGraphviz)
253 C.viewCFG();
254 else
255 C.dump();
256 }
Ted Kremenek1e3c2022007-09-07 23:47:56 +0000257 };
258} // end anonymous namespace
259
Chris Lattner52332d02007-09-15 23:21:08 +0000260ASTConsumer *clang::CreateCFGDumper(bool ViewGraphs) {
261 return new CFGDumper(ViewGraphs);
Ted Kremenek97f75312007-08-21 21:42:03 +0000262}
263
Ted Kremenek1e3c2022007-09-07 23:47:56 +0000264//===----------------------------------------------------------------------===//
265// AnalyzeLiveVariables - perform live variable analysis and dump results
266
267namespace {
268 class LivenessVisitor : public CFGVisitor {
Chris Lattner52332d02007-09-15 23:21:08 +0000269 SourceManager *SM;
Ted Kremenek1e3c2022007-09-07 23:47:56 +0000270 public:
Chris Lattner52332d02007-09-15 23:21:08 +0000271 virtual void Initialize(ASTContext &Context, unsigned MainFileID) {
272 SM = &Context.SourceMgr;
273 }
274
Ted Kremenek1e3c2022007-09-07 23:47:56 +0000275 virtual void VisitCFG(CFG& C) {
Ted Kremenek8ce772b2007-10-01 20:33:52 +0000276 LiveVariables L(C);
Ted Kremenek1e3c2022007-09-07 23:47:56 +0000277 L.runOnCFG(C);
Ted Kremenekd7a2f812007-09-25 04:31:27 +0000278 L.dumpBlockLiveness(*SM);
Ted Kremenekaa04c512007-09-06 00:17:54 +0000279 }
Ted Kremenek1e3c2022007-09-07 23:47:56 +0000280 };
281} // end anonymous namespace
282
Chris Lattner52332d02007-09-15 23:21:08 +0000283ASTConsumer *clang::CreateLiveVarAnalyzer() {
284 return new LivenessVisitor();
Ted Kremenekaa04c512007-09-06 00:17:54 +0000285}
286
Ted Kremenek1e3c2022007-09-07 23:47:56 +0000287//===----------------------------------------------------------------------===//
Ted Kremenek0a03ce62007-09-17 20:49:30 +0000288// DeadStores - run checker to locate dead stores in a function
Ted Kremenek1e3c2022007-09-07 23:47:56 +0000289
290namespace {
291 class DeadStoreVisitor : public CFGVisitor {
Chris Lattner52332d02007-09-15 23:21:08 +0000292 Diagnostic &Diags;
293 ASTContext *Ctx;
Ted Kremenek1e3c2022007-09-07 23:47:56 +0000294 public:
Chris Lattner52332d02007-09-15 23:21:08 +0000295 DeadStoreVisitor(Diagnostic &diags) : Diags(diags) {}
296 virtual void Initialize(ASTContext &Context, unsigned MainFileID) {
297 Ctx = &Context;
298 }
299
300 virtual void VisitCFG(CFG& C) { CheckDeadStores(C, *Ctx, Diags); }
Ted Kremenek39b8c4b2007-09-07 23:54:15 +0000301 virtual bool printFuncDeclStart() { return false; }
Ted Kremenek1e3c2022007-09-07 23:47:56 +0000302 };
303} // end anonymous namespace
304
Chris Lattner52332d02007-09-15 23:21:08 +0000305ASTConsumer *clang::CreateDeadStoreChecker(Diagnostic &Diags) {
306 return new DeadStoreVisitor(Diags);
Ted Kremeneke805c4a2007-09-06 23:00:42 +0000307}
Chris Lattner129758d2007-09-16 19:46:59 +0000308
309//===----------------------------------------------------------------------===//
Ted Kremenek0a03ce62007-09-17 20:49:30 +0000310// Unitialized Values - run checker to flag potential uses of uninitalized
311// variables.
312
313namespace {
314 class UninitValsVisitor : public CFGVisitor {
315 Diagnostic &Diags;
316 ASTContext *Ctx;
317 public:
318 UninitValsVisitor(Diagnostic &diags) : Diags(diags) {}
319 virtual void Initialize(ASTContext &Context, unsigned MainFileID) {
320 Ctx = &Context;
321 }
322
323 virtual void VisitCFG(CFG& C) { CheckUninitializedValues(C, *Ctx, Diags); }
324 virtual bool printFuncDeclStart() { return false; }
325 };
326} // end anonymous namespace
327
328ASTConsumer *clang::CreateUnitValsChecker(Diagnostic &Diags) {
329 return new UninitValsVisitor(Diags);
330}
331
332//===----------------------------------------------------------------------===//
Chris Lattner129758d2007-09-16 19:46:59 +0000333// LLVM Emitter
334
335#include "clang/Basic/Diagnostic.h"
336#include "clang/CodeGen/ModuleBuilder.h"
337#include "llvm/Module.h"
338#include <iostream>
339
340namespace {
341 class LLVMEmitter : public ASTConsumer {
342 Diagnostic &Diags;
343 llvm::Module *M;
344 ASTContext *Ctx;
345 CodeGen::BuilderTy *Builder;
346 public:
347 LLVMEmitter(Diagnostic &diags) : Diags(diags) {}
348 virtual void Initialize(ASTContext &Context, unsigned MainFileID) {
349 Ctx = &Context;
350 M = new llvm::Module("foo");
351 Builder = CodeGen::Init(Context, *M);
352 }
353
354 virtual void HandleTopLevelDecl(Decl *D) {
355 // If an error occurred, stop code generation, but continue parsing and
356 // semantic analysis (to ensure all warnings and errors are emitted).
357 if (Diags.hasErrorOccurred())
358 return;
359
360 if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
361 CodeGen::CodeGenFunction(Builder, FD);
362 } else if (FileVarDecl *FVD = dyn_cast<FileVarDecl>(D)) {
363 CodeGen::CodeGenGlobalVar(Builder, FVD);
364 } else {
365 assert(isa<TypedefDecl>(D) && "Only expected typedefs here");
366 // don't codegen for now, eventually pass down for debug info.
367 //std::cerr << "Read top-level typedef decl: '" << D->getName() << "'\n";
368 }
369 }
370
371 ~LLVMEmitter() {
372 CodeGen::Terminate(Builder);
373
374 // Print the generated code.
375 M->print(std::cout);
376 delete M;
377 }
378 };
379} // end anonymous namespace
380
381ASTConsumer *clang::CreateLLVMEmitter(Diagnostic &Diags) {
382 return new LLVMEmitter(Diags);
383}
384