201 lines · cpp
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-exception6//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 21using testing::ElementsAre;22 23namespace clang {24namespace ast_matchers {25 26TEST(GetParents, ReturnsParentForDecl) {27 MatchVerifier<Decl> Verifier;28 EXPECT_TRUE(29 Verifier.match("class C { void f(); };",30 cxxMethodDecl(hasParent(recordDecl(hasName("C"))))));31}32 33TEST(GetParents, ReturnsParentForStmt) {34 MatchVerifier<Stmt> Verifier;35 EXPECT_TRUE(Verifier.match("class C { void f() { if (true) {} } };",36 ifStmt(hasParent(compoundStmt()))));37}38 39TEST(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 46TEST(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 52TEST(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 73TEST(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 83TEST(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 111TEST(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 122TEST(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 bool FrAOwnsTag = FrALoc.getTypePtr()->getAs<TagType>()->isTagOwned();135 TagDecl *FrATagDecl = FrALoc.getTypePtr()->getAs<TagType>()->getDecl();136 bool FrBOwnsTag = FrBLoc.getTypePtr()->getAs<TagType>()->isTagOwned();137 138 EXPECT_THAT(Ctx.getParents(A), ElementsAre(DynTypedNode::create(TU)));139 EXPECT_THAT(Ctx.getParents(B), ElementsAre(DynTypedNode::create(TU)));140 EXPECT_THAT(Ctx.getParents(FrA), ElementsAre(DynTypedNode::create(A)));141 EXPECT_THAT(Ctx.getParents(FrB), ElementsAre(DynTypedNode::create(B)));142 EXPECT_THAT(Ctx.getParents(FrALoc), ElementsAre(DynTypedNode::create(FrA)));143 EXPECT_THAT(Ctx.getParents(FrBLoc), ElementsAre(DynTypedNode::create(FrB)));144 EXPECT_TRUE(FrAOwnsTag);145 EXPECT_FALSE(FrBOwnsTag);146 EXPECT_THAT(Ctx.getParents(*FrATagDecl),147 ElementsAre(DynTypedNode::create(FrA)));148}149 150TEST(GetParents, UserDefinedTupleLikeTypes) {151 MatchVerifier<VarDecl> Verifier;152 EXPECT_TRUE(Verifier.match(153 R"(154namespace std {155 156using size_t = __typeof(sizeof(int));157 158template <typename T>159struct tuple_size;160 161template <typename T>162struct tuple_size<T&> : tuple_size<T>{};163 164template <typename T>165requires requires { tuple_size<T>::value; }166struct tuple_size<const T> : tuple_size<T>{};167 168 169template<size_t i, typename T>170struct tuple_element;171 172 173} // namespace std174 175struct Decomposable {};176 177template<> struct std::tuple_size<Decomposable> {178 static constexpr size_t value = 2;179};180 181template<std::size_t i> struct std::tuple_element<i, Decomposable> {182 using type = int;183};184 185template<std::size_t i> struct std::tuple_element<i, const Decomposable> {186 using type = const int;187};188 189template<std::size_t i>190const int& get(const Decomposable& d);191 192void F(const Decomposable& d) {193 const auto& [x, y] = d;194}195)",196 varDecl(hasName("x"), hasAncestor(decompositionDecl())), Lang_CXX20));197}198 199} // end namespace ast_matchers200} // end namespace clang201