1//===-- XRefsTests.cpp ---------------------------*- C++ -*--------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8#include "Annotations.h"
9#include "AST.h"
10#include "ParsedAST.h"
11#include "Protocol.h"
12#include "SourceCode.h"
13#include "SyncAPI.h"
14#include "TestFS.h"
15#include "TestTU.h"
16#include "XRefs.h"
17#include "index/MemIndex.h"
18#include "clang/AST/Decl.h"
19#include "clang/Basic/SourceLocation.h"
20#include "llvm/ADT/StringRef.h"
21#include "llvm/Support/Casting.h"
22#include "llvm/Support/Error.h"
23#include "llvm/Support/Path.h"
24#include "llvm/Support/ScopedPrinter.h"
25#include "gmock/gmock.h"
26#include "gtest/gtest.h"
27#include <optional>
28#include <string>
29#include <vector>
30
31namespace clang {
32namespace clangd {
33namespace {
34
35using ::testing::AllOf;
36using ::testing::ElementsAre;
37using ::testing::Eq;
38using ::testing::IsEmpty;
39using ::testing::Matcher;
40using ::testing::UnorderedElementsAre;
41using ::testing::UnorderedElementsAreArray;
42using ::testing::UnorderedPointwise;
43
44std::string guard(llvm::StringRef Code) {
45 return "#pragma once\n" + Code.str();
46}
47
48MATCHER_P2(FileRange, File, Range, "") {
49 return Location{URIForFile::canonicalize(AbsPath: File, TUPath: testRoot()), Range} == arg;
50}
51MATCHER(declRange, "") {
52 const LocatedSymbol &Sym = ::testing::get<0>(arg);
53 const Range &Range = ::testing::get<1>(arg);
54 return Sym.PreferredDeclaration.range == Range;
55}
56
57// Extracts ranges from an annotated example, and constructs a matcher for a
58// highlight set. Ranges should be named $read/$write as appropriate.
59Matcher<const std::vector<DocumentHighlight> &>
60highlightsFrom(const Annotations &Test) {
61 std::vector<DocumentHighlight> Expected;
62 auto Add = [&](const Range &R, DocumentHighlightKind K) {
63 Expected.emplace_back();
64 Expected.back().range = R;
65 Expected.back().kind = K;
66 };
67 for (const auto &Range : Test.ranges())
68 Add(Range, DocumentHighlightKind::Text);
69 for (const auto &Range : Test.ranges(Name: "read"))
70 Add(Range, DocumentHighlightKind::Read);
71 for (const auto &Range : Test.ranges(Name: "write"))
72 Add(Range, DocumentHighlightKind::Write);
73 return UnorderedElementsAreArray(container: Expected);
74}
75
76TEST(HighlightsTest, All) {
77 const char *Tests[] = {
78 R"cpp(// Local variable
79 int main() {
80 int [[bonjour]];
81 $write[[^bonjour]] = 2;
82 int test1 = $read[[bonjour]];
83 }
84 )cpp",
85
86 R"cpp(// Struct
87 namespace ns1 {
88 struct [[MyClass]] {
89 static void foo([[MyClass]]*) {}
90 };
91 } // namespace ns1
92 int main() {
93 ns1::[[My^Class]]* Params;
94 }
95 )cpp",
96
97 R"cpp(// Function
98 int [[^foo]](int) { return 0; }
99 int main() {
100 [[foo]]([[foo]](42));
101 auto *X = &[[foo]];
102 }
103 )cpp",
104
105 R"cpp(// Function parameter in decl
106 void foo(int [[^bar]]);
107 )cpp",
108 R"cpp(// Not touching any identifiers.
109 struct Foo {
110 [[~]]Foo() {};
111 };
112 void foo() {
113 Foo f;
114 f.[[^~]]Foo();
115 }
116 )cpp",
117 R"cpp(// ObjC methods with split selectors.
118 @interface Foo
119 +(void) [[x]]:(int)a [[y]]:(int)b;
120 @end
121 @implementation Foo
122 +(void) [[x]]:(int)a [[y]]:(int)b {}
123 @end
124 void go() {
125 [Foo [[x]]:2 [[^y]]:4];
126 }
127 )cpp",
128 R"cpp( // Label
129 int main() {
130 goto [[^theLabel]];
131 [[theLabel]]:
132 return 1;
133 }
134 )cpp",
135 };
136 for (const char *Test : Tests) {
137 Annotations T(Test);
138 auto TU = TestTU::withCode(Code: T.code());
139 TU.ExtraArgs.push_back(x: "-xobjective-c++");
140 auto AST = TU.build();
141 EXPECT_THAT(findDocumentHighlights(AST, T.point()), highlightsFrom(T))
142 << Test;
143 }
144}
145
146TEST(HighlightsTest, ControlFlow) {
147 const char *Tests[] = {
148 R"cpp(
149 // Highlight same-function returns.
150 int fib(unsigned n) {
151 if (n <= 1) [[ret^urn]] 1;
152 [[return]] fib(n - 1) + fib(n - 2);
153
154 // Returns from other functions not highlighted.
155 auto Lambda = [] { return; };
156 class LocalClass { void x() { return; } };
157 }
158 )cpp",
159
160 R"cpp(
161 #define FAIL() return false
162 #define DO(x) { x; }
163 bool foo(int n) {
164 if (n < 0) [[FAIL]]();
165 DO([[re^turn]] true)
166 }
167 )cpp",
168
169 R"cpp(
170 // Highlight loop control flow
171 int magic() {
172 int counter = 0;
173 [[^for]] (char c : "fruit loops!") {
174 if (c == ' ') [[continue]];
175 counter += c;
176 if (c == '!') [[break]];
177 if (c == '?') [[return]] -1;
178 }
179 return counter;
180 }
181 )cpp",
182
183 R"cpp(
184 // Highlight loop and same-loop control flow
185 void nonsense() {
186 [[while]] (true) {
187 if (false) [[bre^ak]];
188 switch (1) break;
189 [[continue]];
190 }
191 }
192 )cpp",
193
194 R"cpp(
195 // Highlight switch for break (but not other breaks).
196 void describe(unsigned n) {
197 [[switch]](n) {
198 case 0:
199 break;
200 [[default]]:
201 [[^break]];
202 }
203 }
204 )cpp",
205
206 R"cpp(
207 // Highlight case and exits for switch-break (but not other cases).
208 void describe(unsigned n) {
209 [[switch]](n) {
210 case 0:
211 break;
212 [[case]] 1:
213 [[default]]:
214 [[return]];
215 [[^break]];
216 }
217 }
218 )cpp",
219
220 R"cpp(
221 // Highlight exits and switch for case
222 void describe(unsigned n) {
223 [[switch]](n) {
224 case 0:
225 break;
226 [[case]] 1:
227 [[d^efault]]:
228 [[return]];
229 [[break]];
230 }
231 }
232 )cpp",
233
234 R"cpp(
235 // Highlight nothing for switch.
236 void describe(unsigned n) {
237 s^witch(n) {
238 case 0:
239 break;
240 case 1:
241 default:
242 return;
243 break;
244 }
245 }
246 )cpp",
247
248 R"cpp(
249 // FIXME: match exception type against catch blocks
250 int catchy() {
251 try { // wrong: highlight try with matching catch
252 try { // correct: has no matching catch
253 [[thr^ow]] "oh no!";
254 } catch (int) { } // correct: catch doesn't match type
255 [[return]] -1; // correct: exits the matching catch
256 } catch (const char*) { } // wrong: highlight matching catch
257 [[return]] 42; // wrong: throw doesn't exit function
258 }
259 )cpp",
260
261 R"cpp(
262 // Loop highlights goto exiting the loop, but not jumping within it.
263 void jumpy() {
264 [[wh^ile]](1) {
265 up:
266 if (0) [[goto]] out;
267 goto up;
268 }
269 out: return;
270 }
271 )cpp",
272 };
273 for (const char *Test : Tests) {
274 Annotations T(Test);
275 auto TU = TestTU::withCode(Code: T.code());
276 TU.ExtraArgs.push_back(x: "-fexceptions"); // FIXME: stop testing on PS4.
277 auto AST = TU.build();
278 EXPECT_THAT(findDocumentHighlights(AST, T.point()), highlightsFrom(T))
279 << Test;
280 }
281}
282
283MATCHER_P3(sym, Name, Decl, DefOrNone, "") {
284 std::optional<Range> Def = DefOrNone;
285 if (Name != arg.Name) {
286 *result_listener << "Name is " << arg.Name;
287 return false;
288 }
289 if (Decl != arg.PreferredDeclaration.range) {
290 *result_listener << "Declaration is "
291 << llvm::to_string(arg.PreferredDeclaration);
292 return false;
293 }
294 if (!Def && !arg.Definition)
295 return true;
296 if (Def && !arg.Definition) {
297 *result_listener << "Has no definition";
298 return false;
299 }
300 if (!Def && arg.Definition) {
301 *result_listener << "Definition is " << llvm::to_string(*arg.Definition);
302 return false;
303 }
304 if (arg.Definition->range != *Def) {
305 *result_listener << "Definition is " << llvm::to_string(*arg.Definition);
306 return false;
307 }
308 return true;
309}
310
311MATCHER_P(sym, Name, "") { return arg.Name == Name; }
312
313MATCHER_P(rangeIs, R, "") { return arg.Loc.range == R; }
314MATCHER_P(containerIs, C, "") {
315 return arg.Loc.containerName.value_or("") == C;
316}
317MATCHER_P(attrsAre, A, "") { return arg.Attributes == A; }
318MATCHER_P(hasID, ID, "") { return arg.ID == ID; }
319
320TEST(LocateSymbol, WithIndex) {
321 Annotations SymbolHeader(R"cpp(
322 class $forward[[Forward]];
323 class $foo[[Foo]] {};
324
325 void $f1[[f1]]();
326
327 inline void $f2[[f2]]() {}
328 )cpp");
329 Annotations SymbolCpp(R"cpp(
330 class $forward[[forward]] {};
331 void $f1[[f1]]() {}
332 )cpp");
333
334 TestTU TU;
335 TU.Code = std::string(SymbolCpp.code());
336 TU.HeaderCode = std::string(SymbolHeader.code());
337 auto Index = TU.index();
338 auto LocateWithIndex = [&Index](const Annotations &Main) {
339 auto AST = TestTU::withCode(Code: Main.code()).build();
340 return clangd::locateSymbolAt(AST, Pos: Main.point(), Index: Index.get());
341 };
342
343 Annotations Test(R"cpp(// only declaration in AST.
344 void [[f1]]();
345 int main() {
346 ^f1();
347 }
348 )cpp");
349 EXPECT_THAT(LocateWithIndex(Test),
350 ElementsAre(sym("f1", Test.range(), SymbolCpp.range("f1"))));
351
352 Test = Annotations(R"cpp(// definition in AST.
353 void [[f1]]() {}
354 int main() {
355 ^f1();
356 }
357 )cpp");
358 EXPECT_THAT(LocateWithIndex(Test),
359 ElementsAre(sym("f1", SymbolHeader.range("f1"), Test.range())));
360
361 Test = Annotations(R"cpp(// forward declaration in AST.
362 class [[Foo]];
363 F^oo* create();
364 )cpp");
365 EXPECT_THAT(LocateWithIndex(Test),
366 ElementsAre(sym("Foo", Test.range(), SymbolHeader.range("foo"))));
367
368 Test = Annotations(R"cpp(// definition in AST.
369 class [[Forward]] {};
370 F^orward create();
371 )cpp");
372 EXPECT_THAT(
373 LocateWithIndex(Test),
374 ElementsAre(sym("Forward", SymbolHeader.range("forward"), Test.range())));
375}
376
377TEST(LocateSymbol, AnonymousStructFields) {
378 auto Code = Annotations(R"cpp(
379 struct $2[[Foo]] {
380 struct { int $1[[x]]; };
381 void foo() {
382 // Make sure the implicit base is skipped.
383 $1^x = 42;
384 }
385 };
386 // Check that we don't skip explicit bases.
387 int a = $2^Foo{}.x;
388 )cpp");
389 TestTU TU = TestTU::withCode(Code: Code.code());
390 auto AST = TU.build();
391 EXPECT_THAT(locateSymbolAt(AST, Code.point("1"), TU.index().get()),
392 UnorderedElementsAre(sym("x", Code.range("1"), Code.range("1"))));
393 EXPECT_THAT(
394 locateSymbolAt(AST, Code.point("2"), TU.index().get()),
395 UnorderedElementsAre(sym("Foo", Code.range("2"), Code.range("2"))));
396}
397
398TEST(LocateSymbol, FindOverrides) {
399 auto Code = Annotations(R"cpp(
400 class Foo {
401 virtual void $1[[fo^o]]() = 0;
402 };
403 class Bar : public Foo {
404 void $2[[foo]]() override;
405 };
406 )cpp");
407 TestTU TU = TestTU::withCode(Code: Code.code());
408 auto AST = TU.build();
409 EXPECT_THAT(locateSymbolAt(AST, Code.point(), TU.index().get()),
410 UnorderedElementsAre(sym("foo", Code.range("1"), std::nullopt),
411 sym("foo", Code.range("2"), std::nullopt)));
412}
413
414TEST(LocateSymbol, FindOverridesFromDefObjC) {
415 auto Code = Annotations(R"objc(
416 @protocol Fooey
417 - (void)foo;
418 @end
419 @interface Base
420 - (void)foo;
421 @end
422 @interface Foo : Base<Fooey>
423 - (void)$1[[foo]];
424 @end
425
426 @interface Bar : Foo
427 - (void)$2[[foo]];
428 @end
429 @implementation Bar
430 - (void)$3[[fo^o]] {}
431 @end
432 )objc");
433 TestTU TU = TestTU::withCode(Code: Code.code());
434 TU.ExtraArgs.push_back(x: "-xobjective-c++");
435 auto AST = TU.build();
436 EXPECT_THAT(
437 locateSymbolAt(AST, Code.point(), TU.index().get()),
438 UnorderedElementsAre(sym("foo", Code.range("1"), std::nullopt),
439 sym("foo", Code.range("2"), Code.range("3"))));
440}
441
442TEST(LocateSymbol, NoOverridesFromDeclObjC) {
443 auto Code = Annotations(R"objc(
444 @protocol Fooey
445 - (void)foo;
446 @end
447 @interface Base
448 - (void)foo;
449 @end
450 @interface Foo : Base<Fooey>
451 - (void)foo;
452 @end
453
454 @interface Bar : Foo
455 - (void)$2[[fo^o]];
456 @end
457 @implementation Bar
458 - (void)$3[[foo]] {}
459 @end
460 )objc");
461 TestTU TU = TestTU::withCode(Code: Code.code());
462 TU.ExtraArgs.push_back(x: "-xobjective-c++");
463 auto AST = TU.build();
464 EXPECT_THAT(
465 locateSymbolAt(AST, Code.point(), TU.index().get()),
466 UnorderedElementsAre(sym("foo", Code.range("2"), Code.range("3"))));
467}
468
469TEST(LocateSymbol, ObjCNoOverridesOnUsage) {
470 auto Code = Annotations(R"objc(
471 @interface Foo
472 - (void)foo;
473 @end
474
475 @interface Bar : Foo
476 - (void)$1[[foo]];
477 @end
478 @implementation Bar
479 - (void)$2[[foo]] {}
480 @end
481 void doSomething(Bar *bar) {
482 [bar fo^o];
483 }
484 )objc");
485 TestTU TU = TestTU::withCode(Code: Code.code());
486 TU.ExtraArgs.push_back(x: "-xobjective-c++");
487 auto AST = TU.build();
488 EXPECT_THAT(
489 locateSymbolAt(AST, Code.point(), TU.index().get()),
490 UnorderedElementsAre(sym("foo", Code.range("1"), Code.range("2"))));
491}
492
493TEST(LocateSymbol, WithIndexPreferredLocation) {
494 Annotations SymbolHeader(R"cpp(
495 class $p[[Proto]] {};
496 void $f[[func]]() {};
497 )cpp");
498 TestTU TU;
499 TU.HeaderCode = std::string(SymbolHeader.code());
500 TU.HeaderFilename = "x.proto"; // Prefer locations in codegen files.
501 auto Index = TU.index();
502
503 Annotations Test(R"cpp(// only declaration in AST.
504 // Shift to make range different.
505 class Proto;
506 void func() {}
507 P$p^roto* create() {
508 fu$f^nc();
509 return nullptr;
510 }
511 )cpp");
512
513 auto AST = TestTU::withCode(Code: Test.code()).build();
514 {
515 auto Locs = clangd::locateSymbolAt(AST, Pos: Test.point(Name: "p"), Index: Index.get());
516 auto CodeGenLoc = SymbolHeader.range(Name: "p");
517 EXPECT_THAT(Locs, ElementsAre(sym("Proto", CodeGenLoc, CodeGenLoc)));
518 }
519 {
520 auto Locs = clangd::locateSymbolAt(AST, Pos: Test.point(Name: "f"), Index: Index.get());
521 auto CodeGenLoc = SymbolHeader.range(Name: "f");
522 EXPECT_THAT(Locs, ElementsAre(sym("func", CodeGenLoc, CodeGenLoc)));
523 }
524}
525
526TEST(LocateSymbol, All) {
527 // Ranges in tests:
528 // $decl is the declaration location (if absent, no symbol is located)
529 // $def is the definition location (if absent, symbol has no definition)
530 // unnamed range becomes both $decl and $def.
531 const char *Tests[] = {
532 R"cpp(
533 struct X {
534 union {
535 int [[a]];
536 float b;
537 };
538 };
539 int test(X &x) {
540 return x.^a;
541 }
542 )cpp",
543
544 R"cpp(// Local variable
545 int main() {
546 int [[bonjour]];
547 ^bonjour = 2;
548 int test1 = bonjour;
549 }
550 )cpp",
551
552 R"cpp(// Struct
553 namespace ns1 {
554 struct [[MyClass]] {};
555 } // namespace ns1
556 int main() {
557 ns1::My^Class* Params;
558 }
559 )cpp",
560
561 R"cpp(// Function definition via pointer
562 void [[foo]](int) {}
563 int main() {
564 auto *X = &^foo;
565 }
566 )cpp",
567
568 R"cpp(// Function declaration via call
569 int $decl[[foo]](int);
570 int main() {
571 return ^foo(42);
572 }
573 )cpp",
574
575 R"cpp(// Field
576 struct Foo { int [[x]]; };
577 int main() {
578 Foo bar;
579 (void)bar.^x;
580 }
581 )cpp",
582
583 R"cpp(// Field, member initializer
584 struct Foo {
585 int [[x]];
586 Foo() : ^x(0) {}
587 };
588 )cpp",
589
590 R"cpp(// Field, field designator
591 struct Foo { int [[x]]; };
592 int main() {
593 Foo bar = { .^x = 2 };
594 }
595 )cpp",
596
597 R"cpp(// Method call
598 struct Foo { int $decl[[x]](); };
599 int main() {
600 Foo bar;
601 bar.^x();
602 }
603 )cpp",
604
605 R"cpp(// Typedef
606 typedef int $decl[[Foo]];
607 int main() {
608 ^Foo bar;
609 }
610 )cpp",
611
612 R"cpp(// Template type parameter
613 template <typename [[T]]>
614 void foo() { ^T t; }
615 )cpp",
616
617 R"cpp(// Template template type parameter
618 template <template<typename> class [[T]]>
619 void foo() { ^T<int> t; }
620 )cpp",
621
622 R"cpp(// Namespace
623 namespace $decl[[ns]] {
624 struct Foo { static void bar(); };
625 } // namespace ns
626 int main() { ^ns::Foo::bar(); }
627 )cpp",
628
629 R"cpp(// Macro
630 class TTT { public: int a; };
631 #define [[FF]](S) if (int b = S.a) {}
632 void f() {
633 TTT t;
634 F^F(t);
635 }
636 )cpp",
637
638 R"cpp(// Macro argument
639 int [[i]];
640 #define ADDRESSOF(X) &X;
641 int *j = ADDRESSOF(^i);
642 )cpp",
643 R"cpp(// Macro argument appearing multiple times in expansion
644 #define VALIDATE_TYPE(x) (void)x;
645 #define ASSERT(expr) \
646 do { \
647 VALIDATE_TYPE(expr); \
648 if (!expr); \
649 } while (false)
650 bool [[waldo]]() { return true; }
651 void foo() {
652 ASSERT(wa^ldo());
653 }
654 )cpp",
655 R"cpp(// Symbol concatenated inside macro (not supported)
656 int *pi;
657 #define POINTER(X) p ## X;
658 int x = *POINTER(^i);
659 )cpp",
660
661 R"cpp(// Forward class declaration
662 class $decl[[Foo]];
663 class $def[[Foo]] {};
664 F^oo* foo();
665 )cpp",
666
667 R"cpp(// Function declaration
668 void $decl[[foo]]();
669 void g() { f^oo(); }
670 void $def[[foo]]() {}
671 )cpp",
672
673 R"cpp(
674 #define FF(name) class name##_Test {};
675 [[FF]](my);
676 void f() { my^_Test a; }
677 )cpp",
678
679 R"cpp(
680 #define FF() class [[Test]] {};
681 FF();
682 void f() { T^est a; }
683 )cpp",
684
685 R"cpp(// explicit template specialization
686 template <typename T>
687 struct Foo { void bar() {} };
688
689 template <>
690 struct [[Foo]]<int> { void bar() {} };
691
692 void foo() {
693 Foo<char> abc;
694 Fo^o<int> b;
695 }
696 )cpp",
697
698 R"cpp(// implicit template specialization
699 template <typename T>
700 struct [[Foo]] { void bar() {} };
701 template <>
702 struct Foo<int> { void bar() {} };
703 void foo() {
704 Fo^o<char> abc;
705 Foo<int> b;
706 }
707 )cpp",
708
709 R"cpp(// partial template specialization
710 template <typename T>
711 struct Foo { void bar() {} };
712 template <typename T>
713 struct [[Foo]]<T*> { void bar() {} };
714 ^Foo<int*> x;
715 )cpp",
716
717 R"cpp(// function template specializations
718 template <class T>
719 void foo(T) {}
720 template <>
721 void [[foo]](int) {}
722 void bar() {
723 fo^o(10);
724 }
725 )cpp",
726
727 R"cpp(// variable template decls
728 template <class T>
729 T var = T();
730
731 template <>
732 double [[var]]<int> = 10;
733
734 double y = va^r<int>;
735 )cpp",
736
737 R"cpp(// No implicit constructors
738 struct X {
739 X(X&& x) = default;
740 };
741 X $decl[[makeX]]();
742 void foo() {
743 auto x = m^akeX();
744 }
745 )cpp",
746
747 R"cpp(
748 struct X {
749 X& $decl[[operator]]++();
750 };
751 void foo(X& x) {
752 +^+x;
753 }
754 )cpp",
755
756 R"cpp(
757 struct S1 { void f(); };
758 struct S2 { S1 * $decl[[operator]]->(); };
759 void test(S2 s2) {
760 s2-^>f();
761 }
762 )cpp",
763
764 R"cpp(// Declaration of explicit template specialization
765 template <typename T>
766 struct $decl[[$def[[Foo]]]] {};
767
768 template <>
769 struct Fo^o<int> {};
770 )cpp",
771
772 R"cpp(// Declaration of partial template specialization
773 template <typename T>
774 struct $decl[[$def[[Foo]]]] {};
775
776 template <typename T>
777 struct Fo^o<T*> {};
778 )cpp",
779
780 R"cpp(// Definition on ClassTemplateDecl
781 namespace ns {
782 // Forward declaration.
783 template<typename T>
784 struct $decl[[Foo]];
785
786 template <typename T>
787 struct $def[[Foo]] {};
788 }
789
790 using ::ns::Fo^o;
791 )cpp",
792
793 R"cpp(// auto builtin type (not supported)
794 ^auto x = 42;
795 )cpp",
796
797 R"cpp(// auto on lambda
798 auto x = [[[]]]{};
799 ^auto y = x;
800 )cpp",
801
802 R"cpp(// auto on struct
803 namespace ns1 {
804 struct [[S1]] {};
805 } // namespace ns1
806
807 ^auto x = ns1::S1{};
808 )cpp",
809
810 R"cpp(// decltype on struct
811 namespace ns1 {
812 struct [[S1]] {};
813 } // namespace ns1
814
815 ns1::S1 i;
816 ^decltype(i) j;
817 )cpp",
818
819 R"cpp(// decltype(auto) on struct
820 namespace ns1 {
821 struct [[S1]] {};
822 } // namespace ns1
823
824 ns1::S1 i;
825 ns1::S1& j = i;
826 ^decltype(auto) k = j;
827 )cpp",
828
829 R"cpp(// auto on template class
830 template<typename T> class [[Foo]] {};
831
832 ^auto x = Foo<int>();
833 )cpp",
834
835 R"cpp(// auto on template class with forward declared class
836 template<typename T> class [[Foo]] {};
837 class X;
838
839 ^auto x = Foo<X>();
840 )cpp",
841
842 R"cpp(// auto on specialized template class
843 template<typename T> class Foo {};
844 template<> class [[Foo]]<int> {};
845
846 ^auto x = Foo<int>();
847 )cpp",
848
849 R"cpp(// auto on initializer list.
850 namespace std
851 {
852 template<class _E>
853 class [[initializer_list]] { const _E *a, *b; };
854 }
855
856 ^auto i = {1,2};
857 )cpp",
858
859 R"cpp(// auto function return with trailing type
860 struct [[Bar]] {};
861 ^auto test() -> decltype(Bar()) {
862 return Bar();
863 }
864 )cpp",
865
866 R"cpp(// decltype in trailing return type
867 struct [[Bar]] {};
868 auto test() -> ^decltype(Bar()) {
869 return Bar();
870 }
871 )cpp",
872
873 R"cpp(// auto in function return
874 struct [[Bar]] {};
875 ^auto test() {
876 return Bar();
877 }
878 )cpp",
879
880 R"cpp(// auto& in function return
881 struct [[Bar]] {};
882 ^auto& test() {
883 static Bar x;
884 return x;
885 }
886 )cpp",
887
888 R"cpp(// auto* in function return
889 struct [[Bar]] {};
890 ^auto* test() {
891 Bar* x;
892 return x;
893 }
894 )cpp",
895
896 R"cpp(// const auto& in function return
897 struct [[Bar]] {};
898 const ^auto& test() {
899 static Bar x;
900 return x;
901 }
902 )cpp",
903
904 R"cpp(// auto lambda param where there's a single instantiation
905 struct [[Bar]] {};
906 auto Lambda = [](^auto){ return 0; };
907 int x = Lambda(Bar{});
908 )cpp",
909
910 R"cpp(// decltype(auto) in function return
911 struct [[Bar]] {};
912 ^decltype(auto) test() {
913 return Bar();
914 }
915 )cpp",
916
917 R"cpp(// decltype of function with trailing return type.
918 struct [[Bar]] {};
919 auto test() -> decltype(Bar()) {
920 return Bar();
921 }
922 void foo() {
923 ^decltype(test()) i = test();
924 }
925 )cpp",
926
927 R"cpp(// Override specifier jumps to overridden method
928 class Y { virtual void $decl[[a]]() = 0; };
929 class X : Y { void a() ^override {} };
930 )cpp",
931
932 R"cpp(// Final specifier jumps to overridden method
933 class Y { virtual void $decl[[a]]() = 0; };
934 class X : Y { void a() ^final {} };
935 )cpp",
936
937 R"cpp(// Heuristic resolution of dependent method
938 template <typename T>
939 struct S {
940 void [[bar]]() {}
941 };
942
943 template <typename T>
944 void foo(S<T> arg) {
945 arg.ba^r();
946 }
947 )cpp",
948
949 R"cpp(// Heuristic resolution of dependent method via this->
950 template <typename T>
951 struct S {
952 void [[foo]]() {
953 this->fo^o();
954 }
955 };
956 )cpp",
957
958 R"cpp(// Heuristic resolution of dependent static method
959 template <typename T>
960 struct S {
961 static void [[bar]]() {}
962 };
963
964 template <typename T>
965 void foo() {
966 S<T>::ba^r();
967 }
968 )cpp",
969
970 R"cpp(// Heuristic resolution of dependent method
971 // invoked via smart pointer
972 template <typename> struct S { void [[foo]]() {} };
973 template <typename T> struct unique_ptr {
974 T* operator->();
975 };
976 template <typename T>
977 void test(unique_ptr<S<T>>& V) {
978 V->fo^o();
979 }
980 )cpp",
981
982 R"cpp(// Heuristic resolution of dependent enumerator
983 template <typename T>
984 struct Foo {
985 enum class E { [[A]], B };
986 E e = E::A^;
987 };
988 )cpp",
989
990 R"cpp(// Enum base
991 typedef int $decl[[MyTypeDef]];
992 enum Foo : My^TypeDef {};
993 )cpp",
994 R"cpp(// Enum base
995 typedef int $decl[[MyTypeDef]];
996 enum Foo : My^TypeDef;
997 )cpp",
998 R"cpp(// Enum base
999 using $decl[[MyTypeDef]] = int;
1000 enum Foo : My^TypeDef {};
1001 )cpp",
1002
1003 R"objc(
1004 @protocol Dog;
1005 @protocol $decl[[Dog]]
1006 - (void)bark;
1007 @end
1008 id<Do^g> getDoggo() {
1009 return 0;
1010 }
1011 )objc",
1012
1013 R"objc(
1014 @interface Cat
1015 @end
1016 @implementation Cat
1017 @end
1018 @interface $decl[[Cat]] (Exte^nsion)
1019 - (void)meow;
1020 @end
1021 @implementation $def[[Cat]] (Extension)
1022 - (void)meow {}
1023 @end
1024 )objc",
1025
1026 R"objc(
1027 @class $decl[[Foo]];
1028 Fo^o * getFoo() {
1029 return 0;
1030 }
1031 )objc",
1032
1033 R"objc(// Prefer interface definition over forward declaration
1034 @class Foo;
1035 @interface $decl[[Foo]]
1036 @end
1037 Fo^o * getFoo() {
1038 return 0;
1039 }
1040 )objc",
1041
1042 R"objc(
1043 @class Foo;
1044 @interface $decl[[Foo]]
1045 @end
1046 @implementation $def[[Foo]]
1047 @end
1048 Fo^o * getFoo() {
1049 return 0;
1050 }
1051 )objc",
1052
1053 R"objc(// Method decl and definition for ObjC class.
1054 @interface Cat
1055 - (void)$decl[[meow]];
1056 @end
1057 @implementation Cat
1058 - (void)$def[[meow]] {}
1059 @end
1060 void makeNoise(Cat *kitty) {
1061 [kitty me^ow];
1062 }
1063 )objc",
1064
1065 R"objc(// Method decl and definition for ObjC category.
1066 @interface Dog
1067 @end
1068 @interface Dog (Play)
1069 - (void)$decl[[runAround]];
1070 @end
1071 @implementation Dog (Play)
1072 - (void)$def[[runAround]] {}
1073 @end
1074 void play(Dog *dog) {
1075 [dog run^Around];
1076 }
1077 )objc",
1078
1079 R"objc(// Method decl and definition for ObjC class extension.
1080 @interface Dog
1081 @end
1082 @interface Dog ()
1083 - (void)$decl[[howl]];
1084 @end
1085 @implementation Dog
1086 - (void)$def[[howl]] {}
1087 @end
1088 void play(Dog *dog) {
1089 [dog ho^wl];
1090 }
1091 )objc",
1092 R"cpp(
1093 struct PointerIntPairInfo {
1094 static void *$decl[[getPointer]](void *Value);
1095 };
1096
1097 template <typename Info = PointerIntPairInfo> struct PointerIntPair {
1098 void *Value;
1099 void *getPointer() const { return Info::get^Pointer(Value); }
1100 };
1101 )cpp",
1102 R"cpp(// Deducing this
1103 struct S {
1104 int bar(this S&);
1105 };
1106 void foo() {
1107 S [[waldo]];
1108 int x = wa^ldo.bar();
1109 }
1110 )cpp"};
1111 for (const char *Test : Tests) {
1112 Annotations T(Test);
1113 std::optional<Range> WantDecl;
1114 std::optional<Range> WantDef;
1115 if (!T.ranges().empty())
1116 WantDecl = WantDef = T.range();
1117 if (!T.ranges(Name: "decl").empty())
1118 WantDecl = T.range(Name: "decl");
1119 if (!T.ranges(Name: "def").empty())
1120 WantDef = T.range(Name: "def");
1121
1122 TestTU TU;
1123 TU.Code = std::string(T.code());
1124
1125 TU.ExtraArgs.push_back(x: "-xobjective-c++");
1126 TU.ExtraArgs.push_back(x: "-std=c++23");
1127
1128 auto AST = TU.build();
1129 auto Results = locateSymbolAt(AST, Pos: T.point());
1130
1131 if (!WantDecl) {
1132 EXPECT_THAT(Results, IsEmpty()) << Test;
1133 } else {
1134 ASSERT_THAT(Results, ::testing::SizeIs(1)) << Test;
1135 EXPECT_EQ(Results[0].PreferredDeclaration.range, *WantDecl) << Test;
1136 EXPECT_TRUE(Results[0].ID) << Test;
1137 std::optional<Range> GotDef;
1138 if (Results[0].Definition)
1139 GotDef = Results[0].Definition->range;
1140 EXPECT_EQ(WantDef, GotDef) << Test;
1141 }
1142 }
1143}
1144TEST(LocateSymbol, ValidSymbolID) {
1145 auto T = Annotations(R"cpp(
1146 #define MACRO(x, y) ((x) + (y))
1147 int add(int x, int y) { return $MACRO^MACRO(x, y); }
1148 int sum = $add^add(1, 2);
1149 )cpp");
1150
1151 TestTU TU = TestTU::withCode(Code: T.code());
1152 auto AST = TU.build();
1153 auto Index = TU.index();
1154 EXPECT_THAT(locateSymbolAt(AST, T.point("add"), Index.get()),
1155 ElementsAre(AllOf(sym("add"),
1156 hasID(getSymbolID(&findDecl(AST, "add"))))));
1157 EXPECT_THAT(
1158 locateSymbolAt(AST, T.point("MACRO"), Index.get()),
1159 ElementsAre(AllOf(sym("MACRO"),
1160 hasID(findSymbol(TU.headerSymbols(), "MACRO").ID))));
1161}
1162
1163TEST(LocateSymbol, AllMulti) {
1164 // Ranges in tests:
1165 // $declN is the declaration location
1166 // $defN is the definition location (if absent, symbol has no definition)
1167 //
1168 // NOTE:
1169 // N starts at 0.
1170 struct ExpectedRanges {
1171 Range WantDecl;
1172 std::optional<Range> WantDef;
1173 };
1174 const char *Tests[] = {
1175 R"objc(
1176 @interface $decl0[[Cat]]
1177 @end
1178 @implementation $def0[[Cat]]
1179 @end
1180 @interface $decl1[[Ca^t]] (Extension)
1181 - (void)meow;
1182 @end
1183 @implementation $def1[[Cat]] (Extension)
1184 - (void)meow {}
1185 @end
1186 )objc",
1187
1188 R"objc(
1189 @interface $decl0[[Cat]]
1190 @end
1191 @implementation $def0[[Cat]]
1192 @end
1193 @interface $decl1[[Cat]] (Extension)
1194 - (void)meow;
1195 @end
1196 @implementation $def1[[Ca^t]] (Extension)
1197 - (void)meow {}
1198 @end
1199 )objc",
1200
1201 R"objc(
1202 @interface $decl0[[Cat]]
1203 @end
1204 @interface $decl1[[Ca^t]] ()
1205 - (void)meow;
1206 @end
1207 @implementation $def0[[$def1[[Cat]]]]
1208 - (void)meow {}
1209 @end
1210 )objc",
1211 };
1212 for (const char *Test : Tests) {
1213 Annotations T(Test);
1214 std::vector<ExpectedRanges> Ranges;
1215 for (int Idx = 0; true; Idx++) {
1216 bool HasDecl = !T.ranges(Name: "decl" + std::to_string(val: Idx)).empty();
1217 bool HasDef = !T.ranges(Name: "def" + std::to_string(val: Idx)).empty();
1218 if (!HasDecl && !HasDef)
1219 break;
1220 ExpectedRanges Range;
1221 if (HasDecl)
1222 Range.WantDecl = T.range(Name: "decl" + std::to_string(val: Idx));
1223 if (HasDef)
1224 Range.WantDef = T.range(Name: "def" + std::to_string(val: Idx));
1225 Ranges.push_back(x: Range);
1226 }
1227
1228 TestTU TU;
1229 TU.Code = std::string(T.code());
1230 TU.ExtraArgs.push_back(x: "-xobjective-c++");
1231
1232 auto AST = TU.build();
1233 auto Results = locateSymbolAt(AST, Pos: T.point());
1234
1235 ASSERT_THAT(Results, ::testing::SizeIs(Ranges.size())) << Test;
1236 for (size_t Idx = 0; Idx < Ranges.size(); Idx++) {
1237 EXPECT_EQ(Results[Idx].PreferredDeclaration.range, Ranges[Idx].WantDecl)
1238 << "($decl" << Idx << ")" << Test;
1239 std::optional<Range> GotDef;
1240 if (Results[Idx].Definition)
1241 GotDef = Results[Idx].Definition->range;
1242 EXPECT_EQ(GotDef, Ranges[Idx].WantDef) << "($def" << Idx << ")" << Test;
1243 }
1244 }
1245}
1246
1247// LocateSymbol test cases that produce warnings.
1248// These are separated out from All so that in All we can assert
1249// that there are no diagnostics.
1250TEST(LocateSymbol, Warnings) {
1251 const char *Tests[] = {
1252 R"cpp(// Field, GNU old-style field designator
1253 struct Foo { int [[x]]; };
1254 int main() {
1255 Foo bar = { ^x : 1 };
1256 }
1257 )cpp",
1258
1259 R"cpp(// Macro
1260 #define MACRO 0
1261 #define [[MACRO]] 1
1262 int main() { return ^MACRO; }
1263 #define MACRO 2
1264 #undef macro
1265 )cpp",
1266 };
1267
1268 for (const char *Test : Tests) {
1269 Annotations T(Test);
1270 std::optional<Range> WantDecl;
1271 std::optional<Range> WantDef;
1272 if (!T.ranges().empty())
1273 WantDecl = WantDef = T.range();
1274 if (!T.ranges(Name: "decl").empty())
1275 WantDecl = T.range(Name: "decl");
1276 if (!T.ranges(Name: "def").empty())
1277 WantDef = T.range(Name: "def");
1278
1279 TestTU TU;
1280 TU.Code = std::string(T.code());
1281
1282 auto AST = TU.build();
1283 auto Results = locateSymbolAt(AST, Pos: T.point());
1284
1285 if (!WantDecl) {
1286 EXPECT_THAT(Results, IsEmpty()) << Test;
1287 } else {
1288 ASSERT_THAT(Results, ::testing::SizeIs(1)) << Test;
1289 EXPECT_EQ(Results[0].PreferredDeclaration.range, *WantDecl) << Test;
1290 std::optional<Range> GotDef;
1291 if (Results[0].Definition)
1292 GotDef = Results[0].Definition->range;
1293 EXPECT_EQ(WantDef, GotDef) << Test;
1294 }
1295 }
1296}
1297
1298TEST(LocateSymbol, TextualSmoke) {
1299 auto T = Annotations(
1300 R"cpp(
1301 struct [[MyClass]] {};
1302 // Comment mentioning M^yClass
1303 )cpp");
1304
1305 auto TU = TestTU::withCode(Code: T.code());
1306 auto AST = TU.build();
1307 auto Index = TU.index();
1308 EXPECT_THAT(
1309 locateSymbolAt(AST, T.point(), Index.get()),
1310 ElementsAre(AllOf(sym("MyClass", T.range(), T.range()),
1311 hasID(getSymbolID(&findDecl(AST, "MyClass"))))));
1312}
1313
1314TEST(LocateSymbol, Textual) {
1315 const char *Tests[] = {
1316 R"cpp(// Comment
1317 struct [[MyClass]] {};
1318 // Comment mentioning M^yClass
1319 )cpp",
1320 R"cpp(// String
1321 struct MyClass {};
1322 // Not triggered for string literal tokens.
1323 const char* s = "String literal mentioning M^yClass";
1324 )cpp",
1325 R"cpp(// Ifdef'ed out code
1326 struct [[MyClass]] {};
1327 #ifdef WALDO
1328 M^yClass var;
1329 #endif
1330 )cpp",
1331 R"cpp(// Macro definition
1332 struct [[MyClass]] {};
1333 #define DECLARE_MYCLASS_OBJ(name) M^yClass name;
1334 )cpp",
1335 R"cpp(// Invalid code
1336 /*error-ok*/
1337 int myFunction(int);
1338 // Not triggered for token which survived preprocessing.
1339 int var = m^yFunction();
1340 )cpp"};
1341
1342 for (const char *Test : Tests) {
1343 Annotations T(Test);
1344 std::optional<Range> WantDecl;
1345 if (!T.ranges().empty())
1346 WantDecl = T.range();
1347
1348 auto TU = TestTU::withCode(Code: T.code());
1349
1350 auto AST = TU.build();
1351 auto Index = TU.index();
1352 auto Word = SpelledWord::touching(
1353 SpelledLoc: cantFail(ValOrErr: sourceLocationInMainFile(SM: AST.getSourceManager(), P: T.point())),
1354 TB: AST.getTokens(), LangOpts: AST.getLangOpts());
1355 if (!Word) {
1356 ADD_FAILURE() << "No word touching point!" << Test;
1357 continue;
1358 }
1359 auto Results = locateSymbolTextually(Word: *Word, AST, Index: Index.get(),
1360 MainFilePath: testPath(File: TU.Filename), NodeKind: ASTNodeKind());
1361
1362 if (!WantDecl) {
1363 EXPECT_THAT(Results, IsEmpty()) << Test;
1364 } else {
1365 ASSERT_THAT(Results, ::testing::SizeIs(1)) << Test;
1366 EXPECT_EQ(Results[0].PreferredDeclaration.range, *WantDecl) << Test;
1367 }
1368 }
1369} // namespace
1370
1371TEST(LocateSymbol, Ambiguous) {
1372 auto T = Annotations(R"cpp(
1373 struct Foo {
1374 Foo();
1375 Foo(Foo&&);
1376 $ConstructorLoc[[Foo]](const char*);
1377 };
1378
1379 Foo f();
1380
1381 void g(Foo foo);
1382
1383 void call() {
1384 const char* str = "123";
1385 Foo a = $1^str;
1386 Foo b = Foo($2^str);
1387 Foo c = $3^f();
1388 $4^g($5^f());
1389 g($6^str);
1390 Foo ab$7^c;
1391 Foo ab$8^cd("asdf");
1392 Foo foox = Fo$9^o("asdf");
1393 Foo abcde$10^("asdf");
1394 Foo foox2 = Foo$11^("asdf");
1395 }
1396
1397 template <typename T>
1398 struct S {
1399 void $NonstaticOverload1[[bar]](int);
1400 void $NonstaticOverload2[[bar]](float);
1401
1402 static void $StaticOverload1[[baz]](int);
1403 static void $StaticOverload2[[baz]](float);
1404 };
1405
1406 template <typename T, typename U>
1407 void dependent_call(S<T> s, U u) {
1408 s.ba$12^r(u);
1409 S<T>::ba$13^z(u);
1410 }
1411 )cpp");
1412 auto TU = TestTU::withCode(Code: T.code());
1413 // FIXME: Go-to-definition in a template requires disabling delayed template
1414 // parsing.
1415 TU.ExtraArgs.push_back(x: "-fno-delayed-template-parsing");
1416 auto AST = TU.build();
1417 // Ordered assertions are deliberate: we expect a predictable order.
1418 EXPECT_THAT(locateSymbolAt(AST, T.point("1")), ElementsAre(sym("str")));
1419 EXPECT_THAT(locateSymbolAt(AST, T.point("2")), ElementsAre(sym("str")));
1420 EXPECT_THAT(locateSymbolAt(AST, T.point("3")), ElementsAre(sym("f")));
1421 EXPECT_THAT(locateSymbolAt(AST, T.point("4")), ElementsAre(sym("g")));
1422 EXPECT_THAT(locateSymbolAt(AST, T.point("5")), ElementsAre(sym("f")));
1423 EXPECT_THAT(locateSymbolAt(AST, T.point("6")), ElementsAre(sym("str")));
1424 // FIXME: Target the constructor as well.
1425 EXPECT_THAT(locateSymbolAt(AST, T.point("7")), ElementsAre(sym("abc")));
1426 // FIXME: Target the constructor as well.
1427 EXPECT_THAT(locateSymbolAt(AST, T.point("8")), ElementsAre(sym("abcd")));
1428 // FIXME: Target the constructor as well.
1429 EXPECT_THAT(locateSymbolAt(AST, T.point("9")), ElementsAre(sym("Foo")));
1430 EXPECT_THAT(locateSymbolAt(AST, T.point("10")),
1431 ElementsAre(sym("Foo", T.range("ConstructorLoc"), std::nullopt)));
1432 EXPECT_THAT(locateSymbolAt(AST, T.point("11")),
1433 ElementsAre(sym("Foo", T.range("ConstructorLoc"), std::nullopt)));
1434 // These assertions are unordered because the order comes from
1435 // CXXRecordDecl::lookupDependentName() which doesn't appear to provide
1436 // an order guarantee.
1437 EXPECT_THAT(locateSymbolAt(AST, T.point("12")),
1438 UnorderedElementsAre(
1439 sym("bar", T.range("NonstaticOverload1"), std::nullopt),
1440 sym("bar", T.range("NonstaticOverload2"), std::nullopt)));
1441 EXPECT_THAT(locateSymbolAt(AST, T.point("13")),
1442 UnorderedElementsAre(
1443 sym("baz", T.range("StaticOverload1"), std::nullopt),
1444 sym("baz", T.range("StaticOverload2"), std::nullopt)));
1445}
1446
1447TEST(LocateSymbol, TextualDependent) {
1448 // Put the declarations in the header to make sure we are
1449 // finding them via the index heuristic and not the
1450 // nearby-ident heuristic.
1451 Annotations Header(R"cpp(
1452 struct Foo {
1453 void $FooLoc[[uniqueMethodName]]();
1454 };
1455 struct Bar {
1456 void $BarLoc[[uniqueMethodName]]();
1457 };
1458 )cpp");
1459 Annotations Source(R"cpp(
1460 template <typename T>
1461 void f(T t) {
1462 t.u^niqueMethodName();
1463 }
1464 )cpp");
1465 TestTU TU;
1466 TU.Code = std::string(Source.code());
1467 TU.HeaderCode = std::string(Header.code());
1468 auto AST = TU.build();
1469 auto Index = TU.index();
1470 // Need to use locateSymbolAt() since we are testing an
1471 // interaction between locateASTReferent() and
1472 // locateSymbolNamedTextuallyAt().
1473 auto Results = locateSymbolAt(AST, Pos: Source.point(), Index: Index.get());
1474 EXPECT_THAT(
1475 Results,
1476 UnorderedElementsAre(
1477 sym("uniqueMethodName", Header.range("FooLoc"), std::nullopt),
1478 sym("uniqueMethodName", Header.range("BarLoc"), std::nullopt)));
1479}
1480
1481TEST(LocateSymbol, Alias) {
1482 const char *Tests[] = {
1483 R"cpp(
1484 template <class T> struct function {};
1485 template <class T> using [[callback]] = function<T()>;
1486
1487 c^allback<int> foo;
1488 )cpp",
1489
1490 // triggered on non-definition of a renaming alias: should not give any
1491 // underlying decls.
1492 R"cpp(
1493 class Foo {};
1494 typedef Foo [[Bar]];
1495
1496 B^ar b;
1497 )cpp",
1498 R"cpp(
1499 class Foo {};
1500 using [[Bar]] = Foo; // definition
1501 Ba^r b;
1502 )cpp",
1503
1504 // triggered on the underlying decl of a renaming alias.
1505 R"cpp(
1506 class [[Foo]];
1507 using Bar = Fo^o;
1508 )cpp",
1509
1510 // triggered on definition of a non-renaming alias: should give underlying
1511 // decls.
1512 R"cpp(
1513 namespace ns { class [[Foo]] {}; }
1514 using ns::F^oo;
1515 )cpp",
1516
1517 R"cpp(
1518 namespace ns { int [[x]](char); int [[x]](double); }
1519 using ns::^x;
1520 )cpp",
1521
1522 R"cpp(
1523 namespace ns { int [[x]](char); int x(double); }
1524 using ns::[[x]];
1525 int y = ^x('a');
1526 )cpp",
1527
1528 R"cpp(
1529 namespace ns { class [[Foo]] {}; }
1530 using ns::[[Foo]];
1531 F^oo f;
1532 )cpp",
1533
1534 // other cases that don't matter much.
1535 R"cpp(
1536 class Foo {};
1537 typedef Foo [[Ba^r]];
1538 )cpp",
1539 R"cpp(
1540 class Foo {};
1541 using [[B^ar]] = Foo;
1542 )cpp",
1543
1544 // Member of dependent base
1545 R"cpp(
1546 template <typename T>
1547 struct Base {
1548 void [[waldo]]() {}
1549 };
1550 template <typename T>
1551 struct Derived : Base<T> {
1552 using Base<T>::w^aldo;
1553 };
1554 )cpp",
1555 };
1556
1557 for (const auto *Case : Tests) {
1558 SCOPED_TRACE(Case);
1559 auto T = Annotations(Case);
1560 auto AST = TestTU::withCode(Code: T.code()).build();
1561 EXPECT_THAT(locateSymbolAt(AST, T.point()),
1562 UnorderedPointwise(declRange(), T.ranges()));
1563 }
1564}
1565
1566TEST(LocateSymbol, RelPathsInCompileCommand) {
1567 // The source is in "/clangd-test/src".
1568 // We build in "/clangd-test/build".
1569
1570 Annotations SourceAnnotations(R"cpp(
1571#include "header_in_preamble.h"
1572int [[foo]];
1573#include "header_not_in_preamble.h"
1574int baz = f$p1^oo + bar_pre$p2^amble + bar_not_pre$p3^amble;
1575)cpp");
1576
1577 Annotations HeaderInPreambleAnnotations(R"cpp(
1578int [[bar_preamble]];
1579)cpp");
1580
1581 Annotations HeaderNotInPreambleAnnotations(R"cpp(
1582int [[bar_not_preamble]];
1583)cpp");
1584
1585 // Make the compilation paths appear as ../src/foo.cpp in the compile
1586 // commands.
1587 SmallString<32> RelPathPrefix("..");
1588 llvm::sys::path::append(path&: RelPathPrefix, a: "src");
1589 std::string BuildDir = testPath(File: "build");
1590 MockCompilationDatabase CDB(BuildDir, RelPathPrefix);
1591
1592 MockFS FS;
1593 ClangdServer Server(CDB, FS, ClangdServer::optsForTest());
1594
1595 // Fill the filesystem.
1596 auto FooCpp = testPath(File: "src/foo.cpp");
1597 FS.Files[FooCpp] = "";
1598 auto HeaderInPreambleH = testPath(File: "src/header_in_preamble.h");
1599 FS.Files[HeaderInPreambleH] = std::string(HeaderInPreambleAnnotations.code());
1600 auto HeaderNotInPreambleH = testPath(File: "src/header_not_in_preamble.h");
1601 FS.Files[HeaderNotInPreambleH] =
1602 std::string(HeaderNotInPreambleAnnotations.code());
1603
1604 runAddDocument(Server, File: FooCpp, Contents: SourceAnnotations.code());
1605
1606 // Go to a definition in main source file.
1607 auto Locations =
1608 runLocateSymbolAt(Server, File: FooCpp, Pos: SourceAnnotations.point(Name: "p1"));
1609 EXPECT_TRUE(bool(Locations)) << "findDefinitions returned an error";
1610 EXPECT_THAT(*Locations, ElementsAre(sym("foo", SourceAnnotations.range(),
1611 SourceAnnotations.range())));
1612
1613 // Go to a definition in header_in_preamble.h.
1614 Locations = runLocateSymbolAt(Server, File: FooCpp, Pos: SourceAnnotations.point(Name: "p2"));
1615 EXPECT_TRUE(bool(Locations)) << "findDefinitions returned an error";
1616 EXPECT_THAT(
1617 *Locations,
1618 ElementsAre(sym("bar_preamble", HeaderInPreambleAnnotations.range(),
1619 HeaderInPreambleAnnotations.range())));
1620
1621 // Go to a definition in header_not_in_preamble.h.
1622 Locations = runLocateSymbolAt(Server, File: FooCpp, Pos: SourceAnnotations.point(Name: "p3"));
1623 EXPECT_TRUE(bool(Locations)) << "findDefinitions returned an error";
1624 EXPECT_THAT(*Locations,
1625 ElementsAre(sym("bar_not_preamble",
1626 HeaderNotInPreambleAnnotations.range(),
1627 HeaderNotInPreambleAnnotations.range())));
1628}
1629
1630TEST(GoToInclude, All) {
1631 MockFS FS;
1632 MockCompilationDatabase CDB;
1633 ClangdServer Server(CDB, FS, ClangdServer::optsForTest());
1634
1635 auto FooCpp = testPath(File: "foo.cpp");
1636 const char *SourceContents = R"cpp(
1637 #include ^"$2^foo.h$3^"
1638 #include "$4^invalid.h"
1639 int b = a;
1640 // test
1641 int foo;
1642 #in$5^clude "$6^foo.h"$7^
1643 )cpp";
1644 Annotations SourceAnnotations(SourceContents);
1645 FS.Files[FooCpp] = std::string(SourceAnnotations.code());
1646 auto FooH = testPath(File: "foo.h");
1647
1648 const char *HeaderContents = R"cpp([[]]#pragma once
1649 int a;
1650 )cpp";
1651 Annotations HeaderAnnotations(HeaderContents);
1652 FS.Files[FooH] = std::string(HeaderAnnotations.code());
1653
1654 runAddDocument(Server, File: FooH, Contents: HeaderAnnotations.code());
1655 runAddDocument(Server, File: FooCpp, Contents: SourceAnnotations.code());
1656
1657 // Test include in preamble.
1658 auto Locations = runLocateSymbolAt(Server, File: FooCpp, Pos: SourceAnnotations.point());
1659 ASSERT_TRUE(bool(Locations)) << "locateSymbolAt returned an error";
1660 EXPECT_THAT(*Locations, ElementsAre(sym("foo.h", HeaderAnnotations.range(),
1661 HeaderAnnotations.range())));
1662
1663 // Test include in preamble, last char.
1664 Locations = runLocateSymbolAt(Server, File: FooCpp, Pos: SourceAnnotations.point(Name: "2"));
1665 ASSERT_TRUE(bool(Locations)) << "locateSymbolAt returned an error";
1666 EXPECT_THAT(*Locations, ElementsAre(sym("foo.h", HeaderAnnotations.range(),
1667 HeaderAnnotations.range())));
1668
1669 Locations = runLocateSymbolAt(Server, File: FooCpp, Pos: SourceAnnotations.point(Name: "3"));
1670 ASSERT_TRUE(bool(Locations)) << "locateSymbolAt returned an error";
1671 EXPECT_THAT(*Locations, ElementsAre(sym("foo.h", HeaderAnnotations.range(),
1672 HeaderAnnotations.range())));
1673
1674 // Test include outside of preamble.
1675 Locations = runLocateSymbolAt(Server, File: FooCpp, Pos: SourceAnnotations.point(Name: "6"));
1676 ASSERT_TRUE(bool(Locations)) << "locateSymbolAt returned an error";
1677 EXPECT_THAT(*Locations, ElementsAre(sym("foo.h", HeaderAnnotations.range(),
1678 HeaderAnnotations.range())));
1679
1680 // Test a few positions that do not result in Locations.
1681 Locations = runLocateSymbolAt(Server, File: FooCpp, Pos: SourceAnnotations.point(Name: "4"));
1682 ASSERT_TRUE(bool(Locations)) << "locateSymbolAt returned an error";
1683 EXPECT_THAT(*Locations, IsEmpty());
1684
1685 Locations = runLocateSymbolAt(Server, File: FooCpp, Pos: SourceAnnotations.point(Name: "5"));
1686 ASSERT_TRUE(bool(Locations)) << "locateSymbolAt returned an error";
1687 EXPECT_THAT(*Locations, ElementsAre(sym("foo.h", HeaderAnnotations.range(),
1688 HeaderAnnotations.range())));
1689
1690 Locations = runLocateSymbolAt(Server, File: FooCpp, Pos: SourceAnnotations.point(Name: "7"));
1691 ASSERT_TRUE(bool(Locations)) << "locateSymbolAt returned an error";
1692 EXPECT_THAT(*Locations, ElementsAre(sym("foo.h", HeaderAnnotations.range(),
1693 HeaderAnnotations.range())));
1694
1695 // Objective C #import directive.
1696 Annotations ObjC(R"objc(
1697 #import "^foo.h"
1698 )objc");
1699 auto FooM = testPath(File: "foo.m");
1700 FS.Files[FooM] = std::string(ObjC.code());
1701
1702 runAddDocument(Server, File: FooM, Contents: ObjC.code());
1703 Locations = runLocateSymbolAt(Server, File: FooM, Pos: ObjC.point());
1704 ASSERT_TRUE(bool(Locations)) << "locateSymbolAt returned an error";
1705 EXPECT_THAT(*Locations, ElementsAre(sym("foo.h", HeaderAnnotations.range(),
1706 HeaderAnnotations.range())));
1707}
1708
1709TEST(LocateSymbol, WithPreamble) {
1710 // Test stragety: AST should always use the latest preamble instead of last
1711 // good preamble.
1712 MockFS FS;
1713 MockCompilationDatabase CDB;
1714 ClangdServer Server(CDB, FS, ClangdServer::optsForTest());
1715
1716 auto FooCpp = testPath(File: "foo.cpp");
1717 // The trigger locations must be the same.
1718 Annotations FooWithHeader(R"cpp(#include "fo^o.h")cpp");
1719 Annotations FooWithoutHeader(R"cpp(double [[fo^o]]();)cpp");
1720
1721 FS.Files[FooCpp] = std::string(FooWithHeader.code());
1722
1723 auto FooH = testPath(File: "foo.h");
1724 Annotations FooHeader(R"cpp([[]])cpp");
1725 FS.Files[FooH] = std::string(FooHeader.code());
1726
1727 runAddDocument(Server, File: FooCpp, Contents: FooWithHeader.code());
1728 // LocateSymbol goes to a #include file: the result comes from the preamble.
1729 EXPECT_THAT(
1730 cantFail(runLocateSymbolAt(Server, FooCpp, FooWithHeader.point())),
1731 ElementsAre(sym("foo.h", FooHeader.range(), FooHeader.range())));
1732
1733 // Only preamble is built, and no AST is built in this request.
1734 Server.addDocument(File: FooCpp, Contents: FooWithoutHeader.code(), Version: "null",
1735 WD: WantDiagnostics::No);
1736 // We build AST here, and it should use the latest preamble rather than the
1737 // stale one.
1738 EXPECT_THAT(
1739 cantFail(runLocateSymbolAt(Server, FooCpp, FooWithoutHeader.point())),
1740 ElementsAre(sym("foo", FooWithoutHeader.range(), std::nullopt)));
1741
1742 // Reset test environment.
1743 runAddDocument(Server, File: FooCpp, Contents: FooWithHeader.code());
1744 // Both preamble and AST are built in this request.
1745 Server.addDocument(File: FooCpp, Contents: FooWithoutHeader.code(), Version: "null",
1746 WD: WantDiagnostics::Yes);
1747 // Use the AST being built in above request.
1748 EXPECT_THAT(
1749 cantFail(runLocateSymbolAt(Server, FooCpp, FooWithoutHeader.point())),
1750 ElementsAre(sym("foo", FooWithoutHeader.range(), std::nullopt)));
1751}
1752
1753TEST(LocateSymbol, NearbyTokenSmoke) {
1754 auto T = Annotations(R"cpp(
1755 // prints e^rr and crashes
1756 void die(const char* [[err]]);
1757 )cpp");
1758 auto AST = TestTU::withCode(Code: T.code()).build();
1759 // We don't pass an index, so can't hit index-based fallback.
1760 EXPECT_THAT(locateSymbolAt(AST, T.point()),
1761 ElementsAre(sym("err", T.range(), T.range())));
1762}
1763
1764TEST(LocateSymbol, NearbyIdentifier) {
1765 const char *Tests[] = {
1766 R"cpp(
1767 // regular identifiers (won't trigger)
1768 int hello;
1769 int y = he^llo;
1770 )cpp",
1771 R"cpp(
1772 // disabled preprocessor sections
1773 int [[hello]];
1774 #if 0
1775 int y = ^hello;
1776 #endif
1777 )cpp",
1778 R"cpp(
1779 // comments
1780 // he^llo, world
1781 int [[hello]];
1782 )cpp",
1783 R"cpp(
1784 // not triggered by string literals
1785 int hello;
1786 const char* greeting = "h^ello, world";
1787 )cpp",
1788
1789 R"cpp(
1790 // can refer to macro invocations
1791 #define INT int
1792 [[INT]] x;
1793 // I^NT
1794 )cpp",
1795
1796 R"cpp(
1797 // can refer to macro invocations (even if they expand to nothing)
1798 #define EMPTY
1799 [[EMPTY]] int x;
1800 // E^MPTY
1801 )cpp",
1802
1803 R"cpp(
1804 // prefer nearest occurrence, backwards is worse than forwards
1805 int hello;
1806 int x = hello;
1807 // h^ello
1808 int y = [[hello]];
1809 int z = hello;
1810 )cpp",
1811
1812 R"cpp(
1813 // short identifiers find near results
1814 int [[hi]];
1815 // h^i
1816 )cpp",
1817 R"cpp(
1818 // short identifiers don't find far results
1819 int hi;
1820
1821
1822
1823 // h^i
1824
1825
1826
1827
1828 int x = hi;
1829 )cpp",
1830 R"cpp(
1831 // prefer nearest occurrence even if several matched tokens
1832 // have the same value of `floor(log2(<token line> - <word line>))`.
1833 int hello;
1834 int x = hello, y = hello;
1835 int z = [[hello]];
1836 // h^ello
1837 )cpp"};
1838 for (const char *Test : Tests) {
1839 Annotations T(Test);
1840 auto AST = TestTU::withCode(Code: T.code()).build();
1841 const auto &SM = AST.getSourceManager();
1842 std::optional<Range> Nearby;
1843 auto Word =
1844 SpelledWord::touching(SpelledLoc: cantFail(ValOrErr: sourceLocationInMainFile(SM, P: T.point())),
1845 TB: AST.getTokens(), LangOpts: AST.getLangOpts());
1846 if (!Word) {
1847 ADD_FAILURE() << "No word at point! " << Test;
1848 continue;
1849 }
1850 if (const auto *Tok = findNearbyIdentifier(Word: *Word, TB: AST.getTokens()))
1851 Nearby = halfOpenToRange(SM, R: CharSourceRange::getCharRange(
1852 B: Tok->location(), E: Tok->endLocation()));
1853 if (T.ranges().empty())
1854 EXPECT_THAT(Nearby, Eq(std::nullopt)) << Test;
1855 else
1856 EXPECT_EQ(Nearby, T.range()) << Test;
1857 }
1858}
1859
1860TEST(FindImplementations, Inheritance) {
1861 llvm::StringRef Test = R"cpp(
1862 struct $0^Base {
1863 virtual void F$1^oo();
1864 void C$4^oncrete();
1865 };
1866 struct $0[[Child1]] : Base {
1867 void $1[[Fo$3^o]]() override;
1868 virtual void B$2^ar();
1869 void Concrete(); // No implementations for concrete methods.
1870 };
1871 struct Child2 : Child1 {
1872 void $3[[Foo]]() override;
1873 void $2[[Bar]]() override;
1874 };
1875 void FromReference() {
1876 $0^Base* B;
1877 B->Fo$1^o();
1878 B->C$4^oncrete();
1879 &Base::Fo$1^o;
1880 Child1 * C1;
1881 C1->B$2^ar();
1882 C1->Fo$3^o();
1883 }
1884 // CRTP should work.
1885 template<typename T>
1886 struct $5^TemplateBase {};
1887 struct $5[[Child3]] : public TemplateBase<Child3> {};
1888
1889 // Local classes.
1890 void LocationFunction() {
1891 struct $0[[LocalClass1]] : Base {
1892 void $1[[Foo]]() override;
1893 };
1894 struct $6^LocalBase {
1895 virtual void $7^Bar();
1896 };
1897 struct $6[[LocalClass2]]: LocalBase {
1898 void $7[[Bar]]() override;
1899 };
1900 }
1901 )cpp";
1902
1903 Annotations Code(Test);
1904 auto TU = TestTU::withCode(Code: Code.code());
1905 auto AST = TU.build();
1906 auto Index = TU.index();
1907 for (StringRef Label : {"0", "1", "2", "3", "4", "5", "6", "7"}) {
1908 for (const auto &Point : Code.points(Name: Label)) {
1909 EXPECT_THAT(findImplementations(AST, Point, Index.get()),
1910 UnorderedPointwise(declRange(), Code.ranges(Label)))
1911 << Code.code() << " at " << Point << " for Label " << Label;
1912 }
1913 }
1914}
1915
1916TEST(FindImplementations, InheritanceObjC) {
1917 llvm::StringRef Test = R"objc(
1918 @interface $base^Base
1919 - (void)fo$foo^o;
1920 @end
1921 @protocol Protocol
1922 - (void)$protocol^protocol;
1923 @end
1924 @interface $ChildDecl[[Child]] : Base <Protocol>
1925 - (void)concrete;
1926 - (void)$fooDecl[[foo]];
1927 @end
1928 @implementation $ChildDef[[Child]]
1929 - (void)concrete {}
1930 - (void)$fooDef[[foo]] {}
1931 - (void)$protocolDef[[protocol]] {}
1932 @end
1933 )objc";
1934
1935 Annotations Code(Test);
1936 auto TU = TestTU::withCode(Code: Code.code());
1937 TU.ExtraArgs.push_back(x: "-xobjective-c++");
1938 auto AST = TU.build();
1939 auto Index = TU.index();
1940 EXPECT_THAT(findImplementations(AST, Code.point("base"), Index.get()),
1941 UnorderedElementsAre(sym("Child", Code.range("ChildDecl"),
1942 Code.range("ChildDef"))));
1943 EXPECT_THAT(findImplementations(AST, Code.point("foo"), Index.get()),
1944 UnorderedElementsAre(
1945 sym("foo", Code.range("fooDecl"), Code.range("fooDef"))));
1946 EXPECT_THAT(findImplementations(AST, Code.point("protocol"), Index.get()),
1947 UnorderedElementsAre(sym("protocol", Code.range("protocolDef"),
1948 Code.range("protocolDef"))));
1949}
1950
1951TEST(FindImplementations, CaptureDefinition) {
1952 llvm::StringRef Test = R"cpp(
1953 struct Base {
1954 virtual void F^oo();
1955 };
1956 struct Child1 : Base {
1957 void $Decl[[Foo]]() override;
1958 };
1959 struct Child2 : Base {
1960 void $Child2[[Foo]]() override;
1961 };
1962 void Child1::$Def[[Foo]]() { /* Definition */ }
1963 )cpp";
1964 Annotations Code(Test);
1965 auto TU = TestTU::withCode(Code: Code.code());
1966 auto AST = TU.build();
1967 EXPECT_THAT(
1968 findImplementations(AST, Code.point(), TU.index().get()),
1969 UnorderedElementsAre(sym("Foo", Code.range("Decl"), Code.range("Def")),
1970 sym("Foo", Code.range("Child2"), std::nullopt)))
1971 << Test;
1972}
1973
1974TEST(FindType, All) {
1975 Annotations HeaderA(R"cpp(
1976 struct $Target[[Target]] { operator int() const; };
1977 struct Aggregate { Target a, b; };
1978 Target t;
1979 Target make();
1980
1981 template <typename T> struct $smart_ptr[[smart_ptr]] {
1982 T& operator*();
1983 T* operator->();
1984 T* get();
1985 };
1986 )cpp");
1987 auto TU = TestTU::withHeaderCode(HeaderCode: HeaderA.code());
1988 for (const llvm::StringRef Case : {
1989 "str^uct Target;",
1990 "T^arget x;",
1991 "Target ^x;",
1992 "a^uto x = Target{};",
1993 "namespace m { Target tgt; } auto x = m^::tgt;",
1994 "Target funcCall(); auto x = ^funcCall();",
1995 "Aggregate a = { {}, ^{} };",
1996 "Aggregate a = { ^.a=t, };",
1997 "struct X { Target a; X() : ^a() {} };",
1998 "^using T = Target; ^T foo();",
1999 "^template <int> Target foo();",
2000 "void x() { try {} ^catch(Target e) {} }",
2001 "void x() { ^throw t; }",
2002 "int x() { ^return t; }",
2003 "void x() { ^switch(t) {} }",
2004 "void x() { ^delete (Target*)nullptr; }",
2005 "Target& ^tref = t;",
2006 "void x() { ^if (t) {} }",
2007 "void x() { ^while (t) {} }",
2008 "void x() { ^do { } while (t); }",
2009 "void x() { ^make(); }",
2010 "void x(smart_ptr<Target> &t) { t.^get(); }",
2011 "^auto x = []() { return t; };",
2012 "Target* ^tptr = &t;",
2013 "Target ^tarray[3];",
2014 }) {
2015 Annotations A(Case);
2016 TU.Code = A.code().str();
2017 ParsedAST AST = TU.build();
2018
2019 ASSERT_GT(A.points().size(), 0u) << Case;
2020 for (auto Pos : A.points())
2021 EXPECT_THAT(findType(AST, Pos, nullptr),
2022 ElementsAre(
2023 sym("Target", HeaderA.range("Target"), HeaderA.range("Target"))))
2024 << Case;
2025 }
2026
2027 for (const llvm::StringRef Case : {
2028 "smart_ptr<Target> ^tsmart;",
2029 }) {
2030 Annotations A(Case);
2031 TU.Code = A.code().str();
2032 ParsedAST AST = TU.build();
2033
2034 EXPECT_THAT(findType(AST, A.point(), nullptr),
2035 UnorderedElementsAre(
2036 sym("Target", HeaderA.range("Target"), HeaderA.range("Target")),
2037 sym("smart_ptr", HeaderA.range("smart_ptr"), HeaderA.range("smart_ptr"))
2038 ))
2039 << Case;
2040 }
2041}
2042
2043TEST(FindType, Definition) {
2044 Annotations A(R"cpp(
2045 class $decl[[X]];
2046 X *^x;
2047 class $def[[X]] {};
2048 )cpp");
2049 auto TU = TestTU::withCode(Code: A.code().str());
2050 ParsedAST AST = TU.build();
2051
2052 EXPECT_THAT(findType(AST, A.point(), nullptr),
2053 ElementsAre(sym("X", A.range("decl"), A.range("def"))));
2054}
2055
2056TEST(FindType, Index) {
2057 Annotations Def(R"cpp(
2058 // This definition is only available through the index.
2059 class [[X]] {};
2060 )cpp");
2061 TestTU DefTU = TestTU::withHeaderCode(HeaderCode: Def.code());
2062 DefTU.HeaderFilename = "def.h";
2063 auto DefIdx = DefTU.index();
2064
2065 Annotations A(R"cpp(
2066 class [[X]];
2067 X *^x;
2068 )cpp");
2069 auto TU = TestTU::withCode(Code: A.code().str());
2070 ParsedAST AST = TU.build();
2071
2072 EXPECT_THAT(findType(AST, A.point(), DefIdx.get()),
2073 ElementsAre(sym("X", A.range(), Def.range())));
2074}
2075
2076void checkFindRefs(llvm::StringRef Test, bool UseIndex = false) {
2077 Annotations T(Test);
2078 auto TU = TestTU::withCode(Code: T.code());
2079 TU.ExtraArgs.push_back(x: "-std=c++20");
2080 TU.ExtraArgs.push_back(x: "-xobjective-c++");
2081
2082 auto AST = TU.build();
2083 std::vector<Matcher<ReferencesResult::Reference>> ExpectedLocations;
2084 for (const auto &[R, Context] : T.rangesWithPayload())
2085 ExpectedLocations.push_back(
2086 x: AllOf(matchers: rangeIs(gmock_p0: R), matchers: containerIs(gmock_p0: Context), matchers: attrsAre(gmock_p0: 0u)));
2087 // $def is actually shorthand for both definition and declaration.
2088 // If we have cases that are definition-only, we should change this.
2089 for (const auto &[R, Context] : T.rangesWithPayload(Name: "def"))
2090 ExpectedLocations.push_back(x: AllOf(matchers: rangeIs(gmock_p0: R), matchers: containerIs(gmock_p0: Context),
2091 matchers: attrsAre(gmock_p0: ReferencesResult::Definition |
2092 ReferencesResult::Declaration)));
2093 for (const auto &[R, Context] : T.rangesWithPayload(Name: "decl"))
2094 ExpectedLocations.push_back(x: AllOf(matchers: rangeIs(gmock_p0: R), matchers: containerIs(gmock_p0: Context),
2095 matchers: attrsAre(gmock_p0: ReferencesResult::Declaration)));
2096 for (const auto &[R, Context] : T.rangesWithPayload(Name: "overridedecl"))
2097 ExpectedLocations.push_back(x: AllOf(
2098 matchers: rangeIs(gmock_p0: R), matchers: containerIs(gmock_p0: Context),
2099 matchers: attrsAre(gmock_p0: ReferencesResult::Declaration | ReferencesResult::Override)));
2100 for (const auto &[R, Context] : T.rangesWithPayload(Name: "overridedef"))
2101 ExpectedLocations.push_back(x: AllOf(matchers: rangeIs(gmock_p0: R), matchers: containerIs(gmock_p0: Context),
2102 matchers: attrsAre(gmock_p0: ReferencesResult::Declaration |
2103 ReferencesResult::Definition |
2104 ReferencesResult::Override)));
2105 for (const auto &P : T.points()) {
2106 EXPECT_THAT(findReferences(AST, P, 0, UseIndex ? TU.index().get() : nullptr,
2107 /*AddContext*/ true)
2108 .References,
2109 UnorderedElementsAreArray(ExpectedLocations))
2110 << "Failed for Refs at " << P << "\n"
2111 << Test;
2112 }
2113}
2114
2115TEST(FindReferences, WithinAST) {
2116 const char *Tests[] = {
2117 R"cpp(// Local variable
2118 int main() {
2119 int $def(main)[[foo]];
2120 $(main)[[^foo]] = 2;
2121 int test1 = $(main)[[foo]];
2122 }
2123 )cpp",
2124
2125 R"cpp(// Struct
2126 namespace ns1 {
2127 struct $def(ns1)[[Foo]] {};
2128 } // namespace ns1
2129 int main() {
2130 ns1::$(main)[[Fo^o]]* Params;
2131 }
2132 )cpp",
2133
2134 R"cpp(// Forward declaration
2135 class $decl[[Foo]];
2136 class $def[[Foo]] {};
2137 int main() {
2138 $(main)[[Fo^o]] foo;
2139 }
2140 )cpp",
2141
2142 R"cpp(// Function
2143 int $def[[foo]](int) { return 0; }
2144 int main() {
2145 auto *X = &$(main)[[^foo]];
2146 $(main)[[foo]](42);
2147 }
2148 )cpp",
2149
2150 R"cpp(// Field
2151 struct Foo {
2152 int $def(Foo)[[foo]];
2153 Foo() : $(Foo::Foo)[[foo]](0) {}
2154 };
2155 int main() {
2156 Foo f;
2157 f.$(main)[[f^oo]] = 1;
2158 }
2159 )cpp",
2160
2161 R"cpp(// Method call
2162 struct Foo { int $decl(Foo)[[foo]](); };
2163 int Foo::$def(Foo)[[foo]]() { return 0; }
2164 int main() {
2165 Foo f;
2166 f.$(main)[[^foo]]();
2167 }
2168 )cpp",
2169
2170 R"cpp(// Constructor
2171 struct Foo {
2172 $decl(Foo)[[F^oo]](int);
2173 };
2174 void foo() {
2175 Foo f = $(foo)[[Foo]](42);
2176 }
2177 )cpp",
2178
2179 R"cpp(// Typedef
2180 typedef int $def[[Foo]];
2181 int main() {
2182 $(main)[[^Foo]] bar;
2183 }
2184 )cpp",
2185
2186 R"cpp(// Namespace
2187 namespace $decl[[ns]] { // FIXME: def?
2188 struct Foo {};
2189 } // namespace ns
2190 int main() { $(main)[[^ns]]::Foo foo; }
2191 )cpp",
2192
2193 R"cpp(// Macros
2194 #define TYPE(X) X
2195 #define FOO Foo
2196 #define CAT(X, Y) X##Y
2197 class $def[[Fo^o]] {};
2198 void test() {
2199 TYPE($(test)[[Foo]]) foo;
2200 $(test)[[FOO]] foo2;
2201 TYPE(TYPE($(test)[[Foo]])) foo3;
2202 $(test)[[CAT]](Fo, o) foo4;
2203 }
2204 )cpp",
2205
2206 R"cpp(// Macros
2207 #define $def[[MA^CRO]](X) (X+1)
2208 void test() {
2209 int x = $[[MACRO]]($[[MACRO]](1));
2210 }
2211 )cpp",
2212
2213 R"cpp(// Macro outside preamble
2214 int breakPreamble;
2215 #define $def[[MA^CRO]](X) (X+1)
2216 void test() {
2217 int x = $[[MACRO]]($[[MACRO]](1));
2218 }
2219 )cpp",
2220
2221 R"cpp(
2222 int $def[[v^ar]] = 0;
2223 void foo(int s = $(foo)[[var]]);
2224 )cpp",
2225
2226 R"cpp(
2227 template <typename T>
2228 class $def[[Fo^o]] {};
2229 void func($(func)[[Foo]]<int>);
2230 )cpp",
2231
2232 R"cpp(
2233 template <typename T>
2234 class $def[[Foo]] {};
2235 void func($(func)[[Fo^o]]<int>);
2236 )cpp",
2237 R"cpp(// Not touching any identifiers.
2238 struct Foo {
2239 $def(Foo)[[~]]Foo() {};
2240 };
2241 void foo() {
2242 Foo f;
2243 f.$(foo)[[^~]]Foo();
2244 }
2245 )cpp",
2246 R"cpp(// Lambda capture initializer
2247 void foo() {
2248 int $def(foo)[[w^aldo]] = 42;
2249 auto lambda = [x = $(foo)[[waldo]]](){};
2250 }
2251 )cpp",
2252 R"cpp(// Renaming alias
2253 template <typename> class Vector {};
2254 using $def[[^X]] = Vector<int>;
2255 $(x1)[[X]] x1;
2256 Vector<int> x2;
2257 Vector<double> y;
2258 )cpp",
2259 R"cpp(// Dependent code
2260 template <typename T> void $decl[[foo]](T t);
2261 template <typename T> void bar(T t) { $(bar)[[foo]](t); } // foo in bar is uninstantiated.
2262 void baz(int x) { $(baz)[[f^oo]](x); }
2263 )cpp",
2264 R"cpp(
2265 namespace ns {
2266 struct S{};
2267 void $decl(ns)[[foo]](S s);
2268 } // namespace ns
2269 template <typename T> void foo(T t);
2270 // FIXME: Maybe report this foo as a ref to ns::foo (because of ADL)
2271 // when bar<ns::S> is instantiated?
2272 template <typename T> void bar(T t) { foo(t); }
2273 void baz(int x) {
2274 ns::S s;
2275 bar<ns::S>(s);
2276 $(baz)[[f^oo]](s);
2277 }
2278 )cpp",
2279 R"cpp(// unresolved member expression
2280 struct Foo {
2281 template <typename T> void $decl(Foo)[[b^ar]](T t);
2282 };
2283 template <typename T> void test(Foo F, T t) {
2284 F.$(test)[[bar]](t);
2285 }
2286 )cpp",
2287
2288 // Enum base
2289 R"cpp(
2290 typedef int $def[[MyTypeD^ef]];
2291 enum MyEnum : $(MyEnum)[[MyTy^peDef]] { };
2292 )cpp",
2293 R"cpp(
2294 typedef int $def[[MyType^Def]];
2295 enum MyEnum : $(MyEnum)[[MyTypeD^ef]];
2296 )cpp",
2297 R"cpp(
2298 using $def[[MyTypeD^ef]] = int;
2299 enum MyEnum : $(MyEnum)[[MyTy^peDef]] { };
2300 )cpp",
2301 // UDL
2302 R"cpp(
2303 bool $decl[[operator]]"" _u^dl(unsigned long long value);
2304 bool x = $(x)[[1_udl]];
2305 )cpp",
2306 R"cpp(
2307 struct S {
2308 public:
2309 static void $decl(S)[[operator]] delete(void *);
2310 static void deleteObject(S *S) {
2311 $(S::deleteObject)[[de^lete]] S;
2312 }
2313 };
2314 )cpp"};
2315 for (const char *Test : Tests)
2316 checkFindRefs(Test);
2317}
2318
2319TEST(FindReferences, ConceptsWithinAST) {
2320 constexpr llvm::StringLiteral Code = R"cpp(
2321 template <class T>
2322 concept $def[[IsSmal^l]] = sizeof(T) <= 8;
2323
2324 template <class T>
2325 concept IsSmallPtr = requires(T x) {
2326 { *x } -> $(IsSmallPtr)[[IsSmal^l]];
2327 };
2328
2329 $(i)[[IsSmall]] auto i = 'c';
2330 template<$(foo)[[IsSmal^l]] U> void foo();
2331 template<class U> void bar() requires $(bar)[[IsSmal^l]]<U>;
2332 template<class U> requires $(baz)[[IsSmal^l]]<U> void baz();
2333 static_assert([[IsSma^ll]]<char>);
2334 )cpp";
2335 checkFindRefs(Test: Code);
2336}
2337
2338TEST(FindReferences, ConceptReq) {
2339 constexpr llvm::StringLiteral Code = R"cpp(
2340 template <class T>
2341 concept $def[[IsSmal^l]] = sizeof(T) <= 8;
2342
2343 template <class T>
2344 concept IsSmallPtr = requires(T x) {
2345 { *x } -> $(IsSmallPtr)[[IsSmal^l]];
2346 };
2347 )cpp";
2348 checkFindRefs(Test: Code);
2349}
2350
2351TEST(FindReferences, RequiresExprParameters) {
2352 constexpr llvm::StringLiteral Code = R"cpp(
2353 template <class T>
2354 concept IsSmall = sizeof(T) <= 8;
2355
2356 template <class T>
2357 concept IsSmallPtr = requires(T $def[[^x]]) {
2358 { *$(IsSmallPtr)[[^x]] } -> IsSmall;
2359 };
2360 )cpp";
2361 checkFindRefs(Test: Code);
2362}
2363
2364TEST(FindReferences, IncludeOverrides) {
2365 llvm::StringRef Test =
2366 R"cpp(
2367 class Base {
2368 public:
2369 virtu^al void $decl(Base)[[f^unc]]() ^= ^0;
2370 };
2371 class Derived : public Base {
2372 public:
2373 void $overridedecl(Derived::func)[[func]]() override;
2374 };
2375 void Derived::$overridedef[[func]]() {}
2376 class Derived2 : public Base {
2377 void $overridedef(Derived2::func)[[func]]() override {}
2378 };
2379 void test(Derived* D, Base* B) {
2380 D->func(); // No references to the overrides.
2381 B->$(test)[[func]]();
2382 })cpp";
2383 checkFindRefs(Test, /*UseIndex=*/true);
2384}
2385
2386TEST(FindReferences, IncludeOverridesObjC) {
2387 llvm::StringRef Test =
2388 R"objc(
2389 @interface Base
2390 - (void)$decl(Base)[[f^unc]];
2391 @end
2392 @interface Derived : Base
2393 - (void)$overridedecl(Derived::func)[[func]];
2394 @end
2395 @implementation Derived
2396 - (void)$overridedef[[func]] {}
2397 @end
2398 void test(Derived *derived, Base *base) {
2399 [derived func]; // No references to the overrides.
2400 [base $(test)[[func]]];
2401 })objc";
2402 checkFindRefs(Test, /*UseIndex=*/true);
2403}
2404
2405TEST(FindReferences, RefsToBaseMethod) {
2406 llvm::StringRef Test =
2407 R"cpp(
2408 class BaseBase {
2409 public:
2410 virtual void $(BaseBase)[[func]]();
2411 };
2412 class Base : public BaseBase {
2413 public:
2414 void $(Base)[[func]]() override;
2415 };
2416 class Derived : public Base {
2417 public:
2418 void $decl(Derived)[[fu^nc]]() over^ride;
2419 };
2420 void test(BaseBase* BB, Base* B, Derived* D) {
2421 // refs to overridden methods in complete type hierarchy are reported.
2422 BB->$(test)[[func]]();
2423 B->$(test)[[func]]();
2424 D->$(test)[[fu^nc]]();
2425 })cpp";
2426 checkFindRefs(Test, /*UseIndex=*/true);
2427}
2428
2429TEST(FindReferences, RefsToBaseMethodObjC) {
2430 llvm::StringRef Test =
2431 R"objc(
2432 @interface BaseBase
2433 - (void)$(BaseBase)[[func]];
2434 @end
2435 @interface Base : BaseBase
2436 - (void)$(Base)[[func]];
2437 @end
2438 @interface Derived : Base
2439 - (void)$decl(Derived)[[fu^nc]];
2440 @end
2441 void test(BaseBase *bb, Base *b, Derived *d) {
2442 // refs to overridden methods in complete type hierarchy are reported.
2443 [bb $(test)[[func]]];
2444 [b $(test)[[func]]];
2445 [d $(test)[[fu^nc]]];
2446 })objc";
2447 checkFindRefs(Test, /*UseIndex=*/true);
2448}
2449
2450TEST(FindReferences, MainFileReferencesOnly) {
2451 llvm::StringRef Test =
2452 R"cpp(
2453 void test() {
2454 int [[fo^o]] = 1;
2455 // refs not from main file should not be included.
2456 #include "foo.inc"
2457 })cpp";
2458
2459 Annotations Code(Test);
2460 auto TU = TestTU::withCode(Code: Code.code());
2461 TU.AdditionalFiles["foo.inc"] = R"cpp(
2462 foo = 3;
2463 )cpp";
2464 auto AST = TU.build();
2465
2466 std::vector<Matcher<ReferencesResult::Reference>> ExpectedLocations;
2467 for (const auto &R : Code.ranges())
2468 ExpectedLocations.push_back(x: rangeIs(gmock_p0: R));
2469 EXPECT_THAT(findReferences(AST, Code.point(), 0).References,
2470 ElementsAreArray(ExpectedLocations))
2471 << Test;
2472}
2473
2474TEST(FindReferences, ExplicitSymbols) {
2475 const char *Tests[] = {
2476 R"cpp(
2477 struct Foo { Foo* $decl(Foo)[[self]]() const; };
2478 void f() {
2479 Foo foo;
2480 if (Foo* T = foo.$(f)[[^self]]()) {} // Foo member call expr.
2481 }
2482 )cpp",
2483
2484 R"cpp(
2485 struct Foo { Foo(int); };
2486 Foo f() {
2487 int $def(f)[[b]];
2488 return $(f)[[^b]]; // Foo constructor expr.
2489 }
2490 )cpp",
2491
2492 R"cpp(
2493 struct Foo {};
2494 void g(Foo);
2495 Foo $decl[[f]]();
2496 void call() {
2497 g($(call)[[^f]]()); // Foo constructor expr.
2498 }
2499 )cpp",
2500
2501 R"cpp(
2502 void $decl[[foo]](int);
2503 void $decl[[foo]](double);
2504
2505 namespace ns {
2506 using ::$decl(ns)[[fo^o]];
2507 }
2508 )cpp",
2509
2510 R"cpp(
2511 struct X {
2512 operator bool();
2513 };
2514
2515 int test() {
2516 X $def(test)[[a]];
2517 $(test)[[a]].operator bool();
2518 if ($(test)[[a^]]) {} // ignore implicit conversion-operator AST node
2519 return 0;
2520 }
2521 )cpp",
2522 };
2523 for (const char *Test : Tests)
2524 checkFindRefs(Test);
2525}
2526
2527TEST(FindReferences, UsedSymbolsFromInclude) {
2528 const char *Tests[] = {
2529 R"cpp( [[#include ^"bar.h"]]
2530 #include <vector>
2531 int fstBar = [[bar1]]();
2532 int sndBar = [[bar2]]();
2533 [[Bar]] bar;
2534 int macroBar = [[BAR]];
2535 std::vector<int> vec;
2536 )cpp",
2537
2538 R"cpp([[#in^clude <vector>]]
2539 std::[[vector]]<int> vec;
2540 )cpp",
2541
2542 R"cpp(
2543 [[#include ^"udl_header.h"]]
2544 auto x = [[1_b]];
2545 )cpp",
2546 };
2547 for (const char *Test : Tests) {
2548 Annotations T(Test);
2549 auto TU = TestTU::withCode(Code: T.code());
2550 TU.ExtraArgs.push_back(x: "-std=c++20");
2551 TU.AdditionalFiles["bar.h"] = guard(Code: R"cpp(
2552 #define BAR 5
2553 int bar1();
2554 int bar2();
2555 class Bar {};
2556 )cpp");
2557 TU.AdditionalFiles["system/vector"] = guard(Code: R"cpp(
2558 namespace std {
2559 template<typename>
2560 class vector{};
2561 }
2562 )cpp");
2563 TU.AdditionalFiles["udl_header.h"] = guard(Code: R"cpp(
2564 bool operator"" _b(unsigned long long value);
2565 )cpp");
2566 TU.ExtraArgs.push_back(x: "-isystem" + testPath(File: "system"));
2567
2568 auto AST = TU.build();
2569 std::vector<Matcher<ReferencesResult::Reference>> ExpectedLocations;
2570 for (const auto &R : T.ranges())
2571 ExpectedLocations.push_back(x: AllOf(matchers: rangeIs(gmock_p0: R), matchers: attrsAre(gmock_p0: 0u)));
2572 for (const auto &P : T.points())
2573 EXPECT_THAT(findReferences(AST, P, 0).References,
2574 UnorderedElementsAreArray(ExpectedLocations))
2575 << "Failed for Refs at " << P << "\n"
2576 << Test;
2577 }
2578}
2579
2580TEST(FindReferences, NeedsIndexForSymbols) {
2581 const char *Header = "int foo();";
2582 Annotations Main("int main() { [[f^oo]](); }");
2583 TestTU TU;
2584 TU.Code = std::string(Main.code());
2585 TU.HeaderCode = Header;
2586 auto AST = TU.build();
2587
2588 // References in main file are returned without index.
2589 EXPECT_THAT(
2590 findReferences(AST, Main.point(), 0, /*Index=*/nullptr).References,
2591 ElementsAre(rangeIs(Main.range())));
2592 Annotations IndexedMain(R"cpp(
2593 int $decl[[foo]]() { return 42; }
2594 void bar() { $bar(bar)[[foo]](); }
2595 struct S { void bar() { $S(S::bar)[[foo]](); } };
2596 namespace N { void bar() { $N(N::bar)[[foo]](); } }
2597 )cpp");
2598
2599 // References from indexed files are included.
2600 TestTU IndexedTU;
2601 IndexedTU.Code = std::string(IndexedMain.code());
2602 IndexedTU.Filename = "Indexed.cpp";
2603 IndexedTU.HeaderCode = Header;
2604 EXPECT_THAT(
2605 findReferences(AST, Main.point(), 0, IndexedTU.index().get(),
2606 /*AddContext*/ true)
2607 .References,
2608 ElementsAre(
2609 rangeIs(Main.range()),
2610 AllOf(rangeIs(IndexedMain.range("decl")),
2611 attrsAre(ReferencesResult::Declaration |
2612 ReferencesResult::Definition)),
2613 AllOf(rangeIs(IndexedMain.range("bar")), containerIs("bar")),
2614 AllOf(rangeIs(IndexedMain.range("S")), containerIs("S::bar")),
2615 AllOf(rangeIs(IndexedMain.range("N")), containerIs("N::bar"))));
2616 auto LimitRefs =
2617 findReferences(AST, Pos: Main.point(), /*Limit*/ 1, Index: IndexedTU.index().get());
2618 EXPECT_EQ(1u, LimitRefs.References.size());
2619 EXPECT_TRUE(LimitRefs.HasMore);
2620
2621 // Avoid indexed results for the main file. Use AST for the mainfile.
2622 TU.Code = ("\n\n" + Main.code()).str();
2623 EXPECT_THAT(findReferences(AST, Main.point(), 0, TU.index().get()).References,
2624 ElementsAre(rangeIs(Main.range())));
2625}
2626
2627TEST(FindReferences, NeedsIndexForMacro) {
2628 const char *Header = "#define MACRO(X) (X+1)";
2629 Annotations Main(R"cpp(
2630 int main() {
2631 int a = [[MA^CRO]](1);
2632 }
2633 )cpp");
2634 TestTU TU;
2635 TU.Code = std::string(Main.code());
2636 TU.HeaderCode = Header;
2637 auto AST = TU.build();
2638
2639 // References in main file are returned without index.
2640 EXPECT_THAT(
2641 findReferences(AST, Main.point(), 0, /*Index=*/nullptr).References,
2642 ElementsAre(rangeIs(Main.range())));
2643
2644 Annotations IndexedMain(R"cpp(
2645 int indexed_main() {
2646 int a = [[MACRO]](1);
2647 return 0;
2648 }
2649 )cpp");
2650
2651 // References from indexed files are included.
2652 TestTU IndexedTU;
2653 IndexedTU.Code = std::string(IndexedMain.code());
2654 IndexedTU.Filename = "Indexed.cpp";
2655 IndexedTU.HeaderCode = Header;
2656 EXPECT_THAT(
2657 findReferences(AST, Main.point(), 0, IndexedTU.index().get()).References,
2658 ElementsAre(rangeIs(Main.range()), rangeIs(IndexedMain.range())));
2659 auto LimitRefs =
2660 findReferences(AST, Pos: Main.point(), /*Limit*/ 1, Index: IndexedTU.index().get());
2661 EXPECT_EQ(1u, LimitRefs.References.size());
2662 EXPECT_TRUE(LimitRefs.HasMore);
2663}
2664
2665TEST(FindReferences, NoQueryForLocalSymbols) {
2666 struct RecordingIndex : public MemIndex {
2667 mutable std::optional<llvm::DenseSet<SymbolID>> RefIDs;
2668 bool refs(const RefsRequest &Req,
2669 llvm::function_ref<void(const Ref &)>) const override {
2670 RefIDs = Req.IDs;
2671 return false;
2672 }
2673 };
2674
2675 struct Test {
2676 StringRef AnnotatedCode;
2677 bool WantQuery;
2678 } Tests[] = {
2679 {.AnnotatedCode: "int ^x;", .WantQuery: true},
2680 // For now we don't assume header structure which would allow skipping.
2681 {.AnnotatedCode: "namespace { int ^x; }", .WantQuery: true},
2682 {.AnnotatedCode: "static int ^x;", .WantQuery: true},
2683 // Anything in a function certainly can't be referenced though.
2684 {.AnnotatedCode: "void foo() { int ^x; }", .WantQuery: false},
2685 {.AnnotatedCode: "void foo() { struct ^x{}; }", .WantQuery: false},
2686 {.AnnotatedCode: "auto lambda = []{ int ^x; };", .WantQuery: false},
2687 };
2688 for (Test T : Tests) {
2689 Annotations File(T.AnnotatedCode);
2690 RecordingIndex Rec;
2691 auto AST = TestTU::withCode(Code: File.code()).build();
2692 findReferences(AST, Pos: File.point(), Limit: 0, Index: &Rec);
2693 if (T.WantQuery)
2694 EXPECT_NE(Rec.RefIDs, std::nullopt) << T.AnnotatedCode;
2695 else
2696 EXPECT_EQ(Rec.RefIDs, std::nullopt) << T.AnnotatedCode;
2697 }
2698}
2699
2700TEST(GetNonLocalDeclRefs, All) {
2701 struct Case {
2702 llvm::StringRef AnnotatedCode;
2703 std::vector<std::string> ExpectedDecls;
2704 } Cases[] = {
2705 {
2706 // VarDecl and ParamVarDecl
2707 .AnnotatedCode: R"cpp(
2708 void bar();
2709 void ^foo(int baz) {
2710 int x = 10;
2711 bar();
2712 })cpp",
2713 .ExpectedDecls: {"bar"},
2714 },
2715 {
2716 // Method from class
2717 .AnnotatedCode: R"cpp(
2718 class Foo { public: void foo(); };
2719 class Bar {
2720 void foo();
2721 void bar();
2722 };
2723 void Bar::^foo() {
2724 Foo f;
2725 bar();
2726 f.foo();
2727 })cpp",
2728 .ExpectedDecls: {"Bar", "Bar::bar", "Foo", "Foo::foo"},
2729 },
2730 {
2731 // Local types
2732 .AnnotatedCode: R"cpp(
2733 void ^foo() {
2734 class Foo { public: void foo() {} };
2735 class Bar { public: void bar() {} };
2736 Foo f;
2737 Bar b;
2738 b.bar();
2739 f.foo();
2740 })cpp",
2741 .ExpectedDecls: {},
2742 },
2743 {
2744 // Template params
2745 .AnnotatedCode: R"cpp(
2746 template <typename T, template<typename> class Q>
2747 void ^foo() {
2748 T x;
2749 Q<T> y;
2750 })cpp",
2751 .ExpectedDecls: {},
2752 },
2753 };
2754 for (const Case &C : Cases) {
2755 Annotations File(C.AnnotatedCode);
2756 auto AST = TestTU::withCode(Code: File.code()).build();
2757 SourceLocation SL = llvm::cantFail(
2758 ValOrErr: sourceLocationInMainFile(SM: AST.getSourceManager(), P: File.point()));
2759
2760 const FunctionDecl *FD =
2761 llvm::dyn_cast<FunctionDecl>(Val: &findDecl(AST, [SL](const NamedDecl &ND) {
2762 return ND.getLocation() == SL && llvm::isa<FunctionDecl>(ND);
2763 }));
2764 ASSERT_NE(FD, nullptr);
2765
2766 auto NonLocalDeclRefs = getNonLocalDeclRefs(AST, FD);
2767 std::vector<std::string> Names;
2768 for (const Decl *D : NonLocalDeclRefs) {
2769 if (const auto *ND = llvm::dyn_cast<NamedDecl>(D))
2770 Names.push_back(ND->getQualifiedNameAsString());
2771 }
2772 EXPECT_THAT(Names, UnorderedElementsAreArray(C.ExpectedDecls))
2773 << File.code();
2774 }
2775}
2776
2777TEST(DocumentLinks, All) {
2778 Annotations MainCpp(R"cpp(
2779 #/*comments*/include /*comments*/ $foo[["foo.h"]] //more comments
2780 int end_of_preamble = 0;
2781 #include $bar[[<bar.h>]]
2782 )cpp");
2783
2784 TestTU TU;
2785 TU.Code = std::string(MainCpp.code());
2786 TU.AdditionalFiles = {{"foo.h", ""}, {"bar.h", ""}};
2787 TU.ExtraArgs = {"-isystem."};
2788 auto AST = TU.build();
2789
2790 EXPECT_THAT(
2791 clangd::getDocumentLinks(AST),
2792 ElementsAre(
2793 DocumentLink({MainCpp.range("foo"),
2794 URIForFile::canonicalize(testPath("foo.h"), "")}),
2795 DocumentLink({MainCpp.range("bar"),
2796 URIForFile::canonicalize(testPath("bar.h"), "")})));
2797}
2798
2799} // namespace
2800} // namespace clangd
2801} // namespace clang
2802

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

source code of clang-tools-extra/clangd/unittests/XRefsTests.cpp