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