Instead of printing spaces at the beginning of a line, use '|', '-' and '\' to
display the tree. This addition will make reading the AST easier, especially
with line-spanning nodes.
Indenting:
Indenting is still handled by IndentScope. Instead of an unsigned, a vector is
used to track the indent status. The vector is easily transformed to the
proper output in indent().
Last Child:
Determining the last child of a node is important to printing the proper tree.
Each caller is responsible to call lastChild() before each possible last child.
In order to prevent multiple calls to lastChild() from messing up the indents,
hasMoreChildren(true) can be called, which prevents the effects of lastChild()
from taking effect. hasMoreChildren(false) will allow lastChild() to work
again.
http://llvm-reviews.chandlerc.com/D281
Files:
utils/TableGen/ClangAttrEmitter.cpp
lib/AST/ASTDumper.cpp
test/Misc/ast-dump-decl.c
test/Misc/ast-dump-attr.cpp
test/Misc/ast-dump-stmt.c
Index: utils/TableGen/ClangAttrEmitter.cpp
===================================================================
--- utils/TableGen/ClangAttrEmitter.cpp
+++ utils/TableGen/ClangAttrEmitter.cpp
@@ -127,6 +127,7 @@
virtual void writeValue(raw_ostream &OS) const = 0;
virtual void writeDump(raw_ostream &OS) const = 0;
virtual void writeDumpChildren(raw_ostream &OS) const {}
+ virtual void writeHasChildren(raw_ostream &OS) const { OS << "false"; }
};
class SimpleArgument : public Argument {
@@ -384,12 +385,16 @@
void writeDump(raw_ostream &OS) const {
}
void writeDumpChildren(raw_ostream &OS) const {
- OS << " if (SA->is" << getUpperName() << "Expr())\n";
+ OS << " if (SA->is" << getUpperName() << "Expr()) {\n";
+ OS << " lastChild();\n";
OS << " dumpStmt(SA->get" << getUpperName() << "Expr());\n";
- OS << " else\n";
+ OS << " } else\n";
OS << " dumpType(SA->get" << getUpperName()
<< "Type()->getType());\n";
}
+ void writeHasChildren(raw_ostream &OS) const {
+ OS << "SA->is" << getUpperName() << "Expr()";
+ }
};
class VariadicArgument : public Argument {
@@ -635,8 +640,10 @@
}
void writeDumpChildren(raw_ostream &OS) const {
+ OS << " lastChild();\n";
OS << " dumpStmt(SA->get" << getUpperName() << "());\n";
}
+ void writeHasChildren(raw_ostream &OS) const { OS << "true"; }
};
class VariadicExprArgument : public VariadicArgument {
@@ -676,9 +683,17 @@
void writeDumpChildren(raw_ostream &OS) const {
OS << " for (" << getAttrName() << "Attr::" << getLowerName()
<< "_iterator I = SA->" << getLowerName() << "_begin(), E = SA->"
- << getLowerName() << "_end(); I != E; ++I)\n";
+ << getLowerName() << "_end(); I != E; ++I) {\n";
+ OS << " if (I + 1 == E)\n";
+ OS << " lastChild();\n";
OS << " dumpStmt(*I);\n";
+ OS << " }\n";
}
+
+ void writeHasChildren(raw_ostream &OS) const {
+ OS << "SA->" << getLowerName() << "_begin() != "
+ << "SA->" << getLowerName() << "_end()";
+ }
};
}
@@ -1256,9 +1271,27 @@
for (std::vector<Record*>::iterator I = Args.begin(), E = Args.end();
I != E; ++I)
createArgument(**I, R.getName())->writeDump(OS);
+
+ // Code for detecting the last child.
+ OS << " bool oldMoreChildren = hasMoreChildren();\n";
+ OS << " bool MoreChildren = oldMoreChildren;\n";
+
for (std::vector<Record*>::iterator I = Args.begin(), E = Args.end();
- I != E; ++I)
+ I != E; ++I) {
+ // More code for detecting the last child.
+ OS << " MoreChildren = oldMoreChildren";
+ for (std::vector<Record*>::iterator Next = I + 1; Next != E; ++Next) {
+ OS << " || ";
+ createArgument(**Next, R.getName())->writeHasChildren(OS);
+ }
+ OS << ";\n";
+ OS << " setMoreChildren(MoreChildren);\n";
+
createArgument(**I, R.getName())->writeDumpChildren(OS);
+ }
+
+ // Reset the last child.
+ OS << " setMoreChildren(oldMoreChildren);\n";
}
OS <<
" break;\n"
Index: lib/AST/ASTDumper.cpp
===================================================================
--- lib/AST/ASTDumper.cpp
+++ lib/AST/ASTDumper.cpp
@@ -32,9 +32,20 @@
: public DeclVisitor<ASTDumper>, public StmtVisitor<ASTDumper> {
SourceManager *SM;
raw_ostream &OS;
- unsigned IndentLevel;
bool IsFirstLine;
+ // Indicates whether more child are expected at the current tree depth
+ enum IndentType { IT_Child, IT_LastChild };
+
+ /// Indents - Indents[i] indicates if another child exists at level i.
+ /// Used by Indent() to print the tree structure.
+ llvm::SmallVector<IndentType, 32> Indents;
+
+ /// MoreChildren - Indicates that more children will be needed at this
+ /// indent level. If true, prevents lastChild() from marking the node
+ /// as the last child.
+ bool MoreChildren;
+
/// Keep track of the last location we print out so that we can
/// print out deltas from then on out.
const char *LastLocFilename;
@@ -42,18 +53,23 @@
class IndentScope {
ASTDumper &Dumper;
+ // Preserve the Dumper's MoreChildren value from the previous IndentScope
+ bool MoreChildren;
public:
IndentScope(ASTDumper &Dumper) : Dumper(Dumper) {
+ MoreChildren = Dumper.hasMoreChildren();
+ Dumper.setMoreChildren(false);
Dumper.indent();
}
~IndentScope() {
+ Dumper.setMoreChildren(MoreChildren);
Dumper.unindent();
}
};
public:
ASTDumper(SourceManager *SM, raw_ostream &OS)
- : SM(SM), OS(OS), IndentLevel(0), IsFirstLine(true),
+ : SM(SM), OS(OS), IsFirstLine(true), MoreChildren(false),
LastLocFilename(""), LastLocLine(~0U) { }
~ASTDumper() {
@@ -63,9 +79,14 @@
void dumpDecl(Decl *D);
void dumpStmt(Stmt *S);
- // Utilities
+ // Formatting
void indent();
void unindent();
+ void lastChild();
+ bool hasMoreChildren();
+ void setMoreChildren(bool Value);
+
+ // Utilities
void dumpPointer(const void *Ptr);
void dumpSourceRange(SourceRange R);
void dumpLocation(SourceLocation Loc);
@@ -74,6 +95,7 @@
void dumpBareDeclRef(const Decl *Node);
void dumpDeclRef(const Decl *Node, const char *Label = 0);
void dumpName(const NamedDecl *D);
+ bool hasNodes(const DeclContext *DC);
void dumpDeclContext(const DeclContext *DC);
void dumpAttr(const Attr *A);
@@ -195,21 +217,69 @@
// Utilities
//===----------------------------------------------------------------------===//
+// Print out the appropriate tree structure using the Indents vector.
+// Example of tree and the Indents vector at each level.
+// (A { }
+// |-(B { IT_Child }
+// | \-(C)) { IT_Child, IT_LastChild }
+// \-(D { IT_LastChild }
+// |-(E) { IT_LastChild, IT_Child }
+// \-(F))) { IT_LastChild, IT_LastChild }
+// Type non-last element, last element
+// IT_Child "| " "|-"
+// IT_LastChild " " "\-"
void ASTDumper::indent() {
if (IsFirstLine)
IsFirstLine = false;
else
OS << "\n";
- OS.indent(IndentLevel * 2);
+
+ for (llvm::SmallVector<IndentType, 32>::const_iterator I =
+ Indents.begin(), E = Indents.end();
+ I != E; ++I) {
+ switch (*I) {
+ case IT_Child:
+ if (I == E - 1)
+ OS << "|-";
+ else
+ OS << "| ";
+ break;
+ case IT_LastChild:
+ if (I == E - 1)
+ OS << "\\-";
+ else
+ OS << " ";
+ break;
+ default:
+ llvm_unreachable("Invalid IndentType");
+ }
+ }
OS << "(";
- IndentLevel++;
+ Indents.push_back(IT_Child);
}
void ASTDumper::unindent() {
+ Indents.pop_back();
OS << ")";
- IndentLevel--;
}
+// Call before each potential last child node is to be dumped. If MoreChildren
+// is false, then this is the last child, otherwise treat as a regular node.
+void ASTDumper::lastChild() {
+ if (!hasMoreChildren())
+ Indents.back() = IT_LastChild;
+}
+
+// MoreChildren should be set before calling another function that may print
+// additional nodes to prevent conflicting final child nodes.
+bool ASTDumper::hasMoreChildren() {
+ return MoreChildren;
+}
+
+void ASTDumper::setMoreChildren(bool Value) {
+ MoreChildren = Value;
+}
+
void ASTDumper::dumpPointer(const void *Ptr) {
OS << ' ' << Ptr;
}
@@ -303,12 +373,24 @@
OS << ' ' << ND->getNameAsString();
}
+bool ASTDumper::hasNodes(const DeclContext *DC) {
+ if (!DC)
+ return false;
+
+ return DC->decls_begin() != DC->decls_end();
+}
+
void ASTDumper::dumpDeclContext(const DeclContext *DC) {
if (!DC)
return;
for (DeclContext::decl_iterator I = DC->decls_begin(), E = DC->decls_end();
- I != E; ++I)
+ I != E; ++I) {
+ DeclContext::decl_iterator Next = I;
+ ++Next;
+ if (Next == E)
+ lastChild();
dumpDecl(*I);
+ }
}
void ASTDumper::dumpAttr(const Attr *A) {
@@ -367,8 +449,11 @@
void ASTDumper::dumpTemplateArgumentListInfo(
const TemplateArgumentListInfo &TALI) {
- for (unsigned i = 0, e = TALI.size(); i < e; ++i)
+ for (unsigned i = 0, e = TALI.size(); i < e; ++i) {
+ if (i + 1 == e)
+ lastChild();
dumpTemplateArgumentLoc(TALI[i]);
+ }
}
void ASTDumper::dumpTemplateArgumentLoc(const TemplateArgumentLoc &A) {
@@ -392,10 +477,12 @@
break;
case TemplateArgument::Type:
OS << " type";
+ lastChild();
dumpType(A.getAsType());
break;
case TemplateArgument::Declaration:
OS << " decl";
+ lastChild();
dumpDeclRef(A.getAsDecl());
break;
case TemplateArgument::NullPtr:
@@ -414,13 +501,17 @@
break;
case TemplateArgument::Expression:
OS << " expr";
+ lastChild();
dumpStmt(A.getAsExpr());
break;
case TemplateArgument::Pack:
OS << " pack";
for (TemplateArgument::pack_iterator I = A.pack_begin(), E = A.pack_end();
- I != E; ++I)
+ I != E; ++I) {
+ if (I + 1 == E)
+ lastChild();
dumpTemplateArgument(*I);
+ }
break;
}
}
@@ -431,7 +522,6 @@
void ASTDumper::dumpDecl(Decl *D) {
IndentScope Indent(*this);
-
if (!D) {
OS << "<<<NULL>>>";
return;
@@ -440,14 +530,26 @@
OS << D->getDeclKindName() << "Decl";
dumpPointer(D);
dumpSourceRange(D->getSourceRange());
+
+ bool HasAttrs = D->hasAttrs() && D->getAttrs().begin() != D->getAttrs().end();
+ bool HasDeclContext = !isa<FunctionDecl>(*D) && !isa<ObjCMethodDecl>(*D) &&
+ hasNodes(dyn_cast<DeclContext>(D));
+
+ setMoreChildren(HasAttrs || HasDeclContext);
DeclVisitor<ASTDumper>::Visit(D);
- if (D->hasAttrs()) {
+
+ setMoreChildren(HasDeclContext);
+ if (HasAttrs) {
for (AttrVec::const_iterator I = D->getAttrs().begin(),
- E = D->getAttrs().end(); I != E; ++I)
+ E = D->getAttrs().end(); I != E; ++I) {
+ if (I + 1 == E)
+ lastChild();
dumpAttr(*I);
+ }
}
// Decls within functions are visited by the body
- if (!isa<FunctionDecl>(*D) && !isa<ObjCMethodDecl>(*D))
+ setMoreChildren(false);
+ if (HasDeclContext)
dumpDeclContext(dyn_cast<DeclContext>(D));
}
@@ -486,16 +588,21 @@
void ASTDumper::VisitEnumConstantDecl(EnumConstantDecl *D) {
dumpName(D);
dumpType(D->getType());
- if (Expr *Init = D->getInitExpr())
+ if (Expr *Init = D->getInitExpr()) {
+ lastChild();
dumpStmt(Init);
+ }
}
void ASTDumper::VisitIndirectFieldDecl(IndirectFieldDecl *D) {
dumpName(D);
dumpType(D->getType());
for (IndirectFieldDecl::chain_iterator I = D->chain_begin(),
- E = D->chain_end(); I != E; ++I)
+ E = D->chain_end(); I != E; ++I) {
+ if (I + 1 == E)
+ lastChild();
dumpDeclRef(*I);
+ }
}
void ASTDumper::VisitFunctionDecl(FunctionDecl *D) {
@@ -517,26 +624,60 @@
else if (D->isDeletedAsWritten())
OS << " delete";
- if (const FunctionTemplateSpecializationInfo *FTSI =
- D->getTemplateSpecializationInfo())
+ bool oldMoreChildren = hasMoreChildren();
+ const FunctionTemplateSpecializationInfo *FTSI =
+ D->getTemplateSpecializationInfo();
+ bool hasTemplateSpecialization = FTSI;
+
+ bool hasNamedDecls = D->getDeclsInPrototypeScope().begin() !=
+ D->getDeclsInPrototypeScope().end();
+
+ bool hasFunctionDecls = D->param_begin() != D->param_end();
+
+ CXXConstructorDecl *C = dyn_cast<CXXConstructorDecl>(D);
+ bool hasCtorInitializers = C && C->init_begin() != C->init_end();
+
+ bool hasDeclarationBody = D->doesThisDeclarationHaveABody();
+
+ setMoreChildren(oldMoreChildren || hasNamedDecls || hasFunctionDecls ||
+ hasCtorInitializers || hasDeclarationBody);
+ if (hasTemplateSpecialization) {
+ lastChild();
dumpTemplateArgumentList(*FTSI->TemplateArguments);
+ }
+ setMoreChildren(oldMoreChildren || hasFunctionDecls ||
+ hasCtorInitializers || hasDeclarationBody);
for (llvm::ArrayRef<NamedDecl*>::iterator
I = D->getDeclsInPrototypeScope().begin(),
- E = D->getDeclsInPrototypeScope().end(); I != E; ++I)
+ E = D->getDeclsInPrototypeScope().end(); I != E; ++I) {
+ if (I + 1 == E)
+ lastChild();
dumpDecl(*I);
+ }
+ setMoreChildren(oldMoreChildren || hasCtorInitializers || hasDeclarationBody);
for (FunctionDecl::param_iterator I = D->param_begin(), E = D->param_end();
- I != E; ++I)
+ I != E; ++I) {
+ if (I + 1 == E)
+ lastChild();
dumpDecl(*I);
-
- if (CXXConstructorDecl *C = dyn_cast<CXXConstructorDecl>(D))
+ }
+
+ setMoreChildren(oldMoreChildren || hasDeclarationBody);
+ if (hasCtorInitializers)
for (CXXConstructorDecl::init_const_iterator I = C->init_begin(),
- E = C->init_end(); I != E; ++I)
+ E = C->init_end(); I != E; ++I) {
+ if (I + 1 == E)
+ lastChild();
dumpCXXCtorInitializer(*I);
+ }
- if (D->doesThisDeclarationHaveABody())
+ setMoreChildren(oldMoreChildren);
+ if (hasDeclarationBody) {
+ lastChild();
dumpStmt(D->getBody());
+ }
}
void ASTDumper::VisitFieldDecl(FieldDecl *D) {
@@ -546,10 +687,22 @@
OS << " mutable";
if (D->isModulePrivate())
OS << " __module_private__";
- if (D->isBitField())
+
+ bool oldMoreChildren = hasMoreChildren();
+ bool isBitField = D->isBitField();
+ Expr *Init = D->getInClassInitializer();
+ bool hasInit = Init;
+
+ setMoreChildren(oldMoreChildren || hasInit);
+ if (isBitField) {
+ lastChild();
dumpStmt(D->getBitWidth());
- if (Expr *Init = D->getInClassInitializer())
+ }
+ setMoreChildren(oldMoreChildren);
+ if (hasInit) {
+ lastChild();
dumpStmt(Init);
+ }
}
void ASTDumper::VisitVarDecl(VarDecl *D) {
@@ -564,11 +717,14 @@
OS << " __module_private__";
if (D->isNRVOVariable())
OS << " nrvo";
- if (D->hasInit())
+ if (D->hasInit()) {
+ lastChild();
dumpStmt(D->getInit());
+ }
}
void ASTDumper::VisitFileScopeAsmDecl(FileScopeAsmDecl *D) {
+ lastChild();
dumpStmt(D->getAsmString());
}
@@ -628,6 +784,7 @@
void ASTDumper::VisitStaticAssertDecl(StaticAssertDecl *D) {
dumpStmt(D->getAssertExpr());
+ lastChild();
dumpStmt(D->getMessage());
}
@@ -637,6 +794,10 @@
dumpDecl(D->getTemplatedDecl());
for (FunctionTemplateDecl::spec_iterator I = D->spec_begin(),
E = D->spec_end(); I != E; ++I) {
+ FunctionTemplateDecl::spec_iterator Next = I;
+ ++Next;
+ if (Next == E)
+ lastChild();
switch (I->getTemplateSpecializationKind()) {
case TSK_Undeclared:
case TSK_ImplicitInstantiation:
@@ -654,9 +815,16 @@
void ASTDumper::VisitClassTemplateDecl(ClassTemplateDecl *D) {
dumpName(D);
dumpTemplateParameters(D->getTemplateParameters());
+
+ if (D->spec_begin() == D->spec_end())
+ lastChild();
dumpDecl(D->getTemplatedDecl());
for (ClassTemplateDecl::spec_iterator I = D->spec_begin(), E = D->spec_end();
I != E; ++I) {
+ ClassTemplateDecl::spec_iterator Next = I;
+ ++Next;
+ if (Next == E)
+ lastChild();
switch (I->getTemplateSpecializationKind()) {
case TSK_Undeclared:
case TSK_ImplicitInstantiation:
@@ -801,66 +969,99 @@
dumpName(D);
dumpType(D->getResultType());
- if (D->isThisDeclarationADefinition())
+ bool oldMoreChildren = hasMoreChildren();
+ bool isVariadic = D->isVariadic();
+ bool hasBody = D->hasBody();
+
+ setMoreChildren(oldMoreChildren || isVariadic || hasBody);
+ if (D->isThisDeclarationADefinition()) {
+ lastChild();
dumpDeclContext(D);
- else {
+ } else {
for (ObjCMethodDecl::param_iterator I = D->param_begin(),
E = D->param_end(); I != E; ++I) {
+ if (I + 1 == E)
+ lastChild();
dumpDecl(*I);
}
}
- if (D->isVariadic()) {
+ setMoreChildren(oldMoreChildren || hasBody);
+ if (isVariadic) {
+ lastChild();
IndentScope Indent(*this);
OS << "...";
}
- if (D->hasBody())
+ setMoreChildren(oldMoreChildren);
+ if (hasBody) {
+ lastChild();
dumpStmt(D->getBody());
+ }
}
void ASTDumper::VisitObjCCategoryDecl(ObjCCategoryDecl *D) {
dumpName(D);
dumpDeclRef(D->getClassInterface());
+ if (D->protocol_begin() == D->protocol_end())
+ lastChild();
dumpDeclRef(D->getImplementation());
for (ObjCCategoryDecl::protocol_iterator I = D->protocol_begin(),
- E = D->protocol_end(); I != E; ++I)
+ E = D->protocol_end(); I != E; ++I) {
+ if (I + 1 == E)
+ lastChild();
dumpDeclRef(*I);
+ }
}
void ASTDumper::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) {
dumpName(D);
dumpDeclRef(D->getClassInterface());
+ lastChild();
dumpDeclRef(D->getCategoryDecl());
}
void ASTDumper::VisitObjCProtocolDecl(ObjCProtocolDecl *D) {
dumpName(D);
for (ObjCProtocolDecl::protocol_iterator I = D->protocol_begin(),
- E = D->protocol_end(); I != E; ++I)
+ E = D->protocol_end(); I != E; ++I) {
+ if (I + 1 == E)
+ lastChild();
dumpDeclRef(*I);
+ }
}
void ASTDumper::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
dumpName(D);
dumpDeclRef(D->getSuperClass(), "super");
+ if (D->protocol_begin() == D->protocol_end())
+ lastChild();
dumpDeclRef(D->getImplementation());
for (ObjCInterfaceDecl::protocol_iterator I = D->protocol_begin(),
- E = D->protocol_end(); I != E; ++I)
+ E = D->protocol_end(); I != E; ++I) {
+ if (I + 1 == E)
+ lastChild();
dumpDeclRef(*I);
+ }
}
void ASTDumper::VisitObjCImplementationDecl(ObjCImplementationDecl *D) {
dumpName(D);
dumpDeclRef(D->getSuperClass(), "super");
+ if (D->init_begin() == D->init_end())
+ lastChild();
dumpDeclRef(D->getClassInterface());
for (ObjCImplementationDecl::init_iterator I = D->init_begin(),
- E = D->init_end(); I != E; ++I)
+ E = D->init_end(); I != E; ++I) {
+ if (I + 1 == E)
+ lastChild();
dumpCXXCtorInitializer(*I);
+ }
}
void ASTDumper::VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *D) {
dumpName(D);
+ lastChild();
dumpDeclRef(D->getClassInterface());
}
@@ -895,10 +1096,15 @@
OS << " strong";
if (Attrs & ObjCPropertyDecl::OBJC_PR_unsafe_unretained)
OS << " unsafe_unretained";
- if (Attrs & ObjCPropertyDecl::OBJC_PR_getter)
+ if (Attrs & ObjCPropertyDecl::OBJC_PR_getter) {
+ if (!(Attrs & ObjCPropertyDecl::OBJC_PR_setter))
+ lastChild();
dumpDeclRef(D->getGetterMethodDecl(), "getter");
- if (Attrs & ObjCPropertyDecl::OBJC_PR_setter)
+ }
+ if (Attrs & ObjCPropertyDecl::OBJC_PR_setter) {
+ lastChild();
dumpDeclRef(D->getSetterMethodDecl(), "setter");
+ }
}
}
@@ -909,6 +1115,7 @@
else
OS << " dynamic";
dumpDeclRef(D->getPropertyDecl());
+ lastChild();
dumpDeclRef(D->getPropertyIvarDecl());
}
@@ -941,7 +1148,7 @@
if (I->hasCopyExpr())
dumpStmt(I->getCopyExpr());
}
-
+ lastChild();
dumpStmt(D->getBody());
}
@@ -962,9 +1169,16 @@
return;
}
+ setMoreChildren(S->children());
StmtVisitor<ASTDumper>::Visit(S);
- for (Stmt::child_range CI = S->children(); CI; ++CI)
+ setMoreChildren(false);
+ for (Stmt::child_range CI = S->children(); CI; ++CI) {
+ Stmt::child_range Next = CI;
+ ++Next;
+ if (!Next)
+ lastChild();
dumpStmt(*CI);
+ }
}
void ASTDumper::VisitStmt(Stmt *Node) {
@@ -976,15 +1190,21 @@
void ASTDumper::VisitDeclStmt(DeclStmt *Node) {
VisitStmt(Node);
for (DeclStmt::decl_iterator I = Node->decl_begin(), E = Node->decl_end();
- I != E; ++I)
+ I != E; ++I) {
+ if (I + 1 == E)
+ lastChild();
dumpDecl(*I);
+ }
}
void ASTDumper::VisitAttributedStmt(AttributedStmt *Node) {
VisitStmt(Node);
for (ArrayRef<const Attr*>::iterator I = Node->getAttrs().begin(),
- E = Node->getAttrs().end(); I != E; ++I)
+ E = Node->getAttrs().end(); I != E; ++I) {
+ if (I + 1 == E)
+ lastChild();
dumpAttr(*I);
+ }
}
void ASTDumper::VisitLabelStmt(LabelStmt *Node) {
@@ -1193,6 +1413,7 @@
void ASTDumper::VisitOpaqueValueExpr(OpaqueValueExpr *Node) {
VisitExpr(Node);
+ lastChild();
if (Expr *Source = Node->getSourceExpr())
dumpStmt(Source);
}
Index: test/Misc/ast-dump-decl.c
===================================================================
--- test/Misc/ast-dump-decl.c
+++ test/Misc/ast-dump-decl.c
@@ -7,8 +7,8 @@
struct TestIndent {
int x;
};
-// CHECK: {{^\(RecordDecl.*TestIndent[^()]*$}}
-// CHECK-NEXT: {{^ \(FieldDecl.*x[^()]*\)\)$}}
+// CHECK: {{^}}(RecordDecl{{.*TestIndent[^()]*$}}
+// CHECK-NEXT: {{^}}\-(FieldDecl{{.*x[^()]*\)\)$}}
struct TestChildren {
int x;
Index: test/Misc/ast-dump-attr.cpp
===================================================================
--- test/Misc/ast-dump-attr.cpp
+++ test/Misc/ast-dump-attr.cpp
@@ -7,8 +7,8 @@
int TestIndent
__attribute__((unused));
-// CHECK: {{^\(VarDecl.*TestIndent[^()]*$}}
-// CHECK-NEXT: {{^ \(UnusedAttr[^()]*\)\)$}}
+// CHECK: {{^}}(VarDecl{{.*TestIndent[^()]*$}}
+// CHECK-NEXT: {{^}}\-(UnusedAttr{{[^()]*\)\)$}}
void TestAttributedStmt() {
switch (1) {
Index: test/Misc/ast-dump-stmt.c
===================================================================
--- test/Misc/ast-dump-stmt.c
+++ test/Misc/ast-dump-stmt.c
@@ -6,10 +6,10 @@
int TestIndent = 1 + (1);
// CHECK: VarDecl{{.*}}TestIndent
-// CHECK-NEXT: {{^ \(BinaryOperator[^()]*$}}
-// CHECK-NEXT: {{^ \(IntegerLiteral.*0[^()]*\)$}}
-// CHECK-NEXT: {{^ \(ParenExpr.*0[^()]*$}}
-// CHECK-NEXT: {{^ \(IntegerLiteral.*0[^()]*\)\)\)\)$}}
+// CHECK-NEXT: {{^}}\-(BinaryOperator{{[^()]*$}}
+// CHECK-NEXT: {{^}} |-(IntegerLiteral{{.*0[^()]*\)$}}
+// CHECK-NEXT: {{^}} \-(ParenExpr{{.*0[^()]*$}}
+// CHECK-NEXT: {{^}} \-(IntegerLiteral{{.*0[^()]*\)\)\)\)$}}
void TestDeclStmt() {
int x = 0;
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits