зеркало из https://github.com/microsoft/clang-1.git
Create helper functions in StmtDumper for outputting the indentation, newlines, and brackets.
This is preparation for adding Decl dumping. Patch by Philip Craig. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@167509 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
530564196f
Коммит
cb7b45e6d8
|
@ -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<DeclStmt>(S))
|
||||
VisitDeclStmt(DS);
|
||||
else {
|
||||
Visit(S);
|
||||
IndentScope Indent(*this);
|
||||
|
||||
// Print out children.
|
||||
Stmt::child_range CI = S->children();
|
||||
if (CI) {
|
||||
while (CI) {
|
||||
OS << '\n';
|
||||
DumpSubTree(*CI++);
|
||||
}
|
||||
}
|
||||
}
|
||||
OS << ')';
|
||||
} else {
|
||||
Indent();
|
||||
if (!S) {
|
||||
OS << "<<<NULL>>>";
|
||||
return;
|
||||
}
|
||||
--IndentLevel;
|
||||
|
||||
if (DeclStmt* DS = dyn_cast<DeclStmt>(S)) {
|
||||
VisitDeclStmt(DS);
|
||||
return;
|
||||
}
|
||||
|
||||
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<VarDecl>(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<LabelDecl>(D)) {
|
||||
OS << "label " << *LD;
|
||||
} else if (StaticAssertDecl *SAD = dyn_cast<StaticAssertDecl>(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<Stmt*>(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<Stmt*>(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<Stmt*>(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<Stmt*>(this));
|
||||
llvm::errs() << "\n";
|
||||
}
|
||||
|
|
|
@ -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
|
|
@ -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
|
Загрузка…
Ссылка в новой задаче