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