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

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