* dump types for FunctionDecl and VarDecl
* added simple test cases for FunctionDecl, VarDecl and DeclStmt
Hi alexfh, doug.gregor,
http://llvm-reviews.chandlerc.com/D52
CHANGE SINCE LAST DIFF
http://llvm-reviews.chandlerc.com/D52?vs=139&id=141#toc
Files:
include/clang/AST/Stmt.h
lib/AST/ASTDumper.cpp
lib/AST/ASTDumper.h
lib/AST/CMakeLists.txt
lib/AST/DeclDumper.cpp
lib/AST/DeclPrinter.cpp
lib/AST/StmtDumper.cpp
unittests/AST/CMakeLists.txt
unittests/AST/DeclDumperTest.cpp
unittests/AST/StmtDumperTest.cpp
Index: include/clang/AST/Stmt.h
===================================================================
--- include/clang/AST/Stmt.h
+++ include/clang/AST/Stmt.h
@@ -360,17 +360,12 @@
static void EnableStatistics();
static void PrintStats();
- /// dump - This does a local dump of the specified AST fragment. It dumps the
- /// specified node and a few nodes underneath it, but not the whole subtree.
+ /// dump - This does a dump of the specified AST fragment and all subtrees.
/// 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;
- /// dumpAll - This does a dump of the specified AST fragment and all subtrees.
- void dumpAll() const;
- void dumpAll(SourceManager &SM) const;
-
/// dumpPretty/printPretty - These two methods do a "pretty print" of the AST
/// back to its original source language syntax.
void dumpPretty(ASTContext &Context) const;
Index: lib/AST/ASTDumper.cpp
===================================================================
--- /dev/null
+++ lib/AST/ASTDumper.cpp
@@ -0,0 +1,96 @@
+//===--- ASTDumper.cpp - Dumping implementation for ASTs ------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the ASTDumper class, which dumps out the
+// AST in a form that exposes type details and other fields.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ASTDumper.h"
+#include "clang/AST/Type.h"
+#include "clang/Basic/SourceManager.h"
+#include "llvm/Support/raw_ostream.h"
+using namespace clang;
+
+void ASTDumper::flush() {
+ if (NeedNewLine)
+ OS << "\n";
+ NeedNewLine = false;
+}
+
+void ASTDumper::indent() {
+ if (NeedNewLine)
+ OS << "\n";
+
+ NeedNewLine = true;
+ for (int i = 0, e = IndentLevel; i < e; ++i)
+ OS << " ";
+ OS << "(";
+ IndentLevel++;
+}
+
+void ASTDumper::unindent() {
+ OS << ")";
+ IndentLevel--;
+}
+
+void ASTDumper::dumpType(QualType T) {
+ SplitQualType T_split = T.split();
+ OS << "'" << QualType::getAsString(T_split) << "'";
+
+ if (!T.isNull()) {
+ // If the type is sugared, also dump a (shallow) desugared type.
+ SplitQualType D_split = T.getSplitDesugaredType();
+ if (T_split != D_split)
+ OS << ":'" << QualType::getAsString(D_split) << "'";
+ }
+}
+
+void ASTDumper::dumpLocation(SourceLocation Loc) {
+ SourceLocation SpellingLoc = SM->getSpellingLoc(Loc);
+
+ // The general format we print out is filename:line:col, but we drop pieces
+ // that haven't changed since the last loc printed.
+ PresumedLoc PLoc = SM->getPresumedLoc(SpellingLoc);
+
+ if (PLoc.isInvalid()) {
+ OS << "<invalid sloc>";
+ return;
+ }
+
+ if (strcmp(PLoc.getFilename(), LastLocFilename) != 0) {
+ OS << PLoc.getFilename() << ':' << PLoc.getLine()
+ << ':' << PLoc.getColumn();
+ LastLocFilename = PLoc.getFilename();
+ LastLocLine = PLoc.getLine();
+ } else if (PLoc.getLine() != LastLocLine) {
+ OS << "line" << ':' << PLoc.getLine()
+ << ':' << PLoc.getColumn();
+ LastLocLine = PLoc.getLine();
+ } else {
+ OS << "col" << ':' << PLoc.getColumn();
+ }
+}
+
+void ASTDumper::dumpSourceRange(SourceRange R) {
+ // Can't translate locations if a SourceManager isn't available.
+ if (SM == 0)
+ return;
+
+ // TODO: If the parent expression is available, we can print a delta vs its
+ // location.
+
+ OS << " <";
+ dumpLocation(R.getBegin());
+ if (R.getBegin() != R.getEnd()) {
+ OS << ", ";
+ dumpLocation(R.getEnd());
+ }
+ OS << ">";
+}
Index: lib/AST/ASTDumper.h
===================================================================
--- /dev/null
+++ lib/AST/ASTDumper.h
@@ -0,0 +1,62 @@
+//===--- ASTDumper.h - Dumping implementation for ASTs ----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the ASTDumper class, which dumps out the
+// AST in a form that exposes type details and other fields.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_ASTDUMPER_H
+#define LLVM_CLANG_AST_ASTDUMPER_H
+
+#include "clang/Basic/LLVM.h"
+
+namespace clang {
+
+class SourceManager;
+class SourceRange;
+class SourceLocation;
+class QualType;
+class Decl;
+class Stmt;
+
+class ASTDumper {
+public:
+ ASTDumper(SourceManager *SM, raw_ostream &OS)
+ : SM(SM), OS(OS), IndentLevel(0), LastLocFilename(""), LastLocLine(~0U),
+ NeedNewLine(false) {
+ }
+
+ void flush();
+ void indent();
+ void unindent();
+
+ void dumpDecl(Decl *D);
+ void dumpStmt(Stmt *S);
+ void dumpType(QualType T);
+ void dumpSourceRange(SourceRange R);
+
+private:
+ void dumpLocation(SourceLocation Loc);
+
+ SourceManager *SM;
+ raw_ostream &OS;
+ unsigned IndentLevel;
+
+ /// 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;
+ unsigned LastLocLine;
+
+ bool NeedNewLine;
+};
+
+}
+
+#endif
Index: lib/AST/CMakeLists.txt
===================================================================
--- lib/AST/CMakeLists.txt
+++ lib/AST/CMakeLists.txt
@@ -5,6 +5,7 @@
ASTConsumer.cpp
ASTContext.cpp
ASTDiagnostic.cpp
+ ASTDumper.cpp
ASTImporter.cpp
AttrImpl.cpp
CXXInheritance.cpp
@@ -19,6 +20,7 @@
DeclarationName.cpp
DeclBase.cpp
DeclCXX.cpp
+ DeclDumper.cpp
DeclFriend.cpp
DeclGroup.cpp
DeclObjC.cpp
Index: lib/AST/DeclDumper.cpp
===================================================================
--- /dev/null
+++ lib/AST/DeclDumper.cpp
@@ -0,0 +1,114 @@
+//===--- DeclDumper.cpp - Dumping implementation for Decl ASTs ------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the Decl::dump method, which dumps out the
+// AST in a form that exposes type details and other fields.
+//
+//===----------------------------------------------------------------------===//
+#include "ASTDumper.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclVisitor.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
+#include "llvm/Support/raw_ostream.h"
+using namespace clang;
+
+namespace {
+ class DeclDumper : public DeclVisitor<DeclDumper> {
+ ASTDumper &Dumper;
+ raw_ostream &OS;
+
+ public:
+ DeclDumper(ASTDumper &Dumper, raw_ostream &OS)
+ : Dumper(Dumper), OS(OS) {
+ }
+
+ void dumpDecl(Decl *D);
+ void dumpDeclContext(DeclContext *DC);
+
+ void VisitEnumConstantDecl(EnumConstantDecl *D);
+ void VisitFunctionDecl(FunctionDecl *D);
+ void VisitFieldDecl(FieldDecl *D);
+ void VisitVarDecl(VarDecl *D);
+ };
+}
+
+void DeclDumper::dumpDecl(Decl *D) {
+ Dumper.indent();
+ if (D) {
+ OS << D->getDeclKindName() << "Decl"
+ << " " << (const void*)D;
+ Dumper.dumpSourceRange(D->getSourceRange());
+ if (isa<NamedDecl>(D))
+ OS << " " << cast<NamedDecl>(D)->getNameAsString();
+ Visit(D);
+ dumpDeclContext(dyn_cast<DeclContext>(D));
+ } else {
+ OS << "<<<NULL>>>";
+ }
+ Dumper.unindent();
+}
+
+void DeclDumper::dumpDeclContext(DeclContext *DC) {
+ // Decls within functions are visited by the body
+ if (!DC || isa<FunctionDecl>(*DC))
+ return;
+
+ for (DeclContext::decl_iterator D = DC->decls_begin(), DEnd = DC->decls_end();
+ D != DEnd; ++D)
+ dumpDecl(*D);
+}
+
+//----------------------------------------------------------------------------
+// Common C declarations
+//----------------------------------------------------------------------------
+
+void DeclDumper::VisitEnumConstantDecl(EnumConstantDecl *D) {
+ if (Expr *Init = D->getInitExpr())
+ Dumper.dumpStmt(Init);
+}
+
+void DeclDumper::VisitFunctionDecl(FunctionDecl *D) {
+ OS << ' ';
+ Dumper.dumpType(D->getType());
+ if (D->doesThisDeclarationHaveABody())
+ Dumper.dumpStmt(D->getBody());
+}
+
+void DeclDumper::VisitFieldDecl(FieldDecl *D) {
+ if (Expr *Init = D->getInClassInitializer())
+ Dumper.dumpStmt(Init);
+}
+
+void DeclDumper::VisitVarDecl(VarDecl *D) {
+ OS << ' ';
+ Dumper.dumpType(D->getType());
+ if (Expr *Init = D->getInit())
+ Dumper.dumpStmt(Init);
+}
+
+//===----------------------------------------------------------------------===//
+// Decl method implementations
+//===----------------------------------------------------------------------===//
+
+void ASTDumper::dumpDecl(Decl *D) {
+ DeclDumper Dumper(*this, OS);
+ Dumper.dumpDecl(D);
+}
+
+void Decl::dump(raw_ostream &OS) const {
+ ASTDumper Dumper(&getASTContext().getSourceManager(), OS);
+ Dumper.dumpDecl(const_cast<Decl*>(this));
+ Dumper.flush();
+}
+
+void Decl::dump() const {
+ dump(llvm::errs());
+}
Index: lib/AST/DeclPrinter.cpp
===================================================================
--- lib/AST/DeclPrinter.cpp
+++ lib/AST/DeclPrinter.cpp
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
//
-// This file implements the Decl::dump method, which pretty print the
+// This file implements the Decl::print method, which pretty prints the
// AST back out to C/Objective-C/C++/Objective-C++ code.
//
//===----------------------------------------------------------------------===//
@@ -172,16 +172,6 @@
Printer.VisitDeclContext(const_cast<DeclContext *>(this), /*Indent=*/false);
}
-void Decl::dump() const {
- dump(llvm::errs());
-}
-
-void Decl::dump(raw_ostream &Out) const {
- PrintingPolicy Policy = getASTContext().getPrintingPolicy();
- Policy.DumpSourceManager = &getASTContext().getSourceManager();
- print(Out, Policy, /*Indentation*/ 0, /*PrintInstantiation*/ true);
-}
-
raw_ostream& DeclPrinter::Indent(unsigned Indentation) {
for (unsigned i = 0; i != Indentation; ++i)
Out << " ";
Index: lib/AST/StmtDumper.cpp
===================================================================
--- lib/AST/StmtDumper.cpp
+++ lib/AST/StmtDumper.cpp
@@ -7,17 +7,15 @@
//
//===----------------------------------------------------------------------===//
//
-// 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.
//
//===----------------------------------------------------------------------===//
+#include "ASTDumper.h"
#include "clang/AST/StmtVisitor.h"
-#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclCXX.h"
-#include "clang/AST/PrettyPrinter.h"
-#include "clang/Basic/SourceManager.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
@@ -27,79 +25,41 @@
namespace {
class StmtDumper : public StmtVisitor<StmtDumper> {
- SourceManager *SM;
+ ASTDumper &Dumper;
raw_ostream &OS;
- unsigned IndentLevel;
-
- /// 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.
- unsigned MaxDepth;
-
- /// 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;
- unsigned LastLocLine;
public:
- StmtDumper(SourceManager *sm, raw_ostream &os, unsigned maxDepth)
- : SM(sm), OS(os), IndentLevel(0-1), MaxDepth(maxDepth) {
- LastLocFilename = "";
- LastLocLine = ~0U;
+ StmtDumper(ASTDumper &Dumper, raw_ostream &OS)
+ : Dumper(Dumper), OS(OS) {
}
void DumpSubTree(Stmt *S) {
- // Prune the recursion if not using dump all.
- if (MaxDepth == 0) return;
-
- ++IndentLevel;
+ Dumper.indent();
if (S) {
if (DeclStmt* DS = dyn_cast<DeclStmt>(S))
VisitDeclStmt(DS);
else {
Visit(S);
// Print out children.
Stmt::child_range CI = S->children();
- if (CI) {
- while (CI) {
- OS << '\n';
- DumpSubTree(*CI++);
- }
- }
+ while (CI)
+ DumpSubTree(*CI++);
}
- OS << ')';
} else {
- Indent();
OS << "<<<NULL>>>";
}
- --IndentLevel;
- }
-
- void DumpDeclarator(Decl *D);
-
- void Indent() const {
- for (int i = 0, e = IndentLevel; i < e; ++i)
- OS << " ";
+ Dumper.unindent();
}
void DumpType(QualType T) {
- SplitQualType T_split = T.split();
- OS << "'" << QualType::getAsString(T_split) << "'";
-
- if (!T.isNull()) {
- // If the type is sugared, also dump a (shallow) desugared type.
- SplitQualType D_split = T.getSplitDesugaredType();
- if (T_split != D_split)
- OS << ":'" << QualType::getAsString(D_split) << "'";
- }
+ Dumper.dumpType(T);
}
void DumpDeclRef(Decl *node);
void DumpStmt(const Stmt *Node) {
- Indent();
- OS << "(" << Node->getStmtClassName()
+ OS << Node->getStmtClassName()
<< " " << (const void*)Node;
- DumpSourceRange(Node);
+ Dumper.dumpSourceRange(Node->getSourceRange());
}
void DumpValueKind(ExprValueKind K) {
switch (K) {
@@ -124,8 +84,6 @@
DumpValueKind(Node->getValueKind());
DumpObjectKind(Node->getObjectKind());
}
- void DumpSourceRange(const Stmt *Node);
- void DumpLocation(SourceLocation Loc);
// Stmts.
void VisitStmt(Stmt *Node);
@@ -178,146 +136,18 @@
}
//===----------------------------------------------------------------------===//
-// Utilities
-//===----------------------------------------------------------------------===//
-
-void StmtDumper::DumpLocation(SourceLocation Loc) {
- SourceLocation SpellingLoc = SM->getSpellingLoc(Loc);
-
- // The general format we print out is filename:line:col, but we drop pieces
- // that haven't changed since the last loc printed.
- PresumedLoc PLoc = SM->getPresumedLoc(SpellingLoc);
-
- if (PLoc.isInvalid()) {
- OS << "<invalid sloc>";
- return;
- }
-
- if (strcmp(PLoc.getFilename(), LastLocFilename) != 0) {
- OS << PLoc.getFilename() << ':' << PLoc.getLine()
- << ':' << PLoc.getColumn();
- LastLocFilename = PLoc.getFilename();
- LastLocLine = PLoc.getLine();
- } else if (PLoc.getLine() != LastLocLine) {
- OS << "line" << ':' << PLoc.getLine()
- << ':' << PLoc.getColumn();
- LastLocLine = PLoc.getLine();
- } else {
- OS << "col" << ':' << PLoc.getColumn();
- }
-}
-
-void StmtDumper::DumpSourceRange(const Stmt *Node) {
- // Can't translate locations if a SourceManager isn't available.
- if (SM == 0) return;
-
- // TODO: If the parent expression is available, we can print a delta vs its
- // location.
- SourceRange R = Node->getSourceRange();
-
- OS << " <";
- DumpLocation(R.getBegin());
- if (R.getBegin() != R.getEnd()) {
- OS << ", ";
- DumpLocation(R.getEnd());
- }
- OS << ">";
-
- // <t2.c:123:421[blah], t2.c:412:321>
-
-}
-
-
-//===----------------------------------------------------------------------===//
// Stmt printing methods.
//===----------------------------------------------------------------------===//
void StmtDumper::VisitStmt(Stmt *Node) {
DumpStmt(Node);
}
-void StmtDumper::DumpDeclarator(Decl *D) {
- // FIXME: Need to complete/beautify this... this code simply shows the
- // nodes are where they need to be.
- if (TypedefDecl *localType = dyn_cast<TypedefDecl>(D)) {
- OS << "\"typedef " << localType->getUnderlyingType().getAsString()
- << ' ' << *localType << '"';
- } else if (TypeAliasDecl *localType = dyn_cast<TypeAliasDecl>(D)) {
- OS << "\"using " << *localType << " = "
- << localType->getUnderlyingType().getAsString() << '"';
- } else if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) {
- OS << "\"";
- // Emit storage class for vardecls.
- if (VarDecl *V = dyn_cast<VarDecl>(VD)) {
- if (V->getStorageClass() != SC_None)
- OS << VarDecl::getStorageClassSpecifierString(V->getStorageClass())
- << " ";
- }
-
- std::string Name = VD->getNameAsString();
- VD->getType().getAsStringInternal(Name,
- PrintingPolicy(VD->getASTContext().getLangOpts()));
- OS << Name;
-
- // If this is a vardecl with an initializer, emit it.
- if (VarDecl *V = dyn_cast<VarDecl>(VD)) {
- if (V->getInit()) {
- OS << " =\n";
- DumpSubTree(V->getInit());
- }
- }
- OS << '"';
- } else if (TagDecl *TD = dyn_cast<TagDecl>(D)) {
- // print a free standing tag decl (e.g. "struct x;").
- const char *tagname;
- if (const IdentifierInfo *II = TD->getIdentifier())
- tagname = II->getNameStart();
- else
- tagname = "<anonymous>";
- OS << '"' << TD->getKindName() << ' ' << tagname << ";\"";
- // FIXME: print tag bodies.
- } else if (UsingDirectiveDecl *UD = dyn_cast<UsingDirectiveDecl>(D)) {
- // print using-directive decl (e.g. "using namespace x;")
- const char *ns;
- if (const IdentifierInfo *II = UD->getNominatedNamespace()->getIdentifier())
- ns = II->getNameStart();
- else
- ns = "<anonymous>";
- OS << '"' << UD->getDeclKindName() << ns << ";\"";
- } else if (UsingDecl *UD = dyn_cast<UsingDecl>(D)) {
- // print using decl (e.g. "using std::string;")
- const char *tn = UD->isTypeName() ? "typename " : "";
- OS << '"' << UD->getDeclKindName() << tn;
- UD->getQualifier()->print(OS,
- PrintingPolicy(UD->getASTContext().getLangOpts()));
- OS << ";\"";
- } else if (LabelDecl *LD = dyn_cast<LabelDecl>(D)) {
- OS << "label " << *LD;
- } else if (StaticAssertDecl *SAD = dyn_cast<StaticAssertDecl>(D)) {
- OS << "\"static_assert(\n";
- DumpSubTree(SAD->getAssertExpr());
- OS << ",\n";
- DumpSubTree(SAD->getMessage());
- OS << ");\"";
- } else {
- llvm_unreachable("Unexpected decl");
- }
-}
-
void StmtDumper::VisitDeclStmt(DeclStmt *Node) {
DumpStmt(Node);
- OS << "\n";
for (DeclStmt::decl_iterator DI = Node->decl_begin(), DE = Node->decl_end();
- DI != DE; ++DI) {
- Decl* D = *DI;
- ++IndentLevel;
- Indent();
- OS << (void*) D << " ";
- DumpDeclarator(D);
- if (DI+1 != DE)
- OS << "\n";
- --IndentLevel;
- }
+ DI != DE; ++DI)
+ Dumper.dumpDecl(*DI);
}
void StmtDumper::VisitLabelStmt(LabelStmt *Node) {
@@ -503,35 +333,31 @@
BlockDecl *block = Node->getBlockDecl();
OS << " decl=" << block;
- IndentLevel++;
if (block->capturesCXXThis()) {
- OS << '\n'; Indent(); OS << "(capture this)";
+ Dumper.indent();
+ OS << "capture this";
+ Dumper.unindent();
}
for (BlockDecl::capture_iterator
i = block->capture_begin(), e = block->capture_end(); i != e; ++i) {
- OS << '\n';
- Indent();
- OS << "(capture ";
+ Dumper.indent();
+ 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 << ")";
+ Dumper.unindent();
}
- 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 +415,12 @@
void StmtDumper::VisitExprWithCleanups(ExprWithCleanups *Node) {
DumpExpr(Node);
- ++IndentLevel;
for (unsigned i = 0, e = Node->getNumObjects(); i != e; ++i) {
- OS << "\n";
- Indent();
- OS << "(cleanup ";
+ Dumper.indent();
+ OS << "cleanup ";
DumpDeclRef(Node->getObject(i));
- OS << ")";
+ Dumper.unindent();
}
- --IndentLevel;
}
void StmtDumper::DumpCXXTemporary(CXXTemporary *Temporary) {
@@ -638,8 +461,7 @@
void StmtDumper::VisitObjCAtCatchStmt(ObjCAtCatchStmt *Node) {
DumpStmt(Node);
if (VarDecl *CatchParam = Node->getCatchParamDecl()) {
- OS << " catch parm = ";
- DumpDeclarator(CatchParam);
+ Dumper.dumpDecl(CatchParam);
} else {
OS << " catch all";
}
@@ -724,38 +546,26 @@
// Stmt method implementations
//===----------------------------------------------------------------------===//
-/// dump - This does a local dump of the specified AST fragment. It dumps the
-/// specified node and a few nodes underneath it, but not the whole subtree.
-/// This is useful in a debugger.
+void ASTDumper::dumpStmt(Stmt *S) {
+ StmtDumper P(*this, OS);
+ P.DumpSubTree(S);
+}
+
+/// \brief This does a dump of the specified AST fragment and all subtrees.
void Stmt::dump(SourceManager &SM) const {
dump(llvm::errs(), SM);
}
+/// \brief This does a dump of the specified AST fragment and all subtrees.
void Stmt::dump(raw_ostream &OS, SourceManager &SM) const {
- StmtDumper P(&SM, OS, 4);
- P.DumpSubTree(const_cast<Stmt*>(this));
- OS << "\n";
+ ASTDumper Dumper(&SM, OS);
+ Dumper.dumpStmt(const_cast<Stmt*>(this));
+ Dumper.flush();
}
-/// dump - This does a local dump of the specified AST fragment. It dumps the
-/// specified node and a few nodes underneath it, but not the whole subtree.
-/// This is useful in a debugger.
+/// \brief This does a dump of the specified AST fragment and all subtrees.
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";
+ ASTDumper Dumper(0, llvm::errs());
+ Dumper.dumpStmt(const_cast<Stmt*>(this));
+ Dumper.flush();
}
Index: unittests/AST/CMakeLists.txt
===================================================================
--- unittests/AST/CMakeLists.txt
+++ unittests/AST/CMakeLists.txt
@@ -1,7 +1,9 @@
add_clang_unittest(ASTTests
CommentLexer.cpp
CommentParser.cpp
+ DeclDumperTest.cpp
DeclPrinterTest.cpp
+ StmtDumperTest.cpp
StmtPrinterTest.cpp
)
Index: unittests/AST/DeclDumperTest.cpp
===================================================================
--- /dev/null
+++ unittests/AST/DeclDumperTest.cpp
@@ -0,0 +1,126 @@
+//===- unittests/AST/DeclDumperTest.cpp --- Declaration dumper tests ------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains tests for Decl::dump() and related methods.
+//
+// These tests have a coding convention:
+// * declaration to be dumped is named 'A' unless it should have some special
+// name (e.g., 'operator+');
+// * additional helper declarations are 'Z', 'Y', 'X' and so on.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/Regex.h"
+#include "gtest/gtest.h"
+
+using namespace clang;
+using namespace ast_matchers;
+using namespace tooling;
+
+namespace {
+
+class DumpMatch : public MatchFinder::MatchCallback {
+ SmallString<1024> Dumped;
+ unsigned NumFoundDecls;
+
+public:
+ DumpMatch() : NumFoundDecls(0) {}
+
+ virtual void run(const MatchFinder::MatchResult &Result) {
+ const Decl *D = Result.Nodes.getDeclAs<Decl>("id");
+ if (!D || D->isImplicit())
+ return;
+ NumFoundDecls++;
+ if (NumFoundDecls > 1)
+ return;
+
+ llvm::raw_svector_ostream Out(Dumped);
+ D->dump(Out);
+ }
+
+ StringRef getDumped() const {
+ return Dumped;
+ }
+
+ unsigned getNumFoundDecls() const {
+ return NumFoundDecls;
+ }
+};
+
+::testing::AssertionResult DumpedDeclMatches(
+ StringRef Code,
+ const std::vector<std::string> &Args,
+ const DeclarationMatcher &NodeMatch,
+ StringRef ExpectedDumped) {
+ DumpMatch Dumper;
+ MatchFinder Finder;
+ Finder.addMatcher(NodeMatch, &Dumper);
+ OwningPtr<FrontendActionFactory> Factory(newFrontendActionFactory(&Finder));
+
+ if (!runToolOnCodeWithArgs(Factory->create(), Code, Args))
+ return testing::AssertionFailure() << "Parsing error in \"" << Code << "\"";
+
+ if (Dumper.getNumFoundDecls() == 0)
+ return testing::AssertionFailure()
+ << "Matcher didn't find any declarations";
+
+ if (Dumper.getNumFoundDecls() > 1)
+ return testing::AssertionFailure()
+ << "Matcher should match only one declaration "
+ "(found " << Dumper.getNumFoundDecls() << ")";
+
+ std::string Dumped = Dumper.getDumped();
+ llvm::Regex AddressRegex("0x[^X ]+");
+ while (AddressRegex.match(Dumped))
+ Dumped = AddressRegex.sub("0xXXXXXXXX", Dumped);
+
+ if (Dumped != ExpectedDumped)
+ return ::testing::AssertionFailure()
+ << "Expected \"" << ExpectedDumped << "\", got \"" << Dumped << "\"";
+
+ return ::testing::AssertionSuccess();
+}
+
+::testing::AssertionResult DumpedDeclCXX98Matches(StringRef Code,
+ StringRef DeclName,
+ StringRef ExpectedDumped) {
+ std::vector<std::string> Args(1, "-std=c++98");
+ return DumpedDeclMatches(Code,
+ Args,
+ namedDecl(hasName(DeclName)).bind("id"),
+ ExpectedDumped);
+}
+
+} // unnamed namespace
+
+TEST(DeclDumper, TestFunctionDecl) {
+ ASSERT_TRUE(DumpedDeclCXX98Matches(
+ "int A(int a) {\n"
+ " return a;\n"
+ "}\n",
+ "A",
+ "(FunctionDecl 0xXXXXXXXX <input.cc:1:1, line:3:1> A 'int (int)'\n"
+ " (CompoundStmt 0xXXXXXXXX <line:1:14, line:3:1>\n"
+ " (ReturnStmt 0xXXXXXXXX <line:2:3, col:10>\n"
+ " (ImplicitCastExpr 0xXXXXXXXX <col:10> 'int' <LValueToRValue>\n"
+ " (DeclRefExpr 0xXXXXXXXX <col:10> 'int' lvalue ParmVar 0xXXXXXXXX 'a' 'int')))))\n"));
+}
+
+
+TEST(DeclDumper, TestVarDecl) {
+ ASSERT_TRUE(DumpedDeclCXX98Matches(
+ "int A = 1;",
+ "A",
+ "(VarDecl 0xXXXXXXXX <input.cc:1:1, col:9> A 'int'\n"
+ " (IntegerLiteral 0xXXXXXXXX <col:9> 'int' 1))\n"));
+}
Index: unittests/AST/StmtDumperTest.cpp
===================================================================
--- /dev/null
+++ unittests/AST/StmtDumperTest.cpp
@@ -0,0 +1,121 @@
+//===- unittests/AST/StmtDumperTest.cpp --- Statement dumper tests --------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains tests for Stmt::dump() and related methods.
+//
+// These tests have a coding convention:
+// * statements to be dumped should be contained within a function named 'A'
+// unless it should have some special name (e.g., 'operator+');
+// * additional helper declarations are 'Z', 'Y', 'X' and so on.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/Regex.h"
+#include "gtest/gtest.h"
+
+using namespace clang;
+using namespace ast_matchers;
+using namespace tooling;
+
+namespace {
+
+class DumpMatch : public MatchFinder::MatchCallback {
+ SmallString<1024> Dumped;
+ unsigned NumFoundStmts;
+
+public:
+ DumpMatch() : NumFoundStmts(0) {}
+
+ virtual void run(const MatchFinder::MatchResult &Result) {
+ const Stmt *S = Result.Nodes.getStmtAs<Stmt>("id");
+ if (!S)
+ return;
+ NumFoundStmts++;
+ if (NumFoundStmts > 1)
+ return;
+
+ llvm::raw_svector_ostream Out(Dumped);
+ S->dump(Out, Result.Context->getSourceManager());
+ }
+
+ StringRef getDumped() const {
+ return Dumped;
+ }
+
+ unsigned getNumFoundStmts() const {
+ return NumFoundStmts;
+ }
+};
+
+::testing::AssertionResult DumpedStmtMatches(
+ StringRef Code,
+ const std::vector<std::string> &Args,
+ const DeclarationMatcher &NodeMatch,
+ StringRef ExpectedDumped) {
+
+ DumpMatch Dumper;
+ MatchFinder Finder;
+ Finder.addMatcher(NodeMatch, &Dumper);
+ OwningPtr<FrontendActionFactory> Factory(newFrontendActionFactory(&Finder));
+
+ if (!runToolOnCodeWithArgs(Factory->create(), Code, Args))
+ return testing::AssertionFailure() << "Parsing error in \"" << Code << "\"";
+
+ if (Dumper.getNumFoundStmts() == 0)
+ return testing::AssertionFailure()
+ << "Matcher didn't find any statements";
+
+ if (Dumper.getNumFoundStmts() > 1)
+ return testing::AssertionFailure()
+ << "Matcher should match only one statement "
+ "(found " << Dumper.getNumFoundStmts() << ")";
+
+ std::string Dumped = Dumper.getDumped();
+ llvm::Regex AddressRegex("0x[^X ]+");
+ while (AddressRegex.match(Dumped))
+ Dumped = AddressRegex.sub("0xXXXXXXXX", Dumped);
+
+ if (Dumped != ExpectedDumped)
+ return ::testing::AssertionFailure()
+ << "Expected \"" << ExpectedDumped << "\", got \"" << Dumped << "\"";
+
+ return ::testing::AssertionSuccess();
+}
+
+::testing::AssertionResult DumpedStmtCXX98Matches(
+ StringRef Code,
+ StringRef ContainingFunction,
+ StringRef ExpectedDumped) {
+ std::vector<std::string> Args;
+ Args.push_back("-std=c++98");
+ Args.push_back("-Wno-unused-value");
+ return DumpedStmtMatches(Code,
+ Args,
+ functionDecl(hasName(ContainingFunction),
+ has(compoundStmt(has(stmt().bind("id"))))),
+ ExpectedDumped);
+}
+
+} // unnamed namespace
+
+TEST(StmtDumper, TestDeclStmt) {
+ ASSERT_TRUE(DumpedStmtCXX98Matches(
+ "void A() {\n"
+ " int a = 1, b;\n"
+ "}",
+ "A",
+ "(DeclStmt 0xXXXXXXXX <input.cc:2:3, col:15>\n"
+ " (VarDecl 0xXXXXXXXX <col:3, col:11> a 'int'\n"
+ " (IntegerLiteral 0xXXXXXXXX <col:11> 'int' 1))\n"
+ " (VarDecl 0xXXXXXXXX <col:3, col:14> b 'int'))\n"));
+}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits