Hi doug.gregor,
StmtDumper has some incomplete support for limiting the maximum dump depth.
This patch completes that support, and exposes it as an -ast-dump-depth option.
By completing the max depth support, this patch changes the behavior of
Stmt::dump() to limit the depth to 4 by default. I don't know whether current
users of dump() want this change or not. The behavior of Stmt::dumpAll() is
unchanged, as is the default behavior of -ast-dump.
I originally thought this option would be useful for testing Decl dumping, but
now I'm not finding many places where it helps much. So alternatively, I could
submit a patch that removes the incomplete support in StmtDumper.
http://llvm-reviews.chandlerc.com/D98
Files:
test/Misc/ast-dump-stmt.c
test/Misc/ast-dump-stmt.m
include/clang/AST/DeclBase.h
include/clang/AST/PrettyPrinter.h
include/clang/AST/Stmt.h
include/clang/Driver/CC1Options.td
include/clang/Frontend/ASTConsumers.h
include/clang/Frontend/FrontendOptions.h
lib/AST/DeclPrinter.cpp
lib/AST/DumpXML.cpp
lib/AST/StmtDumper.cpp
lib/AST/StmtPrinter.cpp
lib/Frontend/ASTConsumers.cpp
lib/Frontend/CompilerInvocation.cpp
lib/Frontend/FrontendActions.cpp
test/Tooling/clang-check-ast-dump.cpp
tools/clang-check/ClangCheck.cpp
Index: test/Misc/ast-dump-stmt.c
===================================================================
--- test/Misc/ast-dump-stmt.c
+++ test/Misc/ast-dump-stmt.c
@@ -1,16 +1,36 @@
// RUN: %clang_cc1 -ast-dump -ast-dump-filter Test %s | FileCheck -strict-whitespace %s
+// RUN: %clang_cc1 -ast-dump -ast-dump-depth 1 -ast-dump-filter Test %s | FileCheck -check-prefix CHECK1 -strict-whitespace %s
+// RUN: %clang_cc1 -ast-dump -ast-dump-depth 2 -ast-dump-filter Test %s | FileCheck -check-prefix CHECK2 -strict-whitespace %s
int TestLocation = 0;
// CHECK: Dumping TestLocation
-// CHECK-NEXT: IntegerLiteral 0x{{[^ ]*}} <{{.*}}:3:20> 'int' 0
+// CHECK-NEXT: IntegerLiteral 0x{{[^ ]*}} <{{.*}}:5: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[^()]*\)\)\)$}}
+int TestChildren = 1 + (1);
+// CHECK: Dumping TestChildren
+// CHECK-NEXT: BinaryOperator
+// CHECK-NEXT: IntegerLiteral
+// CHECK-NEXT: ParenExpr
+// CHECK-NEXT: IntegerLiteral
+
+// CHECK1: Dumping TestChildren
+// CHECK1-NEXT: BinaryOperator{{.*}} ...)
+// CHECK1-NEXT-NOT: IntegerLiteral
+// CHECK1-NEXT-NOT: ParenExpr
+
+// CHECK2: Dumping TestChildren
+// CHECK2-NEXT: BinaryOperator
+// CHECK2-NEXT: IntegerLiteral
+// CHECK2-NEXT: ParenExpr{{.*}} ...)
+// CHECK2-NEXT-NOT: IntegerLiteral
+
void TestDeclStmt() {
int x = 0;
int y, z;
@@ -24,6 +44,11 @@
// CHECK-NEXT: int y
// CHECK-NEXT: int z
+// CHECK2: Dumping TestDeclStmt
+// CHECK2-NEXT: CompoundStmt
+// CHECK2-NEXT: DeclStmt
+// CHECK2-NEXT: DeclStmt
+
int TestOpaqueValueExpr = 0 ?: 1;
// CHECK: Dumping TestOpaqueValueExpr
// CHECK-NEXT: BinaryConditionalOperator
@@ -33,3 +58,10 @@
// CHECK-NEXT: OpaqueValueExpr
// CHECK-NEXT: IntegerLiteral
// CHECK-NEXT: IntegerLiteral
+
+// CHECK2: Dumping TestOpaqueValueExpr
+// CHECK2-NEXT: BinaryConditionalOperator
+// CHECK2-NEXT: IntegerLiteral
+// CHECK2-NEXT: OpaqueValueExpr
+// CHECK2-NEXT: OpaqueValueExpr
+// CHECK2-NEXT: IntegerLiteral
Index: test/Misc/ast-dump-stmt.m
===================================================================
--- test/Misc/ast-dump-stmt.m
+++ test/Misc/ast-dump-stmt.m
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -Wno-unused -fblocks -fobjc-exceptions -ast-dump -ast-dump-filter Test %s | FileCheck -strict-whitespace %s
+// RUN: %clang_cc1 -Wno-unused -fblocks -fobjc-exceptions -ast-dump -ast-dump-depth 2 -ast-dump-filter Test %s | FileCheck -check-prefix CHECK2 -strict-whitespace %s
+// RUN: %clang_cc1 -Wno-unused -fblocks -fobjc-exceptions -ast-dump -ast-dump-depth 3 -ast-dump-filter Test %s | FileCheck -check-prefix CHECK3 -strict-whitespace %s
void TestBlockExpr(int x) {
^{ x; };
@@ -8,14 +10,24 @@
// CHECK-NEXT: capture ParmVar
// CHECK-NEXT: CompoundStmt
+// CHECK3: Dumping TestBlockExpr
+// CHECK3: BlockExpr{{.*}} decl=
+// CHECK3-NEXT-NOT: capture
+// CHECK3-NEXT-NOT: CompoundStmt
+
void TestExprWithCleanup(int x) {
^{ x; };
}
// CHECK: Dumping TestExprWithCleanup
// CHECK: ExprWithCleanups
// CHECK-NEXT: cleanup Block
// CHECK-NEXT: BlockExpr
+// CHECK2: Dumping TestExprWithCleanup
+// CHECK2: ExprWithCleanups
+// CHECK2-NEXT-NOT: cleanup
+// CHECK2-NEXT-NOT: BlockExpr
+
@interface A
@end
@@ -34,3 +46,10 @@
// CHECK-NEXT: ObjCAtCatchStmt{{.*}} catch all
// CHECK-NEXT: CompoundStmt
// CHECK-NEXT: ObjCAtFinallyStmt
+
+// CHECK3: Dumping TestObjCAtCatchStmt
+// CHECK3: ObjCAtTryStmt
+// CHECK3-NEXT: CompoundStmt
+// CHECK3-NEXT: ObjCAtCatchStmt{{.*}} catch parm = "A *a"
+// CHECK3-NEXT: ObjCAtCatchStmt{{.*}} catch all
+// CHECK3-NEXT: ObjCAtFinallyStmt
Index: include/clang/AST/DeclBase.h
===================================================================
--- include/clang/AST/DeclBase.h
+++ include/clang/AST/DeclBase.h
@@ -851,7 +851,7 @@
unsigned Indentation = 0);
// Debuggers don't usually respect default arguments.
LLVM_ATTRIBUTE_USED void dump() const;
- void dump(raw_ostream &Out) const;
+ void dump(raw_ostream &Out, unsigned MaxDepth) const;
// Debuggers don't usually respect default arguments.
LLVM_ATTRIBUTE_USED void dumpXML() const;
void dumpXML(raw_ostream &OS) const;
Index: include/clang/AST/PrettyPrinter.h
===================================================================
--- include/clang/AST/PrettyPrinter.h
+++ include/clang/AST/PrettyPrinter.h
@@ -40,7 +40,7 @@
ConstantArraySizeAsWritten(false), AnonymousTagLocations(true),
SuppressStrongLifetime(false), Bool(LO.Bool),
TerseOutput(false), SuppressAttributes(false),
- DumpSourceManager(0) { }
+ DumpSourceManager(0), DumpDepth(0) { }
/// \brief What language we're printing.
LangOptions LangOpts;
@@ -151,6 +151,10 @@
/// involves printing the internal details of the AST and pretty-printing
/// involves printing something similar to source code.
SourceManager *DumpSourceManager;
+
+ /// \brief If we are "dumping" rather than "pretty-printing", this is the
+ /// maximum AST traversal depth.
+ unsigned DumpDepth;
};
} // end namespace clang
Index: include/clang/AST/Stmt.h
===================================================================
--- include/clang/AST/Stmt.h
+++ include/clang/AST/Stmt.h
@@ -365,7 +365,7 @@
/// This is useful in a debugger.
LLVM_ATTRIBUTE_USED void dump() const;
LLVM_ATTRIBUTE_USED void dump(SourceManager &SM) const;
- void dump(raw_ostream &OS, SourceManager &SM) const;
+ void dump(raw_ostream &OS, SourceManager &SM, unsigned MaxDepth) const;
/// dumpAll - This does a dump of the specified AST fragment and all subtrees.
void dumpAll() const;
Index: include/clang/Driver/CC1Options.td
===================================================================
--- include/clang/Driver/CC1Options.td
+++ include/clang/Driver/CC1Options.td
@@ -294,6 +294,8 @@
HelpText<"Use with -ast-dump or -ast-print to dump/print only AST declaration"
" nodes having a certain substring in a qualified name. Use"
" -ast-list to list all filterable declaration node names.">;
+def ast_dump_depth : Separate<["-"], "ast-dump-depth">,
+ HelpText<"Maximum AST traversal depth while dumping with -ast-dump.">;
let Group = Action_Group in {
Index: include/clang/Frontend/ASTConsumers.h
===================================================================
--- include/clang/Frontend/ASTConsumers.h
+++ include/clang/Frontend/ASTConsumers.h
@@ -37,7 +37,7 @@
// AST dumper: dumps the raw AST in human-readable form to stderr; this is
// intended for debugging.
-ASTConsumer *CreateASTDumper(StringRef FilterString);
+ASTConsumer *CreateASTDumper(StringRef FilterString, unsigned MaxDepth);
// AST Decl node lister: prints qualified names of all filterable AST Decl
// nodes.
Index: include/clang/Frontend/FrontendOptions.h
===================================================================
--- include/clang/Frontend/FrontendOptions.h
+++ include/clang/Frontend/FrontendOptions.h
@@ -145,6 +145,9 @@
/// If given, filter dumped AST Decl nodes by this substring.
std::string ASTDumpFilter;
+ /// If nonzero, the maximum AST traversal depth while dumping.
+ unsigned ASTDumpDepth;
+
/// If given, enable code completion at the provided location.
ParsedSourceLocation CodeCompletionAt;
Index: lib/AST/DeclPrinter.cpp
===================================================================
--- lib/AST/DeclPrinter.cpp
+++ lib/AST/DeclPrinter.cpp
@@ -175,12 +175,13 @@
}
void Decl::dump() const {
- dump(llvm::errs());
+ dump(llvm::errs(), 0);
}
-void Decl::dump(raw_ostream &Out) const {
+void Decl::dump(raw_ostream &Out, unsigned MaxDepth) const {
PrintingPolicy Policy = getASTContext().getPrintingPolicy();
Policy.DumpSourceManager = &getASTContext().getSourceManager();
+ Policy.DumpDepth = MaxDepth;
print(Out, Policy, /*Indentation*/ 0, /*PrintInstantiation*/ true);
}
Index: lib/AST/DumpXML.cpp
===================================================================
--- lib/AST/DumpXML.cpp
+++ lib/AST/DumpXML.cpp
@@ -1028,7 +1028,7 @@
push("Stmt");
out << ">\n";
Stack.back().State = NS_Children; // explicitly become non-lazy
- S->dump(out, Context.getSourceManager());
+ S->dump(out, Context.getSourceManager(), 0);
out << '\n';
pop();
}
Index: lib/AST/StmtDumper.cpp
===================================================================
--- lib/AST/StmtDumper.cpp
+++ lib/AST/StmtDumper.cpp
@@ -32,11 +32,19 @@
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
- /// are left.
+ /// \brief When doing a normal dump (not dumpAll) we only want to dump
+ /// the first few levels of an AST. This is the maximum indentation
+ /// level to reach. If this is zero then the depth is unlimited.
unsigned MaxDepth;
+ /// \brief True if any children of the current node were pruned due to
+ /// reaching the maximum depth.
+ ///
+ /// Used to determine if an indication of the truncation needs to be
+ /// displayed. This is not displayed immediately because that may result
+ /// in the indication being displayed more than once.
+ bool Truncated;
+
/// LastLocFilename/LastLocLine - Keep track of the last location we print
/// out so that we can print out deltas from then on out.
const char *LastLocFilename;
@@ -55,7 +63,8 @@
public:
StmtDumper(SourceManager *sm, raw_ostream &os, unsigned maxDepth)
- : SM(sm), OS(os), IndentLevel(0), IsFirstLine(true), MaxDepth(maxDepth) {
+ : SM(sm), OS(os), IndentLevel(0), IsFirstLine(true), MaxDepth(maxDepth),
+ Truncated(false) {
LastLocFilename = "";
LastLocLine = ~0U;
}
@@ -66,8 +75,8 @@
void DumpSubTree(Stmt *S) {
// Prune the recursion if not using dump all.
- if (MaxDepth == 0) return;
-
+ if (atMaxDepth())
+ return;
IndentScope Indent(*this);
if (!S) {
@@ -98,10 +107,21 @@
}
void unindent() {
+ if (Truncated) {
+ OS << " ...";
+ Truncated = false;
+ }
OS << ")";
IndentLevel--;
}
+ bool atMaxDepth() {
+ if (!MaxDepth || MaxDepth > IndentLevel)
+ return false;
+ Truncated = true;
+ return true;
+ }
+
void DumpType(QualType T) {
SplitQualType T_split = T.split();
OS << "'" << QualType::getAsString(T_split) << "'";
@@ -324,6 +344,9 @@
void StmtDumper::VisitDeclStmt(DeclStmt *Node) {
DumpStmt(Node);
+ if (atMaxDepth())
+ return;
+
for (DeclStmt::decl_iterator DI = Node->decl_begin(), DE = Node->decl_end();
DI != DE; ++DI) {
IndentScope Indent(*this);
@@ -516,6 +539,9 @@
BlockDecl *block = Node->getBlockDecl();
OS << " decl=" << block;
+ if (atMaxDepth())
+ return;
+
if (block->capturesCXXThis()) {
IndentScope Indent(*this);
OS << "capture this";
@@ -536,7 +562,6 @@
void StmtDumper::VisitOpaqueValueExpr(OpaqueValueExpr *Node) {
DumpExpr(Node);
-
if (Expr *Source = Node->getSourceExpr())
DumpSubTree(Source);
}
@@ -596,6 +621,9 @@
void StmtDumper::VisitExprWithCleanups(ExprWithCleanups *Node) {
DumpExpr(Node);
+ if (atMaxDepth())
+ return;
+
for (unsigned i = 0, e = Node->getNumObjects(); i != e; ++i) {
IndentScope Indent(*this);
OS << "cleanup ";
@@ -731,11 +759,11 @@
/// specified node and a few nodes underneath it, but not the whole subtree.
/// This is useful in a debugger.
void Stmt::dump(SourceManager &SM) const {
- dump(llvm::errs(), SM);
+ dump(llvm::errs(), SM, 4);
}
-void Stmt::dump(raw_ostream &OS, SourceManager &SM) const {
- StmtDumper P(&SM, OS, 4);
+void Stmt::dump(raw_ostream &OS, SourceManager &SM, unsigned MaxDepth) const {
+ StmtDumper P(&SM, OS, MaxDepth);
P.DumpSubTree(const_cast<Stmt*>(this));
}
@@ -749,12 +777,12 @@
/// 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);
+ StmtDumper P(&SM, llvm::errs(), 0);
P.DumpSubTree(const_cast<Stmt*>(this));
}
/// dumpAll - This does a dump of the specified AST fragment and all subtrees.
void Stmt::dumpAll() const {
- StmtDumper P(0, llvm::errs(), ~0U);
+ StmtDumper P(0, llvm::errs(), 0);
P.DumpSubTree(const_cast<Stmt*>(this));
}
Index: lib/AST/StmtPrinter.cpp
===================================================================
--- lib/AST/StmtPrinter.cpp
+++ lib/AST/StmtPrinter.cpp
@@ -1859,7 +1859,7 @@
}
if (Policy.DumpSourceManager) {
- dump(OS, *Policy.DumpSourceManager);
+ dump(OS, *Policy.DumpSourceManager, Policy.DumpDepth);
return;
}
Index: lib/Frontend/ASTConsumers.cpp
===================================================================
--- lib/Frontend/ASTConsumers.cpp
+++ lib/Frontend/ASTConsumers.cpp
@@ -37,16 +37,16 @@
public:
ASTPrinter(raw_ostream *Out = NULL, bool Dump = false,
- StringRef FilterString = "")
+ StringRef FilterString = "", unsigned MaxDepth = 0)
: Out(Out ? *Out : llvm::outs()), Dump(Dump),
- FilterString(FilterString) {}
+ FilterString(FilterString), MaxDepth(MaxDepth) {}
virtual void HandleTranslationUnit(ASTContext &Context) {
TranslationUnitDecl *D = Context.getTranslationUnitDecl();
if (FilterString.empty()) {
if (Dump)
- D->dump(Out);
+ D->dump(Out, MaxDepth);
else
D->print(Out, /*Indentation=*/0, /*PrintInstantiation=*/true);
return;
@@ -65,7 +65,7 @@
(Dump ? "Dumping " : "Printing ") << getName(D) << ":\n";
Out.resetColor();
if (Dump)
- D->dump(Out);
+ D->dump(Out, MaxDepth);
else
D->print(Out, /*Indentation=*/0, /*PrintInstantiation=*/true);
Out << "\n";
@@ -88,6 +88,7 @@
raw_ostream &Out;
bool Dump;
std::string FilterString;
+ unsigned MaxDepth;
};
class ASTDeclNodeLister : public ASTConsumer,
@@ -117,8 +118,8 @@
return new ASTPrinter(Out, /*Dump=*/ false, FilterString);
}
-ASTConsumer *clang::CreateASTDumper(StringRef FilterString) {
- return new ASTPrinter(0, /*Dump=*/ true, FilterString);
+ASTConsumer *clang::CreateASTDumper(StringRef FilterString, unsigned MaxDepth) {
+ return new ASTPrinter(0, /*Dump=*/ true, FilterString, MaxDepth);
}
ASTConsumer *clang::CreateASTDeclNodeLister() {
Index: lib/Frontend/CompilerInvocation.cpp
===================================================================
--- lib/Frontend/CompilerInvocation.cpp
+++ lib/Frontend/CompilerInvocation.cpp
@@ -564,6 +564,8 @@
}
if (!Opts.ASTDumpFilter.empty())
Res.push_back("-ast-dump-filter", Opts.ASTDumpFilter);
+ if (Opts.ASTDumpDepth != 0)
+ Res.push_back("-ast-dump-depth", llvm::utostr(Opts.ASTDumpDepth));
for (unsigned i = 0, e = Opts.Plugins.size(); i != e; ++i)
Res.push_back("-load", Opts.Plugins[i]);
for (unsigned i = 0, e = Opts.AddPluginActions.size(); i != e; ++i) {
@@ -1585,6 +1587,7 @@
Opts.FixAndRecompile = Args.hasArg(OPT_fixit_recompile);
Opts.FixToTemporaries = Args.hasArg(OPT_fixit_to_temp);
Opts.ASTDumpFilter = Args.getLastArgValue(OPT_ast_dump_filter);
+ Opts.ASTDumpDepth = Args.getLastArgIntValue(OPT_ast_dump_depth, 0, Diags);
Opts.CodeCompleteOpts.IncludeMacros
= Args.hasArg(OPT_code_completion_macros);
Index: lib/Frontend/FrontendActions.cpp
===================================================================
--- lib/Frontend/FrontendActions.cpp
+++ lib/Frontend/FrontendActions.cpp
@@ -53,7 +53,8 @@
ASTConsumer *ASTDumpAction::CreateASTConsumer(CompilerInstance &CI,
StringRef InFile) {
- return CreateASTDumper(CI.getFrontendOpts().ASTDumpFilter);
+ return CreateASTDumper(CI.getFrontendOpts().ASTDumpFilter,
+ CI.getFrontendOpts().ASTDumpDepth);
}
ASTConsumer *ASTDeclListAction::CreateASTConsumer(CompilerInstance &CI,
Index: test/Tooling/clang-check-ast-dump.cpp
===================================================================
--- test/Tooling/clang-check-ast-dump.cpp
+++ test/Tooling/clang-check-ast-dump.cpp
@@ -12,6 +12,11 @@
// CHECK-FILTER-NEXT: (ReturnStmt
// CHECK-FILTER-NEXT: (BinaryOperator
//
+// RUN: clang-check -ast-dump -ast-dump-filter test_namespace::TheClass::theMethod -ast-dump-depth 2 "%s" -- 2>&1 | FileCheck -check-prefix CHECK-DEPTH %s
+// CHECK-DEPTH: int theMethod(int x) (CompoundStmt
+// CHECK-DEPTH-NEXT: (ReturnStmt{{.*}} ...)
+// CHECK-DEPTH-NOT: (BinaryOperator
+//
// RUN: clang-check -ast-print "%s" -- 2>&1 | FileCheck -check-prefix CHECK-PRINT %s
// CHECK-PRINT: namespace test_namespace
// CHECK-PRINT: class TheClass
Index: tools/clang-check/ClangCheck.cpp
===================================================================
--- tools/clang-check/ClangCheck.cpp
+++ tools/clang-check/ClangCheck.cpp
@@ -61,6 +61,9 @@
static cl::opt<std::string> ASTDumpFilter(
"ast-dump-filter",
cl::desc(Options->getOptionHelpText(options::OPT_ast_dump_filter)));
+static cl::opt<unsigned> ASTDumpDepth(
+ "ast-dump-depth",
+ cl::desc(Options->getOptionHelpText(options::OPT_ast_dump_depth)));
static cl::opt<bool> Fixit(
"fixit",
@@ -133,7 +136,7 @@
if (ASTList)
return clang::CreateASTDeclNodeLister();
if (ASTDump)
- return clang::CreateASTDumper(ASTDumpFilter);
+ return clang::CreateASTDumper(ASTDumpFilter, ASTDumpDepth);
if (ASTPrint)
return clang::CreateASTPrinter(&llvm::outs(), ASTDumpFilter);
return new clang::ASTConsumer();
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits