14#include "llvm/Support/Path.h"
15#include "gmock/gmock.h"
16#include "gtest/gtest.h"
28 Stream <<
"{ from: " <<
Call.from <<
", ranges: [";
29 for (
const auto &R :
Call.fromRanges) {
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(withDetail, N,
"") {
return arg.detail == N; }
48MATCHER_P(withFile, N,
"") {
return arg.uri.file() == N; }
49MATCHER_P(withSelectionRange, R,
"") {
return arg.selectionRange == R; }
51template <
class ItemMatcher>
52::testing::Matcher<CallHierarchyIncomingCall> from(ItemMatcher M) {
55template <
class ItemMatcher>
56::testing::Matcher<CallHierarchyOutgoingCall> to(ItemMatcher M) {
59template <
class... RangeMatchers>
60::testing::Matcher<CallHierarchyIncomingCall> iFromRanges(RangeMatchers... M) {
62 UnorderedElementsAre(M...));
64template <
class... RangeMatchers>
65::testing::Matcher<CallHierarchyOutgoingCall> oFromRanges(RangeMatchers... M) {
67 UnorderedElementsAre(M...));
70TEST(CallHierarchy, IncomingOneFileCpp) {
74 $Callee[[callee]](42);
77 $Caller1A[[caller1]]();
78 $Caller1B[[caller1]]();
81 $Caller1C[[caller1]]();
82 $Caller2[[caller2]]();
86 auto AST = TU.build();
87 auto Index = TU.index();
89 std::vector<CallHierarchyItem> Items =
91 ASSERT_THAT(Items, ElementsAre(withName(
"callee")));
95 ElementsAre(AllOf(from(AllOf(withName(
"caller1"), withDetail(
""))),
96 iFromRanges(Source.range(
"Callee")))));
97 auto IncomingLevel2 =
incomingCalls(IncomingLevel1[0].from, Index.get());
100 ElementsAre(AllOf(from(AllOf(withName(
"caller2"), withDetail(
""))),
101 iFromRanges(Source.range(
"Caller1A"),
102 Source.range(
"Caller1B"))),
103 AllOf(from(AllOf(withName(
"caller3"), withDetail(
""))),
104 iFromRanges(Source.range(
"Caller1C")))));
106 auto IncomingLevel3 =
incomingCalls(IncomingLevel2[0].from, Index.get());
109 ElementsAre(AllOf(from(AllOf(withName(
"caller3"), withDetail(
""))),
110 iFromRanges(Source.range(
"Caller2")))));
112 auto IncomingLevel4 =
incomingCalls(IncomingLevel3[0].from, Index.get());
113 EXPECT_THAT(IncomingLevel4, IsEmpty());
116TEST(CallHierarchy, IncomingOneFileObjC) {
118 @implementation MyClass {}
121 [MyClass $Callee[[callee]]];
124 [MyClass $Caller1A[[caller1]]];
125 [MyClass $Caller1B[[caller1]]];
128 [MyClass $Caller1C[[caller1]]];
129 [MyClass $Caller2[[caller2]]];
134 TU.Filename = "TestTU.m";
135 auto AST = TU.build();
136 auto Index = TU.index();
137 std::vector<CallHierarchyItem> Items =
139 ASSERT_THAT(Items, ElementsAre(withName(
"callee")));
143 ElementsAre(AllOf(from(AllOf(withName(
"caller1"), withDetail(
"MyClass"))),
144 iFromRanges(Source.range(
"Callee")))));
145 auto IncomingLevel2 =
incomingCalls(IncomingLevel1[0].from, Index.get());
148 ElementsAre(AllOf(from(AllOf(withName(
"caller2"), withDetail(
"MyClass"))),
149 iFromRanges(Source.range(
"Caller1A"),
150 Source.range(
"Caller1B"))),
151 AllOf(from(AllOf(withName(
"caller3"), withDetail(
"MyClass"))),
152 iFromRanges(Source.range(
"Caller1C")))));
154 auto IncomingLevel3 =
incomingCalls(IncomingLevel2[0].from, Index.get());
157 ElementsAre(AllOf(from(AllOf(withName(
"caller3"), withDetail(
"MyClass"))),
158 iFromRanges(Source.range(
"Caller2")))));
160 auto IncomingLevel4 =
incomingCalls(IncomingLevel3[0].from, Index.get());
161 EXPECT_THAT(IncomingLevel4, IsEmpty());
164TEST(CallHierarchy, IncomingIncludeOverrides) {
168 virtual void Func() = 0;
170 struct Implementation : public Interface {
171 void Func() override {
175 void Test(Interface& cls){
176 cls.$FuncCall[[Func]]();
180 auto AST = TU.build();
181 auto Index = TU.index();
183 std::vector<CallHierarchyItem> Items =
185 ASSERT_THAT(Items, ElementsAre(withName(
"callee")));
187 ASSERT_THAT(IncomingLevel1,
189 from(AllOf(withName(
"Func"), withDetail(
"Implementation"))),
190 iFromRanges(Source.range(
"Callee")))));
191 auto IncomingLevel2 =
incomingCalls(IncomingLevel1[0].from, Index.get());
192 ASSERT_THAT(IncomingLevel2,
193 ElementsAre(AllOf(from(AllOf(withName(
"Test"), withDetail(
""))),
194 iFromRanges(Source.range(
"FuncCall")))));
196 auto IncomingLevel3 =
incomingCalls(IncomingLevel2[0].from, Index.get());
197 EXPECT_THAT(IncomingLevel3, IsEmpty());
200TEST(CallHierarchy, MainFileOnlyRef) {
208 $Callee[[callee]](42);
212 $Caller1[[caller1]]();
216 auto AST = TU.build();
217 auto Index = TU.index();
219 std::vector<CallHierarchyItem> Items =
221 ASSERT_THAT(Items, ElementsAre(withName(
"callee")));
225 ElementsAre(AllOf(from(AllOf(withName(
"caller1"), withDetail(
""))),
226 iFromRanges(Source.range(
"Callee")))));
228 auto IncomingLevel2 =
incomingCalls(IncomingLevel1[0].from, Index.get());
231 ElementsAre(AllOf(from(AllOf(withName(
"caller2"), withDetail(
""))),
232 iFromRanges(Source.range(
"Caller1")))));
235TEST(CallHierarchy, IncomingQualified) {
241 void Waldo::find() {}
242 void caller1(Waldo &W) {
243 W.$Caller1[[f^ind]]();
245 void caller2(Waldo &W) {
246 W.$Caller2[[find]]();
251 auto AST = TU.build();
252 auto Index = TU.index();
254 std::vector<CallHierarchyItem> Items =
256 ASSERT_THAT(Items, ElementsAre(withName(
"Waldo::find")));
260 ElementsAre(AllOf(from(AllOf(withName(
"caller1"), withDetail(
"ns"))),
261 iFromRanges(Source.range(
"Caller1"))),
262 AllOf(from(AllOf(withName(
"caller2"), withDetail(
"ns"))),
263 iFromRanges(Source.range(
"Caller2")))));
266TEST(CallHierarchy, OutgoingOneFile) {
274 void Foo::caller1() {
275 $Callee[[callee]](42);
279 void caller2(ns::Foo& F) {
280 F.$Caller1A[[caller1]]();
281 F.$Caller1B[[caller1]]();
284 void call^er3(ns::Foo& F) {
285 F.$Caller1C[[caller1]]();
286 $Caller2[[caller2]](F);
290 auto AST = TU.build();
291 auto Index = TU.index();
293 std::vector<CallHierarchyItem> Items =
295 ASSERT_THAT(Items, ElementsAre(withName(
"caller3")));
299 ElementsAre(AllOf(to(AllOf(withName(
"caller1"), withDetail(
"ns::Foo"))),
300 oFromRanges(Source.range(
"Caller1C"))),
301 AllOf(to(AllOf(withName(
"caller2"), withDetail(
""))),
302 oFromRanges(Source.range(
"Caller2")))));
304 auto OutgoingLevel2 =
outgoingCalls(OugoingLevel1[1].to, Index.get());
308 to(AllOf(withName(
"caller1"), withDetail(
"ns::Foo"))),
309 oFromRanges(Source.range(
"Caller1A"), Source.range(
"Caller1B")))));
311 auto OutgoingLevel3 =
outgoingCalls(OutgoingLevel2[0].to, Index.get());
312 ASSERT_THAT(OutgoingLevel3,
313 ElementsAre(AllOf(to(AllOf(withName(
"callee"), withDetail(
""))),
314 oFromRanges(Source.range(
"Callee")))));
316 auto OutgoingLevel4 =
outgoingCalls(OutgoingLevel3[0].to, Index.get());
317 EXPECT_THAT(OutgoingLevel4, IsEmpty());
320TEST(CallHierarchy, MultiFileCpp) {
340 #include "caller1.hh"
353 #include "caller1.hh"
354 #include "caller2.hh"
357 nsa::$A[[caller1]]();
358 nsa::$B[[caller1]]();
368 #include "caller1.hh"
369 #include "caller2.hh"
372 $Caller1[[caller1]]();
373 nsb::$Caller2[[caller2]]();
379 Workspace.addSource("callee.hh", CalleeH.code());
380 Workspace.addSource(
"caller1.hh", Caller1H.code());
381 Workspace.addSource(
"caller2.hh", Caller2H.code());
382 Workspace.addSource(
"caller3.hh", Caller3H.code());
383 Workspace.addMainFile(
"callee.cc", CalleeC.code());
384 Workspace.addMainFile(
"caller1.cc", Caller1C.code());
385 Workspace.addMainFile(
"caller2.cc", Caller2C.code());
386 Workspace.addMainFile(
"caller3.cc", Caller3C.code());
388 auto Index = Workspace.index();
391 std::vector<CallHierarchyItem> Items =
393 ASSERT_THAT(Items, ElementsAre(withName(
"callee")));
397 ElementsAre(AllOf(from(AllOf(withName(
"caller1"), withDetail(
"nsa"))),
398 iFromRanges(Caller1C.range()))));
400 auto IncomingLevel2 =
incomingCalls(IncomingLevel1[0].from, Index.get());
404 AllOf(from(AllOf(withName(
"caller2"), withDetail(
"nsb"))),
405 iFromRanges(Caller2C.range(
"A"), Caller2C.range(
"B"))),
406 AllOf(from(AllOf(withName(
"caller3"), withDetail(
"nsa"))),
407 iFromRanges(Caller3C.range(
"Caller1")))));
409 auto IncomingLevel3 =
incomingCalls(IncomingLevel2[0].from, Index.get());
412 ElementsAre(AllOf(from(AllOf(withName(
"caller3"), withDetail(
"nsa"))),
413 iFromRanges(Caller3C.range(
"Caller2")))));
415 auto IncomingLevel4 =
incomingCalls(IncomingLevel3[0].from, Index.get());
416 EXPECT_THAT(IncomingLevel4, IsEmpty());
420 bool IsDeclaration) {
421 std::vector<CallHierarchyItem> Items =
427 withFile(
testPath(IsDeclaration ?
"caller3.hh" :
"caller3.cc")))));
435 AllOf(to(AllOf(withName(
"caller1"), withDetail(
"nsa"))),
436 IsDeclaration ? oFromRanges()
437 : oFromRanges(Caller3C.range(
"Caller1"))),
438 AllOf(to(AllOf(withName(
"caller2"), withDetail(
"nsb"))),
439 IsDeclaration ? oFromRanges()
440 : oFromRanges(Caller3C.range(
"Caller2")))));
442 auto OutgoingLevel2 =
outgoingCalls(OutgoingLevel1[1].to, Index.get());
443 ASSERT_THAT(OutgoingLevel2,
445 to(AllOf(withName(
"caller1"), withDetail(
"nsa"))),
446 oFromRanges(Caller2C.range(
"A"), Caller2C.range(
"B")))));
448 auto OutgoingLevel3 =
outgoingCalls(OutgoingLevel2[0].to, Index.get());
449 ASSERT_THAT(OutgoingLevel3,
450 ElementsAre(AllOf(to(AllOf(withName(
"callee"), withDetail(
""))),
451 oFromRanges(Caller1C.range()))));
453 auto OutgoingLevel4 =
outgoingCalls(OutgoingLevel3[0].to, Index.get());
454 EXPECT_THAT(OutgoingLevel4, IsEmpty());
458 auto AST = Workspace.openFile(
"caller1.cc");
459 ASSERT_TRUE(
bool(
AST));
460 CheckIncomingCalls(*
AST, Caller1C.point(),
testPath(
"caller1.cc"));
463 AST = Workspace.openFile(
"callee.hh");
464 ASSERT_TRUE(
bool(
AST));
465 CheckIncomingCalls(*
AST, CalleeH.point(),
testPath(
"callee.hh"));
466 AST = Workspace.openFile(
"caller3.hh");
467 ASSERT_TRUE(
bool(
AST));
468 CheckOutgoingCalls(*
AST, Caller3H.point(),
testPath(
"caller3.hh"),
true);
471 AST = Workspace.openFile(
"callee.cc");
472 ASSERT_TRUE(
bool(
AST));
473 CheckIncomingCalls(*
AST, CalleeC.point(),
testPath(
"callee.cc"));
474 AST = Workspace.openFile(
"caller3.cc");
475 ASSERT_TRUE(
bool(
AST));
476 CheckOutgoingCalls(*
AST, Caller3C.point(),
testPath(
"caller3.cc"),
false);
479TEST(CallHierarchy, IncomingMultiFileObjC) {
486 @interface CalleeClass
492 @implementation CalleeClass {}
497 @interface Caller1Class
504 @implementation Caller1Class {}
506 [CalleeClass [[calle^e]]];
511 @interface Caller2Class
518 @implementation Caller2Class {}
520 [Caller1Class $A[[caller1]]];
521 [Caller1Class $B[[caller1]]];
528 @implementation Caller3Class {}
530 [Caller1Class $Caller1[[caller1]]];
531 [Caller2Class $Caller2[[caller2]]];
537 Workspace.addSource("callee.mi", CalleeH.code());
538 Workspace.addSource(
"caller1.mi", Caller1H.code());
539 Workspace.addSource(
"caller2.mi", Caller2H.code());
540 Workspace.addMainFile(
"callee.m", CalleeC.code());
541 Workspace.addMainFile(
"caller1.m", Caller1C.code());
542 Workspace.addMainFile(
"caller2.m", Caller2C.code());
543 Workspace.addMainFile(
"caller3.m", Caller3C.code());
544 auto Index = Workspace.index();
547 std::vector<CallHierarchyItem> Items =
549 ASSERT_THAT(Items, ElementsAre(withName(
"callee")));
551 ASSERT_THAT(IncomingLevel1,
552 ElementsAre(AllOf(from(withName(
"caller1")),
553 iFromRanges(Caller1C.range()))));
555 auto IncomingLevel2 =
incomingCalls(IncomingLevel1[0].from, Index.get());
556 ASSERT_THAT(IncomingLevel2,
557 ElementsAre(AllOf(from(withName(
"caller2")),
558 iFromRanges(Caller2C.range(
"A"),
559 Caller2C.range(
"B"))),
560 AllOf(from(withName(
"caller3")),
561 iFromRanges(Caller3C.range(
"Caller1")))));
563 auto IncomingLevel3 =
incomingCalls(IncomingLevel2[0].from, Index.get());
564 ASSERT_THAT(IncomingLevel3,
565 ElementsAre(AllOf(from(withName(
"caller3")),
566 iFromRanges(Caller3C.range(
"Caller2")))));
568 auto IncomingLevel4 =
incomingCalls(IncomingLevel3[0].from, Index.get());
569 EXPECT_THAT(IncomingLevel4, IsEmpty());
573 auto AST = Workspace.openFile(
"caller1.m");
574 ASSERT_TRUE(
bool(
AST));
575 CheckCallHierarchy(*
AST, Caller1C.point(),
testPath(
"caller1.m"));
578 AST = Workspace.openFile(
"callee.mi");
579 ASSERT_TRUE(
bool(
AST));
580 CheckCallHierarchy(*
AST, CalleeH.point(),
testPath(
"callee.mi"));
583 AST = Workspace.openFile(
"callee.m");
584 ASSERT_TRUE(
bool(
AST));
585 CheckCallHierarchy(*
AST, CalleeC.point(),
testPath(
"callee.m"));
588TEST(CallHierarchy, CallInLocalVarDecl) {
601 int localVar = $call2[[callee]]();
603 int caller3 = $call3[[callee]]();
606 auto AST = TU.build();
607 auto Index = TU.index();
609 std::vector<CallHierarchyItem> Items =
611 ASSERT_THAT(Items, ElementsAre(withName(
"callee")));
614 ASSERT_THAT(Incoming, ElementsAre(AllOf(from(withName(
"caller1")),
615 iFromRanges(Source.range(
"call1"))),
616 AllOf(from(withName(
"caller2")),
617 iFromRanges(Source.range(
"call2"))),
618 AllOf(from(withName(
"caller3")),
619 iFromRanges(Source.range(
"call3")))));
622TEST(CallHierarchy, HierarchyOnField) {
630 values.$Callee[[var1]];
634 auto AST = TU.build();
635 auto Index = TU.index();
637 std::vector<CallHierarchyItem> Items =
639 ASSERT_THAT(Items, ElementsAre(withName(
"var1")));
641 ASSERT_THAT(IncomingLevel1,
642 ElementsAre(AllOf(from(withName(
"caller")),
643 iFromRanges(Source.range(
"Callee")))));
646TEST(CallHierarchy, HierarchyOnVar) {
655 auto AST = TU.build();
656 auto Index = TU.index();
658 std::vector<CallHierarchyItem> Items =
660 ASSERT_THAT(Items, ElementsAre(withName(
"var")));
662 ASSERT_THAT(IncomingLevel1,
663 ElementsAre(AllOf(from(withName(
"caller")),
664 iFromRanges(Source.range(
"Callee")))));
667TEST(CallHierarchy, HierarchyOnEnumConstant) {
670 enum class Coin { heads$Heads^ , tai$Tails^ls };
672 Coin::$CallerH[[heads]];
673 Coin::$CallerT[[tails]];
677 auto AST = TU.build();
678 auto Index = TU.index();
680 std::vector<CallHierarchyItem> Items =
682 ASSERT_THAT(Items, ElementsAre(withName(
"heads")));
684 ASSERT_THAT(IncomingLevel1,
685 ElementsAre(AllOf(from(withName(
"caller")),
686 iFromRanges(Source.range(
"CallerH")))));
689 ASSERT_THAT(Items, ElementsAre(withName(
"tails")));
691 ASSERT_THAT(IncomingLevel1,
692 ElementsAre(AllOf(from(withName(
"caller")),
693 iFromRanges(Source.range(
"CallerT")))));
696TEST(CallHierarchy, CallInDifferentFileThanCaller) {
698 #define WALDO void caller() {
707 TU.HeaderCode = Header.code();
708 auto AST = TU.build();
709 auto Index = TU.index();
711 std::vector<CallHierarchyItem> Items =
713 ASSERT_THAT(Items, ElementsAre(withName(
"callee")));
721 EXPECT_THAT(Incoming,
722 ElementsAre(AllOf(from(withName(
"caller")), iFromRanges())));
Same as llvm::Annotations, but adjusts functions to LSP-specific types for positions and ranges.
Stores and provides access to parsed AST.
void addSource(llvm::StringRef Filename, llvm::StringRef Code)
FIXME: Skip testing on windows temporarily due to the different escaping code mode.
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< CallHierarchyOutgoingCall > outgoingCalls(const CallHierarchyItem &Item, const SymbolIndex *Index)
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....
std::vector< Range > fromRanges
The range at which this item is called.
CallHierarchyItem to
The item that is called.
static TestTU withCode(llvm::StringRef Code)