summaryrefslogtreecommitdiff
path: root/unittests/AST
diff options
context:
space:
mode:
authorStephen Kelly <steveire@gmail.com>2019-05-19 13:03:48 +0000
committerStephen Kelly <steveire@gmail.com>2019-05-19 13:03:48 +0000
commit68bcda164b8dfc9f374bbd98db5012c0d0ebd33d (patch)
treefa89c8f7f5712ed390e7f95f4a59f92d4489f3b1 /unittests/AST
parent2a333fbcb8eb17cbd7f97fbbb35e39fffa2471ed (diff)
downloadclang-68bcda164b8dfc9f374bbd98db5012c0d0ebd33d.tar.gz
Add a Visit overload for DynTypedNode to ASTNodeTraverser
Reviewers: aaron.ballman Subscribers: cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D61834 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@361117 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'unittests/AST')
-rw-r--r--unittests/AST/ASTTraverserTest.cpp224
-rw-r--r--unittests/AST/CMakeLists.txt1
2 files changed, 225 insertions, 0 deletions
diff --git a/unittests/AST/ASTTraverserTest.cpp b/unittests/AST/ASTTraverserTest.cpp
new file mode 100644
index 0000000000..cddb219a79
--- /dev/null
+++ b/unittests/AST/ASTTraverserTest.cpp
@@ -0,0 +1,224 @@
+//===- unittests/AST/ASTTraverserTest.h------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTNodeTraverser.h"
+#include "clang/AST/TextNodeDumper.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Tooling/Tooling.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+using namespace clang::tooling;
+using namespace clang::ast_matchers;
+
+namespace clang {
+
+class NodeTreePrinter : public TextTreeStructure {
+ llvm::raw_ostream &OS;
+
+public:
+ NodeTreePrinter(llvm::raw_ostream &OS)
+ : TextTreeStructure(OS, /* showColors */ false), OS(OS) {}
+
+ void Visit(const Decl *D) { OS << D->getDeclKindName() << "Decl"; }
+
+ void Visit(const Stmt *S) { OS << S->getStmtClassName(); }
+
+ void Visit(QualType QT) {
+ OS << "QualType " << QT.split().Quals.getAsString();
+ }
+
+ void Visit(const Type *T) { OS << T->getTypeClassName() << "Type"; }
+
+ void Visit(const comments::Comment *C, const comments::FullComment *FC) {
+ OS << C->getCommentKindName();
+ }
+
+ void Visit(const CXXCtorInitializer *Init) { OS << "CXXCtorInitializer"; }
+
+ void Visit(const Attr *A) {
+ switch (A->getKind()) {
+#define ATTR(X) \
+ case attr::X: \
+ OS << #X; \
+ break;
+#include "clang/Basic/AttrList.inc"
+ }
+ OS << "Attr";
+ }
+
+ void Visit(const OMPClause *C) { OS << "OMPClause"; }
+ void Visit(const TemplateArgument &A, SourceRange R = {},
+ const Decl *From = nullptr, const char *Label = nullptr) {
+ OS << "TemplateArgument";
+ }
+
+ template <typename... T> void Visit(T...) {}
+};
+
+class TestASTDumper : public ASTNodeTraverser<TestASTDumper, NodeTreePrinter> {
+
+ NodeTreePrinter MyNodeRecorder;
+
+public:
+ TestASTDumper(llvm::raw_ostream &OS) : MyNodeRecorder(OS) {}
+ NodeTreePrinter &doGetNodeDelegate() { return MyNodeRecorder; }
+};
+
+template <typename... NodeType> std::string dumpASTString(NodeType &&... N) {
+ std::string Buffer;
+ llvm::raw_string_ostream OS(Buffer);
+
+ TestASTDumper Dumper(OS);
+
+ OS << "\n";
+
+ Dumper.Visit(std::forward<NodeType &&>(N)...);
+
+ return OS.str();
+}
+
+const FunctionDecl *getFunctionNode(clang::ASTUnit *AST,
+ const std::string &Name) {
+ auto Result = ast_matchers::match(functionDecl(hasName(Name)).bind("fn"),
+ AST->getASTContext());
+ EXPECT_EQ(Result.size(), 1u);
+ return Result[0].getNodeAs<FunctionDecl>("fn");
+}
+
+template <typename T> struct Verifier {
+ static void withDynNode(T Node, const std::string &DumpString) {
+ EXPECT_EQ(dumpASTString(ast_type_traits::DynTypedNode::create(Node)),
+ DumpString);
+ }
+};
+
+template <typename T> struct Verifier<T *> {
+ static void withDynNode(T *Node, const std::string &DumpString) {
+ EXPECT_EQ(dumpASTString(ast_type_traits::DynTypedNode::create(*Node)),
+ DumpString);
+ }
+};
+
+template <typename T>
+void verifyWithDynNode(T Node, const std::string &DumpString) {
+ EXPECT_EQ(dumpASTString(Node), DumpString);
+
+ Verifier<T>::withDynNode(Node, DumpString);
+}
+
+TEST(Traverse, Dump) {
+
+ auto AST = buildASTFromCode(R"cpp(
+struct A {
+ int m_number;
+
+ /// CTor
+ A() : m_number(42) {}
+
+ [[nodiscard]] const int func() {
+ return 42;
+ }
+
+};
+
+template<typename T>
+struct templ
+{
+};
+
+template<>
+struct templ<int>
+{
+};
+
+)cpp");
+
+ const FunctionDecl *Func = getFunctionNode(AST.get(), "func");
+
+ verifyWithDynNode(Func,
+ R"cpp(
+CXXMethodDecl
+|-CompoundStmt
+| `-ReturnStmt
+| `-IntegerLiteral
+`-WarnUnusedResultAttr
+)cpp");
+
+ Stmt *Body = Func->getBody();
+
+ verifyWithDynNode(Body,
+ R"cpp(
+CompoundStmt
+`-ReturnStmt
+ `-IntegerLiteral
+)cpp");
+
+ QualType QT = Func->getType();
+
+ verifyWithDynNode(QT,
+ R"cpp(
+FunctionProtoType
+`-QualType const
+ `-BuiltinType
+)cpp");
+
+ const FunctionDecl *CTorFunc = getFunctionNode(AST.get(), "A");
+
+ verifyWithDynNode(CTorFunc->getType(),
+ R"cpp(
+FunctionProtoType
+`-BuiltinType
+)cpp");
+
+ Attr *A = *Func->attr_begin();
+
+ {
+ std::string expectedString = R"cpp(
+WarnUnusedResultAttr
+)cpp";
+
+ EXPECT_EQ(dumpASTString(A), expectedString);
+ }
+
+ auto *CTor = dyn_cast<CXXConstructorDecl>(CTorFunc);
+ const CXXCtorInitializer *Init = *CTor->init_begin();
+
+ verifyWithDynNode(Init,
+ R"cpp(
+CXXCtorInitializer
+`-IntegerLiteral
+)cpp");
+
+ const comments::FullComment *Comment =
+ AST->getASTContext().getLocalCommentForDeclUncached(CTorFunc);
+ {
+ std::string expectedString = R"cpp(
+FullComment
+`-ParagraphComment
+ `-TextComment
+)cpp";
+ EXPECT_EQ(dumpASTString(Comment, Comment), expectedString);
+ }
+
+ auto Result = ast_matchers::match(
+ classTemplateSpecializationDecl(hasName("templ")).bind("fn"),
+ AST->getASTContext());
+ EXPECT_EQ(Result.size(), 1u);
+ auto Templ = Result[0].getNodeAs<ClassTemplateSpecializationDecl>("fn");
+
+ TemplateArgument TA = Templ->getTemplateArgs()[0];
+
+ verifyWithDynNode(TA,
+ R"cpp(
+TemplateArgument
+)cpp");
+}
+} // namespace clang
diff --git a/unittests/AST/CMakeLists.txt b/unittests/AST/CMakeLists.txt
index 05cdca0f89..2151dc4cd8 100644
--- a/unittests/AST/CMakeLists.txt
+++ b/unittests/AST/CMakeLists.txt
@@ -12,6 +12,7 @@ add_clang_unittest(ASTTests
ASTImporterTest.cpp
ASTImporterGenericRedeclTest.cpp
ASTImporterVisibilityTest.cpp
+ ASTTraverserTest.cpp
ASTTypeTraitsTest.cpp
ASTVectorTest.cpp
CommentLexer.cpp