1 //===--- StmtDumper.cpp - Dumping implementation for Stmt ASTs ------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
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.
13 //===----------------------------------------------------------------------===//
15 #include "clang/AST/StmtVisitor.h"
16 #include "clang/AST/DeclObjC.h"
17 #include "clang/AST/DeclCXX.h"
18 #include "clang/AST/PrettyPrinter.h"
19 #include "clang/Basic/SourceManager.h"
20 #include "llvm/Support/raw_ostream.h"
21 using namespace clang
;
23 //===----------------------------------------------------------------------===//
25 //===----------------------------------------------------------------------===//
28 class StmtDumper
: public StmtVisitor
<StmtDumper
> {
30 llvm::raw_ostream
&OS
;
33 /// MaxDepth - When doing a normal dump (not dumpAll) we only want to dump
34 /// the first few levels of an AST. This keeps track of how many ast levels
38 /// LastLocFilename/LastLocLine - Keep track of the last location we print
39 /// out so that we can print out deltas from then on out.
40 const char *LastLocFilename
;
44 StmtDumper(SourceManager
*sm
, llvm::raw_ostream
&os
, unsigned maxDepth
)
45 : SM(sm
), OS(os
), IndentLevel(0-1), MaxDepth(maxDepth
) {
50 void DumpSubTree(Stmt
*S
) {
51 // Prune the recursion if not using dump all.
52 if (MaxDepth
== 0) return;
56 if (DeclStmt
* DS
= dyn_cast
<DeclStmt
>(S
))
61 // Print out children.
62 Stmt::child_range CI
= S
->children();
78 void DumpDeclarator(Decl
*D
);
81 for (int i
= 0, e
= IndentLevel
; i
< e
; ++i
)
85 void DumpType(QualType T
) {
86 SplitQualType T_split
= T
.split();
87 OS
<< "'" << QualType::getAsString(T_split
) << "'";
90 // If the type is sugared, also dump a (shallow) desugared type.
91 SplitQualType D_split
= T
.getSplitDesugaredType();
92 if (T_split
!= D_split
)
93 OS
<< ":'" << QualType::getAsString(D_split
) << "'";
96 void DumpDeclRef(Decl
*node
);
97 void DumpStmt(const Stmt
*Node
) {
99 OS
<< "(" << Node
->getStmtClassName()
100 << " " << (void*)Node
;
101 DumpSourceRange(Node
);
103 void DumpValueKind(ExprValueKind K
) {
105 case VK_RValue
: break;
106 case VK_LValue
: OS
<< " lvalue"; break;
107 case VK_XValue
: OS
<< " xvalue"; break;
110 void DumpObjectKind(ExprObjectKind K
) {
112 case OK_Ordinary
: break;
113 case OK_BitField
: OS
<< " bitfield"; break;
114 case OK_ObjCProperty
: OS
<< " objcproperty"; break;
115 case OK_VectorComponent
: OS
<< " vectorcomponent"; break;
118 void DumpExpr(const Expr
*Node
) {
121 DumpType(Node
->getType());
122 DumpValueKind(Node
->getValueKind());
123 DumpObjectKind(Node
->getObjectKind());
125 void DumpSourceRange(const Stmt
*Node
);
126 void DumpLocation(SourceLocation Loc
);
129 void VisitStmt(Stmt
*Node
);
130 void VisitDeclStmt(DeclStmt
*Node
);
131 void VisitLabelStmt(LabelStmt
*Node
);
132 void VisitGotoStmt(GotoStmt
*Node
);
135 void VisitExpr(Expr
*Node
);
136 void VisitCastExpr(CastExpr
*Node
);
137 void VisitDeclRefExpr(DeclRefExpr
*Node
);
138 void VisitPredefinedExpr(PredefinedExpr
*Node
);
139 void VisitCharacterLiteral(CharacterLiteral
*Node
);
140 void VisitIntegerLiteral(IntegerLiteral
*Node
);
141 void VisitFloatingLiteral(FloatingLiteral
*Node
);
142 void VisitStringLiteral(StringLiteral
*Str
);
143 void VisitUnaryOperator(UnaryOperator
*Node
);
144 void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr
*Node
);
145 void VisitMemberExpr(MemberExpr
*Node
);
146 void VisitExtVectorElementExpr(ExtVectorElementExpr
*Node
);
147 void VisitBinaryOperator(BinaryOperator
*Node
);
148 void VisitCompoundAssignOperator(CompoundAssignOperator
*Node
);
149 void VisitAddrLabelExpr(AddrLabelExpr
*Node
);
150 void VisitBlockExpr(BlockExpr
*Node
);
153 void VisitCXXNamedCastExpr(CXXNamedCastExpr
*Node
);
154 void VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr
*Node
);
155 void VisitCXXThisExpr(CXXThisExpr
*Node
);
156 void VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr
*Node
);
157 void VisitCXXConstructExpr(CXXConstructExpr
*Node
);
158 void VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr
*Node
);
159 void VisitExprWithCleanups(ExprWithCleanups
*Node
);
160 void VisitUnresolvedLookupExpr(UnresolvedLookupExpr
*Node
);
161 void DumpCXXTemporary(CXXTemporary
*Temporary
);
164 void VisitObjCAtCatchStmt(ObjCAtCatchStmt
*Node
);
165 void VisitObjCEncodeExpr(ObjCEncodeExpr
*Node
);
166 void VisitObjCMessageExpr(ObjCMessageExpr
* Node
);
167 void VisitObjCSelectorExpr(ObjCSelectorExpr
*Node
);
168 void VisitObjCProtocolExpr(ObjCProtocolExpr
*Node
);
169 void VisitObjCPropertyRefExpr(ObjCPropertyRefExpr
*Node
);
170 void VisitObjCIvarRefExpr(ObjCIvarRefExpr
*Node
);
174 //===----------------------------------------------------------------------===//
176 //===----------------------------------------------------------------------===//
178 void StmtDumper::DumpLocation(SourceLocation Loc
) {
179 SourceLocation SpellingLoc
= SM
->getSpellingLoc(Loc
);
181 // The general format we print out is filename:line:col, but we drop pieces
182 // that haven't changed since the last loc printed.
183 PresumedLoc PLoc
= SM
->getPresumedLoc(SpellingLoc
);
185 if (PLoc
.isInvalid()) {
186 OS
<< "<invalid sloc>";
190 if (strcmp(PLoc
.getFilename(), LastLocFilename
) != 0) {
191 OS
<< PLoc
.getFilename() << ':' << PLoc
.getLine()
192 << ':' << PLoc
.getColumn();
193 LastLocFilename
= PLoc
.getFilename();
194 LastLocLine
= PLoc
.getLine();
195 } else if (PLoc
.getLine() != LastLocLine
) {
196 OS
<< "line" << ':' << PLoc
.getLine()
197 << ':' << PLoc
.getColumn();
198 LastLocLine
= PLoc
.getLine();
200 OS
<< "col" << ':' << PLoc
.getColumn();
204 void StmtDumper::DumpSourceRange(const Stmt
*Node
) {
205 // Can't translate locations if a SourceManager isn't available.
208 // TODO: If the parent expression is available, we can print a delta vs its
210 SourceRange R
= Node
->getSourceRange();
213 DumpLocation(R
.getBegin());
214 if (R
.getBegin() != R
.getEnd()) {
216 DumpLocation(R
.getEnd());
220 // <t2.c:123:421[blah], t2.c:412:321>
225 //===----------------------------------------------------------------------===//
226 // Stmt printing methods.
227 //===----------------------------------------------------------------------===//
229 void StmtDumper::VisitStmt(Stmt
*Node
) {
233 void StmtDumper::DumpDeclarator(Decl
*D
) {
234 // FIXME: Need to complete/beautify this... this code simply shows the
235 // nodes are where they need to be.
236 if (TypedefDecl
*localType
= dyn_cast
<TypedefDecl
>(D
)) {
237 OS
<< "\"typedef " << localType
->getUnderlyingType().getAsString()
238 << ' ' << localType
<< '"';
239 } else if (ValueDecl
*VD
= dyn_cast
<ValueDecl
>(D
)) {
241 // Emit storage class for vardecls.
242 if (VarDecl
*V
= dyn_cast
<VarDecl
>(VD
)) {
243 if (V
->getStorageClass() != SC_None
)
244 OS
<< VarDecl::getStorageClassSpecifierString(V
->getStorageClass())
248 std::string Name
= VD
->getNameAsString();
249 VD
->getType().getAsStringInternal(Name
,
250 PrintingPolicy(VD
->getASTContext().getLangOptions()));
253 // If this is a vardecl with an initializer, emit it.
254 if (VarDecl
*V
= dyn_cast
<VarDecl
>(VD
)) {
257 DumpSubTree(V
->getInit());
261 } else if (TagDecl
*TD
= dyn_cast
<TagDecl
>(D
)) {
262 // print a free standing tag decl (e.g. "struct x;").
264 if (const IdentifierInfo
*II
= TD
->getIdentifier())
265 tagname
= II
->getNameStart();
267 tagname
= "<anonymous>";
268 OS
<< '"' << TD
->getKindName() << ' ' << tagname
<< ";\"";
269 // FIXME: print tag bodies.
270 } else if (UsingDirectiveDecl
*UD
= dyn_cast
<UsingDirectiveDecl
>(D
)) {
271 // print using-directive decl (e.g. "using namespace x;")
273 if (const IdentifierInfo
*II
= UD
->getNominatedNamespace()->getIdentifier())
274 ns
= II
->getNameStart();
277 OS
<< '"' << UD
->getDeclKindName() << ns
<< ";\"";
278 } else if (UsingDecl
*UD
= dyn_cast
<UsingDecl
>(D
)) {
279 // print using decl (e.g. "using std::string;")
280 const char *tn
= UD
->isTypeName() ? "typename " : "";
281 OS
<< '"' << UD
->getDeclKindName() << tn
;
282 UD
->getTargetNestedNameDecl()->print(OS
,
283 PrintingPolicy(UD
->getASTContext().getLangOptions()));
285 } else if (LabelDecl
*LD
= dyn_cast
<LabelDecl
>(D
)) {
286 OS
<< "label " << LD
->getNameAsString();
288 assert(0 && "Unexpected decl");
292 void StmtDumper::VisitDeclStmt(DeclStmt
*Node
) {
295 for (DeclStmt::decl_iterator DI
= Node
->decl_begin(), DE
= Node
->decl_end();
300 OS
<< (void*) D
<< " ";
308 void StmtDumper::VisitLabelStmt(LabelStmt
*Node
) {
310 OS
<< " '" << Node
->getName() << "'";
313 void StmtDumper::VisitGotoStmt(GotoStmt
*Node
) {
315 OS
<< " '" << Node
->getLabel()->getName()
316 << "':" << (void*)Node
->getLabel();
319 //===----------------------------------------------------------------------===//
320 // Expr printing methods.
321 //===----------------------------------------------------------------------===//
323 void StmtDumper::VisitExpr(Expr
*Node
) {
327 static void DumpBasePath(llvm::raw_ostream
&OS
, CastExpr
*Node
) {
328 if (Node
->path_empty())
333 for (CastExpr::path_iterator
334 I
= Node
->path_begin(), E
= Node
->path_end(); I
!= E
; ++I
) {
335 const CXXBaseSpecifier
*Base
= *I
;
339 const CXXRecordDecl
*RD
=
340 cast
<CXXRecordDecl
>(Base
->getType()->getAs
<RecordType
>()->getDecl());
342 if (Base
->isVirtual())
351 void StmtDumper::VisitCastExpr(CastExpr
*Node
) {
353 OS
<< " <" << Node
->getCastKindName();
354 DumpBasePath(OS
, Node
);
358 void StmtDumper::VisitDeclRefExpr(DeclRefExpr
*Node
) {
362 DumpDeclRef(Node
->getDecl());
365 void StmtDumper::DumpDeclRef(Decl
*d
) {
366 OS
<< d
->getDeclKindName() << ' ' << (void*) d
;
368 if (NamedDecl
*nd
= dyn_cast
<NamedDecl
>(d
)) {
370 nd
->getDeclName().printName(OS
);
374 if (ValueDecl
*vd
= dyn_cast
<ValueDecl
>(d
)) {
375 OS
<< ' '; DumpType(vd
->getType());
379 void StmtDumper::VisitUnresolvedLookupExpr(UnresolvedLookupExpr
*Node
) {
382 if (!Node
->requiresADL()) OS
<< "no ";
383 OS
<< "ADL) = '" << Node
->getName() << '\'';
385 UnresolvedLookupExpr::decls_iterator
386 I
= Node
->decls_begin(), E
= Node
->decls_end();
387 if (I
== E
) OS
<< " empty";
389 OS
<< " " << (void*) *I
;
392 void StmtDumper::VisitObjCIvarRefExpr(ObjCIvarRefExpr
*Node
) {
395 OS
<< " " << Node
->getDecl()->getDeclKindName()
396 << "Decl='" << Node
->getDecl()
397 << "' " << (void*)Node
->getDecl();
398 if (Node
->isFreeIvar())
402 void StmtDumper::VisitPredefinedExpr(PredefinedExpr
*Node
) {
404 switch (Node
->getIdentType()) {
405 default: assert(0 && "unknown case");
406 case PredefinedExpr::Func
: OS
<< " __func__"; break;
407 case PredefinedExpr::Function
: OS
<< " __FUNCTION__"; break;
408 case PredefinedExpr::PrettyFunction
: OS
<< " __PRETTY_FUNCTION__";break;
412 void StmtDumper::VisitCharacterLiteral(CharacterLiteral
*Node
) {
414 OS
<< Node
->getValue();
417 void StmtDumper::VisitIntegerLiteral(IntegerLiteral
*Node
) {
420 bool isSigned
= Node
->getType()->isSignedIntegerType();
421 OS
<< " " << Node
->getValue().toString(10, isSigned
);
423 void StmtDumper::VisitFloatingLiteral(FloatingLiteral
*Node
) {
425 OS
<< " " << Node
->getValueAsApproximateDouble();
428 void StmtDumper::VisitStringLiteral(StringLiteral
*Str
) {
430 // FIXME: this doesn't print wstrings right.
435 OS
.write_escaped(Str
->getString());
439 void StmtDumper::VisitUnaryOperator(UnaryOperator
*Node
) {
441 OS
<< " " << (Node
->isPostfix() ? "postfix" : "prefix")
442 << " '" << UnaryOperator::getOpcodeStr(Node
->getOpcode()) << "'";
444 void StmtDumper::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr
*Node
) {
446 OS
<< " " << (Node
->isSizeOf() ? "sizeof" : "alignof") << " ";
447 if (Node
->isArgumentType())
448 DumpType(Node
->getArgumentType());
451 void StmtDumper::VisitMemberExpr(MemberExpr
*Node
) {
453 OS
<< " " << (Node
->isArrow() ? "->" : ".")
454 << Node
->getMemberDecl() << ' '
455 << (void*)Node
->getMemberDecl();
457 void StmtDumper::VisitExtVectorElementExpr(ExtVectorElementExpr
*Node
) {
459 OS
<< " " << Node
->getAccessor().getNameStart();
461 void StmtDumper::VisitBinaryOperator(BinaryOperator
*Node
) {
463 OS
<< " '" << BinaryOperator::getOpcodeStr(Node
->getOpcode()) << "'";
465 void StmtDumper::VisitCompoundAssignOperator(CompoundAssignOperator
*Node
) {
467 OS
<< " '" << BinaryOperator::getOpcodeStr(Node
->getOpcode())
468 << "' ComputeLHSTy=";
469 DumpType(Node
->getComputationLHSType());
470 OS
<< " ComputeResultTy=";
471 DumpType(Node
->getComputationResultType());
474 void StmtDumper::VisitBlockExpr(BlockExpr
*Node
) {
478 BlockDecl
*block
= Node
->getBlockDecl();
479 if (block
->capturesCXXThis()) {
480 OS
<< '\n'; Indent(); OS
<< "(capture this)";
482 for (BlockDecl::capture_iterator
483 i
= block
->capture_begin(), e
= block
->capture_end(); i
!= e
; ++i
) {
487 if (i
->isByRef()) OS
<< "byref ";
488 if (i
->isNested()) OS
<< "nested ";
489 DumpDeclRef(i
->getVariable());
490 if (i
->hasCopyExpr()) DumpSubTree(i
->getCopyExpr());
495 DumpSubTree(block
->getBody());
500 void StmtDumper::VisitAddrLabelExpr(AddrLabelExpr
*Node
) {
502 OS
<< " " << Node
->getLabel()->getName()
503 << " " << (void*)Node
->getLabel();
506 //===----------------------------------------------------------------------===//
508 //===----------------------------------------------------------------------===//
510 void StmtDumper::VisitCXXNamedCastExpr(CXXNamedCastExpr
*Node
) {
512 OS
<< " " << Node
->getCastName()
513 << "<" << Node
->getTypeAsWritten().getAsString() << ">"
514 << " <" << Node
->getCastKindName();
515 DumpBasePath(OS
, Node
);
519 void StmtDumper::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr
*Node
) {
521 OS
<< " " << (Node
->getValue() ? "true" : "false");
524 void StmtDumper::VisitCXXThisExpr(CXXThisExpr
*Node
) {
529 void StmtDumper::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr
*Node
) {
531 OS
<< " functional cast to " << Node
->getTypeAsWritten().getAsString();
534 void StmtDumper::VisitCXXConstructExpr(CXXConstructExpr
*Node
) {
536 CXXConstructorDecl
*Ctor
= Node
->getConstructor();
537 DumpType(Ctor
->getType());
538 if (Node
->isElidable())
540 if (Node
->requiresZeroInitialization())
544 void StmtDumper::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr
*Node
) {
547 DumpCXXTemporary(Node
->getTemporary());
550 void StmtDumper::VisitExprWithCleanups(ExprWithCleanups
*Node
) {
553 for (unsigned i
= 0, e
= Node
->getNumTemporaries(); i
!= e
; ++i
) {
556 DumpCXXTemporary(Node
->getTemporary(i
));
561 void StmtDumper::DumpCXXTemporary(CXXTemporary
*Temporary
) {
562 OS
<< "(CXXTemporary " << (void *)Temporary
<< ")";
565 //===----------------------------------------------------------------------===//
567 //===----------------------------------------------------------------------===//
569 void StmtDumper::VisitObjCMessageExpr(ObjCMessageExpr
* Node
) {
571 OS
<< " selector=" << Node
->getSelector().getAsString();
572 switch (Node
->getReceiverKind()) {
573 case ObjCMessageExpr::Instance
:
576 case ObjCMessageExpr::Class
:
578 DumpType(Node
->getClassReceiver());
581 case ObjCMessageExpr::SuperInstance
:
582 OS
<< " super (instance)";
585 case ObjCMessageExpr::SuperClass
:
586 OS
<< " super (class)";
591 void StmtDumper::VisitObjCAtCatchStmt(ObjCAtCatchStmt
*Node
) {
593 if (VarDecl
*CatchParam
= Node
->getCatchParamDecl()) {
594 OS
<< " catch parm = ";
595 DumpDeclarator(CatchParam
);
601 void StmtDumper::VisitObjCEncodeExpr(ObjCEncodeExpr
*Node
) {
604 DumpType(Node
->getEncodedType());
607 void StmtDumper::VisitObjCSelectorExpr(ObjCSelectorExpr
*Node
) {
610 OS
<< " " << Node
->getSelector().getAsString();
613 void StmtDumper::VisitObjCProtocolExpr(ObjCProtocolExpr
*Node
) {
616 OS
<< ' ' << Node
->getProtocol();
619 void StmtDumper::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr
*Node
) {
621 if (Node
->isImplicitProperty()) {
622 OS
<< " Kind=MethodRef Getter=\"";
623 if (Node
->getImplicitPropertyGetter())
624 OS
<< Node
->getImplicitPropertyGetter()->getSelector().getAsString();
628 OS
<< "\" Setter=\"";
629 if (ObjCMethodDecl
*Setter
= Node
->getImplicitPropertySetter())
630 OS
<< Setter
->getSelector().getAsString();
635 OS
<< " Kind=PropertyRef Property=\"" << Node
->getExplicitProperty() << '"';
638 if (Node
->isSuperReceiver())
642 //===----------------------------------------------------------------------===//
643 // Stmt method implementations
644 //===----------------------------------------------------------------------===//
646 /// dump - This does a local dump of the specified AST fragment. It dumps the
647 /// specified node and a few nodes underneath it, but not the whole subtree.
648 /// This is useful in a debugger.
649 void Stmt::dump(SourceManager
&SM
) const {
650 dump(llvm::errs(), SM
);
653 void Stmt::dump(llvm::raw_ostream
&OS
, SourceManager
&SM
) const {
654 StmtDumper
P(&SM
, OS
, 4);
655 P
.DumpSubTree(const_cast<Stmt
*>(this));
659 /// dump - This does a local dump of the specified AST fragment. It dumps the
660 /// specified node and a few nodes underneath it, but not the whole subtree.
661 /// This is useful in a debugger.
662 void Stmt::dump() const {
663 StmtDumper
P(0, llvm::errs(), 4);
664 P
.DumpSubTree(const_cast<Stmt
*>(this));
665 llvm::errs() << "\n";
668 /// dumpAll - This does a dump of the specified AST fragment and all subtrees.
669 void Stmt::dumpAll(SourceManager
&SM
) const {
670 StmtDumper
P(&SM
, llvm::errs(), ~0U);
671 P
.DumpSubTree(const_cast<Stmt
*>(this));
672 llvm::errs() << "\n";
675 /// dumpAll - This does a dump of the specified AST fragment and all subtrees.
676 void Stmt::dumpAll() const {
677 StmtDumper
P(0, llvm::errs(), ~0U);
678 P
.DumpSubTree(const_cast<Stmt
*>(this));
679 llvm::errs() << "\n";