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 #include "clang/AST/TypeLoc.h"
12 #include "clang/Basic/SourceLocation.h"
13 using namespace clang
;
16 struct GetDeclsVisitor
: TestVisitor
{
17 std::function
<void(CallExpr
*)> OnCall
;
18 std::function
<void(RecordTypeLoc
)> OnRecordTypeLoc
;
19 std::function
<void(UsingTypeLoc
)> OnUsingTypeLoc
;
20 SmallVector
<Decl
*, 4> DeclStack
;
22 bool VisitCallExpr(CallExpr
*Expr
) override
{
28 bool VisitRecordTypeLoc(RecordTypeLoc Loc
) override
{
34 bool VisitUsingTypeLoc(UsingTypeLoc Loc
) override
{
40 bool TraverseDecl(Decl
*D
) override
{
41 DeclStack
.push_back(D
);
42 bool Ret
= TestVisitor::TraverseDecl(D
);
48 TEST(LookupTest
, replaceNestedFunctionName
) {
49 GetDeclsVisitor Visitor
;
51 auto replaceCallExpr
= [&](const CallExpr
*Expr
,
52 StringRef ReplacementString
) {
53 const auto *Callee
= cast
<DeclRefExpr
>(Expr
->getCallee()->IgnoreImplicit());
54 const ValueDecl
*FD
= Callee
->getDecl();
55 return tooling::replaceNestedName(
56 Callee
->getQualifier(), Callee
->getLocation(),
57 Visitor
.DeclStack
.back()->getDeclContext(), FD
, ReplacementString
);
60 Visitor
.OnCall
= [&](CallExpr
*Expr
) {
61 EXPECT_EQ("bar", replaceCallExpr(Expr
, "::bar"));
63 Visitor
.runOver("namespace a { void foo(); }\n"
64 "namespace a { void f() { foo(); } }\n");
66 Visitor
.OnCall
= [&](CallExpr
*Expr
) {
67 EXPECT_EQ("bar", replaceCallExpr(Expr
, "::a::bar"));
69 Visitor
.runOver("namespace a { void foo(); }\n"
70 "namespace a { void f() { foo(); } }\n");
72 Visitor
.OnCall
= [&](CallExpr
*Expr
) {
73 EXPECT_EQ("a::bar", replaceCallExpr(Expr
, "::a::bar"));
75 Visitor
.runOver("namespace a { void foo(); }\n"
76 "namespace b { void f() { a::foo(); } }\n");
78 Visitor
.OnCall
= [&](CallExpr
*Expr
) {
79 EXPECT_EQ("::a::bar", replaceCallExpr(Expr
, "::a::bar"));
81 Visitor
.runOver("namespace a { void foo(); }\n"
82 "namespace b { namespace a { void foo(); }\n"
83 "void f() { a::foo(); } }\n");
85 Visitor
.OnCall
= [&](CallExpr
*Expr
) {
86 EXPECT_EQ("c::bar", replaceCallExpr(Expr
, "::a::c::bar"));
88 Visitor
.runOver("namespace a { namespace b { void foo(); }\n"
89 "void f() { b::foo(); } }\n");
91 Visitor
.OnCall
= [&](CallExpr
*Expr
) {
92 EXPECT_EQ("bar", replaceCallExpr(Expr
, "::a::bar"));
94 Visitor
.runOver("namespace a { namespace b { void foo(); }\n"
95 "void f() { b::foo(); } }\n");
97 Visitor
.OnCall
= [&](CallExpr
*Expr
) {
98 EXPECT_EQ("bar", replaceCallExpr(Expr
, "::bar"));
100 Visitor
.runOver("void foo(); void f() { foo(); }\n");
102 Visitor
.OnCall
= [&](CallExpr
*Expr
) {
103 EXPECT_EQ("::bar", replaceCallExpr(Expr
, "::bar"));
105 Visitor
.runOver("void foo(); void f() { ::foo(); }\n");
107 Visitor
.OnCall
= [&](CallExpr
*Expr
) {
108 EXPECT_EQ("a::bar", replaceCallExpr(Expr
, "::a::bar"));
110 Visitor
.runOver("namespace a { void foo(); }\nvoid f() { a::foo(); }\n");
112 Visitor
.OnCall
= [&](CallExpr
*Expr
) {
113 EXPECT_EQ("a::bar", replaceCallExpr(Expr
, "::a::bar"));
115 Visitor
.runOver("namespace a { int foo(); }\nauto f = a::foo();\n");
117 Visitor
.OnCall
= [&](CallExpr
*Expr
) {
118 EXPECT_EQ("bar", replaceCallExpr(Expr
, "::a::bar"));
121 "namespace a { int foo(); }\nusing a::foo;\nauto f = foo();\n");
123 Visitor
.OnCall
= [&](CallExpr
*Expr
) {
124 EXPECT_EQ("c::bar", replaceCallExpr(Expr
, "::a::c::bar"));
126 Visitor
.runOver("namespace a { namespace b { void foo(); } }\n"
127 "namespace a { namespace b { namespace {"
128 "void f() { foo(); }"
131 Visitor
.OnCall
= [&](CallExpr
*Expr
) {
132 EXPECT_EQ("x::bar", replaceCallExpr(Expr
, "::a::x::bar"));
134 Visitor
.runOver("namespace a { namespace b { void foo(); } }\n"
135 "namespace a { namespace b { namespace c {"
136 "void f() { foo(); }"
139 // If the shortest name is ambiguous, we need to add more qualifiers.
140 Visitor
.OnCall
= [&](CallExpr
*Expr
) {
141 EXPECT_EQ("a::y::bar", replaceCallExpr(Expr
, "::a::y::bar"));
146 namespace x { void foo() {} }
147 namespace y { void foo() {} }
153 void f() { x::foo(); }
157 Visitor
.OnCall
= [&](CallExpr
*Expr
) {
158 // y::bar would be ambiguous due to "a::b::y".
159 EXPECT_EQ("::y::bar", replaceCallExpr(Expr
, "::y::bar"));
175 Visitor
.OnCall
= [&](CallExpr
*Expr
) {
176 EXPECT_EQ("y::bar", replaceCallExpr(Expr
, "::y::bar"));
181 namespace x { void foo() {} }
182 namespace y { void foo() {} }
186 void f() { a::b::x::foo(); }
190 TEST(LookupTest
, replaceNestedClassName
) {
191 GetDeclsVisitor Visitor
;
193 auto replaceTypeLoc
= [&](const NamedDecl
*ND
, SourceLocation Loc
,
194 StringRef ReplacementString
) {
195 return tooling::replaceNestedName(
196 nullptr, Loc
, Visitor
.DeclStack
.back()->getDeclContext(), ND
,
200 Visitor
.OnRecordTypeLoc
= [&](RecordTypeLoc Type
) {
201 // Filter Types by name since there are other `RecordTypeLoc` in the test
203 if (Type
.getDecl()->getQualifiedNameAsString() == "a::b::Foo") {
204 EXPECT_EQ("x::Bar", replaceTypeLoc(Type
.getDecl(), Type
.getBeginLoc(),
208 Visitor
.runOver("namespace a { namespace b {\n"
210 "namespace c { Foo f();; }\n"
213 Visitor
.OnUsingTypeLoc
= [&](UsingTypeLoc Type
) {
214 // Filter Types by name since there are other `RecordTypeLoc` in the test
216 // `a::b::Foo` in using shadow decl is not `TypeLoc`.
217 auto *TD
= Type
.getFoundDecl()->getTargetDecl();
218 if (TD
->getQualifiedNameAsString() == "a::b::Foo") {
219 EXPECT_EQ("Bar", replaceTypeLoc(TD
, Type
.getBeginLoc(), "::a::x::Bar"));
222 Visitor
.runOver("namespace a { namespace b { class Foo {}; } }\n"
223 "namespace c { using a::b::Foo; Foo f();; }\n");
225 // Rename TypeLoc `x::y::Old` to new name `x::Foo` at [0] and check that the
226 // type is replaced with "Foo" instead of "x::Foo". Although there is a symbol
227 // `x::y::Foo` in c.cc [1], it should not make "Foo" at [0] ambiguous because
228 // it's not visible at [0].
229 Visitor
.OnRecordTypeLoc
= [&](RecordTypeLoc Type
) {
230 if (Type
.getDecl()->getQualifiedNameAsString() == "x::y::Old") {
232 replaceTypeLoc(Type
.getDecl(), Type
.getBeginLoc(), "::x::Foo"));
247 // This is to be renamed to x::Foo
248 // The expected replacement is "Foo
".
256 using Foo = ::x::y::Other; // [1]
262 } // end anonymous namespace