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 <
typename... Tags>
52::testing::Matcher<CallHierarchyItem> withSymbolTags(Tags... tags) {
57template <
class ItemMatcher>
58::testing::Matcher<CallHierarchyIncomingCall> from(ItemMatcher M) {
61template <
class ItemMatcher>
62::testing::Matcher<CallHierarchyOutgoingCall> to(ItemMatcher M) {
65template <
class... RangeMatchers>
66::testing::Matcher<CallHierarchyIncomingCall> iFromRanges(RangeMatchers... M) {
68 UnorderedElementsAre(M...));
70template <
class... RangeMatchers>
71::testing::Matcher<CallHierarchyOutgoingCall> oFromRanges(RangeMatchers... M) {
73 UnorderedElementsAre(M...));
76TEST(CallHierarchy, IncomingOneFileCpp) {
80 $Callee[[callee]](42);
83 $Caller1A[[caller1]]();
84 $Caller1B[[caller1]]();
87 $Caller1C[[caller1]]();
88 $Caller2[[caller2]]();
92 auto AST = TU.build();
93 auto Index = TU.index();
95 std::vector<CallHierarchyItem> Items =
97 ASSERT_THAT(Items, ElementsAre(withName(
"callee")));
101 ElementsAre(AllOf(from(AllOf(withName(
"caller1"), withDetail(
""))),
102 iFromRanges(Source.range(
"Callee")))));
103 auto IncomingLevel2 =
incomingCalls(IncomingLevel1[0].from, Index.get());
106 ElementsAre(AllOf(from(AllOf(withName(
"caller2"), withDetail(
""))),
107 iFromRanges(Source.range(
"Caller1A"),
108 Source.range(
"Caller1B"))),
109 AllOf(from(AllOf(withName(
"caller3"), withDetail(
""))),
110 iFromRanges(Source.range(
"Caller1C")))));
112 auto IncomingLevel3 =
incomingCalls(IncomingLevel2[0].from, Index.get());
115 ElementsAre(AllOf(from(AllOf(withName(
"caller3"), withDetail(
""))),
116 iFromRanges(Source.range(
"Caller2")))));
118 auto IncomingLevel4 =
incomingCalls(IncomingLevel3[0].from, Index.get());
119 EXPECT_THAT(IncomingLevel4, IsEmpty());
122TEST(CallHierarchy, IncomingOneFileObjC) {
124 @implementation MyClass {}
127 [MyClass $Callee[[callee]]];
130 [MyClass $Caller1A[[caller1]]];
131 [MyClass $Caller1B[[caller1]]];
134 [MyClass $Caller1C[[caller1]]];
135 [MyClass $Caller2[[caller2]]];
140 TU.Filename = "TestTU.m";
141 auto AST = TU.build();
142 auto Index = TU.index();
143 std::vector<CallHierarchyItem> Items =
145 ASSERT_THAT(Items, ElementsAre(withName(
"callee")));
149 ElementsAre(AllOf(from(AllOf(withName(
"caller1"), withDetail(
"MyClass"))),
150 iFromRanges(Source.range(
"Callee")))));
151 auto IncomingLevel2 =
incomingCalls(IncomingLevel1[0].from, Index.get());
154 ElementsAre(AllOf(from(AllOf(withName(
"caller2"), withDetail(
"MyClass"))),
155 iFromRanges(Source.range(
"Caller1A"),
156 Source.range(
"Caller1B"))),
157 AllOf(from(AllOf(withName(
"caller3"), withDetail(
"MyClass"))),
158 iFromRanges(Source.range(
"Caller1C")))));
160 auto IncomingLevel3 =
incomingCalls(IncomingLevel2[0].from, Index.get());
163 ElementsAre(AllOf(from(AllOf(withName(
"caller3"), withDetail(
"MyClass"))),
164 iFromRanges(Source.range(
"Caller2")))));
166 auto IncomingLevel4 =
incomingCalls(IncomingLevel3[0].from, Index.get());
167 EXPECT_THAT(IncomingLevel4, IsEmpty());
170TEST(CallHierarchy, IncomingIncludeOverrides) {
174 virtual void Func() = 0;
176 struct Implementation : public Interface {
177 void Func() override {
181 void Test(Interface& cls){
182 cls.$FuncCall[[Func]]();
186 auto AST = TU.build();
187 auto Index = TU.index();
189 std::vector<CallHierarchyItem> Items =
191 ASSERT_THAT(Items, ElementsAre(withName(
"callee")));
193 ASSERT_THAT(IncomingLevel1,
195 from(AllOf(withName(
"Func"), withDetail(
"Implementation"))),
196 iFromRanges(Source.range(
"Callee")))));
197 auto IncomingLevel2 =
incomingCalls(IncomingLevel1[0].from, Index.get());
198 ASSERT_THAT(IncomingLevel2,
199 ElementsAre(AllOf(from(AllOf(withName(
"Test"), withDetail(
""))),
200 iFromRanges(Source.range(
"FuncCall")))));
202 auto IncomingLevel3 =
incomingCalls(IncomingLevel2[0].from, Index.get());
203 EXPECT_THAT(IncomingLevel3, IsEmpty());
206TEST(CallHierarchy, MainFileOnlyRef) {
214 $Callee[[callee]](42);
218 $Caller1[[caller1]]();
222 auto AST = TU.build();
223 auto Index = TU.index();
225 std::vector<CallHierarchyItem> Items =
227 ASSERT_THAT(Items, ElementsAre(withName(
"callee")));
231 ElementsAre(AllOf(from(AllOf(withName(
"caller1"), withDetail(
""))),
232 iFromRanges(Source.range(
"Callee")))));
234 auto IncomingLevel2 =
incomingCalls(IncomingLevel1[0].from, Index.get());
237 ElementsAre(AllOf(from(AllOf(withName(
"caller2"), withDetail(
""))),
238 iFromRanges(Source.range(
"Caller1")))));
241TEST(CallHierarchy, IncomingQualified) {
247 void Waldo::find() {}
248 void caller1(Waldo &W) {
249 W.$Caller1[[f^ind]]();
251 void caller2(Waldo &W) {
252 W.$Caller2[[find]]();
257 auto AST = TU.build();
258 auto Index = TU.index();
260 std::vector<CallHierarchyItem> Items =
262 ASSERT_THAT(Items, ElementsAre(withName(
"Waldo::find")));
266 ElementsAre(AllOf(from(AllOf(withName(
"caller1"), withDetail(
"ns"))),
267 iFromRanges(Source.range(
"Caller1"))),
268 AllOf(from(AllOf(withName(
"caller2"), withDetail(
"ns"))),
269 iFromRanges(Source.range(
"Caller2")))));
272TEST(CallHierarchy, OutgoingOneFile) {
280 void Foo::caller1() {
281 $Callee[[callee]](42);
285 void caller2(ns::Foo& F) {
286 F.$Caller1A[[caller1]]();
287 F.$Caller1B[[caller1]]();
290 void call^er3(ns::Foo& F) {
291 F.$Caller1C[[caller1]]();
292 $Caller2[[caller2]](F);
296 auto AST = TU.build();
297 auto Index = TU.index();
299 std::vector<CallHierarchyItem> Items =
301 ASSERT_THAT(Items, ElementsAre(withName(
"caller3")));
305 ElementsAre(AllOf(to(AllOf(withName(
"caller1"), withDetail(
"ns::Foo"))),
306 oFromRanges(Source.range(
"Caller1C"))),
307 AllOf(to(AllOf(withName(
"caller2"), withDetail(
""))),
308 oFromRanges(Source.range(
"Caller2")))));
310 auto OutgoingLevel2 =
outgoingCalls(OugoingLevel1[1].to, Index.get());
314 to(AllOf(withName(
"caller1"), withDetail(
"ns::Foo"))),
315 oFromRanges(Source.range(
"Caller1A"), Source.range(
"Caller1B")))));
317 auto OutgoingLevel3 =
outgoingCalls(OutgoingLevel2[0].to, Index.get());
318 ASSERT_THAT(OutgoingLevel3,
319 ElementsAre(AllOf(to(AllOf(withName(
"callee"), withDetail(
""))),
320 oFromRanges(Source.range(
"Callee")))));
322 auto OutgoingLevel4 =
outgoingCalls(OutgoingLevel3[0].to, Index.get());
323 EXPECT_THAT(OutgoingLevel4, IsEmpty());
326TEST(CallHierarchy, MultiFileCpp) {
346 #include "caller1.hh"
359 #include "caller1.hh"
360 #include "caller2.hh"
363 nsa::$A[[caller1]]();
364 nsa::$B[[caller1]]();
374 #include "caller1.hh"
375 #include "caller2.hh"
378 $Caller1[[caller1]]();
379 nsb::$Caller2[[caller2]]();
385 Workspace.addSource("callee.hh", CalleeH.code());
386 Workspace.addSource(
"caller1.hh", Caller1H.code());
387 Workspace.addSource(
"caller2.hh", Caller2H.code());
388 Workspace.addSource(
"caller3.hh", Caller3H.code());
389 Workspace.addMainFile(
"callee.cc", CalleeC.code());
390 Workspace.addMainFile(
"caller1.cc", Caller1C.code());
391 Workspace.addMainFile(
"caller2.cc", Caller2C.code());
392 Workspace.addMainFile(
"caller3.cc", Caller3C.code());
394 auto Index = Workspace.index();
397 std::vector<CallHierarchyItem> Items =
399 ASSERT_THAT(Items, ElementsAre(withName(
"callee")));
403 ElementsAre(AllOf(from(AllOf(withName(
"caller1"), withDetail(
"nsa"))),
404 iFromRanges(Caller1C.range()))));
406 auto IncomingLevel2 =
incomingCalls(IncomingLevel1[0].from, Index.get());
410 AllOf(from(AllOf(withName(
"caller2"), withDetail(
"nsb"))),
411 iFromRanges(Caller2C.range(
"A"), Caller2C.range(
"B"))),
412 AllOf(from(AllOf(withName(
"caller3"), withDetail(
"nsa"))),
413 iFromRanges(Caller3C.range(
"Caller1")))));
415 auto IncomingLevel3 =
incomingCalls(IncomingLevel2[0].from, Index.get());
418 ElementsAre(AllOf(from(AllOf(withName(
"caller3"), withDetail(
"nsa"))),
419 iFromRanges(Caller3C.range(
"Caller2")))));
421 auto IncomingLevel4 =
incomingCalls(IncomingLevel3[0].from, Index.get());
422 EXPECT_THAT(IncomingLevel4, IsEmpty());
426 bool IsDeclaration) {
427 std::vector<CallHierarchyItem> Items =
433 withFile(
testPath(IsDeclaration ?
"caller3.hh" :
"caller3.cc")))));
441 AllOf(to(AllOf(withName(
"caller1"), withDetail(
"nsa"))),
442 IsDeclaration ? oFromRanges()
443 : oFromRanges(Caller3C.range(
"Caller1"))),
444 AllOf(to(AllOf(withName(
"caller2"), withDetail(
"nsb"))),
445 IsDeclaration ? oFromRanges()
446 : oFromRanges(Caller3C.range(
"Caller2")))));
448 auto OutgoingLevel2 =
outgoingCalls(OutgoingLevel1[1].to, Index.get());
449 ASSERT_THAT(OutgoingLevel2,
451 to(AllOf(withName(
"caller1"), withDetail(
"nsa"))),
452 oFromRanges(Caller2C.range(
"A"), Caller2C.range(
"B")))));
454 auto OutgoingLevel3 =
outgoingCalls(OutgoingLevel2[0].to, Index.get());
455 ASSERT_THAT(OutgoingLevel3,
456 ElementsAre(AllOf(to(AllOf(withName(
"callee"), withDetail(
""))),
457 oFromRanges(Caller1C.range()))));
459 auto OutgoingLevel4 =
outgoingCalls(OutgoingLevel3[0].to, Index.get());
460 EXPECT_THAT(OutgoingLevel4, IsEmpty());
464 auto AST = Workspace.openFile(
"caller1.cc");
465 ASSERT_TRUE(
bool(
AST));
466 CheckIncomingCalls(*
AST, Caller1C.point(),
testPath(
"caller1.cc"));
469 AST = Workspace.openFile(
"callee.hh");
470 ASSERT_TRUE(
bool(
AST));
471 CheckIncomingCalls(*
AST, CalleeH.point(),
testPath(
"callee.hh"));
472 AST = Workspace.openFile(
"caller3.hh");
473 ASSERT_TRUE(
bool(
AST));
474 CheckOutgoingCalls(*
AST, Caller3H.point(),
testPath(
"caller3.hh"),
true);
477 AST = Workspace.openFile(
"callee.cc");
478 ASSERT_TRUE(
bool(
AST));
479 CheckIncomingCalls(*
AST, CalleeC.point(),
testPath(
"callee.cc"));
480 AST = Workspace.openFile(
"caller3.cc");
481 ASSERT_TRUE(
bool(
AST));
482 CheckOutgoingCalls(*
AST, Caller3C.point(),
testPath(
"caller3.cc"),
false);
485TEST(CallHierarchy, IncomingMultiFileObjC) {
492 @interface CalleeClass
498 @implementation CalleeClass {}
503 @interface Caller1Class
510 @implementation Caller1Class {}
512 [CalleeClass [[calle^e]]];
517 @interface Caller2Class
524 @implementation Caller2Class {}
526 [Caller1Class $A[[caller1]]];
527 [Caller1Class $B[[caller1]]];
534 @implementation Caller3Class {}
536 [Caller1Class $Caller1[[caller1]]];
537 [Caller2Class $Caller2[[caller2]]];
543 Workspace.addSource("callee.mi", CalleeH.code());
544 Workspace.addSource(
"caller1.mi", Caller1H.code());
545 Workspace.addSource(
"caller2.mi", Caller2H.code());
546 Workspace.addMainFile(
"callee.m", CalleeC.code());
547 Workspace.addMainFile(
"caller1.m", Caller1C.code());
548 Workspace.addMainFile(
"caller2.m", Caller2C.code());
549 Workspace.addMainFile(
"caller3.m", Caller3C.code());
550 auto Index = Workspace.index();
553 std::vector<CallHierarchyItem> Items =
555 ASSERT_THAT(Items, ElementsAre(withName(
"callee")));
557 ASSERT_THAT(IncomingLevel1,
558 ElementsAre(AllOf(from(withName(
"caller1")),
559 iFromRanges(Caller1C.range()))));
561 auto IncomingLevel2 =
incomingCalls(IncomingLevel1[0].from, Index.get());
562 ASSERT_THAT(IncomingLevel2,
563 ElementsAre(AllOf(from(withName(
"caller2")),
564 iFromRanges(Caller2C.range(
"A"),
565 Caller2C.range(
"B"))),
566 AllOf(from(withName(
"caller3")),
567 iFromRanges(Caller3C.range(
"Caller1")))));
569 auto IncomingLevel3 =
incomingCalls(IncomingLevel2[0].from, Index.get());
570 ASSERT_THAT(IncomingLevel3,
571 ElementsAre(AllOf(from(withName(
"caller3")),
572 iFromRanges(Caller3C.range(
"Caller2")))));
574 auto IncomingLevel4 =
incomingCalls(IncomingLevel3[0].from, Index.get());
575 EXPECT_THAT(IncomingLevel4, IsEmpty());
579 auto AST = Workspace.openFile(
"caller1.m");
580 ASSERT_TRUE(
bool(
AST));
581 CheckCallHierarchy(*
AST, Caller1C.point(),
testPath(
"caller1.m"));
584 AST = Workspace.openFile(
"callee.mi");
585 ASSERT_TRUE(
bool(
AST));
586 CheckCallHierarchy(*
AST, CalleeH.point(),
testPath(
"callee.mi"));
589 AST = Workspace.openFile(
"callee.m");
590 ASSERT_TRUE(
bool(
AST));
591 CheckCallHierarchy(*
AST, CalleeC.point(),
testPath(
"callee.m"));
594TEST(CallHierarchy, CallInLocalVarDecl) {
607 int localVar = $call2[[callee]]();
609 int caller3 = $call3[[callee]]();
612 auto AST = TU.build();
613 auto Index = TU.index();
615 std::vector<CallHierarchyItem> Items =
617 ASSERT_THAT(Items, ElementsAre(withName(
"callee")));
620 ASSERT_THAT(Incoming, ElementsAre(AllOf(from(withName(
"caller1")),
621 iFromRanges(Source.range(
"call1"))),
622 AllOf(from(withName(
"caller2")),
623 iFromRanges(Source.range(
"call2"))),
624 AllOf(from(withName(
"caller3")),
625 iFromRanges(Source.range(
"call3")))));
628TEST(CallHierarchy, HierarchyOnField) {
636 values.$Callee[[var1]];
640 auto AST = TU.build();
641 auto Index = TU.index();
643 std::vector<CallHierarchyItem> Items =
645 ASSERT_THAT(Items, ElementsAre(withName(
"var1")));
647 ASSERT_THAT(IncomingLevel1,
648 ElementsAre(AllOf(from(withName(
"caller")),
649 iFromRanges(Source.range(
"Callee")))));
652TEST(CallHierarchy, HierarchyOnVar) {
661 auto AST = TU.build();
662 auto Index = TU.index();
664 std::vector<CallHierarchyItem> Items =
666 ASSERT_THAT(Items, ElementsAre(withName(
"var")));
668 ASSERT_THAT(IncomingLevel1,
669 ElementsAre(AllOf(from(withName(
"caller")),
670 iFromRanges(Source.range(
"Callee")))));
673TEST(CallHierarchy, HierarchyOnEnumConstant) {
676 enum class Coin { heads$Heads^ , tai$Tails^ls };
678 Coin::$CallerH[[heads]];
679 Coin::$CallerT[[tails]];
683 auto AST = TU.build();
684 auto Index = TU.index();
686 std::vector<CallHierarchyItem> Items =
688 ASSERT_THAT(Items, ElementsAre(withName(
"heads")));
690 ASSERT_THAT(IncomingLevel1,
691 ElementsAre(AllOf(from(withName(
"caller")),
692 iFromRanges(Source.range(
"CallerH")))));
695 ASSERT_THAT(Items, ElementsAre(withName(
"tails")));
697 ASSERT_THAT(IncomingLevel1,
698 ElementsAre(AllOf(from(withName(
"caller")),
699 iFromRanges(Source.range(
"CallerT")))));
702TEST(CallHierarchy, CallInDifferentFileThanCaller) {
704 #define WALDO void caller() {
713 TU.HeaderCode = Header.code();
714 auto AST = TU.build();
715 auto Index = TU.index();
717 std::vector<CallHierarchyItem> Items =
719 ASSERT_THAT(Items, ElementsAre(withName(
"callee")));
727 EXPECT_THAT(Incoming,
728 ElementsAre(AllOf(from(withName(
"caller")), iFromRanges())));
731TEST(CallHierarchy, IncomingCalls) {
742 auto AST = TU.build();
743 auto Index = TU.index();
745 std::vector<CallHierarchyItem> Items =
747 ASSERT_THAT(Items, ElementsAre(withName(
"callee")));
752 UnorderedElementsAre(AllOf(from(
757TEST(CallHierarchy, OutgoingCalls) {
768 auto AST = TU.build();
769 auto Index = TU.index();
771 std::vector<CallHierarchyItem> Items =
773 ASSERT_THAT(Items, ElementsAre(withName(
"caller")));
776 EXPECT_THAT(Outgoing, UnorderedElementsAre(AllOf(
777 to(AllOf(withName(
"callee"),
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.
std::vector< SymbolTag > tags
Tags for 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)