1 //===- unittest/Tooling/LookupTest.cpp ------------------------------------===// 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 #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; 14 15 namespace { 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; 21 22 bool VisitCallExpr(CallExpr *Expr) override { 23 if (OnCall) 24 OnCall(Expr); 25 return true; 26 } 27 28 bool VisitRecordTypeLoc(RecordTypeLoc Loc) override { 29 if (OnRecordTypeLoc) 30 OnRecordTypeLoc(Loc); 31 return true; 32 } 33 34 bool VisitUsingTypeLoc(UsingTypeLoc Loc) override { 35 if (OnUsingTypeLoc) 36 OnUsingTypeLoc(Loc); 37 return true; 38 } 39 40 bool TraverseDecl(Decl *D) override { 41 DeclStack.push_back(D); 42 bool Ret = TestVisitor::TraverseDecl(D); 43 DeclStack.pop_back(); 44 return Ret; 45 } 46 }; 47 48 TEST(LookupTest, replaceNestedFunctionName) { 49 GetDeclsVisitor Visitor; 50 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); 58 }; 59 60 Visitor.OnCall = [&](CallExpr *Expr) { 61 EXPECT_EQ("bar", replaceCallExpr(Expr, "::bar")); 62 }; 63 Visitor.runOver("namespace a { void foo(); }\n" 64 "namespace a { void f() { foo(); } }\n"); 65 66 Visitor.OnCall = [&](CallExpr *Expr) { 67 EXPECT_EQ("bar", replaceCallExpr(Expr, "::a::bar")); 68 }; 69 Visitor.runOver("namespace a { void foo(); }\n" 70 "namespace a { void f() { foo(); } }\n"); 71 72 Visitor.OnCall = [&](CallExpr *Expr) { 73 EXPECT_EQ("a::bar", replaceCallExpr(Expr, "::a::bar")); 74 }; 75 Visitor.runOver("namespace a { void foo(); }\n" 76 "namespace b { void f() { a::foo(); } }\n"); 77 78 Visitor.OnCall = [&](CallExpr *Expr) { 79 EXPECT_EQ("::a::bar", replaceCallExpr(Expr, "::a::bar")); 80 }; 81 Visitor.runOver("namespace a { void foo(); }\n" 82 "namespace b { namespace a { void foo(); }\n" 83 "void f() { a::foo(); } }\n"); 84 85 Visitor.OnCall = [&](CallExpr *Expr) { 86 EXPECT_EQ("c::bar", replaceCallExpr(Expr, "::a::c::bar")); 87 }; 88 Visitor.runOver("namespace a { namespace b { void foo(); }\n" 89 "void f() { b::foo(); } }\n"); 90 91 Visitor.OnCall = [&](CallExpr *Expr) { 92 EXPECT_EQ("bar", replaceCallExpr(Expr, "::a::bar")); 93 }; 94 Visitor.runOver("namespace a { namespace b { void foo(); }\n" 95 "void f() { b::foo(); } }\n"); 96 97 Visitor.OnCall = [&](CallExpr *Expr) { 98 EXPECT_EQ("bar", replaceCallExpr(Expr, "::bar")); 99 }; 100 Visitor.runOver("void foo(); void f() { foo(); }\n"); 101 102 Visitor.OnCall = [&](CallExpr *Expr) { 103 EXPECT_EQ("::bar", replaceCallExpr(Expr, "::bar")); 104 }; 105 Visitor.runOver("void foo(); void f() { ::foo(); }\n"); 106 107 Visitor.OnCall = [&](CallExpr *Expr) { 108 EXPECT_EQ("a::bar", replaceCallExpr(Expr, "::a::bar")); 109 }; 110 Visitor.runOver("namespace a { void foo(); }\nvoid f() { a::foo(); }\n"); 111 112 Visitor.OnCall = [&](CallExpr *Expr) { 113 EXPECT_EQ("a::bar", replaceCallExpr(Expr, "::a::bar")); 114 }; 115 Visitor.runOver("namespace a { int foo(); }\nauto f = a::foo();\n"); 116 117 Visitor.OnCall = [&](CallExpr *Expr) { 118 EXPECT_EQ("bar", replaceCallExpr(Expr, "::a::bar")); 119 }; 120 Visitor.runOver( 121 "namespace a { int foo(); }\nusing a::foo;\nauto f = foo();\n"); 122 123 Visitor.OnCall = [&](CallExpr *Expr) { 124 EXPECT_EQ("c::bar", replaceCallExpr(Expr, "::a::c::bar")); 125 }; 126 Visitor.runOver("namespace a { namespace b { void foo(); } }\n" 127 "namespace a { namespace b { namespace {" 128 "void f() { foo(); }" 129 "} } }\n"); 130 131 Visitor.OnCall = [&](CallExpr *Expr) { 132 EXPECT_EQ("x::bar", replaceCallExpr(Expr, "::a::x::bar")); 133 }; 134 Visitor.runOver("namespace a { namespace b { void foo(); } }\n" 135 "namespace a { namespace b { namespace c {" 136 "void f() { foo(); }" 137 "} } }\n"); 138 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")); 142 }; 143 Visitor.runOver(R"( 144 namespace a { 145 namespace b { 146 namespace x { void foo() {} } 147 namespace y { void foo() {} } 148 } 149 } 150 151 namespace a { 152 namespace b { 153 void f() { x::foo(); } 154 } 155 })"); 156 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")); 160 }; 161 Visitor.runOver(R"( 162 namespace a { 163 namespace b { 164 void foo() {} 165 namespace y { } 166 } 167 } 168 169 namespace a { 170 namespace b { 171 void f() { foo(); } 172 } 173 })"); 174 175 Visitor.OnCall = [&](CallExpr *Expr) { 176 EXPECT_EQ("y::bar", replaceCallExpr(Expr, "::y::bar")); 177 }; 178 Visitor.runOver(R"( 179 namespace a { 180 namespace b { 181 namespace x { void foo() {} } 182 namespace y { void foo() {} } 183 } 184 } 185 186 void f() { a::b::x::foo(); } 187 )"); 188 } 189 190 TEST(LookupTest, replaceNestedClassName) { 191 GetDeclsVisitor Visitor; 192 193 auto replaceTypeLoc = [&](const NamedDecl *ND, SourceLocation Loc, 194 StringRef ReplacementString) { 195 return tooling::replaceNestedName( 196 nullptr, Loc, Visitor.DeclStack.back()->getDeclContext(), ND, 197 ReplacementString); 198 }; 199 200 Visitor.OnRecordTypeLoc = [&](RecordTypeLoc Type) { 201 // Filter Types by name since there are other `RecordTypeLoc` in the test 202 // file. 203 if (Type.getDecl()->getQualifiedNameAsString() == "a::b::Foo") { 204 EXPECT_EQ("x::Bar", replaceTypeLoc(Type.getDecl(), Type.getBeginLoc(), 205 "::a::x::Bar")); 206 } 207 }; 208 Visitor.runOver("namespace a { namespace b {\n" 209 "class Foo;\n" 210 "namespace c { Foo f();; }\n" 211 "} }\n"); 212 213 Visitor.OnUsingTypeLoc = [&](UsingTypeLoc Type) { 214 // Filter Types by name since there are other `RecordTypeLoc` in the test 215 // file. 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")); 220 } 221 }; 222 Visitor.runOver("namespace a { namespace b { class Foo {}; } }\n" 223 "namespace c { using a::b::Foo; Foo f();; }\n"); 224 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") { 231 EXPECT_EQ("Foo", 232 replaceTypeLoc(Type.getDecl(), Type.getBeginLoc(), "::x::Foo")); 233 } 234 }; 235 Visitor.runOver(R"( 236 // a.h 237 namespace x { 238 namespace y { 239 class Old {}; 240 class Other {}; 241 } 242 } 243 244 // b.h 245 namespace x { 246 namespace y { 247 // This is to be renamed to x::Foo 248 // The expected replacement is "Foo". 249 Old f; // [0]. 250 } 251 } 252 253 // c.cc 254 namespace x { 255 namespace y { 256 using Foo = ::x::y::Other; // [1] 257 } 258 } 259 )"); 260 } 261 262 } // end anonymous namespace 263