14#include "llvm/Support/Path.h"
15#include "gmock/gmock.h"
16#include "gtest/gtest.h"
28 Stream <<
"{ from: " << Call.
from <<
", ranges: [";
33 return Stream <<
"] }";
38using ::testing::AllOf;
39using ::testing::ElementsAre;
40using ::testing::Field;
41using ::testing::IsEmpty;
42using ::testing::Matcher;
43using ::testing::UnorderedElementsAre;
46MATCHER_P(withName, N,
"") {
return arg.name == N; }
47MATCHER_P(withSelectionRange, R,
"") {
return arg.selectionRange == R; }
49template <
class ItemMatcher>
50::testing::Matcher<CallHierarchyIncomingCall> from(ItemMatcher
M) {
53template <
class... RangeMatchers>
54::testing::Matcher<CallHierarchyIncomingCall> fromRanges(RangeMatchers...
M) {
56 UnorderedElementsAre(
M...));
59TEST(CallHierarchy, IncomingOneFileCpp) {
60 Annotations Source(R
"cpp(
63 $Callee[[callee]](42);
66 $Caller1A[[caller1]]();
67 $Caller1B[[caller1]]();
70 $Caller1C[[caller1]]();
71 $Caller2[[caller2]]();
75 auto AST = TU.build();
76 auto Index = TU.index();
78 std::vector<CallHierarchyItem> Items =
80 ASSERT_THAT(Items, ElementsAre(withName(
"callee")));
82 ASSERT_THAT(IncomingLevel1,
83 ElementsAre(AllOf(from(withName(
"caller1")),
84 fromRanges(Source.range(
"Callee")))));
85 auto IncomingLevel2 =
incomingCalls(IncomingLevel1[0].from, Index.get());
86 ASSERT_THAT(IncomingLevel2,
87 ElementsAre(AllOf(from(withName(
"caller2")),
88 fromRanges(Source.range(
"Caller1A"),
89 Source.range(
"Caller1B"))),
90 AllOf(from(withName(
"caller3")),
91 fromRanges(Source.range(
"Caller1C")))));
93 auto IncomingLevel3 =
incomingCalls(IncomingLevel2[0].from, Index.get());
94 ASSERT_THAT(IncomingLevel3,
95 ElementsAre(AllOf(from(withName(
"caller3")),
96 fromRanges(Source.range(
"Caller2")))));
98 auto IncomingLevel4 =
incomingCalls(IncomingLevel3[0].from, Index.get());
99 EXPECT_THAT(IncomingLevel4, IsEmpty());
102TEST(CallHierarchy, IncomingOneFileObjC) {
103 Annotations Source(R
"objc(
104 @implementation MyClass {}
107 [MyClass $Callee[[callee]]];
110 [MyClass $Caller1A[[caller1]]];
111 [MyClass $Caller1B[[caller1]]];
114 [MyClass $Caller1C[[caller1]]];
115 [MyClass $Caller2[[caller2]]];
120 TU.Filename = "TestTU.m";
121 auto AST = TU.build();
122 auto Index = TU.index();
123 std::vector<CallHierarchyItem> Items =
125 ASSERT_THAT(Items, ElementsAre(withName(
"callee")));
127 ASSERT_THAT(IncomingLevel1,
128 ElementsAre(AllOf(from(withName(
"caller1")),
129 fromRanges(Source.range(
"Callee")))));
130 auto IncomingLevel2 =
incomingCalls(IncomingLevel1[0].from, Index.get());
131 ASSERT_THAT(IncomingLevel2,
132 ElementsAre(AllOf(from(withName(
"caller2")),
133 fromRanges(Source.range(
"Caller1A"),
134 Source.range(
"Caller1B"))),
135 AllOf(from(withName(
"caller3")),
136 fromRanges(Source.range(
"Caller1C")))));
138 auto IncomingLevel3 =
incomingCalls(IncomingLevel2[0].from, Index.get());
139 ASSERT_THAT(IncomingLevel3,
140 ElementsAre(AllOf(from(withName(
"caller3")),
141 fromRanges(Source.range(
"Caller2")))));
143 auto IncomingLevel4 =
incomingCalls(IncomingLevel3[0].from, Index.get());
144 EXPECT_THAT(IncomingLevel4, IsEmpty());
147TEST(CallHierarchy, MainFileOnlyRef) {
151 Annotations Source(R
"cpp(
155 $Callee[[callee]](42);
159 $Caller1[[caller1]]();
163 auto AST = TU.build();
164 auto Index = TU.index();
166 std::vector<CallHierarchyItem> Items =
168 ASSERT_THAT(Items, ElementsAre(withName(
"callee")));
170 ASSERT_THAT(IncomingLevel1,
171 ElementsAre(AllOf(from(withName(
"caller1")),
172 fromRanges(Source.range(
"Callee")))));
174 auto IncomingLevel2 =
incomingCalls(IncomingLevel1[0].from, Index.get());
175 EXPECT_THAT(IncomingLevel2,
176 ElementsAre(AllOf(from(withName(
"caller2")),
177 fromRanges(Source.range(
"Caller1")))));
180TEST(CallHierarchy, IncomingQualified) {
181 Annotations Source(R
"cpp(
186 void Waldo::find() {}
187 void caller1(Waldo &W) {
188 W.$Caller1[[f^ind]]();
190 void caller2(Waldo &W) {
191 W.$Caller2[[find]]();
196 auto AST = TU.build();
197 auto Index = TU.index();
199 std::vector<CallHierarchyItem> Items =
201 ASSERT_THAT(Items, ElementsAre(withName(
"Waldo::find")));
203 EXPECT_THAT(Incoming,
204 ElementsAre(AllOf(from(withName(
"caller1")),
205 fromRanges(Source.range(
"Caller1"))),
206 AllOf(from(withName(
"caller2")),
207 fromRanges(Source.range(
"Caller2")))));
210TEST(CallHierarchy, IncomingMultiFileCpp) {
216 Annotations CalleeH(R
"cpp(
219 Annotations CalleeC(R"cpp(
223 Annotations Caller1H(R"cpp(
226 Annotations Caller1C(R"cpp(
228 #include "caller1.hh"
233 Annotations Caller2H(R"cpp(
236 Annotations Caller2C(R"cpp(
237 #include "caller1.hh"
238 #include "caller2.hh"
244 Annotations Caller3C(R"cpp(
245 #include "caller1.hh"
246 #include "caller2.hh"
248 $Caller1[[caller1]]();
249 $Caller2[[caller2]]();
253 TestWorkspace Workspace;
254 Workspace.addSource("callee.hh", CalleeH.code());
255 Workspace.addSource(
"caller1.hh", Caller1H.code());
256 Workspace.addSource(
"caller2.hh", Caller2H.code());
257 Workspace.addMainFile(
"callee.cc", CalleeC.code());
258 Workspace.addMainFile(
"caller1.cc", Caller1C.code());
259 Workspace.addMainFile(
"caller2.cc", Caller2C.code());
260 Workspace.addMainFile(
"caller3.cc", Caller3C.code());
262 auto Index = Workspace.index();
264 auto CheckCallHierarchy = [&](ParsedAST &
AST, Position
Pos,
PathRef TUPath) {
265 std::vector<CallHierarchyItem> Items =
267 ASSERT_THAT(Items, ElementsAre(withName(
"callee")));
269 ASSERT_THAT(IncomingLevel1,
270 ElementsAre(AllOf(from(withName(
"caller1")),
271 fromRanges(Caller1C.range()))));
273 auto IncomingLevel2 =
incomingCalls(IncomingLevel1[0].from, Index.get());
276 ElementsAre(AllOf(from(withName(
"caller2")),
277 fromRanges(Caller2C.range(
"A"), Caller2C.range(
"B"))),
278 AllOf(from(withName(
"caller3")),
279 fromRanges(Caller3C.range(
"Caller1")))));
281 auto IncomingLevel3 =
incomingCalls(IncomingLevel2[0].from, Index.get());
282 ASSERT_THAT(IncomingLevel3,
283 ElementsAre(AllOf(from(withName(
"caller3")),
284 fromRanges(Caller3C.range(
"Caller2")))));
286 auto IncomingLevel4 =
incomingCalls(IncomingLevel3[0].from, Index.get());
287 EXPECT_THAT(IncomingLevel4, IsEmpty());
291 auto AST = Workspace.openFile(
"caller1.cc");
292 ASSERT_TRUE(
bool(
AST));
293 CheckCallHierarchy(*
AST, Caller1C.point(),
testPath(
"caller1.cc"));
296 AST = Workspace.openFile(
"callee.hh");
297 ASSERT_TRUE(
bool(
AST));
298 CheckCallHierarchy(*
AST, CalleeH.point(),
testPath(
"callee.hh"));
301 AST = Workspace.openFile(
"callee.cc");
302 ASSERT_TRUE(
bool(
AST));
303 CheckCallHierarchy(*
AST, CalleeC.point(),
testPath(
"callee.cc"));
306TEST(CallHierarchy, IncomingMultiFileObjC) {
312 Annotations CalleeH(R
"objc(
313 @interface CalleeClass
317 Annotations CalleeC(R"objc(
319 @implementation CalleeClass {}
323 Annotations Caller1H(R"objc(
324 @interface Caller1Class
328 Annotations Caller1C(R"objc(
331 @implementation Caller1Class {}
333 [CalleeClass [[calle^e]]];
337 Annotations Caller2H(R"objc(
338 @interface Caller2Class
342 Annotations Caller2C(R"objc(
345 @implementation Caller2Class {}
347 [Caller1Class $A[[caller1]]];
348 [Caller1Class $B[[caller1]]];
352 Annotations Caller3C(R"objc(
355 @implementation Caller3Class {}
357 [Caller1Class $Caller1[[caller1]]];
358 [Caller2Class $Caller2[[caller2]]];
363 TestWorkspace Workspace;
364 Workspace.addSource("callee.mi", CalleeH.code());
365 Workspace.addSource(
"caller1.mi", Caller1H.code());
366 Workspace.addSource(
"caller2.mi", Caller2H.code());
367 Workspace.addMainFile(
"callee.m", CalleeC.code());
368 Workspace.addMainFile(
"caller1.m", Caller1C.code());
369 Workspace.addMainFile(
"caller2.m", Caller2C.code());
370 Workspace.addMainFile(
"caller3.m", Caller3C.code());
371 auto Index = Workspace.index();
373 auto CheckCallHierarchy = [&](ParsedAST &
AST, Position
Pos,
PathRef TUPath) {
374 std::vector<CallHierarchyItem> Items =
376 ASSERT_THAT(Items, ElementsAre(withName(
"callee")));
378 ASSERT_THAT(IncomingLevel1,
379 ElementsAre(AllOf(from(withName(
"caller1")),
380 fromRanges(Caller1C.range()))));
382 auto IncomingLevel2 =
incomingCalls(IncomingLevel1[0].from, Index.get());
385 ElementsAre(AllOf(from(withName(
"caller2")),
386 fromRanges(Caller2C.range(
"A"), Caller2C.range(
"B"))),
387 AllOf(from(withName(
"caller3")),
388 fromRanges(Caller3C.range(
"Caller1")))));
390 auto IncomingLevel3 =
incomingCalls(IncomingLevel2[0].from, Index.get());
391 ASSERT_THAT(IncomingLevel3,
392 ElementsAre(AllOf(from(withName(
"caller3")),
393 fromRanges(Caller3C.range(
"Caller2")))));
395 auto IncomingLevel4 =
incomingCalls(IncomingLevel3[0].from, Index.get());
396 EXPECT_THAT(IncomingLevel4, IsEmpty());
400 auto AST = Workspace.openFile(
"caller1.m");
401 ASSERT_TRUE(
bool(
AST));
402 CheckCallHierarchy(*
AST, Caller1C.point(),
testPath(
"caller1.m"));
405 AST = Workspace.openFile(
"callee.mi");
406 ASSERT_TRUE(
bool(
AST));
407 CheckCallHierarchy(*
AST, CalleeH.point(),
testPath(
"callee.mi"));
410 AST = Workspace.openFile(
"callee.m");
411 ASSERT_TRUE(
bool(
AST));
412 CheckCallHierarchy(*
AST, CalleeC.point(),
testPath(
"callee.m"));
415TEST(CallHierarchy, CallInLocalVarDecl) {
422 Annotations Source(R
"cpp(
428 int localVar = $call2[[callee]]();
430 int caller3 = $call3[[callee]]();
433 auto AST = TU.build();
434 auto Index = TU.index();
436 std::vector<CallHierarchyItem> Items =
438 ASSERT_THAT(Items, ElementsAre(withName(
"callee")));
444 AllOf(from(withName(
"caller1")), fromRanges(Source.range(
"call1"))),
445 AllOf(from(withName(
"caller2")), fromRanges(Source.range(
"call2"))),
446 AllOf(from(withName(
"caller3")), fromRanges(Source.range(
"call3")))));
const google::protobuf::Message & M
std::vector< CallHierarchyIncomingCall > incomingCalls(const CallHierarchyItem &Item, const SymbolIndex *Index)
llvm::raw_ostream & operator<<(llvm::raw_ostream &OS, const CodeCompletion &C)
std::string testPath(PathRef File, llvm::sys::path::Style Style)
TEST(BackgroundQueueTest, Priority)
llvm::StringRef PathRef
A typedef to represent a ref to file path.
std::vector< CallHierarchyItem > prepareCallHierarchy(ParsedAST &AST, Position Pos, PathRef TUPath)
Get call hierarchy information at Pos.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Represents an incoming call, e.g. a caller of a method or constructor.
CallHierarchyItem from
The item that makes the call.
std::vector< Range > fromRanges
The range at which the calls appear.
Represents programming constructs like functions or constructors in the context of call hierarchy.
std::string name
The name of this item.
Range selectionRange
The range that should be selected and revealed when this symbol is being picked, e....
static TestTU withCode(llvm::StringRef Code)