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 using namespace clang; 12 13 namespace { 14 struct GetDeclsVisitor : TestVisitor<GetDeclsVisitor> { 15 std::function<void(CallExpr *)> OnCall; 16 std::function<void(RecordTypeLoc)> OnRecordTypeLoc; 17 SmallVector<Decl *, 4> DeclStack; 18 19 bool VisitCallExpr(CallExpr *Expr) { 20 if (OnCall) 21 OnCall(Expr); 22 return true; 23 } 24 25 bool VisitRecordTypeLoc(RecordTypeLoc Loc) { 26 if (OnRecordTypeLoc) 27 OnRecordTypeLoc(Loc); 28 return true; 29 } 30 31 bool TraverseDecl(Decl *D) { 32 DeclStack.push_back(D); 33 bool Ret = TestVisitor::TraverseDecl(D); 34 DeclStack.pop_back(); 35 return Ret; 36 } 37 }; 38 39 TEST(LookupTest, replaceNestedFunctionName) { 40 GetDeclsVisitor Visitor; 41 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); 49 }; 50 51 Visitor.OnCall = [&](CallExpr *Expr) { 52 EXPECT_EQ("bar", replaceCallExpr(Expr, "::bar")); 53 }; 54 Visitor.runOver("namespace a { void foo(); }\n" 55 "namespace a { void f() { foo(); } }\n"); 56 57 Visitor.OnCall = [&](CallExpr *Expr) { 58 EXPECT_EQ("bar", replaceCallExpr(Expr, "::a::bar")); 59 }; 60 Visitor.runOver("namespace a { void foo(); }\n" 61 "namespace a { void f() { foo(); } }\n"); 62 63 Visitor.OnCall = [&](CallExpr *Expr) { 64 EXPECT_EQ("a::bar", replaceCallExpr(Expr, "::a::bar")); 65 }; 66 Visitor.runOver("namespace a { void foo(); }\n" 67 "namespace b { void f() { a::foo(); } }\n"); 68 69 Visitor.OnCall = [&](CallExpr *Expr) { 70 EXPECT_EQ("::a::bar", replaceCallExpr(Expr, "::a::bar")); 71 }; 72 Visitor.runOver("namespace a { void foo(); }\n" 73 "namespace b { namespace a { void foo(); }\n" 74 "void f() { a::foo(); } }\n"); 75 76 Visitor.OnCall = [&](CallExpr *Expr) { 77 EXPECT_EQ("c::bar", replaceCallExpr(Expr, "::a::c::bar")); 78 }; 79 Visitor.runOver("namespace a { namespace b { void foo(); }\n" 80 "void f() { b::foo(); } }\n"); 81 82 Visitor.OnCall = [&](CallExpr *Expr) { 83 EXPECT_EQ("bar", replaceCallExpr(Expr, "::a::bar")); 84 }; 85 Visitor.runOver("namespace a { namespace b { void foo(); }\n" 86 "void f() { b::foo(); } }\n"); 87 88 Visitor.OnCall = [&](CallExpr *Expr) { 89 EXPECT_EQ("bar", replaceCallExpr(Expr, "::bar")); 90 }; 91 Visitor.runOver("void foo(); void f() { foo(); }\n"); 92 93 Visitor.OnCall = [&](CallExpr *Expr) { 94 EXPECT_EQ("::bar", replaceCallExpr(Expr, "::bar")); 95 }; 96 Visitor.runOver("void foo(); void f() { ::foo(); }\n"); 97 98 Visitor.OnCall = [&](CallExpr *Expr) { 99 EXPECT_EQ("a::bar", replaceCallExpr(Expr, "::a::bar")); 100 }; 101 Visitor.runOver("namespace a { void foo(); }\nvoid f() { a::foo(); }\n"); 102 103 Visitor.OnCall = [&](CallExpr *Expr) { 104 EXPECT_EQ("a::bar", replaceCallExpr(Expr, "::a::bar")); 105 }; 106 Visitor.runOver("namespace a { int foo(); }\nauto f = a::foo();\n"); 107 108 Visitor.OnCall = [&](CallExpr *Expr) { 109 EXPECT_EQ("bar", replaceCallExpr(Expr, "::a::bar")); 110 }; 111 Visitor.runOver( 112 "namespace a { int foo(); }\nusing a::foo;\nauto f = foo();\n"); 113 114 Visitor.OnCall = [&](CallExpr *Expr) { 115 EXPECT_EQ("c::bar", replaceCallExpr(Expr, "::a::c::bar")); 116 }; 117 Visitor.runOver("namespace a { namespace b { void foo(); } }\n" 118 "namespace a { namespace b { namespace {" 119 "void f() { foo(); }" 120 "} } }\n"); 121 122 Visitor.OnCall = [&](CallExpr *Expr) { 123 EXPECT_EQ("x::bar", replaceCallExpr(Expr, "::a::x::bar")); 124 }; 125 Visitor.runOver("namespace a { namespace b { void foo(); } }\n" 126 "namespace a { namespace b { namespace c {" 127 "void f() { foo(); }" 128 "} } }\n"); 129 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")); 133 }; 134 Visitor.runOver(R"( 135 namespace a { 136 namespace b { 137 namespace x { void foo() {} } 138 namespace y { void foo() {} } 139 } 140 } 141 142 namespace a { 143 namespace b { 144 void f() { x::foo(); } 145 } 146 })"); 147 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")); 151 }; 152 Visitor.runOver(R"( 153 namespace a { 154 namespace b { 155 void foo() {} 156 namespace y { } 157 } 158 } 159 160 namespace a { 161 namespace b { 162 void f() { foo(); } 163 } 164 })"); 165 166 Visitor.OnCall = [&](CallExpr *Expr) { 167 EXPECT_EQ("y::bar", replaceCallExpr(Expr, "::y::bar")); 168 }; 169 Visitor.runOver(R"( 170 namespace a { 171 namespace b { 172 namespace x { void foo() {} } 173 namespace y { void foo() {} } 174 } 175 } 176 177 void f() { a::b::x::foo(); } 178 )"); 179 } 180 181 TEST(LookupTest, replaceNestedClassName) { 182 GetDeclsVisitor Visitor; 183 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); 190 }; 191 192 Visitor.OnRecordTypeLoc = [&](RecordTypeLoc Type) { 193 // Filter Types by name since there are other `RecordTypeLoc` in the test 194 // file. 195 if (Type.getDecl()->getQualifiedNameAsString() == "a::b::Foo") { 196 EXPECT_EQ("x::Bar", replaceRecordTypeLoc(Type, "::a::x::Bar")); 197 } 198 }; 199 Visitor.runOver("namespace a { namespace b {\n" 200 "class Foo;\n" 201 "namespace c { Foo f();; }\n" 202 "} }\n"); 203 204 Visitor.OnRecordTypeLoc = [&](RecordTypeLoc Type) { 205 // Filter Types by name since there are other `RecordTypeLoc` in the test 206 // file. 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")); 210 } 211 }; 212 Visitor.runOver("namespace a { namespace b { class Foo {}; } }\n" 213 "namespace c { using a::b::Foo; Foo f();; }\n"); 214 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")); 222 } 223 }; 224 Visitor.runOver(R"( 225 // a.h 226 namespace x { 227 namespace y { 228 class Old {}; 229 class Other {}; 230 } 231 } 232 233 // b.h 234 namespace x { 235 namespace y { 236 // This is to be renamed to x::Foo 237 // The expected replacement is "Foo". 238 Old f; // [0]. 239 } 240 } 241 242 // c.cc 243 namespace x { 244 namespace y { 245 using Foo = ::x::y::Other; // [1] 246 } 247 } 248 )"); 249 } 250 251 } // end anonymous namespace 252