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