1 //===- unittest/Tooling/LookupTest.cpp ------------------------------------===//
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 #include "clang/Tooling/Refactoring/Lookup.h"
10 #include "TestVisitor.h"
11 using namespace clang
;
14 struct GetDeclsVisitor
: TestVisitor
<GetDeclsVisitor
> {
15 std::function
<void(CallExpr
*)> OnCall
;
16 std::function
<void(RecordTypeLoc
)> OnRecordTypeLoc
;
17 SmallVector
<Decl
*, 4> DeclStack
;
19 bool VisitCallExpr(CallExpr
*Expr
) {
25 bool VisitRecordTypeLoc(RecordTypeLoc Loc
) {
31 bool TraverseDecl(Decl
*D
) {
32 DeclStack
.push_back(D
);
33 bool Ret
= TestVisitor::TraverseDecl(D
);
39 TEST(LookupTest
, replaceNestedFunctionName
) {
40 GetDeclsVisitor Visitor
;
42 auto replaceCallExpr
= [&](const CallExpr
*Expr
,
43 StringRef ReplacementString
) {
44 const auto *Callee
= cast
<DeclRefExpr
>(Expr
->getCallee()->IgnoreImplicit());
45 const ValueDecl
*FD
= Callee
->getDecl();
46 return tooling::replaceNestedName(
47 Callee
->getQualifier(), Callee
->getLocation(),
48 Visitor
.DeclStack
.back()->getDeclContext(), FD
, ReplacementString
);
51 Visitor
.OnCall
= [&](CallExpr
*Expr
) {
52 EXPECT_EQ("bar", replaceCallExpr(Expr
, "::bar"));
54 Visitor
.runOver("namespace a { void foo(); }\n"
55 "namespace a { void f() { foo(); } }\n");
57 Visitor
.OnCall
= [&](CallExpr
*Expr
) {
58 EXPECT_EQ("bar", replaceCallExpr(Expr
, "::a::bar"));
60 Visitor
.runOver("namespace a { void foo(); }\n"
61 "namespace a { void f() { foo(); } }\n");
63 Visitor
.OnCall
= [&](CallExpr
*Expr
) {
64 EXPECT_EQ("a::bar", replaceCallExpr(Expr
, "::a::bar"));
66 Visitor
.runOver("namespace a { void foo(); }\n"
67 "namespace b { void f() { a::foo(); } }\n");
69 Visitor
.OnCall
= [&](CallExpr
*Expr
) {
70 EXPECT_EQ("::a::bar", replaceCallExpr(Expr
, "::a::bar"));
72 Visitor
.runOver("namespace a { void foo(); }\n"
73 "namespace b { namespace a { void foo(); }\n"
74 "void f() { a::foo(); } }\n");
76 Visitor
.OnCall
= [&](CallExpr
*Expr
) {
77 EXPECT_EQ("c::bar", replaceCallExpr(Expr
, "::a::c::bar"));
79 Visitor
.runOver("namespace a { namespace b { void foo(); }\n"
80 "void f() { b::foo(); } }\n");
82 Visitor
.OnCall
= [&](CallExpr
*Expr
) {
83 EXPECT_EQ("bar", replaceCallExpr(Expr
, "::a::bar"));
85 Visitor
.runOver("namespace a { namespace b { void foo(); }\n"
86 "void f() { b::foo(); } }\n");
88 Visitor
.OnCall
= [&](CallExpr
*Expr
) {
89 EXPECT_EQ("bar", replaceCallExpr(Expr
, "::bar"));
91 Visitor
.runOver("void foo(); void f() { foo(); }\n");
93 Visitor
.OnCall
= [&](CallExpr
*Expr
) {
94 EXPECT_EQ("::bar", replaceCallExpr(Expr
, "::bar"));
96 Visitor
.runOver("void foo(); void f() { ::foo(); }\n");
98 Visitor
.OnCall
= [&](CallExpr
*Expr
) {
99 EXPECT_EQ("a::bar", replaceCallExpr(Expr
, "::a::bar"));
101 Visitor
.runOver("namespace a { void foo(); }\nvoid f() { a::foo(); }\n");
103 Visitor
.OnCall
= [&](CallExpr
*Expr
) {
104 EXPECT_EQ("a::bar", replaceCallExpr(Expr
, "::a::bar"));
106 Visitor
.runOver("namespace a { int foo(); }\nauto f = a::foo();\n");
108 Visitor
.OnCall
= [&](CallExpr
*Expr
) {
109 EXPECT_EQ("bar", replaceCallExpr(Expr
, "::a::bar"));
112 "namespace a { int foo(); }\nusing a::foo;\nauto f = foo();\n");
114 Visitor
.OnCall
= [&](CallExpr
*Expr
) {
115 EXPECT_EQ("c::bar", replaceCallExpr(Expr
, "::a::c::bar"));
117 Visitor
.runOver("namespace a { namespace b { void foo(); } }\n"
118 "namespace a { namespace b { namespace {"
119 "void f() { foo(); }"
122 Visitor
.OnCall
= [&](CallExpr
*Expr
) {
123 EXPECT_EQ("x::bar", replaceCallExpr(Expr
, "::a::x::bar"));
125 Visitor
.runOver("namespace a { namespace b { void foo(); } }\n"
126 "namespace a { namespace b { namespace c {"
127 "void f() { foo(); }"
130 // If the shortest name is ambiguous, we need to add more qualifiers.
131 Visitor
.OnCall
= [&](CallExpr
*Expr
) {
132 EXPECT_EQ("a::y::bar", replaceCallExpr(Expr
, "::a::y::bar"));
137 namespace x { void foo() {} }
138 namespace y { void foo() {} }
144 void f() { x::foo(); }
148 Visitor
.OnCall
= [&](CallExpr
*Expr
) {
149 // y::bar would be ambiguous due to "a::b::y".
150 EXPECT_EQ("::y::bar", replaceCallExpr(Expr
, "::y::bar"));
166 Visitor
.OnCall
= [&](CallExpr
*Expr
) {
167 EXPECT_EQ("y::bar", replaceCallExpr(Expr
, "::y::bar"));
172 namespace x { void foo() {} }
173 namespace y { void foo() {} }
177 void f() { a::b::x::foo(); }
181 TEST(LookupTest
, replaceNestedClassName
) {
182 GetDeclsVisitor Visitor
;
184 auto replaceRecordTypeLoc
= [&](RecordTypeLoc TLoc
,
185 StringRef ReplacementString
) {
186 const auto *FD
= cast
<CXXRecordDecl
>(TLoc
.getDecl());
187 return tooling::replaceNestedName(
188 nullptr, TLoc
.getBeginLoc(), Visitor
.DeclStack
.back()->getDeclContext(),
189 FD
, ReplacementString
);
192 Visitor
.OnRecordTypeLoc
= [&](RecordTypeLoc Type
) {
193 // Filter Types by name since there are other `RecordTypeLoc` in the test
195 if (Type
.getDecl()->getQualifiedNameAsString() == "a::b::Foo") {
196 EXPECT_EQ("x::Bar", replaceRecordTypeLoc(Type
, "::a::x::Bar"));
199 Visitor
.runOver("namespace a { namespace b {\n"
201 "namespace c { Foo f();; }\n"
204 Visitor
.OnRecordTypeLoc
= [&](RecordTypeLoc Type
) {
205 // Filter Types by name since there are other `RecordTypeLoc` in the test
207 // `a::b::Foo` in using shadow decl is not `TypeLoc`.
208 if (Type
.getDecl()->getQualifiedNameAsString() == "a::b::Foo") {
209 EXPECT_EQ("Bar", replaceRecordTypeLoc(Type
, "::a::x::Bar"));
212 Visitor
.runOver("namespace a { namespace b { class Foo {}; } }\n"
213 "namespace c { using a::b::Foo; Foo f();; }\n");
215 // Rename TypeLoc `x::y::Old` to new name `x::Foo` at [0] and check that the
216 // type is replaced with "Foo" instead of "x::Foo". Although there is a symbol
217 // `x::y::Foo` in c.cc [1], it should not make "Foo" at [0] ambiguous because
218 // it's not visible at [0].
219 Visitor
.OnRecordTypeLoc
= [&](RecordTypeLoc Type
) {
220 if (Type
.getDecl()->getQualifiedNameAsString() == "x::y::Old") {
221 EXPECT_EQ("Foo", replaceRecordTypeLoc(Type
, "::x::Foo"));
236 // This is to be renamed to x::Foo
237 // The expected replacement is "Foo
".
245 using Foo = ::x::y::Other; // [1]
251 } // end anonymous namespace