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   // If the shortest name is ambiguous, we need to add more qualifiers.
132   Visitor.OnCall = [&](CallExpr *Expr) {
133     EXPECT_EQ("::a::y::bar", replaceCallExpr(Expr, "::a::y::bar"));
134   };
135   Visitor.runOver(R"(
136     namespace a {
137     namespace b {
138     namespace x { void foo() {} }
139     namespace y { void foo() {} }
140     }
141     }
142 
143     namespace a {
144     namespace b {
145     void f() { x::foo(); }
146     }
147     })");
148 
149   Visitor.OnCall = [&](CallExpr *Expr) {
150     EXPECT_EQ("y::bar", replaceCallExpr(Expr, "::y::bar"));
151   };
152   Visitor.runOver(R"(
153     namespace a {
154     namespace b {
155     namespace x { void foo() {} }
156     namespace y { void foo() {} }
157     }
158     }
159 
160     void f() { a::b::x::foo(); }
161     )");
162 }
163 
164 TEST(LookupTest, replaceNestedClassName) {
165   GetDeclsVisitor Visitor;
166 
167   auto replaceRecordTypeLoc = [&](RecordTypeLoc Loc,
168                                   StringRef ReplacementString) {
169     const auto *FD = cast<CXXRecordDecl>(Loc.getDecl());
170     return tooling::replaceNestedName(
171         nullptr, Visitor.DeclStack.back()->getDeclContext(), FD,
172         ReplacementString);
173   };
174 
175   Visitor.OnRecordTypeLoc = [&](RecordTypeLoc Type) {
176     // Filter Types by name since there are other `RecordTypeLoc` in the test
177     // file.
178     if (Type.getDecl()->getQualifiedNameAsString() == "a::b::Foo") {
179       EXPECT_EQ("x::Bar", replaceRecordTypeLoc(Type, "::a::x::Bar"));
180     }
181   };
182   Visitor.runOver("namespace a { namespace b {\n"
183                   "class Foo;\n"
184                   "namespace c { Foo f();; }\n"
185                   "} }\n");
186 
187   Visitor.OnRecordTypeLoc = [&](RecordTypeLoc Type) {
188     // Filter Types by name since there are other `RecordTypeLoc` in the test
189     // file.
190     // `a::b::Foo` in using shadow decl is not `TypeLoc`.
191     if (Type.getDecl()->getQualifiedNameAsString() == "a::b::Foo") {
192       EXPECT_EQ("Bar", replaceRecordTypeLoc(Type, "::a::x::Bar"));
193     }
194   };
195   Visitor.runOver("namespace a { namespace b { class Foo {}; } }\n"
196                   "namespace c { using a::b::Foo; Foo f();; }\n");
197 }
198 
199 } // end anonymous namespace
200