summaryrefslogtreecommitdiff
path: root/unittests/AST
diff options
context:
space:
mode:
Diffstat (limited to 'unittests/AST')
-rw-r--r--unittests/AST/ASTContextParentMapTest.cpp4
-rw-r--r--unittests/AST/ASTImporterTest.cpp460
-rw-r--r--unittests/AST/ASTTypeTraitsTest.cpp17
-rw-r--r--unittests/AST/CMakeLists.txt2
-rw-r--r--unittests/AST/Makefile19
-rw-r--r--unittests/AST/MatchVerifier.h19
-rw-r--r--unittests/AST/PostOrderASTVisitor.cpp123
7 files changed, 618 insertions, 26 deletions
diff --git a/unittests/AST/ASTContextParentMapTest.cpp b/unittests/AST/ASTContextParentMapTest.cpp
index b1d7db4164ef..a39189620b69 100644
--- a/unittests/AST/ASTContextParentMapTest.cpp
+++ b/unittests/AST/ASTContextParentMapTest.cpp
@@ -21,10 +21,6 @@
namespace clang {
namespace ast_matchers {
-using clang::tooling::newFrontendActionFactory;
-using clang::tooling::runToolOnCodeWithArgs;
-using clang::tooling::FrontendActionFactory;
-
TEST(GetParents, ReturnsParentForDecl) {
MatchVerifier<Decl> Verifier;
EXPECT_TRUE(
diff --git a/unittests/AST/ASTImporterTest.cpp b/unittests/AST/ASTImporterTest.cpp
new file mode 100644
index 000000000000..3cc38fb55b2e
--- /dev/null
+++ b/unittests/AST/ASTImporterTest.cpp
@@ -0,0 +1,460 @@
+//===- unittest/AST/ASTImporterTest.cpp - AST node import test ------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Tests for the correct import of AST nodes from one AST context to another.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTImporter.h"
+#include "MatchVerifier.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Tooling/Tooling.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace ast_matchers {
+
+typedef std::vector<std::string> StringVector;
+
+void getLangArgs(Language Lang, StringVector &Args) {
+ switch (Lang) {
+ case Lang_C:
+ Args.insert(Args.end(), { "-x", "c", "-std=c99" });
+ break;
+ case Lang_C89:
+ Args.insert(Args.end(), { "-x", "c", "-std=c89" });
+ break;
+ case Lang_CXX:
+ Args.push_back("-std=c++98");
+ break;
+ case Lang_CXX11:
+ Args.push_back("-std=c++11");
+ break;
+ case Lang_OpenCL:
+ case Lang_OBJCXX:
+ break;
+ }
+}
+
+template<typename NodeType, typename MatcherType>
+testing::AssertionResult
+testImport(const std::string &FromCode, Language FromLang,
+ const std::string &ToCode, Language ToLang,
+ MatchVerifier<NodeType> &Verifier,
+ const MatcherType &AMatcher) {
+ StringVector FromArgs, ToArgs;
+ getLangArgs(FromLang, FromArgs);
+ getLangArgs(ToLang, ToArgs);
+
+ const char *const InputFileName = "input.cc";
+ const char *const OutputFileName = "output.cc";
+
+ std::unique_ptr<ASTUnit>
+ FromAST = tooling::buildASTFromCodeWithArgs(
+ FromCode, FromArgs, InputFileName),
+ ToAST = tooling::buildASTFromCodeWithArgs(ToCode, ToArgs, OutputFileName);
+
+ ASTContext &FromCtx = FromAST->getASTContext(),
+ &ToCtx = ToAST->getASTContext();
+
+ // Add input.cc to virtual file system so importer can 'find' it
+ // while importing SourceLocations.
+ vfs::OverlayFileSystem *OFS = static_cast<vfs::OverlayFileSystem *>(
+ ToCtx.getSourceManager().getFileManager().getVirtualFileSystem().get());
+ vfs::InMemoryFileSystem *MFS = static_cast<vfs::InMemoryFileSystem *>(
+ OFS->overlays_begin()->get());
+ MFS->addFile(InputFileName, 0,
+ llvm::MemoryBuffer::getMemBuffer(FromCode.c_str()));
+
+ ASTImporter Importer(ToCtx, ToAST->getFileManager(),
+ FromCtx, FromAST->getFileManager(), false);
+
+ IdentifierInfo *ImportedII = &FromCtx.Idents.get("declToImport");
+ assert(ImportedII && "Declaration with 'declToImport' name"
+ "should be specified in test!");
+ DeclarationName ImportDeclName(ImportedII);
+ SmallVector<NamedDecl *, 4> FoundDecls;
+ FromCtx.getTranslationUnitDecl()->localUncachedLookup(
+ ImportDeclName, FoundDecls);
+
+ if (FoundDecls.size() != 1)
+ return testing::AssertionFailure() << "Multiple declarations were found!";
+
+ auto Imported = Importer.Import(*FoundDecls.begin());
+ if (!Imported)
+ return testing::AssertionFailure() << "Import failed, nullptr returned!";
+
+ // This should dump source locations and assert if some source locations
+ // were not imported
+ SmallString<1024> ImportChecker;
+ llvm::raw_svector_ostream ToNothing(ImportChecker);
+ ToCtx.getTranslationUnitDecl()->print(ToNothing);
+
+ return Verifier.match(Imported, AMatcher);
+}
+
+TEST(ImportExpr, ImportStringLiteral) {
+ MatchVerifier<Decl> Verifier;
+ EXPECT_TRUE(testImport("void declToImport() { \"foo\"; }",
+ Lang_CXX, "", Lang_CXX, Verifier,
+ functionDecl(
+ hasBody(
+ compoundStmt(
+ has(
+ stringLiteral(
+ hasType(
+ asString("const char [4]")))))))));
+ EXPECT_TRUE(testImport("void declToImport() { L\"foo\"; }",
+ Lang_CXX, "", Lang_CXX, Verifier,
+ functionDecl(
+ hasBody(
+ compoundStmt(
+ has(
+ stringLiteral(
+ hasType(
+ asString("const wchar_t [4]")))))))));
+ EXPECT_TRUE(testImport("void declToImport() { \"foo\" \"bar\"; }",
+ Lang_CXX, "", Lang_CXX, Verifier,
+ functionDecl(
+ hasBody(
+ compoundStmt(
+ has(
+ stringLiteral(
+ hasType(
+ asString("const char [7]")))))))));
+}
+
+TEST(ImportExpr, ImportGNUNullExpr) {
+ MatchVerifier<Decl> Verifier;
+ EXPECT_TRUE(testImport("void declToImport() { __null; }",
+ Lang_CXX, "", Lang_CXX, Verifier,
+ functionDecl(
+ hasBody(
+ compoundStmt(
+ has(
+ gnuNullExpr(
+ hasType(isInteger()))))))));
+}
+
+TEST(ImportExpr, ImportCXXNullPtrLiteralExpr) {
+ MatchVerifier<Decl> Verifier;
+ EXPECT_TRUE(testImport("void declToImport() { nullptr; }",
+ Lang_CXX11, "", Lang_CXX11, Verifier,
+ functionDecl(
+ hasBody(
+ compoundStmt(
+ has(
+ cxxNullPtrLiteralExpr()))))));
+}
+
+
+TEST(ImportExpr, ImportFloatinglLiteralExpr) {
+ MatchVerifier<Decl> Verifier;
+ EXPECT_TRUE(testImport("void declToImport() { 1.0; }",
+ Lang_CXX, "", Lang_CXX, Verifier,
+ functionDecl(
+ hasBody(
+ compoundStmt(
+ has(
+ floatLiteral(
+ equals(1.0),
+ hasType(asString("double")))))))));
+ EXPECT_TRUE(testImport("void declToImport() { 1.0e-5f; }",
+ Lang_CXX, "", Lang_CXX, Verifier,
+ functionDecl(
+ hasBody(
+ compoundStmt(
+ has(
+ floatLiteral(
+ equals(1.0e-5f),
+ hasType(asString("float")))))))));
+}
+
+TEST(ImportExpr, ImportCompoundLiteralExpr) {
+ MatchVerifier<Decl> Verifier;
+ EXPECT_TRUE(
+ testImport(
+ "void declToImport() {"
+ " struct s { int x; long y; unsigned z; }; "
+ " (struct s){ 42, 0L, 1U }; }",
+ Lang_CXX, "", Lang_CXX, Verifier,
+ functionDecl(
+ hasBody(
+ compoundStmt(
+ has(
+ compoundLiteralExpr(
+ hasType(asString("struct s")),
+ has(initListExpr(
+ hasType(asString("struct s")),
+ has(integerLiteral(
+ equals(42), hasType(asString("int")))),
+ has(integerLiteral(
+ equals(0), hasType(asString("long")))),
+ has(integerLiteral(
+ equals(1),
+ hasType(asString("unsigned int"))))
+ )))))))));
+}
+
+TEST(ImportExpr, ImportCXXThisExpr) {
+ MatchVerifier<Decl> Verifier;
+ EXPECT_TRUE(
+ testImport("class declToImport { void f() { this; } };",
+ Lang_CXX, "", Lang_CXX, Verifier,
+ cxxRecordDecl(
+ hasMethod(
+ hasBody(
+ compoundStmt(
+ has(
+ cxxThisExpr(
+ hasType(
+ asString("class declToImport *"))))))))));
+}
+
+TEST(ImportExpr, ImportAtomicExpr) {
+ MatchVerifier<Decl> Verifier;
+ EXPECT_TRUE(testImport(
+ "void declToImport() { int *ptr; __atomic_load_n(ptr, 1); }", Lang_CXX,
+ "", Lang_CXX, Verifier,
+ functionDecl(hasBody(compoundStmt(has(atomicExpr(
+ has(ignoringParenImpCasts(
+ declRefExpr(hasDeclaration(varDecl(hasName("ptr"))),
+ hasType(asString("int *"))))),
+ has(integerLiteral(equals(1), hasType(asString("int")))))))))));
+}
+
+TEST(ImportExpr, ImportLabelDeclAndAddrLabelExpr) {
+ MatchVerifier<Decl> Verifier;
+ EXPECT_TRUE(
+ testImport(
+ "void declToImport() { loop: goto loop; &&loop; }",
+ Lang_CXX, "", Lang_CXX, Verifier,
+ functionDecl(
+ hasBody(
+ compoundStmt(
+ has(labelStmt(hasDeclaration(labelDecl(hasName("loop"))))),
+ has(addrLabelExpr(hasDeclaration(labelDecl(hasName("loop")))))
+ )))));
+}
+
+AST_MATCHER_P(TemplateDecl, hasTemplateDecl,
+ internal::Matcher<NamedDecl>, InnerMatcher) {
+ const NamedDecl *Template = Node.getTemplatedDecl();
+ return Template && InnerMatcher.matches(*Template, Finder, Builder);
+}
+
+TEST(ImportExpr, ImportParenListExpr) {
+ MatchVerifier<Decl> Verifier;
+ EXPECT_TRUE(
+ testImport(
+ "template<typename T> class dummy { void f() { dummy X(*this); } };"
+ "typedef dummy<int> declToImport;"
+ "template class dummy<int>;",
+ Lang_CXX, "", Lang_CXX, Verifier,
+ typedefDecl(
+ hasType(
+ templateSpecializationType(
+ hasDeclaration(
+ classTemplateDecl(
+ hasTemplateDecl(
+ cxxRecordDecl(
+ hasMethod(
+ allOf(
+ hasName("f"),
+ hasBody(
+ compoundStmt(
+ has(
+ declStmt(
+ hasSingleDecl(
+ varDecl(
+ hasInitializer(
+ parenListExpr(
+ has(
+ unaryOperator(
+ hasOperatorName("*"),
+ hasUnaryOperand(cxxThisExpr())
+ )))))))))))))))))))));
+}
+
+TEST(ImportExpr, ImportStmtExpr) {
+ MatchVerifier<Decl> Verifier;
+ // NOTE: has() ignores implicit casts, using hasDescendant() to match it
+ EXPECT_TRUE(
+ testImport(
+ "void declToImport() { int b; int a = b ?: 1; int C = ({int X=4; X;}); }",
+ Lang_CXX, "", Lang_CXX, Verifier,
+ functionDecl(
+ hasBody(
+ compoundStmt(
+ has(
+ declStmt(
+ hasSingleDecl(
+ varDecl(
+ hasName("C"),
+ hasType(asString("int")),
+ hasInitializer(
+ stmtExpr(
+ hasAnySubstatement(
+ declStmt(
+ hasSingleDecl(
+ varDecl(
+ hasName("X"),
+ hasType(asString("int")),
+ hasInitializer(
+ integerLiteral(equals(4))))))),
+ hasDescendant(
+ implicitCastExpr()
+ ))))))))))));
+}
+
+TEST(ImportExpr, ImportConditionalOperator) {
+ MatchVerifier<Decl> Verifier;
+ EXPECT_TRUE(
+ testImport(
+ "void declToImport() { true ? 1 : -5; }",
+ Lang_CXX, "", Lang_CXX, Verifier,
+ functionDecl(
+ hasBody(
+ compoundStmt(
+ has(
+ conditionalOperator(
+ hasCondition(cxxBoolLiteral(equals(true))),
+ hasTrueExpression(integerLiteral(equals(1))),
+ hasFalseExpression(
+ unaryOperator(hasUnaryOperand(integerLiteral(equals(5))))
+ ))))))));
+}
+
+TEST(ImportExpr, ImportBinaryConditionalOperator) {
+ MatchVerifier<Decl> Verifier;
+ EXPECT_TRUE(
+ testImport(
+ "void declToImport() { 1 ?: -5; }",
+ Lang_CXX, "", Lang_CXX, Verifier,
+ functionDecl(
+ hasBody(
+ compoundStmt(
+ has(
+ binaryConditionalOperator(
+ hasCondition(
+ implicitCastExpr(
+ hasSourceExpression(
+ opaqueValueExpr(
+ hasSourceExpression(integerLiteral(equals(1))))),
+ hasType(booleanType()))),
+ hasTrueExpression(
+ opaqueValueExpr(hasSourceExpression(
+ integerLiteral(equals(1))))),
+ hasFalseExpression(
+ unaryOperator(hasOperatorName("-"),
+ hasUnaryOperand(integerLiteral(equals(5)))))
+ )))))));
+}
+
+TEST(ImportExpr, ImportDesignatedInitExpr) {
+ MatchVerifier<Decl> Verifier;
+ EXPECT_TRUE(testImport("void declToImport() {"
+ " struct point { double x; double y; };"
+ " struct point ptarray[10] = "
+ "{ [2].y = 1.0, [2].x = 2.0, [0].x = 1.0 }; }",
+ Lang_C, "", Lang_C, Verifier,
+ functionDecl(
+ hasBody(
+ compoundStmt(
+ has(
+ declStmt(
+ hasSingleDecl(
+ varDecl(
+ hasInitializer(
+ initListExpr(
+ hasSyntacticForm(
+ initListExpr(
+ has(
+ designatedInitExpr(
+ designatorCountIs(2),
+ has(floatLiteral(
+ equals(1.0))),
+ has(integerLiteral(
+ equals(2))))),
+ has(
+ designatedInitExpr(
+ designatorCountIs(2),
+ has(floatLiteral(
+ equals(2.0))),
+ has(integerLiteral(
+ equals(2))))),
+ has(
+ designatedInitExpr(
+ designatorCountIs(2),
+ has(floatLiteral(
+ equals(1.0))),
+ has(integerLiteral(
+ equals(0)))))
+ )))))))))))));
+}
+
+
+TEST(ImportExpr, ImportPredefinedExpr) {
+ MatchVerifier<Decl> Verifier;
+ // __func__ expands as StringLiteral("declToImport")
+ EXPECT_TRUE(testImport("void declToImport() { __func__; }",
+ Lang_CXX, "", Lang_CXX, Verifier,
+ functionDecl(
+ hasBody(
+ compoundStmt(
+ has(
+ predefinedExpr(
+ hasType(
+ asString("const char [13]")),
+ has(
+ stringLiteral(
+ hasType(
+ asString("const char [13]")))))))))));
+}
+
+TEST(ImportExpr, ImportInitListExpr) {
+ MatchVerifier<Decl> Verifier;
+ EXPECT_TRUE(
+ testImport(
+ "void declToImport() {"
+ " struct point { double x; double y; };"
+ " point ptarray[10] = { [2].y = 1.0, [2].x = 2.0,"
+ " [0].x = 1.0 }; }",
+ Lang_CXX, "", Lang_CXX, Verifier,
+ functionDecl(
+ hasBody(
+ compoundStmt(
+ has(
+ declStmt(
+ hasSingleDecl(
+ varDecl(
+ hasInitializer(
+ initListExpr(
+ has(
+ cxxConstructExpr(
+ requiresZeroInitialization())),
+ has(
+ initListExpr(
+ hasType(asString("struct point")),
+ has(floatLiteral(equals(1.0))),
+ has(implicitValueInitExpr(
+ hasType(asString("double")))))),
+ has(
+ initListExpr(
+ hasType(asString("struct point")),
+ has(floatLiteral(equals(2.0))),
+ has(floatLiteral(equals(1.0)))))
+ )))))))))));
+}
+
+
+} // end namespace ast_matchers
+} // end namespace clang
diff --git a/unittests/AST/ASTTypeTraitsTest.cpp b/unittests/AST/ASTTypeTraitsTest.cpp
index b6356538a12a..436cd7751411 100644
--- a/unittests/AST/ASTTypeTraitsTest.cpp
+++ b/unittests/AST/ASTTypeTraitsTest.cpp
@@ -107,10 +107,21 @@ TEST(ASTNodeKind, UnknownKind) {
}
TEST(ASTNodeKind, Name) {
- EXPECT_EQ("Decl", DNT<Decl>().asStringRef());
- EXPECT_EQ("CallExpr", DNT<CallExpr>().asStringRef());
- EXPECT_EQ("ConstantArrayType", DNT<ConstantArrayType>().asStringRef());
EXPECT_EQ("<None>", ASTNodeKind().asStringRef());
+#define VERIFY_NAME(Node) EXPECT_EQ(#Node, DNT<Node>().asStringRef());
+ VERIFY_NAME(TemplateArgument);
+ VERIFY_NAME(NestedNameSpecifierLoc);
+ VERIFY_NAME(QualType);
+ VERIFY_NAME(TypeLoc);
+ VERIFY_NAME(CXXCtorInitializer);
+ VERIFY_NAME(NestedNameSpecifier);
+ VERIFY_NAME(Decl);
+ VERIFY_NAME(CXXRecordDecl);
+ VERIFY_NAME(Stmt);
+ VERIFY_NAME(CallExpr);
+ VERIFY_NAME(Type);
+ VERIFY_NAME(ConstantArrayType);
+#undef VERIFY_NAME
}
TEST(DynTypedNode, DeclSourceRange) {
diff --git a/unittests/AST/CMakeLists.txt b/unittests/AST/CMakeLists.txt
index 2fa1078a5e1b..a7008f3e7e09 100644
--- a/unittests/AST/CMakeLists.txt
+++ b/unittests/AST/CMakeLists.txt
@@ -4,6 +4,7 @@ set(LLVM_LINK_COMPONENTS
add_clang_unittest(ASTTests
ASTContextParentMapTest.cpp
+ ASTImporterTest.cpp
ASTTypeTraitsTest.cpp
ASTVectorTest.cpp
CommentLexer.cpp
@@ -13,6 +14,7 @@ add_clang_unittest(ASTTests
EvaluateAsRValueTest.cpp
ExternalASTSourceTest.cpp
NamedDeclPrinterTest.cpp
+ PostOrderASTVisitor.cpp
SourceLocationTest.cpp
StmtPrinterTest.cpp
)
diff --git a/unittests/AST/Makefile b/unittests/AST/Makefile
deleted file mode 100644
index e3b3d7dc33e8..000000000000
--- a/unittests/AST/Makefile
+++ /dev/null
@@ -1,19 +0,0 @@
-##===- unittests/AST/Makefile ------------------------------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-
-CLANG_LEVEL = ../..
-TESTNAME = AST
-include $(CLANG_LEVEL)/../../Makefile.config
-LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc option
-USEDLIBS = clangTooling.a clangFrontend.a clangSerialization.a clangDriver.a \
- clangRewrite.a clangRewriteFrontend.a \
- clangParse.a clangSema.a clangAnalysis.a \
- clangEdit.a clangAST.a clangASTMatchers.a clangLex.a clangBasic.a
-
-include $(CLANG_LEVEL)/unittests/Makefile
diff --git a/unittests/AST/MatchVerifier.h b/unittests/AST/MatchVerifier.h
index 31932479ef8d..74b9bdfbe7e6 100644
--- a/unittests/AST/MatchVerifier.h
+++ b/unittests/AST/MatchVerifier.h
@@ -62,6 +62,9 @@ public:
std::vector<std::string>& Args,
Language L);
+ template <typename MatcherType>
+ testing::AssertionResult match(const Decl *D, const MatcherType &AMatcher);
+
protected:
void run(const MatchFinder::MatchResult &Result) override;
virtual void verify(const MatchFinder::MatchResult &Result,
@@ -127,6 +130,22 @@ testing::AssertionResult MatchVerifier<NodeType>::match(
return testing::AssertionSuccess();
}
+/// \brief Runs a matcher over some AST, and returns the result of the
+/// verifier for the matched node.
+template <typename NodeType> template <typename MatcherType>
+testing::AssertionResult MatchVerifier<NodeType>::match(
+ const Decl *D, const MatcherType &AMatcher) {
+ MatchFinder Finder;
+ Finder.addMatcher(AMatcher.bind(""), this);
+
+ setFailure("Could not find match");
+ Finder.match(*D, D->getASTContext());
+
+ if (!Verified)
+ return testing::AssertionFailure() << VerifyResult;
+ return testing::AssertionSuccess();
+}
+
template <typename NodeType>
void MatchVerifier<NodeType>::run(const MatchFinder::MatchResult &Result) {
const NodeType *Node = Result.Nodes.getNodeAs<NodeType>("");
diff --git a/unittests/AST/PostOrderASTVisitor.cpp b/unittests/AST/PostOrderASTVisitor.cpp
new file mode 100644
index 000000000000..012f63a48ade
--- /dev/null
+++ b/unittests/AST/PostOrderASTVisitor.cpp
@@ -0,0 +1,123 @@
+//===- unittests/AST/PostOrderASTVisitor.cpp - Declaration printer 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 the post-order traversing functionality
+// of RecursiveASTVisitor.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/Tooling/Tooling.h"
+#include "gtest/gtest.h"
+
+using namespace clang;
+
+namespace {
+
+ class RecordingVisitor
+ : public RecursiveASTVisitor<RecordingVisitor> {
+
+ bool VisitPostOrder;
+ public:
+ explicit RecordingVisitor(bool VisitPostOrder)
+ : VisitPostOrder(VisitPostOrder) {
+ }
+
+ // List of visited nodes during traversal.
+ std::vector<std::string> VisitedNodes;
+
+ bool shouldTraversePostOrder() const { return VisitPostOrder; }
+
+ bool VisitBinaryOperator(BinaryOperator *Op) {
+ VisitedNodes.push_back(Op->getOpcodeStr());
+ return true;
+ }
+
+ bool VisitIntegerLiteral(IntegerLiteral *Lit) {
+ VisitedNodes.push_back(Lit->getValue().toString(10, false));
+ return true;
+ }
+
+ bool VisitVarDecl(VarDecl* D) {
+ VisitedNodes.push_back(D->getNameAsString());
+ return true;
+ }
+
+ bool VisitCXXMethodDecl(CXXMethodDecl *D) {
+ VisitedNodes.push_back(D->getQualifiedNameAsString());
+ return true;
+ }
+
+ bool VisitReturnStmt(ReturnStmt *S) {
+ VisitedNodes.push_back("return");
+ return true;
+ }
+
+ bool VisitCXXRecordDecl(CXXRecordDecl *Declaration) {
+ VisitedNodes.push_back(Declaration->getQualifiedNameAsString());
+ return true;
+ }
+
+ bool VisitTemplateTypeParmType(TemplateTypeParmType *T) {
+ VisitedNodes.push_back(T->getDecl()->getQualifiedNameAsString());
+ return true;
+ }
+ };
+
+}
+
+TEST(RecursiveASTVisitor, PostOrderTraversal) {
+ auto ASTUnit = tooling::buildASTFromCode(
+ "class A {"
+ " class B {"
+ " int foo() { while(4) { int i = 9; } return (1 + 3) + 2; }"
+ " };"
+ "};"
+ );
+ auto TU = ASTUnit->getASTContext().getTranslationUnitDecl();
+ // We traverse the translation unit and store all
+ // visited nodes.
+ RecordingVisitor Visitor(true);
+ Visitor.TraverseTranslationUnitDecl(TU);
+
+ std::vector<std::string> expected = {
+ "4", "9", "i", "1", "3", "+", "2", "+", "return", "A::B::foo", "A::B", "A"
+ };
+ // Compare the list of actually visited nodes
+ // with the expected list of visited nodes.
+ ASSERT_EQ(expected.size(), Visitor.VisitedNodes.size());
+ for (std::size_t I = 0; I < expected.size(); I++) {
+ ASSERT_EQ(expected[I], Visitor.VisitedNodes[I]);
+ }
+}
+
+TEST(RecursiveASTVisitor, NoPostOrderTraversal) {
+ auto ASTUnit = tooling::buildASTFromCode(
+ "class A {"
+ " class B {"
+ " int foo() { return 1 + 2; }"
+ " };"
+ "};"
+ );
+ auto TU = ASTUnit->getASTContext().getTranslationUnitDecl();
+ // We traverse the translation unit and store all
+ // visited nodes.
+ RecordingVisitor Visitor(false);
+ Visitor.TraverseTranslationUnitDecl(TU);
+
+ std::vector<std::string> expected = {
+ "A", "A::B", "A::B::foo", "return", "+", "1", "2"
+ };
+ // Compare the list of actually visited nodes
+ // with the expected list of visited nodes.
+ ASSERT_EQ(expected.size(), Visitor.VisitedNodes.size());
+ for (std::size_t I = 0; I < expected.size(); I++) {
+ ASSERT_EQ(expected[I], Visitor.VisitedNodes[I]);
+ }
+}