1 //===- unittest/AST/ASTContextParentMapTest.cpp - AST parent map test -----===//
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
7 //===----------------------------------------------------------------------===//
9 // Tests for the getParents(...) methods of ASTContext.
11 //===----------------------------------------------------------------------===//
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"
21 using testing::ElementsAre
;
24 namespace ast_matchers
{
26 TEST(GetParents
, ReturnsParentForDecl
) {
27 MatchVerifier
<Decl
> Verifier
;
29 Verifier
.match("class C { void f(); };",
30 cxxMethodDecl(hasParent(recordDecl(hasName("C"))))));
33 TEST(GetParents
, ReturnsParentForStmt
) {
34 MatchVerifier
<Stmt
> Verifier
;
35 EXPECT_TRUE(Verifier
.match("class C { void f() { if (true) {} } };",
36 ifStmt(hasParent(compoundStmt()))));
39 TEST(GetParents
, ReturnsParentForTypeLoc
) {
40 MatchVerifier
<TypeLoc
> Verifier
;
42 Verifier
.match("namespace a { class b {}; } void f(a::b) {}",
43 typeLoc(hasParent(typeLoc(hasParent(functionDecl()))))));
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()))));
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(); }",
69 allOf(hasParent(cxxRecordDecl(unless(isTemplateInstantiation()))),
70 hasParent(cxxRecordDecl(isTemplateInstantiation()))))));
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(); }",
79 hasAncestor(cxxRecordDecl(isTemplateInstantiation())),
80 hasAncestor(cxxRecordDecl(unless(isTemplateInstantiation())))))));
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();
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
)));
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());
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
)));
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())))))),
122 TEST(GetParents
, FriendTypeLoc
) {
123 auto AST
= tooling::buildASTFromCode("struct A { friend struct Fr; };"
124 "struct B { friend 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();
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
)));
151 } // end namespace ast_matchers
152 } // end namespace clang