blob: 98a0bfe2f7c3c0d9a6bed1c7b3fe5f23557992e4 [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) {
Fariborz Jahanianc04aff12007-10-08 23:06:41 +000077 std::string I = OID->getName();
78 ObjcInterfaceDecl *SID = OID->getSuperClass();
79 if (SID) {
80 std::string S = SID->getName();
81 fprintf(stderr, "@interface %s : %s", I.c_str(), S.c_str());
82 }
83 else
84 fprintf(stderr, "@interface %s", I.c_str());
85 // Protocols?
86 int count = OID->getNumIntfRefProtocols();
87 if (count > 0) {
88 ObjcProtocolDecl **refProtocols = OID->getReferencedProtocols();
89 for (int i = 0; i < count; i++)
90 fprintf(stderr, "%c%s", (i == 0 ? '<' : ','),
91 refProtocols[i]->getName());
92 }
93 if (count > 0)
94 fprintf(stderr, ">;\n");
95 else
96 fprintf(stderr, ";\n");
Steve Narofffaed3bf2007-09-10 20:51:04 +000097 // FIXME: implement the rest...
98}
99
Fariborz Jahanianac20be22007-10-08 18:53:38 +0000100static void PrintObjcProtocolDecl(ObjcProtocolDecl *PID) {
101 std::string S = PID->getName();
102 fprintf(stderr, "@protocol %s;\n", S.c_str());
103 // FIXME: implement the rest...
104}
105
106static void PrintObjcCategoryImplDecl(ObjcCategoryImplDecl *PID) {
107 std::string S = PID->getName();
108 std::string I = PID->getClassInterface()->getName();
109 fprintf(stderr, "@implementation %s(%s);\n", I.c_str(), S.c_str());
110 // FIXME: implement the rest...
111}
112
113static void PrintObjcCategoryDecl(ObjcCategoryDecl *PID) {
114 std::string S = PID->getName();
115 std::string I = PID->getClassInterface()->getName();
116 fprintf(stderr, "@interface %s(%s);\n", I.c_str(), S.c_str());
117 // FIXME: implement the rest...
118}
119
Fariborz Jahanian05d212a2007-10-11 23:42:27 +0000120static void PrintObjcCompatibleAliasDecl(ObjcCompatibleAliasDecl *AID) {
121 std::string A = AID->getName();
122 std::string I = AID->getClassInterface()->getName();
123 fprintf(stderr, "@compatibility_alias %s %s;\n", A.c_str(), I.c_str());
124}
125
Chris Lattnerb73abd52007-09-15 23:02:28 +0000126namespace {
127 class ASTPrinter : public ASTConsumer {
128 virtual void HandleTopLevelDecl(Decl *D) {
129 if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
130 PrintFunctionDeclStart(FD);
131
132 if (FD->getBody()) {
133 fprintf(stderr, " ");
134 FD->getBody()->dumpPretty();
135 fprintf(stderr, "\n");
136 }
137 } else if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) {
138 PrintTypeDefDecl(TD);
Chris Lattnerd5c9d3d2007-10-06 18:52:10 +0000139 } else if (ObjcInterfaceDecl *OID = dyn_cast<ObjcInterfaceDecl>(D)) {
140 PrintObjcInterfaceDecl(OID);
Fariborz Jahanianac20be22007-10-08 18:53:38 +0000141 } else if (ObjcProtocolDecl *PID = dyn_cast<ObjcProtocolDecl>(D)) {
142 PrintObjcProtocolDecl(PID);
Chris Lattnerd5c9d3d2007-10-06 18:52:10 +0000143 } else if (ObjcForwardProtocolDecl *OFPD =
144 dyn_cast<ObjcForwardProtocolDecl>(D)) {
145 fprintf(stderr, "@protocol ");
146 for (unsigned i = 0, e = OFPD->getNumForwardDecls(); i != e; ++i) {
147 const ObjcProtocolDecl *D = OFPD->getForwardProtocolDecl(i);
148 if (i) fprintf(stderr, ", ");
149 fprintf(stderr, "%s", D->getName());
150 }
Chris Lattnera845bbe2007-10-06 19:08:22 +0000151 fprintf(stderr, ";\n");
Chris Lattnerd5c9d3d2007-10-06 18:52:10 +0000152 } else if (ObjcImplementationDecl *OID =
153 dyn_cast<ObjcImplementationDecl>(D)) {
154 fprintf(stderr, "@implementation %s [printing todo]\n",
155 OID->getName());
Fariborz Jahanianac20be22007-10-08 18:53:38 +0000156 } else if (ObjcCategoryImplDecl *OID =
157 dyn_cast<ObjcCategoryImplDecl>(D)) {
158 PrintObjcCategoryImplDecl(OID);
159 } else if (ObjcCategoryDecl *OID =
160 dyn_cast<ObjcCategoryDecl>(D)) {
161 PrintObjcCategoryDecl(OID);
Fariborz Jahanian05d212a2007-10-11 23:42:27 +0000162 } else if (ObjcCompatibleAliasDecl *OID =
163 dyn_cast<ObjcCompatibleAliasDecl>(D)) {
164 PrintObjcCompatibleAliasDecl(OID);
Chris Lattnerd5c9d3d2007-10-06 18:52:10 +0000165 } else if (isa<ObjcClassDecl>(D)) {
166 fprintf(stderr, "@class [printing todo]\n");
Fariborz Jahanianac20be22007-10-08 18:53:38 +0000167 } else if (ScopedDecl *SD = dyn_cast<ScopedDecl>(D)) {
168 fprintf(stderr, "Read top-level variable decl: '%s'\n", SD->getName());
Chris Lattnerd5c9d3d2007-10-06 18:52:10 +0000169 } else {
170 assert(0 && "Unknown decl type!");
Chris Lattner95578782007-08-08 22:51:59 +0000171 }
Chris Lattner4b009652007-07-25 00:24:17 +0000172 }
Chris Lattnerb73abd52007-09-15 23:02:28 +0000173 };
Chris Lattner4b009652007-07-25 00:24:17 +0000174}
Chris Lattner95578782007-08-08 22:51:59 +0000175
Chris Lattnerb73abd52007-09-15 23:02:28 +0000176ASTConsumer *clang::CreateASTPrinter() { return new ASTPrinter(); }
177
178namespace {
179 class ASTDumper : public ASTConsumer {
180 SourceManager *SM;
181 public:
182 void Initialize(ASTContext &Context, unsigned MainFileID) {
183 SM = &Context.SourceMgr;
Chris Lattner95578782007-08-08 22:51:59 +0000184 }
Chris Lattnerb73abd52007-09-15 23:02:28 +0000185
186 virtual void HandleTopLevelDecl(Decl *D) {
187 if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
188 PrintFunctionDeclStart(FD);
189
190 if (FD->getBody()) {
191 fprintf(stderr, "\n");
192 FD->getBody()->dumpAll(*SM);
193 fprintf(stderr, "\n");
194 }
195 } else if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) {
196 PrintTypeDefDecl(TD);
197 } else if (ScopedDecl *SD = dyn_cast<ScopedDecl>(D)) {
198 fprintf(stderr, "Read top-level variable decl: '%s'\n", SD->getName());
Chris Lattnerd5c9d3d2007-10-06 18:52:10 +0000199 } else if (ObjcInterfaceDecl *OID = dyn_cast<ObjcInterfaceDecl>(D)) {
200 fprintf(stderr, "Read objc interface '%s'\n", OID->getName());
Steve Naroffd5d18732007-10-14 17:03:01 +0000201 } else if (ObjcProtocolDecl *OPD = dyn_cast<ObjcProtocolDecl>(D)) {
202 fprintf(stderr, "Read objc protocol '%s'\n", OPD->getName());
203 } else if (ObjcCategoryDecl *OCD = dyn_cast<ObjcCategoryDecl>(D)) {
204 fprintf(stderr, "Read objc category '%s'\n", OCD->getName());
Chris Lattnerd5c9d3d2007-10-06 18:52:10 +0000205 } else if (isa<ObjcForwardProtocolDecl>(D)) {
206 fprintf(stderr, "Read objc fwd protocol decl\n");
Steve Naroffd5d18732007-10-14 17:03:01 +0000207 } else if (isa<ObjcClassDecl>(D)) {
208 fprintf(stderr, "Read objc fwd class decl\n");
Chris Lattnerd5c9d3d2007-10-06 18:52:10 +0000209 } else {
210 assert(0 && "Unknown decl type!");
Chris Lattnerb73abd52007-09-15 23:02:28 +0000211 }
212 }
213 };
Chris Lattner95578782007-08-08 22:51:59 +0000214}
215
Chris Lattnerb73abd52007-09-15 23:02:28 +0000216ASTConsumer *clang::CreateASTDumper() { return new ASTDumper(); }
217
Ted Kremenekb6976a22007-09-19 21:29:43 +0000218namespace {
219 class ASTViewer : public ASTConsumer {
220 SourceManager *SM;
221 public:
222 void Initialize(ASTContext &Context, unsigned MainFileID) {
223 SM = &Context.SourceMgr;
224 }
225
226 virtual void HandleTopLevelDecl(Decl *D) {
227 if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
228 PrintFunctionDeclStart(FD);
229
230 if (FD->getBody()) {
231 fprintf(stderr, "\n");
232 FD->getBody()->viewAST();
233 fprintf(stderr, "\n");
234 }
235 }
236 }
237 };
238}
239
240ASTConsumer *clang::CreateASTViewer() { return new ASTViewer(); }
241
242
Ted Kremenek1e3c2022007-09-07 23:47:56 +0000243//===----------------------------------------------------------------------===//
244// CFGVisitor & VisitCFGs - Boilerplate interface and logic to visit
245// the CFGs for all function definitions.
246
247namespace {
248
Chris Lattner52332d02007-09-15 23:21:08 +0000249class CFGVisitor : public ASTConsumer {
Ted Kremenek1e3c2022007-09-07 23:47:56 +0000250public:
Chris Lattner52332d02007-09-15 23:21:08 +0000251 // CFG Visitor interface to be implemented by subclass.
Ted Kremenek1e3c2022007-09-07 23:47:56 +0000252 virtual void VisitCFG(CFG& C) = 0;
253 virtual bool printFuncDeclStart() { return true; }
Chris Lattner52332d02007-09-15 23:21:08 +0000254
255 virtual void HandleTopLevelDecl(Decl *D);
Ted Kremenek1e3c2022007-09-07 23:47:56 +0000256};
257
258} // end anonymous namespace
259
Chris Lattner52332d02007-09-15 23:21:08 +0000260void CFGVisitor::HandleTopLevelDecl(Decl *D) {
261 FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
262 if (!FD || !FD->getBody())
263 return;
264
265 if (printFuncDeclStart()) {
266 PrintFunctionDeclStart(FD);
267 fprintf(stderr,"\n");
Ted Kremenek1e3c2022007-09-07 23:47:56 +0000268 }
Chris Lattner52332d02007-09-15 23:21:08 +0000269
Ted Kremenek3e88d752007-09-17 17:10:02 +0000270 CFG *C = CFG::buildCFG(FD->getBody());
271 VisitCFG(*C);
272 delete C;
Ted Kremenek1e3c2022007-09-07 23:47:56 +0000273}
274
275//===----------------------------------------------------------------------===//
276// DumpCFGs - Dump CFGs to stderr or visualize with Graphviz
277
278namespace {
279 class CFGDumper : public CFGVisitor {
280 const bool UseGraphviz;
281 public:
282 CFGDumper(bool use_graphviz) : UseGraphviz(use_graphviz) {}
283
Chris Lattner52332d02007-09-15 23:21:08 +0000284 virtual void VisitCFG(CFG &C) {
285 if (UseGraphviz)
286 C.viewCFG();
287 else
288 C.dump();
289 }
Ted Kremenek1e3c2022007-09-07 23:47:56 +0000290 };
291} // end anonymous namespace
292
Chris Lattner52332d02007-09-15 23:21:08 +0000293ASTConsumer *clang::CreateCFGDumper(bool ViewGraphs) {
294 return new CFGDumper(ViewGraphs);
Ted Kremenek97f75312007-08-21 21:42:03 +0000295}
296
Ted Kremenek1e3c2022007-09-07 23:47:56 +0000297//===----------------------------------------------------------------------===//
298// AnalyzeLiveVariables - perform live variable analysis and dump results
299
300namespace {
301 class LivenessVisitor : public CFGVisitor {
Chris Lattner52332d02007-09-15 23:21:08 +0000302 SourceManager *SM;
Ted Kremenek1e3c2022007-09-07 23:47:56 +0000303 public:
Chris Lattner52332d02007-09-15 23:21:08 +0000304 virtual void Initialize(ASTContext &Context, unsigned MainFileID) {
305 SM = &Context.SourceMgr;
306 }
307
Ted Kremenek1e3c2022007-09-07 23:47:56 +0000308 virtual void VisitCFG(CFG& C) {
Ted Kremenek8ce772b2007-10-01 20:33:52 +0000309 LiveVariables L(C);
Ted Kremenek1e3c2022007-09-07 23:47:56 +0000310 L.runOnCFG(C);
Ted Kremenekd7a2f812007-09-25 04:31:27 +0000311 L.dumpBlockLiveness(*SM);
Ted Kremenekaa04c512007-09-06 00:17:54 +0000312 }
Ted Kremenek1e3c2022007-09-07 23:47:56 +0000313 };
314} // end anonymous namespace
315
Chris Lattner52332d02007-09-15 23:21:08 +0000316ASTConsumer *clang::CreateLiveVarAnalyzer() {
317 return new LivenessVisitor();
Ted Kremenekaa04c512007-09-06 00:17:54 +0000318}
319
Ted Kremenek1e3c2022007-09-07 23:47:56 +0000320//===----------------------------------------------------------------------===//
Ted Kremenek0a03ce62007-09-17 20:49:30 +0000321// DeadStores - run checker to locate dead stores in a function
Ted Kremenek1e3c2022007-09-07 23:47:56 +0000322
323namespace {
324 class DeadStoreVisitor : public CFGVisitor {
Chris Lattner52332d02007-09-15 23:21:08 +0000325 Diagnostic &Diags;
326 ASTContext *Ctx;
Ted Kremenek1e3c2022007-09-07 23:47:56 +0000327 public:
Chris Lattner52332d02007-09-15 23:21:08 +0000328 DeadStoreVisitor(Diagnostic &diags) : Diags(diags) {}
329 virtual void Initialize(ASTContext &Context, unsigned MainFileID) {
330 Ctx = &Context;
331 }
332
333 virtual void VisitCFG(CFG& C) { CheckDeadStores(C, *Ctx, Diags); }
Ted Kremenek39b8c4b2007-09-07 23:54:15 +0000334 virtual bool printFuncDeclStart() { return false; }
Ted Kremenek1e3c2022007-09-07 23:47:56 +0000335 };
336} // end anonymous namespace
337
Chris Lattner52332d02007-09-15 23:21:08 +0000338ASTConsumer *clang::CreateDeadStoreChecker(Diagnostic &Diags) {
339 return new DeadStoreVisitor(Diags);
Ted Kremeneke805c4a2007-09-06 23:00:42 +0000340}
Chris Lattner129758d2007-09-16 19:46:59 +0000341
342//===----------------------------------------------------------------------===//
Ted Kremenek0a03ce62007-09-17 20:49:30 +0000343// Unitialized Values - run checker to flag potential uses of uninitalized
344// variables.
345
346namespace {
347 class UninitValsVisitor : public CFGVisitor {
348 Diagnostic &Diags;
349 ASTContext *Ctx;
350 public:
351 UninitValsVisitor(Diagnostic &diags) : Diags(diags) {}
352 virtual void Initialize(ASTContext &Context, unsigned MainFileID) {
353 Ctx = &Context;
354 }
355
356 virtual void VisitCFG(CFG& C) { CheckUninitializedValues(C, *Ctx, Diags); }
357 virtual bool printFuncDeclStart() { return false; }
358 };
359} // end anonymous namespace
360
361ASTConsumer *clang::CreateUnitValsChecker(Diagnostic &Diags) {
362 return new UninitValsVisitor(Diags);
363}
364
365//===----------------------------------------------------------------------===//
Chris Lattner129758d2007-09-16 19:46:59 +0000366// LLVM Emitter
367
368#include "clang/Basic/Diagnostic.h"
369#include "clang/CodeGen/ModuleBuilder.h"
370#include "llvm/Module.h"
371#include <iostream>
372
373namespace {
374 class LLVMEmitter : public ASTConsumer {
375 Diagnostic &Diags;
376 llvm::Module *M;
377 ASTContext *Ctx;
378 CodeGen::BuilderTy *Builder;
379 public:
380 LLVMEmitter(Diagnostic &diags) : Diags(diags) {}
381 virtual void Initialize(ASTContext &Context, unsigned MainFileID) {
382 Ctx = &Context;
383 M = new llvm::Module("foo");
384 Builder = CodeGen::Init(Context, *M);
385 }
386
387 virtual void HandleTopLevelDecl(Decl *D) {
388 // If an error occurred, stop code generation, but continue parsing and
389 // semantic analysis (to ensure all warnings and errors are emitted).
390 if (Diags.hasErrorOccurred())
391 return;
392
393 if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
394 CodeGen::CodeGenFunction(Builder, FD);
395 } else if (FileVarDecl *FVD = dyn_cast<FileVarDecl>(D)) {
396 CodeGen::CodeGenGlobalVar(Builder, FVD);
397 } else {
398 assert(isa<TypedefDecl>(D) && "Only expected typedefs here");
399 // don't codegen for now, eventually pass down for debug info.
400 //std::cerr << "Read top-level typedef decl: '" << D->getName() << "'\n";
401 }
402 }
403
404 ~LLVMEmitter() {
405 CodeGen::Terminate(Builder);
406
407 // Print the generated code.
408 M->print(std::cout);
409 delete M;
410 }
411 };
412} // end anonymous namespace
413
414ASTConsumer *clang::CreateLLVMEmitter(Diagnostic &Diags) {
415 return new LLVMEmitter(Diags);
416}
417