Skip to content

Commit

Permalink
Add a Visit overload for DynTypedNode to ASTNodeTraverser
Browse files Browse the repository at this point in the history
Reviewers: aaron.ballman

Subscribers: cfe-commits

Tags: #clang

Differential Revision: https://reviews.llvm.org/D61834

llvm-svn: 361033
  • Loading branch information
steveire authored and MrSidims committed May 24, 2019
1 parent 2f2ee9e commit 94e3685
Show file tree
Hide file tree
Showing 3 changed files with 239 additions and 0 deletions.
18 changes: 18 additions & 0 deletions clang/include/clang/AST/ASTNodeTraverser.h
Expand Up @@ -205,6 +205,24 @@ class ASTNodeTraverser
});
}

void Visit(const ast_type_traits::DynTypedNode &N) {
// FIXME: Improve this with a switch or a visitor pattern.
if (const auto *D = N.get<Decl>())
Visit(D);
else if (const auto *S = N.get<Stmt>())
Visit(S);
else if (const auto *QT = N.get<QualType>())
Visit(*QT);
else if (const auto *T = N.get<Type>())
Visit(T);
else if (const auto *C = N.get<CXXCtorInitializer>())
Visit(C);
else if (const auto *C = N.get<OMPClause>())
Visit(C);
else if (const auto *T = N.get<TemplateArgument>())
Visit(*T);
}

void dumpDeclContext(const DeclContext *DC) {
if (!DC)
return;
Expand Down
220 changes: 220 additions & 0 deletions clang/unittests/AST/ASTTraverserTest.cpp
@@ -0,0 +1,220 @@
//===- 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();

EXPECT_EQ(dumpASTString(A),
R"cpp(
WarnUnusedResultAttr
)cpp");

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);

EXPECT_EQ(dumpASTString(Comment, Comment),
R"cpp(
FullComment
`-ParagraphComment
`-TextComment
)cpp");

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
1 change: 1 addition & 0 deletions clang/unittests/AST/CMakeLists.txt
Expand Up @@ -12,6 +12,7 @@ add_clang_unittest(ASTTests
ASTImporterTest.cpp
ASTImporterGenericRedeclTest.cpp
ASTImporterVisibilityTest.cpp
ASTTraverserTest.cpp
ASTTypeTraitsTest.cpp
ASTVectorTest.cpp
CommentLexer.cpp
Expand Down

0 comments on commit 94e3685

Please sign in to comment.