123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237 |
- //===- 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>
- {
- };
- void parmvardecl_attr(struct A __attribute__((address_space(19)))*);
- )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");
- Func = getFunctionNode(AST.get(), "parmvardecl_attr");
- const auto *Parm = Func->getParamDecl(0);
- const auto TL = Parm->getTypeSourceInfo()->getTypeLoc();
- ASSERT_TRUE(TL.getType()->isPointerType());
- const auto ATL = TL.getNextTypeLoc().getAs<AttributedTypeLoc>();
- const auto *AS = cast<AddressSpaceAttr>(ATL.getAttr());
- EXPECT_EQ(toTargetAddressSpace(static_cast<LangAS>(AS->getAddressSpace())),
- 19u);
- }
- } // namespace clang
|