ASTTraverserTest.cpp 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. //===- unittests/AST/ASTTraverserTest.h------------------------------------===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. #include "clang/AST/ASTContext.h"
  9. #include "clang/AST/ASTNodeTraverser.h"
  10. #include "clang/AST/TextNodeDumper.h"
  11. #include "clang/ASTMatchers/ASTMatchFinder.h"
  12. #include "clang/ASTMatchers/ASTMatchers.h"
  13. #include "clang/Tooling/Tooling.h"
  14. #include "gmock/gmock.h"
  15. #include "gtest/gtest.h"
  16. using namespace clang::tooling;
  17. using namespace clang::ast_matchers;
  18. namespace clang {
  19. class NodeTreePrinter : public TextTreeStructure {
  20. llvm::raw_ostream &OS;
  21. public:
  22. NodeTreePrinter(llvm::raw_ostream &OS)
  23. : TextTreeStructure(OS, /* showColors */ false), OS(OS) {}
  24. void Visit(const Decl *D) { OS << D->getDeclKindName() << "Decl"; }
  25. void Visit(const Stmt *S) { OS << S->getStmtClassName(); }
  26. void Visit(QualType QT) {
  27. OS << "QualType " << QT.split().Quals.getAsString();
  28. }
  29. void Visit(const Type *T) { OS << T->getTypeClassName() << "Type"; }
  30. void Visit(const comments::Comment *C, const comments::FullComment *FC) {
  31. OS << C->getCommentKindName();
  32. }
  33. void Visit(const CXXCtorInitializer *Init) { OS << "CXXCtorInitializer"; }
  34. void Visit(const Attr *A) {
  35. switch (A->getKind()) {
  36. #define ATTR(X) \
  37. case attr::X: \
  38. OS << #X; \
  39. break;
  40. #include "clang/Basic/AttrList.inc"
  41. }
  42. OS << "Attr";
  43. }
  44. void Visit(const OMPClause *C) { OS << "OMPClause"; }
  45. void Visit(const TemplateArgument &A, SourceRange R = {},
  46. const Decl *From = nullptr, const char *Label = nullptr) {
  47. OS << "TemplateArgument";
  48. }
  49. template <typename... T> void Visit(T...) {}
  50. };
  51. class TestASTDumper : public ASTNodeTraverser<TestASTDumper, NodeTreePrinter> {
  52. NodeTreePrinter MyNodeRecorder;
  53. public:
  54. TestASTDumper(llvm::raw_ostream &OS) : MyNodeRecorder(OS) {}
  55. NodeTreePrinter &doGetNodeDelegate() { return MyNodeRecorder; }
  56. };
  57. template <typename... NodeType> std::string dumpASTString(NodeType &&... N) {
  58. std::string Buffer;
  59. llvm::raw_string_ostream OS(Buffer);
  60. TestASTDumper Dumper(OS);
  61. OS << "\n";
  62. Dumper.Visit(std::forward<NodeType &&>(N)...);
  63. return OS.str();
  64. }
  65. const FunctionDecl *getFunctionNode(clang::ASTUnit *AST,
  66. const std::string &Name) {
  67. auto Result = ast_matchers::match(functionDecl(hasName(Name)).bind("fn"),
  68. AST->getASTContext());
  69. EXPECT_EQ(Result.size(), 1u);
  70. return Result[0].getNodeAs<FunctionDecl>("fn");
  71. }
  72. template <typename T> struct Verifier {
  73. static void withDynNode(T Node, const std::string &DumpString) {
  74. EXPECT_EQ(dumpASTString(ast_type_traits::DynTypedNode::create(Node)),
  75. DumpString);
  76. }
  77. };
  78. template <typename T> struct Verifier<T *> {
  79. static void withDynNode(T *Node, const std::string &DumpString) {
  80. EXPECT_EQ(dumpASTString(ast_type_traits::DynTypedNode::create(*Node)),
  81. DumpString);
  82. }
  83. };
  84. template <typename T>
  85. void verifyWithDynNode(T Node, const std::string &DumpString) {
  86. EXPECT_EQ(dumpASTString(Node), DumpString);
  87. Verifier<T>::withDynNode(Node, DumpString);
  88. }
  89. TEST(Traverse, Dump) {
  90. auto AST = buildASTFromCode(R"cpp(
  91. struct A {
  92. int m_number;
  93. /// CTor
  94. A() : m_number(42) {}
  95. [[nodiscard]] const int func() {
  96. return 42;
  97. }
  98. };
  99. template<typename T>
  100. struct templ
  101. {
  102. };
  103. template<>
  104. struct templ<int>
  105. {
  106. };
  107. void parmvardecl_attr(struct A __attribute__((address_space(19)))*);
  108. )cpp");
  109. const FunctionDecl *Func = getFunctionNode(AST.get(), "func");
  110. verifyWithDynNode(Func,
  111. R"cpp(
  112. CXXMethodDecl
  113. |-CompoundStmt
  114. | `-ReturnStmt
  115. | `-IntegerLiteral
  116. `-WarnUnusedResultAttr
  117. )cpp");
  118. Stmt *Body = Func->getBody();
  119. verifyWithDynNode(Body,
  120. R"cpp(
  121. CompoundStmt
  122. `-ReturnStmt
  123. `-IntegerLiteral
  124. )cpp");
  125. QualType QT = Func->getType();
  126. verifyWithDynNode(QT,
  127. R"cpp(
  128. FunctionProtoType
  129. `-QualType const
  130. `-BuiltinType
  131. )cpp");
  132. const FunctionDecl *CTorFunc = getFunctionNode(AST.get(), "A");
  133. verifyWithDynNode(CTorFunc->getType(),
  134. R"cpp(
  135. FunctionProtoType
  136. `-BuiltinType
  137. )cpp");
  138. Attr *A = *Func->attr_begin();
  139. {
  140. std::string expectedString = R"cpp(
  141. WarnUnusedResultAttr
  142. )cpp";
  143. EXPECT_EQ(dumpASTString(A), expectedString);
  144. }
  145. auto *CTor = dyn_cast<CXXConstructorDecl>(CTorFunc);
  146. const CXXCtorInitializer *Init = *CTor->init_begin();
  147. verifyWithDynNode(Init,
  148. R"cpp(
  149. CXXCtorInitializer
  150. `-IntegerLiteral
  151. )cpp");
  152. const comments::FullComment *Comment =
  153. AST->getASTContext().getLocalCommentForDeclUncached(CTorFunc);
  154. {
  155. std::string expectedString = R"cpp(
  156. FullComment
  157. `-ParagraphComment
  158. `-TextComment
  159. )cpp";
  160. EXPECT_EQ(dumpASTString(Comment, Comment), expectedString);
  161. }
  162. auto Result = ast_matchers::match(
  163. classTemplateSpecializationDecl(hasName("templ")).bind("fn"),
  164. AST->getASTContext());
  165. EXPECT_EQ(Result.size(), 1u);
  166. auto Templ = Result[0].getNodeAs<ClassTemplateSpecializationDecl>("fn");
  167. TemplateArgument TA = Templ->getTemplateArgs()[0];
  168. verifyWithDynNode(TA,
  169. R"cpp(
  170. TemplateArgument
  171. )cpp");
  172. Func = getFunctionNode(AST.get(), "parmvardecl_attr");
  173. const auto *Parm = Func->getParamDecl(0);
  174. const auto TL = Parm->getTypeSourceInfo()->getTypeLoc();
  175. ASSERT_TRUE(TL.getType()->isPointerType());
  176. const auto ATL = TL.getNextTypeLoc().getAs<AttributedTypeLoc>();
  177. const auto *AS = cast<AddressSpaceAttr>(ATL.getAttr());
  178. EXPECT_EQ(toTargetAddressSpace(static_cast<LangAS>(AS->getAddressSpace())),
  179. 19u);
  180. }
  181. } // namespace clang