1 //===- unittest/Tooling/LookupTest.cpp ------------------------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "TestVisitor.h" 11 #include "clang/Tooling/Core/Lookup.h" 12 using namespace clang; 13 14 namespace { 15 struct GetDeclsVisitor : TestVisitor<GetDeclsVisitor> { 16 std::function<void(CallExpr *)> OnCall; 17 std::function<void(RecordTypeLoc)> OnRecordTypeLoc; 18 SmallVector<Decl *, 4> DeclStack; 19 20 bool VisitCallExpr(CallExpr *Expr) { 21 if (OnCall) 22 OnCall(Expr); 23 return true; 24 } 25 26 bool VisitRecordTypeLoc(RecordTypeLoc Loc) { 27 if (OnRecordTypeLoc) 28 OnRecordTypeLoc(Loc); 29 return true; 30 } 31 32 bool TraverseDecl(Decl *D) { 33 DeclStack.push_back(D); 34 bool Ret = TestVisitor::TraverseDecl(D); 35 DeclStack.pop_back(); 36 return Ret; 37 } 38 }; 39 40 TEST(LookupTest, replaceNestedFunctionName) { 41 GetDeclsVisitor Visitor; 42 43 auto replaceCallExpr = [&](const CallExpr *Expr, 44 StringRef ReplacementString) { 45 const auto *Callee = cast<DeclRefExpr>(Expr->getCallee()->IgnoreImplicit()); 46 const ValueDecl *FD = Callee->getDecl(); 47 return tooling::replaceNestedName( 48 Callee->getQualifier(), Visitor.DeclStack.back()->getDeclContext(), FD, 49 ReplacementString); 50 }; 51 52 Visitor.OnCall = [&](CallExpr *Expr) { 53 EXPECT_EQ("bar", replaceCallExpr(Expr, "::bar")); 54 }; 55 Visitor.runOver("namespace a { void foo(); }\n" 56 "namespace a { void f() { foo(); } }\n"); 57 58 Visitor.OnCall = [&](CallExpr *Expr) { 59 EXPECT_EQ("bar", replaceCallExpr(Expr, "::a::bar")); 60 }; 61 Visitor.runOver("namespace a { void foo(); }\n" 62 "namespace a { void f() { foo(); } }\n"); 63 64 Visitor.OnCall = [&](CallExpr *Expr) { 65 EXPECT_EQ("a::bar", replaceCallExpr(Expr, "::a::bar")); 66 }; 67 Visitor.runOver("namespace a { void foo(); }\n" 68 "namespace b { void f() { a::foo(); } }\n"); 69 70 Visitor.OnCall = [&](CallExpr *Expr) { 71 EXPECT_EQ("a::bar", replaceCallExpr(Expr, "::a::bar")); 72 }; 73 Visitor.runOver("namespace a { void foo(); }\n" 74 "namespace b { namespace a { void foo(); }\n" 75 "void f() { a::foo(); } }\n"); 76 77 Visitor.OnCall = [&](CallExpr *Expr) { 78 EXPECT_EQ("c::bar", replaceCallExpr(Expr, "::a::c::bar")); 79 }; 80 Visitor.runOver("namespace a { namespace b { void foo(); }\n" 81 "void f() { b::foo(); } }\n"); 82 83 Visitor.OnCall = [&](CallExpr *Expr) { 84 EXPECT_EQ("bar", replaceCallExpr(Expr, "::a::bar")); 85 }; 86 Visitor.runOver("namespace a { namespace b { void foo(); }\n" 87 "void f() { b::foo(); } }\n"); 88 89 Visitor.OnCall = [&](CallExpr *Expr) { 90 EXPECT_EQ("bar", replaceCallExpr(Expr, "::bar")); 91 }; 92 Visitor.runOver("void foo(); void f() { foo(); }\n"); 93 94 Visitor.OnCall = [&](CallExpr *Expr) { 95 EXPECT_EQ("::bar", replaceCallExpr(Expr, "::bar")); 96 }; 97 Visitor.runOver("void foo(); void f() { ::foo(); }\n"); 98 99 Visitor.OnCall = [&](CallExpr *Expr) { 100 EXPECT_EQ("a::bar", replaceCallExpr(Expr, "::a::bar")); 101 }; 102 Visitor.runOver("namespace a { void foo(); }\nvoid f() { a::foo(); }\n"); 103 104 Visitor.OnCall = [&](CallExpr *Expr) { 105 EXPECT_EQ("a::bar", replaceCallExpr(Expr, "::a::bar")); 106 }; 107 Visitor.runOver("namespace a { int foo(); }\nauto f = a::foo();\n"); 108 109 Visitor.OnCall = [&](CallExpr *Expr) { 110 EXPECT_EQ("bar", replaceCallExpr(Expr, "::a::bar")); 111 }; 112 Visitor.runOver( 113 "namespace a { int foo(); }\nusing a::foo;\nauto f = foo();\n"); 114 115 Visitor.OnCall = [&](CallExpr *Expr) { 116 EXPECT_EQ("c::bar", replaceCallExpr(Expr, "::a::c::bar")); 117 }; 118 Visitor.runOver("namespace a { namespace b { void foo(); } }\n" 119 "namespace a { namespace b { namespace {" 120 "void f() { foo(); }" 121 "} } }\n"); 122 123 Visitor.OnCall = [&](CallExpr *Expr) { 124 EXPECT_EQ("x::bar", replaceCallExpr(Expr, "::a::x::bar")); 125 }; 126 Visitor.runOver("namespace a { namespace b { void foo(); } }\n" 127 "namespace a { namespace b { namespace c {" 128 "void f() { foo(); }" 129 "} } }\n"); 130 } 131 132 TEST(LookupTest, replaceNestedClassName) { 133 GetDeclsVisitor Visitor; 134 135 auto replaceRecordTypeLoc = [&](RecordTypeLoc Loc, 136 StringRef ReplacementString) { 137 const auto *FD = cast<CXXRecordDecl>(Loc.getDecl()); 138 return tooling::replaceNestedName( 139 nullptr, Visitor.DeclStack.back()->getDeclContext(), FD, 140 ReplacementString); 141 }; 142 143 Visitor.OnRecordTypeLoc = [&](RecordTypeLoc Type) { 144 // Filter Types by name since there are other `RecordTypeLoc` in the test 145 // file. 146 if (Type.getDecl()->getQualifiedNameAsString() == "a::b::Foo") 147 EXPECT_EQ("x::Bar", replaceRecordTypeLoc(Type, "::a::x::Bar")); 148 }; 149 Visitor.runOver("namespace a { namespace b {\n" 150 "class Foo;\n" 151 "namespace c { Foo f();; }\n" 152 "} }\n"); 153 154 Visitor.OnRecordTypeLoc = [&](RecordTypeLoc Type) { 155 // Filter Types by name since there are other `RecordTypeLoc` in the test 156 // file. 157 // `a::b::Foo` in using shadow decl is not `TypeLoc`. 158 if (Type.getDecl()->getQualifiedNameAsString() == "a::b::Foo") 159 EXPECT_EQ("Bar", replaceRecordTypeLoc(Type, "::a::x::Bar")); 160 }; 161 Visitor.runOver("namespace a { namespace b { class Foo {}; } }\n" 162 "namespace c { using a::b::Foo; Foo f();; }\n"); 163 } 164 165 } // end anonymous namespace 166