From 874030e684ffc1d7bbb99347916c29982c522f8f Mon Sep 17 00:00:00 2001 From: Manuel Klimek Date: Wed, 7 Nov 2012 00:33:12 +0000 Subject: [PATCH] Create helper functions in StmtDumper for outputting the indentation, newlines, and brackets. This is preparation for adding Decl dumping. Patch by Philip Craig. llvm-svn: 167509 --- clang/lib/AST/StmtDumper.cpp | 113 ++++++++++++++++++++-------------------- clang/test/Misc/ast-dump-stmt.c | 35 +++++++++++++ clang/test/Misc/ast-dump-stmt.m | 36 +++++++++++++ 3 files changed, 127 insertions(+), 57 deletions(-) create mode 100644 clang/test/Misc/ast-dump-stmt.c create mode 100644 clang/test/Misc/ast-dump-stmt.m diff --git a/clang/lib/AST/StmtDumper.cpp b/clang/lib/AST/StmtDumper.cpp index 3695bf34..fbc990f 100644 --- a/clang/lib/AST/StmtDumper.cpp +++ b/clang/lib/AST/StmtDumper.cpp @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// // -// This file implements the Stmt::dump/Stmt::print methods, which dump out the +// This file implements the Stmt::dump method, which dumps out the // AST in a form that exposes type details and other fields. // //===----------------------------------------------------------------------===// @@ -30,6 +30,7 @@ namespace { SourceManager *SM; raw_ostream &OS; unsigned IndentLevel; + bool IsFirstLine; /// MaxDepth - When doing a normal dump (not dumpAll) we only want to dump /// the first few levels of an AST. This keeps track of how many ast levels @@ -41,46 +42,64 @@ namespace { const char *LastLocFilename; unsigned LastLocLine; + class IndentScope { + StmtDumper &Dumper; + public: + IndentScope(StmtDumper &Dumper) : Dumper(Dumper) { + Dumper.indent(); + } + ~IndentScope() { + Dumper.unindent(); + } + }; + public: StmtDumper(SourceManager *sm, raw_ostream &os, unsigned maxDepth) - : SM(sm), OS(os), IndentLevel(0-1), MaxDepth(maxDepth) { + : SM(sm), OS(os), IndentLevel(0), IsFirstLine(true), MaxDepth(maxDepth) { LastLocFilename = ""; LastLocLine = ~0U; } + ~StmtDumper() { + OS << "\n"; + } + void DumpSubTree(Stmt *S) { // Prune the recursion if not using dump all. if (MaxDepth == 0) return; - ++IndentLevel; - if (S) { - if (DeclStmt* DS = dyn_cast(S)) - VisitDeclStmt(DS); - else { - Visit(S); - - // Print out children. - Stmt::child_range CI = S->children(); - if (CI) { - while (CI) { - OS << '\n'; - DumpSubTree(*CI++); - } - } - } - OS << ')'; - } else { - Indent(); + IndentScope Indent(*this); + + if (!S) { OS << "<<>>"; + return; + } + + if (DeclStmt* DS = dyn_cast(S)) { + VisitDeclStmt(DS); + return; } - --IndentLevel; + + Visit(S); + for (Stmt::child_range CI = S->children(); CI; CI++) + DumpSubTree(*CI); } void DumpDeclarator(Decl *D); - void Indent() const { - for (int i = 0, e = IndentLevel; i < e; ++i) - OS << " "; + void indent() { + if (IsFirstLine) + IsFirstLine = false; + else + OS << "\n"; + OS.indent(IndentLevel * 2); + OS << "("; + IndentLevel++; + } + + void unindent() { + OS << ")"; + IndentLevel--; } void DumpType(QualType T) { @@ -96,8 +115,7 @@ namespace { } void DumpDeclRef(Decl *node); void DumpStmt(const Stmt *Node) { - Indent(); - OS << "(" << Node->getStmtClassName() + OS << Node->getStmtClassName() << " " << (const void*)Node; DumpSourceRange(Node); } @@ -262,7 +280,7 @@ void StmtDumper::DumpDeclarator(Decl *D) { // If this is a vardecl with an initializer, emit it. if (VarDecl *V = dyn_cast(VD)) { if (V->getInit()) { - OS << " =\n"; + OS << " ="; DumpSubTree(V->getInit()); } } @@ -294,9 +312,9 @@ void StmtDumper::DumpDeclarator(Decl *D) { } else if (LabelDecl *LD = dyn_cast(D)) { OS << "label " << *LD; } else if (StaticAssertDecl *SAD = dyn_cast(D)) { - OS << "\"static_assert(\n"; + OS << "\"static_assert("; DumpSubTree(SAD->getAssertExpr()); - OS << ",\n"; + OS << ","; DumpSubTree(SAD->getMessage()); OS << ");\""; } else { @@ -306,17 +324,12 @@ void StmtDumper::DumpDeclarator(Decl *D) { void StmtDumper::VisitDeclStmt(DeclStmt *Node) { DumpStmt(Node); - OS << "\n"; for (DeclStmt::decl_iterator DI = Node->decl_begin(), DE = Node->decl_end(); DI != DE; ++DI) { + IndentScope Indent(*this); Decl* D = *DI; - ++IndentLevel; - Indent(); OS << (void*) D << " "; DumpDeclarator(D); - if (DI+1 != DE) - OS << "\n"; - --IndentLevel; } } @@ -503,35 +516,29 @@ void StmtDumper::VisitBlockExpr(BlockExpr *Node) { BlockDecl *block = Node->getBlockDecl(); OS << " decl=" << block; - IndentLevel++; if (block->capturesCXXThis()) { - OS << '\n'; Indent(); OS << "(capture this)"; + IndentScope Indent(*this); + OS << "capture this"; } for (BlockDecl::capture_iterator i = block->capture_begin(), e = block->capture_end(); i != e; ++i) { - OS << '\n'; - Indent(); - OS << "(capture "; + IndentScope Indent(*this); + OS << "capture "; if (i->isByRef()) OS << "byref "; if (i->isNested()) OS << "nested "; if (i->getVariable()) DumpDeclRef(i->getVariable()); if (i->hasCopyExpr()) DumpSubTree(i->getCopyExpr()); - OS << ")"; } - IndentLevel--; - OS << '\n'; DumpSubTree(block->getBody()); } void StmtDumper::VisitOpaqueValueExpr(OpaqueValueExpr *Node) { DumpExpr(Node); - if (Expr *Source = Node->getSourceExpr()) { - OS << '\n'; + if (Expr *Source = Node->getSourceExpr()) DumpSubTree(Source); - } } // GNU extensions. @@ -589,15 +596,11 @@ void StmtDumper::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *Node) { void StmtDumper::VisitExprWithCleanups(ExprWithCleanups *Node) { DumpExpr(Node); - ++IndentLevel; for (unsigned i = 0, e = Node->getNumObjects(); i != e; ++i) { - OS << "\n"; - Indent(); - OS << "(cleanup "; + IndentScope Indent(*this); + OS << "cleanup "; DumpDeclRef(Node->getObject(i)); - OS << ")"; } - --IndentLevel; } void StmtDumper::DumpCXXTemporary(CXXTemporary *Temporary) { @@ -734,7 +737,6 @@ void Stmt::dump(SourceManager &SM) const { void Stmt::dump(raw_ostream &OS, SourceManager &SM) const { StmtDumper P(&SM, OS, 4); P.DumpSubTree(const_cast(this)); - OS << "\n"; } /// dump - This does a local dump of the specified AST fragment. It dumps the @@ -743,19 +745,16 @@ void Stmt::dump(raw_ostream &OS, SourceManager &SM) const { void Stmt::dump() const { StmtDumper P(0, llvm::errs(), 4); P.DumpSubTree(const_cast(this)); - llvm::errs() << "\n"; } /// dumpAll - This does a dump of the specified AST fragment and all subtrees. void Stmt::dumpAll(SourceManager &SM) const { StmtDumper P(&SM, llvm::errs(), ~0U); P.DumpSubTree(const_cast(this)); - llvm::errs() << "\n"; } /// dumpAll - This does a dump of the specified AST fragment and all subtrees. void Stmt::dumpAll() const { StmtDumper P(0, llvm::errs(), ~0U); P.DumpSubTree(const_cast(this)); - llvm::errs() << "\n"; } diff --git a/clang/test/Misc/ast-dump-stmt.c b/clang/test/Misc/ast-dump-stmt.c new file mode 100644 index 0000000..d7fdce8 --- /dev/null +++ b/clang/test/Misc/ast-dump-stmt.c @@ -0,0 +1,35 @@ +// RUN: %clang_cc1 -ast-dump -ast-dump-filter Test %s | FileCheck -strict-whitespace %s + +int TestLocation = 0; +// CHECK: Dumping TestLocation +// CHECK-NEXT: IntegerLiteral 0x{{[^ ]*}} <{{.*}}:3:20> 'int' 0 + +int TestIndent = 1 + (1); +// CHECK: Dumping TestIndent +// CHECK-NEXT: {{\(BinaryOperator[^()]*$}} +// CHECK-NEXT: {{^ \(IntegerLiteral.*0[^()]*\)$}} +// CHECK-NEXT: {{^ \(ParenExpr.*0[^()]*$}} +// CHECK-NEXT: {{^ \(IntegerLiteral.*0[^()]*\)\)\)$}} + +void TestDeclStmt() { + int x = 0; + int y, z; +} +// CHECK: Dumping TestDeclStmt +// CHECK-NEXT: CompoundStmt +// CHECK-NEXT: DeclStmt +// CHECK-NEXT: int x = +// CHECK-NEXT: IntegerLiteral +// CHECK-NEXT: DeclStmt +// CHECK-NEXT: int y +// CHECK-NEXT: int z + +int TestOpaqueValueExpr = 0 ?: 1; +// CHECK: Dumping TestOpaqueValueExpr +// CHECK-NEXT: BinaryConditionalOperator +// CHECK-NEXT: IntegerLiteral +// CHECK-NEXT: OpaqueValueExpr +// CHECK-NEXT: IntegerLiteral +// CHECK-NEXT: OpaqueValueExpr +// CHECK-NEXT: IntegerLiteral +// CHECK-NEXT: IntegerLiteral diff --git a/clang/test/Misc/ast-dump-stmt.m b/clang/test/Misc/ast-dump-stmt.m new file mode 100644 index 0000000..8dfee74 --- /dev/null +++ b/clang/test/Misc/ast-dump-stmt.m @@ -0,0 +1,36 @@ +// RUN: %clang_cc1 -Wno-unused -fblocks -fobjc-exceptions -ast-dump -ast-dump-filter Test %s | FileCheck -strict-whitespace %s + +void TestBlockExpr(int x) { + ^{ x; }; +} +// CHECK: Dumping TestBlockExpr +// CHECK: BlockExpr{{.*}} decl= +// CHECK-NEXT: capture ParmVar +// CHECK-NEXT: CompoundStmt + +void TestExprWithCleanup(int x) { + ^{ x; }; +} +// CHECK: Dumping TestExprWithCleanup +// CHECK: ExprWithCleanups +// CHECK-NEXT: cleanup Block +// CHECK-NEXT: BlockExpr + +@interface A +@end + +void TestObjCAtCatchStmt() { + @try { + } @catch(A *a) { + } @catch(...) { + } @finally { + } +} +// CHECK: Dumping TestObjCAtCatchStmt +// CHECK: ObjCAtTryStmt +// CHECK-NEXT: CompoundStmt +// CHECK-NEXT: ObjCAtCatchStmt{{.*}} catch parm = "A *a" +// CHECK-NEXT: CompoundStmt +// CHECK-NEXT: ObjCAtCatchStmt{{.*}} catch all +// CHECK-NEXT: CompoundStmt +// CHECK-NEXT: ObjCAtFinallyStmt -- 2.7.4