StmtDumper.cpp revision 5399ce26f27e6d093417a3882e38da8738a78fef
1//===--- 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/DeclObjC.h"
18#include "clang/AST/ExprCXX.h"
19#include "clang/Basic/IdentifierTable.h"
20#include "clang/Basic/SourceManager.h"
21#include "llvm/Support/Compiler.h"
22#include <cstdio>
23using namespace clang;
24
25//===----------------------------------------------------------------------===//
26// StmtDumper Visitor
27//===----------------------------------------------------------------------===//
28
29namespace  {
30  class VISIBILITY_HIDDEN StmtDumper : public StmtVisitor<StmtDumper> {
31    SourceManager *SM;
32    FILE *F;
33    unsigned IndentLevel;
34
35    /// MaxDepth - When doing a normal dump (not dumpAll) we only want to dump
36    /// the first few levels of an AST.  This keeps track of how many ast levels
37    /// are left.
38    unsigned MaxDepth;
39
40    /// LastLocFilename/LastLocLine - Keep track of the last location we print
41    /// out so that we can print out deltas from then on out.
42    const char *LastLocFilename;
43    unsigned LastLocLine;
44  public:
45    StmtDumper(SourceManager *sm, FILE *f, unsigned maxDepth)
46      : SM(sm), F(f), IndentLevel(0-1), MaxDepth(maxDepth) {
47      LastLocFilename = "";
48      LastLocLine = ~0U;
49    }
50
51    void DumpSubTree(Stmt *S) {
52      // Prune the recursion if not using dump all.
53      if (MaxDepth == 0) return;
54
55      ++IndentLevel;
56      if (S) {
57        if (DeclStmt* DS = dyn_cast<DeclStmt>(S))
58          VisitDeclStmt(DS);
59        else {
60          Visit(S);
61
62          // Print out children.
63          Stmt::child_iterator CI = S->child_begin(), CE = S->child_end();
64          if (CI != CE) {
65            while (CI != CE) {
66              fprintf(F, "\n");
67              DumpSubTree(*CI++);
68            }
69          }
70          fprintf(F, ")");
71        }
72      } else {
73        Indent();
74        fprintf(F, "<<<NULL>>>");
75      }
76      --IndentLevel;
77    }
78
79    void DumpDeclarator(Decl *D);
80
81    void Indent() const {
82      for (int i = 0, e = IndentLevel; i < e; ++i)
83        fprintf(F, "  ");
84    }
85
86    void DumpType(QualType T) {
87      fprintf(F, "'%s'", T.getAsString().c_str());
88
89      // If the type is directly a typedef, strip off typedefness to give at
90      // least one level of concreteness.
91      if (TypedefType *TDT = dyn_cast<TypedefType>(T))
92        fprintf(F, ":'%s'", TDT->LookThroughTypedefs().getAsString().c_str());
93    }
94    void DumpStmt(const Stmt *Node) {
95      Indent();
96      fprintf(F, "(%s %p", Node->getStmtClassName(), (void*)Node);
97      DumpSourceRange(Node);
98    }
99    void DumpExpr(const Expr *Node) {
100      DumpStmt(Node);
101      fprintf(F, " ");
102      DumpType(Node->getType());
103    }
104    void DumpSourceRange(const Stmt *Node);
105    void DumpLocation(SourceLocation Loc);
106
107    // Stmts.
108    void VisitStmt(Stmt *Node);
109    void VisitDeclStmt(DeclStmt *Node);
110    void VisitLabelStmt(LabelStmt *Node);
111    void VisitGotoStmt(GotoStmt *Node);
112
113    // Exprs
114    void VisitExpr(Expr *Node);
115    void VisitDeclRefExpr(DeclRefExpr *Node);
116    void VisitPreDefinedExpr(PreDefinedExpr *Node);
117    void VisitCharacterLiteral(CharacterLiteral *Node);
118    void VisitIntegerLiteral(IntegerLiteral *Node);
119    void VisitFloatingLiteral(FloatingLiteral *Node);
120    void VisitStringLiteral(StringLiteral *Str);
121    void VisitUnaryOperator(UnaryOperator *Node);
122    void VisitSizeOfAlignOfTypeExpr(SizeOfAlignOfTypeExpr *Node);
123    void VisitMemberExpr(MemberExpr *Node);
124    void VisitOCUVectorElementExpr(OCUVectorElementExpr *Node);
125    void VisitBinaryOperator(BinaryOperator *Node);
126    void VisitCompoundAssignOperator(CompoundAssignOperator *Node);
127    void VisitAddrLabelExpr(AddrLabelExpr *Node);
128    void VisitTypesCompatibleExpr(TypesCompatibleExpr *Node);
129
130    // C++
131    void VisitCXXCastExpr(CXXCastExpr *Node);
132    void VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node);
133
134    // ObjC
135    void VisitObjCEncodeExpr(ObjCEncodeExpr *Node);
136    void VisitObjCSelectorExpr(ObjCSelectorExpr *Node);
137    void VisitObjCProtocolExpr(ObjCProtocolExpr *Node);
138  };
139}
140
141//===----------------------------------------------------------------------===//
142//  Utilities
143//===----------------------------------------------------------------------===//
144
145void StmtDumper::DumpLocation(SourceLocation Loc) {
146  SourceLocation PhysLoc = SM->getPhysicalLoc(Loc);
147
148  // The general format we print out is filename:line:col, but we drop pieces
149  // that haven't changed since the last loc printed.
150  const char *Filename = SM->getSourceName(PhysLoc);
151  unsigned LineNo = SM->getLineNumber(PhysLoc);
152  if (strcmp(Filename, LastLocFilename) != 0) {
153    fprintf(stderr, "%s:%u:%u", Filename, LineNo, SM->getColumnNumber(PhysLoc));
154    LastLocFilename = Filename;
155    LastLocLine = LineNo;
156  } else if (LineNo != LastLocLine) {
157    fprintf(stderr, "line:%u:%u", LineNo, SM->getColumnNumber(PhysLoc));
158    LastLocLine = LineNo;
159  } else {
160    fprintf(stderr, "col:%u", SM->getColumnNumber(PhysLoc));
161  }
162}
163
164void StmtDumper::DumpSourceRange(const Stmt *Node) {
165  // Can't translate locations if a SourceManager isn't available.
166  if (SM == 0) return;
167
168  // TODO: If the parent expression is available, we can print a delta vs its
169  // location.
170  SourceRange R = Node->getSourceRange();
171
172  fprintf(stderr, " <");
173  DumpLocation(R.getBegin());
174  if (R.getBegin() != R.getEnd()) {
175    fprintf(stderr, ", ");
176    DumpLocation(R.getEnd());
177  }
178  fprintf(stderr, ">");
179
180  // <t2.c:123:421[blah], t2.c:412:321>
181
182}
183
184
185//===----------------------------------------------------------------------===//
186//  Stmt printing methods.
187//===----------------------------------------------------------------------===//
188
189void StmtDumper::VisitStmt(Stmt *Node) {
190  DumpStmt(Node);
191}
192
193void StmtDumper::DumpDeclarator(Decl *D) {
194  // FIXME: Need to complete/beautify this... this code simply shows the
195  // nodes are where they need to be.
196  if (TypedefDecl *localType = dyn_cast<TypedefDecl>(D)) {
197    fprintf(F, "\"typedef %s %s\"",
198            localType->getUnderlyingType().getAsString().c_str(),
199            localType->getName());
200  } else if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) {
201    fprintf(F, "\"");
202    // Emit storage class for vardecls.
203    if (VarDecl *V = dyn_cast<VarDecl>(VD)) {
204      switch (V->getStorageClass()) {
205      default: assert(0 && "Unknown storage class!");
206      case VarDecl::None:     break;
207      case VarDecl::Extern:   fprintf(F, "extern "); break;
208      case VarDecl::Static:   fprintf(F, "static "); break;
209      case VarDecl::Auto:     fprintf(F, "auto "); break;
210      case VarDecl::Register: fprintf(F, "register "); break;
211      }
212    }
213
214    std::string Name = VD->getName();
215    VD->getType().getAsStringInternal(Name);
216    fprintf(F, "%s", Name.c_str());
217
218    // If this is a vardecl with an initializer, emit it.
219    if (VarDecl *V = dyn_cast<VarDecl>(VD)) {
220      if (V->getInit()) {
221        fprintf(F, " =\n");
222        DumpSubTree(V->getInit());
223      }
224    }
225    fprintf(F, "\"");
226  } else if (TagDecl *TD = dyn_cast<TagDecl>(D)) {
227    // print a free standing tag decl (e.g. "struct x;").
228    const char *tagname;
229    if (const IdentifierInfo *II = TD->getIdentifier())
230      tagname = II->getName();
231    else
232      tagname = "<anonymous>";
233    fprintf(F, "\"%s %s;\"", TD->getKindName(), tagname);
234    // FIXME: print tag bodies.
235  } else {
236    assert(0 && "Unexpected decl");
237  }
238}
239
240void StmtDumper::VisitDeclStmt(DeclStmt *Node) {
241  DumpStmt(Node);
242  fprintf(F,"\n");
243  for (ScopedDecl *D = Node->getDecl(); D; D = D->getNextDeclarator()) {
244    ++IndentLevel;
245    Indent();
246    fprintf(F, "%p ", (void*) D);
247    DumpDeclarator(D);
248    if (D->getNextDeclarator())
249      fprintf(F,"\n");
250    --IndentLevel;
251  }
252}
253
254void StmtDumper::VisitLabelStmt(LabelStmt *Node) {
255  DumpStmt(Node);
256  fprintf(F, " '%s'\n", Node->getName());
257}
258
259void StmtDumper::VisitGotoStmt(GotoStmt *Node) {
260  DumpStmt(Node);
261  fprintf(F, " '%s':%p", Node->getLabel()->getName(), (void*)Node->getLabel());
262}
263
264//===----------------------------------------------------------------------===//
265//  Expr printing methods.
266//===----------------------------------------------------------------------===//
267
268void StmtDumper::VisitExpr(Expr *Node) {
269  DumpExpr(Node);
270}
271
272void StmtDumper::VisitDeclRefExpr(DeclRefExpr *Node) {
273  DumpExpr(Node);
274
275  fprintf(F, " ");
276  switch (Node->getDecl()->getKind()) {
277    case Decl::Function: fprintf(F,"FunctionDecl"); break;
278    case Decl::BlockVar: fprintf(F,"BlockVar"); break;
279    case Decl::FileVar: fprintf(F,"FileVar"); break;
280    case Decl::ParmVar: fprintf(F,"ParmVar"); break;
281    case Decl::EnumConstant: fprintf(F,"EnumConstant"); break;
282    case Decl::Typedef: fprintf(F,"Typedef"); break;
283    case Decl::Struct: fprintf(F,"Struct"); break;
284    case Decl::Union: fprintf(F,"Union"); break;
285    case Decl::Class: fprintf(F,"Class"); break;
286    case Decl::Enum: fprintf(F,"Enum"); break;
287    case Decl::ObjcInterface: fprintf(F,"ObjcInterface"); break;
288    case Decl::ObjcClass: fprintf(F,"ObjcClass"); break;
289    default: fprintf(F,"Decl"); break;
290  }
291
292  fprintf(F, "='%s' %p", Node->getDecl()->getName(), (void*)Node->getDecl());
293}
294
295void StmtDumper::VisitPreDefinedExpr(PreDefinedExpr *Node) {
296  DumpExpr(Node);
297  switch (Node->getIdentType()) {
298  default:
299    assert(0 && "unknown case");
300  case PreDefinedExpr::Func:
301    fprintf(F, " __func__");
302    break;
303  case PreDefinedExpr::Function:
304    fprintf(F, " __FUNCTION__");
305    break;
306  case PreDefinedExpr::PrettyFunction:
307    fprintf(F, " __PRETTY_FUNCTION__");
308    break;
309  }
310}
311
312void StmtDumper::VisitCharacterLiteral(CharacterLiteral *Node) {
313  DumpExpr(Node);
314  fprintf(F, " %d", Node->getValue());
315}
316
317void StmtDumper::VisitIntegerLiteral(IntegerLiteral *Node) {
318  DumpExpr(Node);
319
320  bool isSigned = Node->getType()->isSignedIntegerType();
321  fprintf(F, " %s", Node->getValue().toString(10, isSigned).c_str());
322}
323void StmtDumper::VisitFloatingLiteral(FloatingLiteral *Node) {
324  DumpExpr(Node);
325  fprintf(F, " %f", Node->getValueAsDouble());
326}
327
328void StmtDumper::VisitStringLiteral(StringLiteral *Str) {
329  DumpExpr(Str);
330  // FIXME: this doesn't print wstrings right.
331  fprintf(F, " %s\"", Str->isWide() ? "L" : "");
332
333  for (unsigned i = 0, e = Str->getByteLength(); i != e; ++i) {
334    switch (char C = Str->getStrData()[i]) {
335    default:
336      if (isprint(C))
337        fputc(C, F);
338      else
339        fprintf(F, "\\%03o", C);
340      break;
341    // Handle some common ones to make dumps prettier.
342    case '\\': fprintf(F, "\\\\"); break;
343    case '"':  fprintf(F, "\\\""); break;
344    case '\n': fprintf(F, "\\n"); break;
345    case '\t': fprintf(F, "\\t"); break;
346    case '\a': fprintf(F, "\\a"); break;
347    case '\b': fprintf(F, "\\b"); break;
348    }
349  }
350  fprintf(F, "\"");
351}
352
353void StmtDumper::VisitUnaryOperator(UnaryOperator *Node) {
354  DumpExpr(Node);
355  fprintf(F, " %s '%s'", Node->isPostfix() ? "postfix" : "prefix",
356          UnaryOperator::getOpcodeStr(Node->getOpcode()));
357}
358void StmtDumper::VisitSizeOfAlignOfTypeExpr(SizeOfAlignOfTypeExpr *Node) {
359  DumpExpr(Node);
360  fprintf(F, " %s ", Node->isSizeOf() ? "sizeof" : "alignof");
361  DumpType(Node->getArgumentType());
362}
363
364void StmtDumper::VisitMemberExpr(MemberExpr *Node) {
365  DumpExpr(Node);
366  fprintf(F, " %s%s %p", Node->isArrow() ? "->" : ".",
367          Node->getMemberDecl()->getName(), (void*)Node->getMemberDecl());
368}
369void StmtDumper::VisitOCUVectorElementExpr(OCUVectorElementExpr *Node) {
370  DumpExpr(Node);
371  fprintf(F, " %s", Node->getAccessor().getName());
372}
373void StmtDumper::VisitBinaryOperator(BinaryOperator *Node) {
374  DumpExpr(Node);
375  fprintf(F, " '%s'", BinaryOperator::getOpcodeStr(Node->getOpcode()));
376}
377void StmtDumper::VisitCompoundAssignOperator(CompoundAssignOperator *Node) {
378  DumpExpr(Node);
379  fprintf(F, " '%s' ComputeTy=",
380          BinaryOperator::getOpcodeStr(Node->getOpcode()));
381  DumpType(Node->getComputationType());
382}
383
384// GNU extensions.
385
386void StmtDumper::VisitAddrLabelExpr(AddrLabelExpr *Node) {
387  DumpExpr(Node);
388  fprintf(F, " %s %p", Node->getLabel()->getName(), (void*)Node->getLabel());
389}
390
391void StmtDumper::VisitTypesCompatibleExpr(TypesCompatibleExpr *Node) {
392  DumpExpr(Node);
393  fprintf(F, " ");
394  DumpType(Node->getArgType1());
395  fprintf(F, " ");
396  DumpType(Node->getArgType2());
397}
398
399//===----------------------------------------------------------------------===//
400// C++ Expressions
401//===----------------------------------------------------------------------===//
402
403void StmtDumper::VisitCXXCastExpr(CXXCastExpr *Node) {
404  DumpExpr(Node);
405  fprintf(F, " %s", CXXCastExpr::getOpcodeStr(Node->getOpcode()));
406}
407
408void StmtDumper::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node) {
409  DumpExpr(Node);
410  fprintf(F, " %s", Node->getValue() ? "true" : "false");
411}
412
413//===----------------------------------------------------------------------===//
414// Obj-C Expressions
415//===----------------------------------------------------------------------===//
416
417void StmtDumper::VisitObjCEncodeExpr(ObjCEncodeExpr *Node) {
418  DumpExpr(Node);
419
420  fprintf(F, " ");
421  DumpType(Node->getEncodedType());
422}
423
424void StmtDumper::VisitObjCSelectorExpr(ObjCSelectorExpr *Node) {
425  DumpExpr(Node);
426
427  fprintf(F, " ");
428  Selector &selector = Node->getSelector();
429  fprintf(F, "%s", selector.getName().c_str());
430}
431
432void StmtDumper::VisitObjCProtocolExpr(ObjCProtocolExpr *Node) {
433  DumpExpr(Node);
434
435  fprintf(F, " ");
436  fprintf(F, "%s", Node->getProtocol()->getName());
437}
438//===----------------------------------------------------------------------===//
439// Stmt method implementations
440//===----------------------------------------------------------------------===//
441
442/// dump - This does a local dump of the specified AST fragment.  It dumps the
443/// specified node and a few nodes underneath it, but not the whole subtree.
444/// This is useful in a debugger.
445void Stmt::dump(SourceManager &SM) const {
446  StmtDumper P(&SM, stderr, 4);
447  P.DumpSubTree(const_cast<Stmt*>(this));
448  fprintf(stderr, "\n");
449}
450
451/// dump - This does a local dump of the specified AST fragment.  It dumps the
452/// specified node and a few nodes underneath it, but not the whole subtree.
453/// This is useful in a debugger.
454void Stmt::dump() const {
455  StmtDumper P(0, stderr, 4);
456  P.DumpSubTree(const_cast<Stmt*>(this));
457  fprintf(stderr, "\n");
458}
459
460/// dumpAll - This does a dump of the specified AST fragment and all subtrees.
461void Stmt::dumpAll(SourceManager &SM) const {
462  StmtDumper P(&SM, stderr, ~0U);
463  P.DumpSubTree(const_cast<Stmt*>(this));
464  fprintf(stderr, "\n");
465}
466
467/// dumpAll - This does a dump of the specified AST fragment and all subtrees.
468void Stmt::dumpAll() const {
469  StmtDumper P(0, stderr, ~0U);
470  P.DumpSubTree(const_cast<Stmt*>(this));
471  fprintf(stderr, "\n");
472}
473