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 9 #include "clang/AST/ASTContext.h" 10 #include "clang/AST/ASTNodeTraverser.h" 11 #include "clang/AST/TextNodeDumper.h" 12 #include "clang/ASTMatchers/ASTMatchFinder.h" 13 #include "clang/ASTMatchers/ASTMatchers.h" 14 #include "clang/Tooling/Tooling.h" 15 #include "gmock/gmock.h" 16 #include "gtest/gtest.h" 17 18 using namespace clang::tooling; 19 using namespace clang::ast_matchers; 20 21 namespace clang { 22 23 class NodeTreePrinter : public TextTreeStructure { 24 llvm::raw_ostream &OS; 25 26 public: 27 NodeTreePrinter(llvm::raw_ostream &OS) 28 : TextTreeStructure(OS, /* showColors */ false), OS(OS) {} 29 30 void Visit(const Decl *D) { OS << D->getDeclKindName() << "Decl"; } 31 32 void Visit(const Stmt *S) { OS << S->getStmtClassName(); } 33 34 void Visit(QualType QT) { 35 OS << "QualType " << QT.split().Quals.getAsString(); 36 } 37 38 void Visit(const Type *T) { OS << T->getTypeClassName() << "Type"; } 39 40 void Visit(const comments::Comment *C, const comments::FullComment *FC) { 41 OS << C->getCommentKindName(); 42 } 43 44 void Visit(const CXXCtorInitializer *Init) { OS << "CXXCtorInitializer"; } 45 46 void Visit(const Attr *A) { 47 switch (A->getKind()) { 48 #define ATTR(X) \ 49 case attr::X: \ 50 OS << #X; \ 51 break; 52 #include "clang/Basic/AttrList.inc" 53 } 54 OS << "Attr"; 55 } 56 57 void Visit(const OMPClause *C) { OS << "OMPClause"; } 58 void Visit(const TemplateArgument &A, SourceRange R = {}, 59 const Decl *From = nullptr, const char *Label = nullptr) { 60 OS << "TemplateArgument"; 61 } 62 63 template <typename... T> void Visit(T...) {} 64 }; 65 66 class TestASTDumper : public ASTNodeTraverser<TestASTDumper, NodeTreePrinter> { 67 68 NodeTreePrinter MyNodeRecorder; 69 70 public: 71 TestASTDumper(llvm::raw_ostream &OS) : MyNodeRecorder(OS) {} 72 NodeTreePrinter &doGetNodeDelegate() { return MyNodeRecorder; } 73 }; 74 75 template <typename... NodeType> std::string dumpASTString(NodeType &&... N) { 76 std::string Buffer; 77 llvm::raw_string_ostream OS(Buffer); 78 79 TestASTDumper Dumper(OS); 80 81 OS << "\n"; 82 83 Dumper.Visit(std::forward<NodeType &&>(N)...); 84 85 return OS.str(); 86 } 87 88 const FunctionDecl *getFunctionNode(clang::ASTUnit *AST, 89 const std::string &Name) { 90 auto Result = ast_matchers::match(functionDecl(hasName(Name)).bind("fn"), 91 AST->getASTContext()); 92 EXPECT_EQ(Result.size(), 1u); 93 return Result[0].getNodeAs<FunctionDecl>("fn"); 94 } 95 96 template <typename T> struct Verifier { 97 static void withDynNode(T Node, const std::string &DumpString) { 98 EXPECT_EQ(dumpASTString(ast_type_traits::DynTypedNode::create(Node)), 99 DumpString); 100 } 101 }; 102 103 template <typename T> struct Verifier<T *> { 104 static void withDynNode(T *Node, const std::string &DumpString) { 105 EXPECT_EQ(dumpASTString(ast_type_traits::DynTypedNode::create(*Node)), 106 DumpString); 107 } 108 }; 109 110 template <typename T> 111 void verifyWithDynNode(T Node, const std::string &DumpString) { 112 EXPECT_EQ(dumpASTString(Node), DumpString); 113 114 Verifier<T>::withDynNode(Node, DumpString); 115 } 116 117 TEST(Traverse, Dump) { 118 119 auto AST = buildASTFromCode(R"cpp( 120 struct A { 121 int m_number; 122 123 /// CTor 124 A() : m_number(42) {} 125 126 [[nodiscard]] const int func() { 127 return 42; 128 } 129 130 }; 131 132 template<typename T> 133 struct templ 134 { 135 }; 136 137 template<> 138 struct templ<int> 139 { 140 }; 141 142 void parmvardecl_attr(struct A __attribute__((address_space(19)))*); 143 144 )cpp"); 145 146 const FunctionDecl *Func = getFunctionNode(AST.get(), "func"); 147 148 verifyWithDynNode(Func, 149 R"cpp( 150 CXXMethodDecl 151 |-CompoundStmt 152 | `-ReturnStmt 153 | `-IntegerLiteral 154 `-WarnUnusedResultAttr 155 )cpp"); 156 157 Stmt *Body = Func->getBody(); 158 159 verifyWithDynNode(Body, 160 R"cpp( 161 CompoundStmt 162 `-ReturnStmt 163 `-IntegerLiteral 164 )cpp"); 165 166 QualType QT = Func->getType(); 167 168 verifyWithDynNode(QT, 169 R"cpp( 170 FunctionProtoType 171 `-QualType const 172 `-BuiltinType 173 )cpp"); 174 175 const FunctionDecl *CTorFunc = getFunctionNode(AST.get(), "A"); 176 177 verifyWithDynNode(CTorFunc->getType(), 178 R"cpp( 179 FunctionProtoType 180 `-BuiltinType 181 )cpp"); 182 183 Attr *A = *Func->attr_begin(); 184 185 { 186 std::string expectedString = R"cpp( 187 WarnUnusedResultAttr 188 )cpp"; 189 190 EXPECT_EQ(dumpASTString(A), expectedString); 191 } 192 193 auto *CTor = dyn_cast<CXXConstructorDecl>(CTorFunc); 194 const CXXCtorInitializer *Init = *CTor->init_begin(); 195 196 verifyWithDynNode(Init, 197 R"cpp( 198 CXXCtorInitializer 199 `-IntegerLiteral 200 )cpp"); 201 202 const comments::FullComment *Comment = 203 AST->getASTContext().getLocalCommentForDeclUncached(CTorFunc); 204 { 205 std::string expectedString = R"cpp( 206 FullComment 207 `-ParagraphComment 208 `-TextComment 209 )cpp"; 210 EXPECT_EQ(dumpASTString(Comment, Comment), expectedString); 211 } 212 213 auto Result = ast_matchers::match( 214 classTemplateSpecializationDecl(hasName("templ")).bind("fn"), 215 AST->getASTContext()); 216 EXPECT_EQ(Result.size(), 1u); 217 auto Templ = Result[0].getNodeAs<ClassTemplateSpecializationDecl>("fn"); 218 219 TemplateArgument TA = Templ->getTemplateArgs()[0]; 220 221 verifyWithDynNode(TA, 222 R"cpp( 223 TemplateArgument 224 )cpp"); 225 226 Func = getFunctionNode(AST.get(), "parmvardecl_attr"); 227 228 const auto *Parm = Func->getParamDecl(0); 229 const auto TL = Parm->getTypeSourceInfo()->getTypeLoc(); 230 ASSERT_TRUE(TL.getType()->isPointerType()); 231 232 const auto ATL = TL.getNextTypeLoc().getAs<AttributedTypeLoc>(); 233 const auto *AS = cast<AddressSpaceAttr>(ATL.getAttr()); 234 EXPECT_EQ(toTargetAddressSpace(static_cast<LangAS>(AS->getAddressSpace())), 235 19u); 236 } 237 } // namespace clang 238