blob: ebff1541ca80ee4b9407c2bf8aeae42161fe0157 [file] [log] [blame]
Chris Lattner6000dac2007-08-08 22:51:59 +00001//===--- StmtDumper.cpp - Dumping implementation for Stmt ASTs ------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file was developed by Chris Lattner and is distributed under
6// the University of Illinois Open Source License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file implements the Stmt::dump/Stmt::print methods, which dump out the
11// AST in a form that exposes type details and other fields.
12//
13//===----------------------------------------------------------------------===//
14
15#include "clang/AST/StmtVisitor.h"
16#include "clang/AST/Decl.h"
17#include "clang/AST/ExprCXX.h"
18#include "clang/Lex/IdentifierTable.h"
19#include "llvm/Support/Compiler.h"
20#include <cstdio>
21using namespace clang;
22
23//===----------------------------------------------------------------------===//
24// StmtDumper Visitor
25//===----------------------------------------------------------------------===//
26
27namespace {
28 class VISIBILITY_HIDDEN StmtDumper : public StmtVisitor {
29 FILE *F;
30 unsigned IndentLevel;
31
32 /// MaxDepth - When doing a normal dump (not dumpAll) we only want to dump
33 /// the first few levels of an AST. This keeps track of how many ast levels
34 /// are left.
35 unsigned MaxDepth;
36 public:
37 StmtDumper(FILE *f, unsigned maxDepth)
38 : F(f), IndentLevel(0), MaxDepth(maxDepth) {}
39
40 void DumpSubTree(Stmt *S, int SubIndent = 1) {
41 // Prune the recursion if not using dump all.
42 if (MaxDepth == 0) return;
43
44 IndentLevel += SubIndent;
45 if (S) {
46 S->visit(*this);
47 } else {
48 Indent();
49 fprintf(F, "<<<NULL>>>\n");
50 }
51 IndentLevel -= SubIndent;
52 }
53
54 void PrintRawDecl(Decl *D);
55
56 void Indent() const {
57 for (int i = 0, e = IndentLevel; i < e; ++i)
58 fprintf(F, " ");
59 }
60
61 void DumpStmt(const Stmt *Node) const {
62 Indent();
63 fprintf(F, "(%s %p", Node->getStmtClassName(), (void*)Node);
64 }
65
66 void DumpExpr(Expr *Node) const {
67 DumpStmt(Node);
68 // TODO: DUMP TYPE
69 }
70
71 virtual void VisitStmt(Stmt *Node);
72#define STMT(N, CLASS, PARENT) \
73 virtual void Visit##CLASS(CLASS *Node);
74#include "clang/AST/StmtNodes.def"
75 };
76}
77
78//===----------------------------------------------------------------------===//
79// Stmt printing methods.
80//===----------------------------------------------------------------------===//
81
82void StmtDumper::VisitStmt(Stmt *Node) {
83 Indent();
84 fprintf(F, "<<unknown stmt type>>\n");
85}
86
87void StmtDumper::PrintRawDecl(Decl *D) {
88#if 0
89 // FIXME: Need to complete/beautify this... this code simply shows the
90 // nodes are where they need to be.
91 if (TypedefDecl *localType = dyn_cast<TypedefDecl>(D)) {
92 OS << "typedef " << localType->getUnderlyingType().getAsString();
93 OS << " " << localType->getName();
94 } else if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) {
95 // Emit storage class for vardecls.
96 if (VarDecl *V = dyn_cast<VarDecl>(VD)) {
97 switch (V->getStorageClass()) {
98 default: assert(0 && "Unknown storage class!");
99 case VarDecl::None: break;
100 case VarDecl::Extern: OS << "extern "; break;
101 case VarDecl::Static: OS << "static "; break;
102 case VarDecl::Auto: OS << "auto "; break;
103 case VarDecl::Register: OS << "register "; break;
104 }
105 }
106
107 std::string Name = VD->getName();
108 VD->getType().getAsStringInternal(Name);
109 OS << Name;
110
111 // If this is a vardecl with an initializer, emit it.
112 if (VarDecl *V = dyn_cast<VarDecl>(VD)) {
113 if (V->getInit()) {
114 OS << " = ";
115 DumpExpr(V->getInit());
116 }
117 }
118 } else {
119 // FIXME: "struct x;"
120 assert(0 && "Unexpected decl");
121 }
122#endif
123}
124
125
126void StmtDumper::VisitNullStmt(NullStmt *Node) {
127 DumpStmt(Node);
128 fprintf(F, ")");
129}
130
131void StmtDumper::VisitDeclStmt(DeclStmt *Node) {
132 DumpStmt(Node);
133 // FIXME: implement this better :)
134 fprintf(F, ")");
135#if 0
136 for (Decl *D = Node->getDecl(); D; D = D->getNextDeclarator()) {
137 Indent();
138 PrintRawDecl(D);
139 OS << ";\n";
140 }
141#endif
142}
143
144void StmtDumper::VisitCompoundStmt(CompoundStmt *Node) {
145 DumpStmt(Node);
146 if (!Node->body_empty()) fprintf(F, "\n");
147
148 for (CompoundStmt::body_iterator I = Node->body_begin(), E = Node->body_end();
149 I != E; ) {
150 DumpSubTree(*I);
151 ++I;
152 if (I != E)
153 fprintf(F, "\n");
154 }
155 fprintf(F, ")");
156}
157
158void StmtDumper::VisitCaseStmt(CaseStmt *Node) {
159#if 0
160 Indent(-1) << "case ";
161 DumpExpr(Node->getLHS());
162 if (Node->getRHS()) {
163 OS << " ... ";
164 DumpExpr(Node->getRHS());
165 }
166 OS << ":\n";
167
168 DumpSubTree(Node->getSubStmt(), 0);
169#endif
170}
171
172void StmtDumper::VisitDefaultStmt(DefaultStmt *Node) {
173 DumpStmt(Node);
174 fprintf(F, "\n");
175 DumpSubTree(Node->getSubStmt());
176 fprintf(F, ")");
177}
178
179void StmtDumper::VisitLabelStmt(LabelStmt *Node) {
180 DumpStmt(Node);
181 fprintf(F, " '%s'\n", Node->getName());
182 DumpSubTree(Node->getSubStmt());
183 fprintf(F, "\n");
184}
185
186void StmtDumper::VisitIfStmt(IfStmt *Node) {
187 DumpStmt(Node);
188 fprintf(F, "\n");
189 DumpSubTree(Node->getCond());
190 fprintf(F, "\n");
191 DumpSubTree(Node->getThen());
192 fprintf(F, "\n");
193 DumpSubTree(Node->getElse());
194 fprintf(F, ")");
195}
196
197void StmtDumper::VisitSwitchStmt(SwitchStmt *Node) {
198 DumpStmt(Node);
199 fprintf(F, "\n");
200 DumpSubTree(Node->getCond());
201 fprintf(F, "\n");
202 DumpSubTree(Node->getBody());
203 fprintf(F, ")");
204}
205
206void StmtDumper::VisitSwitchCase(SwitchCase*) {
207 assert(0 && "SwitchCase is an abstract class");
208}
209
210void StmtDumper::VisitWhileStmt(WhileStmt *Node) {
211 DumpStmt(Node);
212 fprintf(F, "\n");
213 DumpSubTree(Node->getCond());
214 fprintf(F, "\n");
215 DumpSubTree(Node->getBody());
216 fprintf(F, ")");
217}
218
219void StmtDumper::VisitDoStmt(DoStmt *Node) {
220 DumpStmt(Node);
221 fprintf(F, "\n");
222 DumpSubTree(Node->getBody());
223 fprintf(F, "\n");
224 DumpSubTree(Node->getCond());
225 fprintf(F, ")");
226}
227
228void StmtDumper::VisitForStmt(ForStmt *Node) {
229 DumpStmt(Node);
230 fprintf(F, "\n");
231 DumpSubTree(Node->getInit());
232 fprintf(F, "\n");
233 DumpSubTree(Node->getCond());
234 fprintf(F, "\n");
235 DumpSubTree(Node->getInc());
236 fprintf(F, "\n");
237 DumpSubTree(Node->getBody());
238 fprintf(F, ")");
239}
240
241void StmtDumper::VisitGotoStmt(GotoStmt *Node) {
242 DumpStmt(Node);
243 fprintf(F, " '%s':%p)", Node->getLabel()->getName(), (void*)Node->getLabel());
244}
245
246void StmtDumper::VisitIndirectGotoStmt(IndirectGotoStmt *Node) {
247 DumpStmt(Node);
248 fprintf(F, "\n");
249 DumpSubTree(Node->getTarget());
250 fprintf(F, ")");
251}
252
253void StmtDumper::VisitContinueStmt(ContinueStmt *Node) {
254 DumpStmt(Node);
255 fprintf(F, ")");
256}
257
258void StmtDumper::VisitBreakStmt(BreakStmt *Node) {
259 DumpStmt(Node);
260 fprintf(F, ")");
261}
262
263
264void StmtDumper::VisitReturnStmt(ReturnStmt *Node) {
265 DumpStmt(Node);
266 if (Expr *RV = Node->getRetValue()) {
267 fprintf(F, "\n");
268 DumpSubTree(RV);
269 }
270 fprintf(F, ")");
271}
272
273//===----------------------------------------------------------------------===//
274// Expr printing methods.
275//===----------------------------------------------------------------------===//
276
277void StmtDumper::VisitExpr(Expr *Node) {
278 DumpExpr(Node);
279 fprintf(F, ": UNKNOWN EXPR to StmtDumper)");
280}
281
282void StmtDumper::VisitDeclRefExpr(DeclRefExpr *Node) {
283 DumpExpr(Node);
284 fprintf(F, " Decl='%s' %p)", Node->getDecl()->getName(),
285 (void*)Node->getDecl());
286}
287
288void StmtDumper::VisitPreDefinedExpr(PreDefinedExpr *Node) {
289 DumpExpr(Node);
290 switch (Node->getIdentType()) {
291 default:
292 assert(0 && "unknown case");
293 case PreDefinedExpr::Func:
294 fprintf(F, " __func__)");
295 break;
296 case PreDefinedExpr::Function:
297 fprintf(F, " __FUNCTION__)");
298 break;
299 case PreDefinedExpr::PrettyFunction:
300 fprintf(F, " __PRETTY_FUNCTION__)");
301 break;
302 }
303}
304
305void StmtDumper::VisitCharacterLiteral(CharacterLiteral *Node) {
306#if 0
307 // FIXME should print an L for wchar_t constants
308 unsigned value = Node->getValue();
309 switch (value) {
310 case '\\':
311 OS << "'\\\\'";
312 break;
313 case '\'':
314 OS << "'\\''";
315 break;
316 case '\a':
317 // TODO: K&R: the meaning of '\\a' is different in traditional C
318 OS << "'\\a'";
319 break;
320 case '\b':
321 OS << "'\\b'";
322 break;
323 // Nonstandard escape sequence.
324 /*case '\e':
325 OS << "'\\e'";
326 break;*/
327 case '\f':
328 OS << "'\\f'";
329 break;
330 case '\n':
331 OS << "'\\n'";
332 break;
333 case '\r':
334 OS << "'\\r'";
335 break;
336 case '\t':
337 OS << "'\\t'";
338 break;
339 case '\v':
340 OS << "'\\v'";
341 break;
342 default:
343 if (isprint(value) && value < 256) {
344 OS << "'" << (char)value << "'";
345 } else if (value < 256) {
346 OS << "'\\x" << std::hex << value << std::dec << "'";
347 } else {
348 // FIXME what to really do here?
349 OS << value;
350 }
351 }
352#endif
353}
354
355void StmtDumper::VisitIntegerLiteral(IntegerLiteral *Node) {
356 DumpExpr(Node);
357
358 bool isSigned = Node->getType()->isSignedIntegerType();
359 fprintf(F, " %s)", Node->getValue().toString(10, isSigned).c_str());
360}
361void StmtDumper::VisitFloatingLiteral(FloatingLiteral *Node) {
362 DumpExpr(Node);
363 fprintf(F, " %f)", Node->getValue());
364}
365void StmtDumper::VisitStringLiteral(StringLiteral *Str) {
366#if 0
367 if (Str->isWide()) OS << 'L';
368 OS << '"';
369
370 // FIXME: this doesn't print wstrings right.
371 for (unsigned i = 0, e = Str->getByteLength(); i != e; ++i) {
372 switch (Str->getStrData()[i]) {
373 default: OS << Str->getStrData()[i]; break;
374 // Handle some common ones to make dumps prettier.
375 case '\\': OS << "\\\\"; break;
376 case '"': OS << "\\\""; break;
377 case '\n': OS << "\\n"; break;
378 case '\t': OS << "\\t"; break;
379 case '\a': OS << "\\a"; break;
380 case '\b': OS << "\\b"; break;
381 }
382 }
383 OS << '"';
384#endif
385}
386void StmtDumper::VisitParenExpr(ParenExpr *Node) {
387 DumpExpr(Node);
388 fprintf(F, "\n");
389 DumpSubTree(Node->getSubExpr());
390 fprintf(F, ")");
391}
392void StmtDumper::VisitUnaryOperator(UnaryOperator *Node) {
393#if 0
394 if (!Node->isPostfix())
395 OS << UnaryOperator::getOpcodeStr(Node->getOpcode());
396 DumpExpr(Node->getSubExpr());
397
398 if (Node->isPostfix())
399 OS << UnaryOperator::getOpcodeStr(Node->getOpcode());
400
401#endif
402}
403void StmtDumper::VisitSizeOfAlignOfTypeExpr(SizeOfAlignOfTypeExpr *Node) {
404#if 0
405 OS << (Node->isSizeOf() ? "sizeof(" : "__alignof(");
406 OS << Node->getArgumentType().getAsString() << ")";
407#endif
408}
409void StmtDumper::VisitArraySubscriptExpr(ArraySubscriptExpr *Node) {
410 DumpExpr(Node);
411 fprintf(F, "\n");
412 DumpSubTree(Node->getBase());
413 fprintf(F, "\n");
414 DumpSubTree(Node->getIdx());
415 fprintf(F, ")");
416}
417
418void StmtDumper::VisitCallExpr(CallExpr *Node) {
419 DumpExpr(Node);
420 fprintf(F, "\n");
421 DumpSubTree(Node->getCallee());
422
423 for (unsigned i = 0, e = Node->getNumArgs(); i != e; ++i) {
424 fprintf(F, "\n");
425 DumpSubTree(Node->getArg(i));
426 }
427 fprintf(F, ")");
428}
429void StmtDumper::VisitMemberExpr(MemberExpr *Node) {
430#if 0
431 DumpExpr(Node->getBase());
432 OS << (Node->isArrow() ? "->" : ".");
433
434 FieldDecl *Field = Node->getMemberDecl();
435 assert(Field && "MemberExpr should alway reference a field!");
436 OS << Field->getName();
437#endif
438}
439void StmtDumper::VisitOCUVectorElementExpr(OCUVectorElementExpr *Node) {
440#if 0
441 DumpExpr(Node->getBase());
442 OS << ".";
443 OS << Node->getAccessor().getName();
444#endif
445}
446void StmtDumper::VisitCastExpr(CastExpr *Node) {
447#if 0
448 OS << "(" << Node->getType().getAsString() << ")";
449 DumpExpr(Node->getSubExpr());
450#endif
451}
452void StmtDumper::VisitCompoundLiteralExpr(CompoundLiteralExpr *Node) {
453#if 0
454 OS << "(" << Node->getType().getAsString() << ")";
455 DumpExpr(Node->getInitializer());
456#endif
457}
458void StmtDumper::VisitImplicitCastExpr(ImplicitCastExpr *Node) {
459 DumpExpr(Node);
460 fprintf(F, "\n");
461 DumpSubTree(Node->getSubExpr());
462 fprintf(F, ")");
463}
464void StmtDumper::VisitBinaryOperator(BinaryOperator *Node) {
465 DumpExpr(Node);
466 fprintf(F, " '%s'\n", BinaryOperator::getOpcodeStr(Node->getOpcode()));
467 DumpSubTree(Node->getLHS());
468 fprintf(F, "\n");
469 DumpSubTree(Node->getRHS());
470 fprintf(F, ")");
471}
472void StmtDumper::VisitConditionalOperator(ConditionalOperator *Node) {
473 DumpExpr(Node);
474 fprintf(F, "\n");
475 DumpSubTree(Node->getCond());
476 fprintf(F, "\n");
477 DumpSubTree(Node->getLHS());
478 fprintf(F, "\n");
479 DumpSubTree(Node->getRHS());
480 fprintf(F, ")");
481}
482
483// GNU extensions.
484
485void StmtDumper::VisitAddrLabelExpr(AddrLabelExpr *Node) {
486#if 0
487 OS << "&&" << Node->getLabel()->getName();
488#endif
489}
490
491void StmtDumper::VisitStmtExpr(StmtExpr *E) {
492#if 0
493 OS << "(";
494 DumpSubTree(E->getSubStmt());
495 OS << ")";
496#endif
497}
498
499void StmtDumper::VisitTypesCompatibleExpr(TypesCompatibleExpr *Node) {
500#if 0
501 OS << "__builtin_types_compatible_p(";
502 OS << Node->getArgType1().getAsString() << ",";
503 OS << Node->getArgType2().getAsString() << ")";
504#endif
505}
506
507void StmtDumper::VisitChooseExpr(ChooseExpr *Node) {
508#if 0
509 OS << "__builtin_choose_expr(";
510 DumpExpr(Node->getCond());
511 OS << ", ";
512 DumpExpr(Node->getLHS());
513 OS << ", ";
514 DumpExpr(Node->getRHS());
515 OS << ")";
516#endif
517}
518
519// C++
520
521void StmtDumper::VisitCXXCastExpr(CXXCastExpr *Node) {
522#if 0
523 switch (Node->getOpcode()) {
524 default:
525 assert(0 && "Not a C++ cast expression");
526 abort();
527 case CXXCastExpr::ConstCast: OS << "const_cast<"; break;
528 case CXXCastExpr::DynamicCast: OS << "dynamic_cast<"; break;
529 case CXXCastExpr::ReinterpretCast: OS << "reinterpret_cast<"; break;
530 case CXXCastExpr::StaticCast: OS << "static_cast<"; break;
531 }
532
533 OS << Node->getDestType().getAsString() << ">(";
534 DumpExpr(Node->getSubExpr());
535 OS << ")";
536#endif
537}
538
539void StmtDumper::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node) {
540#if 0
541 OS << (Node->getValue() ? "true" : "false");
542#endif
543}
544
545
546//===----------------------------------------------------------------------===//
547// Stmt method implementations
548//===----------------------------------------------------------------------===//
549
550/// dump - This does a local dump of the specified AST fragment. It dumps the
551/// specified node and a few nodes underneath it, but not the whole subtree.
552/// This is useful in a debugger.
553void Stmt::dump() const {
554 StmtDumper P(stderr, 4);
555 const_cast<Stmt*>(this)->visit(P);
556}
557
558/// dumpAll - This does a dump of the specified AST fragment and all subtrees.
559void Stmt::dumpAll() const {
560 StmtDumper P(stderr, ~0U);
561 const_cast<Stmt*>(this)->visit(P);
562}