1 //===- unittest/AST/ASTContextParentMapTest.cpp - AST parent map test -----===// 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 // Tests for the getParents(...) methods of ASTContext. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "clang/AST/ASTContext.h" 14 #include "MatchVerifier.h" 15 #include "clang/ASTMatchers/ASTMatchFinder.h" 16 #include "clang/ASTMatchers/ASTMatchers.h" 17 #include "clang/Tooling/Tooling.h" 18 #include "gtest/gtest.h" 19 #include "gmock/gmock.h" 20 21 using testing::ElementsAre; 22 23 namespace clang { 24 namespace ast_matchers { 25 26 TEST(GetParents, ReturnsParentForDecl) { 27 MatchVerifier<Decl> Verifier; 28 EXPECT_TRUE( 29 Verifier.match("class C { void f(); };", 30 cxxMethodDecl(hasParent(recordDecl(hasName("C")))))); 31 } 32 33 TEST(GetParents, ReturnsParentForStmt) { 34 MatchVerifier<Stmt> Verifier; 35 EXPECT_TRUE(Verifier.match("class C { void f() { if (true) {} } };", 36 ifStmt(hasParent(compoundStmt())))); 37 } 38 39 TEST(GetParents, ReturnsParentForTypeLoc) { 40 MatchVerifier<TypeLoc> Verifier; 41 EXPECT_TRUE( 42 Verifier.match("namespace a { class b {}; } void f(a::b) {}", 43 typeLoc(hasParent(typeLoc(hasParent(functionDecl())))))); 44 } 45 46 TEST(GetParents, ReturnsParentForNestedNameSpecifierLoc) { 47 MatchVerifier<NestedNameSpecifierLoc> Verifier; 48 EXPECT_TRUE(Verifier.match("namespace a { class b {}; } void f(a::b) {}", 49 nestedNameSpecifierLoc(hasParent(typeLoc())))); 50 } 51 52 TEST(GetParents, ReturnsParentInsideTemplateInstantiations) { 53 MatchVerifier<Decl> DeclVerifier; 54 EXPECT_TRUE(DeclVerifier.match( 55 "template<typename T> struct C { void f() {} };" 56 "void g() { C<int> c; c.f(); }", 57 cxxMethodDecl(hasName("f"), 58 hasParent(cxxRecordDecl(isTemplateInstantiation()))))); 59 EXPECT_TRUE(DeclVerifier.match( 60 "template<typename T> struct C { void f() {} };" 61 "void g() { C<int> c; c.f(); }", 62 cxxMethodDecl(hasName("f"), 63 hasParent(cxxRecordDecl(unless(isTemplateInstantiation())))))); 64 EXPECT_FALSE(DeclVerifier.match( 65 "template<typename T> struct C { void f() {} };" 66 "void g() { C<int> c; c.f(); }", 67 cxxMethodDecl( 68 hasName("f"), 69 allOf(hasParent(cxxRecordDecl(unless(isTemplateInstantiation()))), 70 hasParent(cxxRecordDecl(isTemplateInstantiation())))))); 71 } 72 73 TEST(GetParents, ReturnsMultipleParentsInTemplateInstantiations) { 74 MatchVerifier<Stmt> TemplateVerifier; 75 EXPECT_TRUE(TemplateVerifier.match( 76 "template<typename T> struct C { void f() {} };" 77 "void g() { C<int> c; c.f(); }", 78 compoundStmt(allOf( 79 hasAncestor(cxxRecordDecl(isTemplateInstantiation())), 80 hasAncestor(cxxRecordDecl(unless(isTemplateInstantiation()))))))); 81 } 82 83 TEST(GetParents, RespectsTraversalScope) { 84 auto AST = tooling::buildASTFromCode( 85 "struct foo { int bar; }; struct baz{};", "foo.cpp", 86 std::make_shared<PCHContainerOperations>()); 87 auto &Ctx = AST->getASTContext(); 88 auto &TU = *Ctx.getTranslationUnitDecl(); 89 auto &Foo = *TU.lookup(&Ctx.Idents.get("foo")).front(); 90 auto &Bar = *cast<DeclContext>(Foo).lookup(&Ctx.Idents.get("bar")).front(); 91 auto &Baz = *TU.lookup(&Ctx.Idents.get("baz")).front(); 92 93 // Initially, scope is the whole TU. 94 EXPECT_THAT(Ctx.getParents(Bar), ElementsAre(DynTypedNode::create(Foo))); 95 EXPECT_THAT(Ctx.getParents(Foo), ElementsAre(DynTypedNode::create(TU))); 96 EXPECT_THAT(Ctx.getParents(Baz), ElementsAre(DynTypedNode::create(TU))); 97 98 // Restrict the scope, now some parents are gone. 99 Ctx.setTraversalScope({&Foo}); 100 EXPECT_THAT(Ctx.getParents(Bar), ElementsAre(DynTypedNode::create(Foo))); 101 EXPECT_THAT(Ctx.getParents(Foo), ElementsAre(DynTypedNode::create(TU))); 102 EXPECT_THAT(Ctx.getParents(Baz), ElementsAre()); 103 104 // Reset the scope, we get back the original results. 105 Ctx.setTraversalScope({&TU}); 106 EXPECT_THAT(Ctx.getParents(Bar), ElementsAre(DynTypedNode::create(Foo))); 107 EXPECT_THAT(Ctx.getParents(Foo), ElementsAre(DynTypedNode::create(TU))); 108 EXPECT_THAT(Ctx.getParents(Baz), ElementsAre(DynTypedNode::create(TU))); 109 } 110 111 TEST(GetParents, ImplicitLambdaNodes) { 112 MatchVerifier<Decl> LambdaVerifier; 113 EXPECT_TRUE(LambdaVerifier.match( 114 "auto x = []{int y;};", 115 varDecl(hasName("y"), hasAncestor(functionDecl( 116 hasOverloadedOperatorName("()"), 117 hasParent(cxxRecordDecl( 118 isImplicit(), hasParent(lambdaExpr())))))), 119 Lang_CXX11)); 120 } 121 122 TEST(GetParents, FriendTypeLoc) { 123 auto AST = tooling::buildASTFromCode("struct A { friend struct Fr; };" 124 "struct B { friend struct Fr; };" 125 "struct Fr;"); 126 auto &Ctx = AST->getASTContext(); 127 auto &TU = *Ctx.getTranslationUnitDecl(); 128 auto &A = *TU.lookup(&Ctx.Idents.get("A")).front(); 129 auto &B = *TU.lookup(&Ctx.Idents.get("B")).front(); 130 auto &FrA = *cast<FriendDecl>(*++(cast<CXXRecordDecl>(A).decls_begin())); 131 auto &FrB = *cast<FriendDecl>(*++(cast<CXXRecordDecl>(B).decls_begin())); 132 TypeLoc FrALoc = FrA.getFriendType()->getTypeLoc(); 133 TypeLoc FrBLoc = FrB.getFriendType()->getTypeLoc(); 134 TagDecl *FrATagDecl = 135 FrALoc.getTypePtr()->getAs<ElaboratedType>()->getOwnedTagDecl(); 136 TagDecl *FrBTagDecl = 137 FrBLoc.getTypePtr()->getAs<ElaboratedType>()->getOwnedTagDecl(); 138 139 EXPECT_THAT(Ctx.getParents(A), ElementsAre(DynTypedNode::create(TU))); 140 EXPECT_THAT(Ctx.getParents(B), ElementsAre(DynTypedNode::create(TU))); 141 EXPECT_THAT(Ctx.getParents(FrA), ElementsAre(DynTypedNode::create(A))); 142 EXPECT_THAT(Ctx.getParents(FrB), ElementsAre(DynTypedNode::create(B))); 143 EXPECT_THAT(Ctx.getParents(FrALoc), ElementsAre(DynTypedNode::create(FrA))); 144 EXPECT_THAT(Ctx.getParents(FrBLoc), ElementsAre(DynTypedNode::create(FrB))); 145 EXPECT_TRUE(FrATagDecl); 146 EXPECT_FALSE(FrBTagDecl); 147 EXPECT_THAT(Ctx.getParents(*FrATagDecl), 148 ElementsAre(DynTypedNode::create(FrA))); 149 } 150 151 TEST(GetParents, UserDefinedTupleLikeTypes) { 152 MatchVerifier<VarDecl> Verifier; 153 EXPECT_TRUE(Verifier.match( 154 R"( 155 namespace std { 156 157 using size_t = __typeof(sizeof(int)); 158 159 template <typename T> 160 struct tuple_size; 161 162 template <typename T> 163 struct tuple_size<T&> : tuple_size<T>{}; 164 165 template <typename T> 166 requires requires { tuple_size<T>::value; } 167 struct tuple_size<const T> : tuple_size<T>{}; 168 169 170 template<size_t i, typename T> 171 struct tuple_element; 172 173 174 } // namespace std 175 176 struct Decomposable {}; 177 178 template<> struct std::tuple_size<Decomposable> { 179 static constexpr size_t value = 2; 180 }; 181 182 template<std::size_t i> struct std::tuple_element<i, Decomposable> { 183 using type = int; 184 }; 185 186 template<std::size_t i> struct std::tuple_element<i, const Decomposable> { 187 using type = const int; 188 }; 189 190 template<std::size_t i> 191 const int& get(const Decomposable& d); 192 193 void F(const Decomposable& d) { 194 const auto& [x, y] = d; 195 } 196 )", 197 varDecl(hasName("x"), hasAncestor(decompositionDecl())), Lang_CXX20)); 198 } 199 200 } // end namespace ast_matchers 201 } // end namespace clang 202