clang-tools 20.0.0git
XRefsTests.cpp
Go to the documentation of this file.
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, "") {
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())
69 for (const auto &Range : Test.ranges("read"))
71 for (const auto &Range : Test.ranges("write"))
73 return UnorderedElementsAreArray(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(T.code());
139 TU.ExtraArgs.push_back("-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(T.code());
276 TU.ExtraArgs.push_back("-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(Main.code()).build();
340 return clangd::locateSymbolAt(AST, Main.point(), 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());
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());
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(Test.code()).build();
435 {
436 auto Locs = clangd::locateSymbolAt(AST, Test.point("p"), Index.get());
437 auto CodeGenLoc = SymbolHeader.range("p");
438 EXPECT_THAT(Locs, ElementsAre(sym("Proto", CodeGenLoc, CodeGenLoc)));
439 }
440 {
441 auto Locs = clangd::locateSymbolAt(AST, Test.point("f"), Index.get());
442 auto CodeGenLoc = SymbolHeader.range("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]] { const _E *a, *b; };
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 R"cpp(// Deducing this
1024 struct S {
1025 int bar(this S&);
1026 };
1027 void foo() {
1028 S [[waldo]];
1029 int x = wa^ldo.bar();
1030 }
1031 )cpp"};
1032 for (const char *Test : Tests) {
1033 Annotations T(Test);
1034 std::optional<Range> WantDecl;
1035 std::optional<Range> WantDef;
1036 if (!T.ranges().empty())
1037 WantDecl = WantDef = T.range();
1038 if (!T.ranges("decl").empty())
1039 WantDecl = T.range("decl");
1040 if (!T.ranges("def").empty())
1041 WantDef = T.range("def");
1042
1043 TestTU TU;
1044 TU.Code = std::string(T.code());
1045
1046 TU.ExtraArgs.push_back("-xobjective-c++");
1047 TU.ExtraArgs.push_back("-std=c++23");
1048
1049 auto AST = TU.build();
1050 auto Results = locateSymbolAt(AST, T.point());
1051
1052 if (!WantDecl) {
1053 EXPECT_THAT(Results, IsEmpty()) << Test;
1054 } else {
1055 ASSERT_THAT(Results, ::testing::SizeIs(1)) << Test;
1056 EXPECT_EQ(Results[0].PreferredDeclaration.range, *WantDecl) << Test;
1057 EXPECT_TRUE(Results[0].ID) << Test;
1058 std::optional<Range> GotDef;
1059 if (Results[0].Definition)
1060 GotDef = Results[0].Definition->range;
1061 EXPECT_EQ(WantDef, GotDef) << Test;
1062 }
1063 }
1064}
1065TEST(LocateSymbol, ValidSymbolID) {
1066 auto T = Annotations(R"cpp(
1067 #define MACRO(x, y) ((x) + (y))
1068 int add(int x, int y) { return $MACRO^MACRO(x, y); }
1069 int sum = $add^add(1, 2);
1070 )cpp");
1071
1072 TestTU TU = TestTU::withCode(T.code());
1073 auto AST = TU.build();
1074 auto Index = TU.index();
1075 EXPECT_THAT(locateSymbolAt(AST, T.point("add"), Index.get()),
1076 ElementsAre(AllOf(sym("add"),
1077 hasID(getSymbolID(&findDecl(AST, "add"))))));
1078 EXPECT_THAT(
1079 locateSymbolAt(AST, T.point("MACRO"), Index.get()),
1080 ElementsAre(AllOf(sym("MACRO"),
1081 hasID(findSymbol(TU.headerSymbols(), "MACRO").ID))));
1082}
1083
1084TEST(LocateSymbol, AllMulti) {
1085 // Ranges in tests:
1086 // $declN is the declaration location
1087 // $defN is the definition location (if absent, symbol has no definition)
1088 //
1089 // NOTE:
1090 // N starts at 0.
1091 struct ExpectedRanges {
1092 Range WantDecl;
1093 std::optional<Range> WantDef;
1094 };
1095 const char *Tests[] = {
1096 R"objc(
1097 @interface $decl0[[Cat]]
1098 @end
1099 @implementation $def0[[Cat]]
1100 @end
1101 @interface $decl1[[Ca^t]] (Extension)
1102 - (void)meow;
1103 @end
1104 @implementation $def1[[Cat]] (Extension)
1105 - (void)meow {}
1106 @end
1107 )objc",
1108
1109 R"objc(
1110 @interface $decl0[[Cat]]
1111 @end
1112 @implementation $def0[[Cat]]
1113 @end
1114 @interface $decl1[[Cat]] (Extension)
1115 - (void)meow;
1116 @end
1117 @implementation $def1[[Ca^t]] (Extension)
1118 - (void)meow {}
1119 @end
1120 )objc",
1121
1122 R"objc(
1123 @interface $decl0[[Cat]]
1124 @end
1125 @interface $decl1[[Ca^t]] ()
1126 - (void)meow;
1127 @end
1128 @implementation $def0[[$def1[[Cat]]]]
1129 - (void)meow {}
1130 @end
1131 )objc",
1132 };
1133 for (const char *Test : Tests) {
1134 Annotations T(Test);
1135 std::vector<ExpectedRanges> Ranges;
1136 for (int Idx = 0; true; Idx++) {
1137 bool HasDecl = !T.ranges("decl" + std::to_string(Idx)).empty();
1138 bool HasDef = !T.ranges("def" + std::to_string(Idx)).empty();
1139 if (!HasDecl && !HasDef)
1140 break;
1141 ExpectedRanges Range;
1142 if (HasDecl)
1143 Range.WantDecl = T.range("decl" + std::to_string(Idx));
1144 if (HasDef)
1145 Range.WantDef = T.range("def" + std::to_string(Idx));
1146 Ranges.push_back(Range);
1147 }
1148
1149 TestTU TU;
1150 TU.Code = std::string(T.code());
1151 TU.ExtraArgs.push_back("-xobjective-c++");
1152
1153 auto AST = TU.build();
1154 auto Results = locateSymbolAt(AST, T.point());
1155
1156 ASSERT_THAT(Results, ::testing::SizeIs(Ranges.size())) << Test;
1157 for (size_t Idx = 0; Idx < Ranges.size(); Idx++) {
1158 EXPECT_EQ(Results[Idx].PreferredDeclaration.range, Ranges[Idx].WantDecl)
1159 << "($decl" << Idx << ")" << Test;
1160 std::optional<Range> GotDef;
1161 if (Results[Idx].Definition)
1162 GotDef = Results[Idx].Definition->range;
1163 EXPECT_EQ(GotDef, Ranges[Idx].WantDef) << "($def" << Idx << ")" << Test;
1164 }
1165 }
1166}
1167
1168// LocateSymbol test cases that produce warnings.
1169// These are separated out from All so that in All we can assert
1170// that there are no diagnostics.
1171TEST(LocateSymbol, Warnings) {
1172 const char *Tests[] = {
1173 R"cpp(// Field, GNU old-style field designator
1174 struct Foo { int [[x]]; };
1175 int main() {
1176 Foo bar = { ^x : 1 };
1177 }
1178 )cpp",
1179
1180 R"cpp(// Macro
1181 #define MACRO 0
1182 #define [[MACRO]] 1
1183 int main() { return ^MACRO; }
1184 #define MACRO 2
1185 #undef macro
1186 )cpp",
1187 };
1188
1189 for (const char *Test : Tests) {
1190 Annotations T(Test);
1191 std::optional<Range> WantDecl;
1192 std::optional<Range> WantDef;
1193 if (!T.ranges().empty())
1194 WantDecl = WantDef = T.range();
1195 if (!T.ranges("decl").empty())
1196 WantDecl = T.range("decl");
1197 if (!T.ranges("def").empty())
1198 WantDef = T.range("def");
1199
1200 TestTU TU;
1201 TU.Code = std::string(T.code());
1202
1203 auto AST = TU.build();
1204 auto Results = locateSymbolAt(AST, T.point());
1205
1206 if (!WantDecl) {
1207 EXPECT_THAT(Results, IsEmpty()) << Test;
1208 } else {
1209 ASSERT_THAT(Results, ::testing::SizeIs(1)) << Test;
1210 EXPECT_EQ(Results[0].PreferredDeclaration.range, *WantDecl) << Test;
1211 std::optional<Range> GotDef;
1212 if (Results[0].Definition)
1213 GotDef = Results[0].Definition->range;
1214 EXPECT_EQ(WantDef, GotDef) << Test;
1215 }
1216 }
1217}
1218
1219TEST(LocateSymbol, TextualSmoke) {
1220 auto T = Annotations(
1221 R"cpp(
1222 struct [[MyClass]] {};
1223 // Comment mentioning M^yClass
1224 )cpp");
1225
1226 auto TU = TestTU::withCode(T.code());
1227 auto AST = TU.build();
1228 auto Index = TU.index();
1229 EXPECT_THAT(
1230 locateSymbolAt(AST, T.point(), Index.get()),
1231 ElementsAre(AllOf(sym("MyClass", T.range(), T.range()),
1232 hasID(getSymbolID(&findDecl(AST, "MyClass"))))));
1233}
1234
1235TEST(LocateSymbol, Textual) {
1236 const char *Tests[] = {
1237 R"cpp(// Comment
1238 struct [[MyClass]] {};
1239 // Comment mentioning M^yClass
1240 )cpp",
1241 R"cpp(// String
1242 struct MyClass {};
1243 // Not triggered for string literal tokens.
1244 const char* s = "String literal mentioning M^yClass";
1245 )cpp",
1246 R"cpp(// Ifdef'ed out code
1247 struct [[MyClass]] {};
1248 #ifdef WALDO
1249 M^yClass var;
1250 #endif
1251 )cpp",
1252 R"cpp(// Macro definition
1253 struct [[MyClass]] {};
1254 #define DECLARE_MYCLASS_OBJ(name) M^yClass name;
1255 )cpp",
1256 R"cpp(// Invalid code
1257 /*error-ok*/
1258 int myFunction(int);
1259 // Not triggered for token which survived preprocessing.
1260 int var = m^yFunction();
1261 )cpp"};
1262
1263 for (const char *Test : Tests) {
1264 Annotations T(Test);
1265 std::optional<Range> WantDecl;
1266 if (!T.ranges().empty())
1267 WantDecl = T.range();
1268
1269 auto TU = TestTU::withCode(T.code());
1270
1271 auto AST = TU.build();
1272 auto Index = TU.index();
1274 cantFail(sourceLocationInMainFile(AST.getSourceManager(), T.point())),
1275 AST.getTokens(), AST.getLangOpts());
1276 if (!Word) {
1277 ADD_FAILURE() << "No word touching point!" << Test;
1278 continue;
1279 }
1280 auto Results = locateSymbolTextually(*Word, AST, Index.get(),
1281 testPath(TU.Filename), ASTNodeKind());
1282
1283 if (!WantDecl) {
1284 EXPECT_THAT(Results, IsEmpty()) << Test;
1285 } else {
1286 ASSERT_THAT(Results, ::testing::SizeIs(1)) << Test;
1287 EXPECT_EQ(Results[0].PreferredDeclaration.range, *WantDecl) << Test;
1288 }
1289 }
1290} // namespace
1291
1292TEST(LocateSymbol, Ambiguous) {
1293 auto T = Annotations(R"cpp(
1294 struct Foo {
1295 Foo();
1296 Foo(Foo&&);
1297 $ConstructorLoc[[Foo]](const char*);
1298 };
1299
1300 Foo f();
1301
1302 void g(Foo foo);
1303
1304 void call() {
1305 const char* str = "123";
1306 Foo a = $1^str;
1307 Foo b = Foo($2^str);
1308 Foo c = $3^f();
1309 $4^g($5^f());
1310 g($6^str);
1311 Foo ab$7^c;
1312 Foo ab$8^cd("asdf");
1313 Foo foox = Fo$9^o("asdf");
1314 Foo abcde$10^("asdf");
1315 Foo foox2 = Foo$11^("asdf");
1316 }
1317
1318 template <typename T>
1319 struct S {
1320 void $NonstaticOverload1[[bar]](int);
1321 void $NonstaticOverload2[[bar]](float);
1322
1323 static void $StaticOverload1[[baz]](int);
1324 static void $StaticOverload2[[baz]](float);
1325 };
1326
1327 template <typename T, typename U>
1328 void dependent_call(S<T> s, U u) {
1329 s.ba$12^r(u);
1330 S<T>::ba$13^z(u);
1331 }
1332 )cpp");
1333 auto TU = TestTU::withCode(T.code());
1334 // FIXME: Go-to-definition in a template requires disabling delayed template
1335 // parsing.
1336 TU.ExtraArgs.push_back("-fno-delayed-template-parsing");
1337 auto AST = TU.build();
1338 // Ordered assertions are deliberate: we expect a predictable order.
1339 EXPECT_THAT(locateSymbolAt(AST, T.point("1")), ElementsAre(sym("str")));
1340 EXPECT_THAT(locateSymbolAt(AST, T.point("2")), ElementsAre(sym("str")));
1341 EXPECT_THAT(locateSymbolAt(AST, T.point("3")), ElementsAre(sym("f")));
1342 EXPECT_THAT(locateSymbolAt(AST, T.point("4")), ElementsAre(sym("g")));
1343 EXPECT_THAT(locateSymbolAt(AST, T.point("5")), ElementsAre(sym("f")));
1344 EXPECT_THAT(locateSymbolAt(AST, T.point("6")), ElementsAre(sym("str")));
1345 // FIXME: Target the constructor as well.
1346 EXPECT_THAT(locateSymbolAt(AST, T.point("7")), ElementsAre(sym("abc")));
1347 // FIXME: Target the constructor as well.
1348 EXPECT_THAT(locateSymbolAt(AST, T.point("8")), ElementsAre(sym("abcd")));
1349 // FIXME: Target the constructor as well.
1350 EXPECT_THAT(locateSymbolAt(AST, T.point("9")), ElementsAre(sym("Foo")));
1351 EXPECT_THAT(locateSymbolAt(AST, T.point("10")),
1352 ElementsAre(sym("Foo", T.range("ConstructorLoc"), std::nullopt)));
1353 EXPECT_THAT(locateSymbolAt(AST, T.point("11")),
1354 ElementsAre(sym("Foo", T.range("ConstructorLoc"), std::nullopt)));
1355 // These assertions are unordered because the order comes from
1356 // CXXRecordDecl::lookupDependentName() which doesn't appear to provide
1357 // an order guarantee.
1358 EXPECT_THAT(locateSymbolAt(AST, T.point("12")),
1359 UnorderedElementsAre(
1360 sym("bar", T.range("NonstaticOverload1"), std::nullopt),
1361 sym("bar", T.range("NonstaticOverload2"), std::nullopt)));
1362 EXPECT_THAT(locateSymbolAt(AST, T.point("13")),
1363 UnorderedElementsAre(
1364 sym("baz", T.range("StaticOverload1"), std::nullopt),
1365 sym("baz", T.range("StaticOverload2"), std::nullopt)));
1366}
1367
1368TEST(LocateSymbol, TextualDependent) {
1369 // Put the declarations in the header to make sure we are
1370 // finding them via the index heuristic and not the
1371 // nearby-ident heuristic.
1372 Annotations Header(R"cpp(
1373 struct Foo {
1374 void $FooLoc[[uniqueMethodName]]();
1375 };
1376 struct Bar {
1377 void $BarLoc[[uniqueMethodName]]();
1378 };
1379 )cpp");
1380 Annotations Source(R"cpp(
1381 template <typename T>
1382 void f(T t) {
1383 t.u^niqueMethodName();
1384 }
1385 )cpp");
1386 TestTU TU;
1387 TU.Code = std::string(Source.code());
1388 TU.HeaderCode = std::string(Header.code());
1389 auto AST = TU.build();
1390 auto Index = TU.index();
1391 // Need to use locateSymbolAt() since we are testing an
1392 // interaction between locateASTReferent() and
1393 // locateSymbolNamedTextuallyAt().
1394 auto Results = locateSymbolAt(AST, Source.point(), Index.get());
1395 EXPECT_THAT(
1396 Results,
1397 UnorderedElementsAre(
1398 sym("uniqueMethodName", Header.range("FooLoc"), std::nullopt),
1399 sym("uniqueMethodName", Header.range("BarLoc"), std::nullopt)));
1400}
1401
1402TEST(LocateSymbol, Alias) {
1403 const char *Tests[] = {
1404 R"cpp(
1405 template <class T> struct function {};
1406 template <class T> using [[callback]] = function<T()>;
1407
1408 c^allback<int> foo;
1409 )cpp",
1410
1411 // triggered on non-definition of a renaming alias: should not give any
1412 // underlying decls.
1413 R"cpp(
1414 class Foo {};
1415 typedef Foo [[Bar]];
1416
1417 B^ar b;
1418 )cpp",
1419 R"cpp(
1420 class Foo {};
1421 using [[Bar]] = Foo; // definition
1422 Ba^r b;
1423 )cpp",
1424
1425 // triggered on the underlying decl of a renaming alias.
1426 R"cpp(
1427 class [[Foo]];
1428 using Bar = Fo^o;
1429 )cpp",
1430
1431 // triggered on definition of a non-renaming alias: should give underlying
1432 // decls.
1433 R"cpp(
1434 namespace ns { class [[Foo]] {}; }
1435 using ns::F^oo;
1436 )cpp",
1437
1438 R"cpp(
1439 namespace ns { int [[x]](char); int [[x]](double); }
1440 using ns::^x;
1441 )cpp",
1442
1443 R"cpp(
1444 namespace ns { int [[x]](char); int x(double); }
1445 using ns::[[x]];
1446 int y = ^x('a');
1447 )cpp",
1448
1449 R"cpp(
1450 namespace ns { class [[Foo]] {}; }
1451 using ns::[[Foo]];
1452 F^oo f;
1453 )cpp",
1454
1455 // other cases that don't matter much.
1456 R"cpp(
1457 class Foo {};
1458 typedef Foo [[Ba^r]];
1459 )cpp",
1460 R"cpp(
1461 class Foo {};
1462 using [[B^ar]] = Foo;
1463 )cpp",
1464
1465 // Member of dependent base
1466 R"cpp(
1467 template <typename T>
1468 struct Base {
1469 void [[waldo]]() {}
1470 };
1471 template <typename T>
1472 struct Derived : Base<T> {
1473 using Base<T>::w^aldo;
1474 };
1475 )cpp",
1476 };
1477
1478 for (const auto *Case : Tests) {
1479 SCOPED_TRACE(Case);
1480 auto T = Annotations(Case);
1481 auto AST = TestTU::withCode(T.code()).build();
1482 EXPECT_THAT(locateSymbolAt(AST, T.point()),
1483 UnorderedPointwise(declRange(), T.ranges()));
1484 }
1485}
1486
1487TEST(LocateSymbol, RelPathsInCompileCommand) {
1488 // The source is in "/clangd-test/src".
1489 // We build in "/clangd-test/build".
1490
1491 Annotations SourceAnnotations(R"cpp(
1492#include "header_in_preamble.h"
1493int [[foo]];
1494#include "header_not_in_preamble.h"
1495int baz = f$p1^oo + bar_pre$p2^amble + bar_not_pre$p3^amble;
1496)cpp");
1497
1498 Annotations HeaderInPreambleAnnotations(R"cpp(
1499int [[bar_preamble]];
1500)cpp");
1501
1502 Annotations HeaderNotInPreambleAnnotations(R"cpp(
1503int [[bar_not_preamble]];
1504)cpp");
1505
1506 // Make the compilation paths appear as ../src/foo.cpp in the compile
1507 // commands.
1508 SmallString<32> RelPathPrefix("..");
1509 llvm::sys::path::append(RelPathPrefix, "src");
1510 std::string BuildDir = testPath("build");
1511 MockCompilationDatabase CDB(BuildDir, RelPathPrefix);
1512
1513 MockFS FS;
1514 ClangdServer Server(CDB, FS, ClangdServer::optsForTest());
1515
1516 // Fill the filesystem.
1517 auto FooCpp = testPath("src/foo.cpp");
1518 FS.Files[FooCpp] = "";
1519 auto HeaderInPreambleH = testPath("src/header_in_preamble.h");
1520 FS.Files[HeaderInPreambleH] = std::string(HeaderInPreambleAnnotations.code());
1521 auto HeaderNotInPreambleH = testPath("src/header_not_in_preamble.h");
1522 FS.Files[HeaderNotInPreambleH] =
1523 std::string(HeaderNotInPreambleAnnotations.code());
1524
1525 runAddDocument(Server, FooCpp, SourceAnnotations.code());
1526
1527 // Go to a definition in main source file.
1528 auto Locations =
1529 runLocateSymbolAt(Server, FooCpp, SourceAnnotations.point("p1"));
1530 EXPECT_TRUE(bool(Locations)) << "findDefinitions returned an error";
1531 EXPECT_THAT(*Locations, ElementsAre(sym("foo", SourceAnnotations.range(),
1532 SourceAnnotations.range())));
1533
1534 // Go to a definition in header_in_preamble.h.
1535 Locations = runLocateSymbolAt(Server, FooCpp, SourceAnnotations.point("p2"));
1536 EXPECT_TRUE(bool(Locations)) << "findDefinitions returned an error";
1537 EXPECT_THAT(
1538 *Locations,
1539 ElementsAre(sym("bar_preamble", HeaderInPreambleAnnotations.range(),
1540 HeaderInPreambleAnnotations.range())));
1541
1542 // Go to a definition in header_not_in_preamble.h.
1543 Locations = runLocateSymbolAt(Server, FooCpp, SourceAnnotations.point("p3"));
1544 EXPECT_TRUE(bool(Locations)) << "findDefinitions returned an error";
1545 EXPECT_THAT(*Locations,
1546 ElementsAre(sym("bar_not_preamble",
1547 HeaderNotInPreambleAnnotations.range(),
1548 HeaderNotInPreambleAnnotations.range())));
1549}
1550
1551TEST(GoToInclude, All) {
1552 MockFS FS;
1553 MockCompilationDatabase CDB;
1554 ClangdServer Server(CDB, FS, ClangdServer::optsForTest());
1555
1556 auto FooCpp = testPath("foo.cpp");
1557 const char *SourceContents = R"cpp(
1558 #include ^"$2^foo.h$3^"
1559 #include "$4^invalid.h"
1560 int b = a;
1561 // test
1562 int foo;
1563 #in$5^clude "$6^foo.h"$7^
1564 )cpp";
1565 Annotations SourceAnnotations(SourceContents);
1566 FS.Files[FooCpp] = std::string(SourceAnnotations.code());
1567 auto FooH = testPath("foo.h");
1568
1569 const char *HeaderContents = R"cpp([[]]#pragma once
1570 int a;
1571 )cpp";
1572 Annotations HeaderAnnotations(HeaderContents);
1573 FS.Files[FooH] = std::string(HeaderAnnotations.code());
1574
1575 runAddDocument(Server, FooH, HeaderAnnotations.code());
1576 runAddDocument(Server, FooCpp, SourceAnnotations.code());
1577
1578 // Test include in preamble.
1579 auto Locations = runLocateSymbolAt(Server, FooCpp, SourceAnnotations.point());
1580 ASSERT_TRUE(bool(Locations)) << "locateSymbolAt returned an error";
1581 EXPECT_THAT(*Locations, ElementsAre(sym("foo.h", HeaderAnnotations.range(),
1582 HeaderAnnotations.range())));
1583
1584 // Test include in preamble, last char.
1585 Locations = runLocateSymbolAt(Server, FooCpp, SourceAnnotations.point("2"));
1586 ASSERT_TRUE(bool(Locations)) << "locateSymbolAt returned an error";
1587 EXPECT_THAT(*Locations, ElementsAre(sym("foo.h", HeaderAnnotations.range(),
1588 HeaderAnnotations.range())));
1589
1590 Locations = runLocateSymbolAt(Server, FooCpp, SourceAnnotations.point("3"));
1591 ASSERT_TRUE(bool(Locations)) << "locateSymbolAt returned an error";
1592 EXPECT_THAT(*Locations, ElementsAre(sym("foo.h", HeaderAnnotations.range(),
1593 HeaderAnnotations.range())));
1594
1595 // Test include outside of preamble.
1596 Locations = runLocateSymbolAt(Server, FooCpp, SourceAnnotations.point("6"));
1597 ASSERT_TRUE(bool(Locations)) << "locateSymbolAt returned an error";
1598 EXPECT_THAT(*Locations, ElementsAre(sym("foo.h", HeaderAnnotations.range(),
1599 HeaderAnnotations.range())));
1600
1601 // Test a few positions that do not result in Locations.
1602 Locations = runLocateSymbolAt(Server, FooCpp, SourceAnnotations.point("4"));
1603 ASSERT_TRUE(bool(Locations)) << "locateSymbolAt returned an error";
1604 EXPECT_THAT(*Locations, IsEmpty());
1605
1606 Locations = runLocateSymbolAt(Server, FooCpp, SourceAnnotations.point("5"));
1607 ASSERT_TRUE(bool(Locations)) << "locateSymbolAt returned an error";
1608 EXPECT_THAT(*Locations, ElementsAre(sym("foo.h", HeaderAnnotations.range(),
1609 HeaderAnnotations.range())));
1610
1611 Locations = runLocateSymbolAt(Server, FooCpp, SourceAnnotations.point("7"));
1612 ASSERT_TRUE(bool(Locations)) << "locateSymbolAt returned an error";
1613 EXPECT_THAT(*Locations, ElementsAre(sym("foo.h", HeaderAnnotations.range(),
1614 HeaderAnnotations.range())));
1615
1616 // Objective C #import directive.
1617 Annotations ObjC(R"objc(
1618 #import "^foo.h"
1619 )objc");
1620 auto FooM = testPath("foo.m");
1621 FS.Files[FooM] = std::string(ObjC.code());
1622
1623 runAddDocument(Server, FooM, ObjC.code());
1624 Locations = runLocateSymbolAt(Server, FooM, ObjC.point());
1625 ASSERT_TRUE(bool(Locations)) << "locateSymbolAt returned an error";
1626 EXPECT_THAT(*Locations, ElementsAre(sym("foo.h", HeaderAnnotations.range(),
1627 HeaderAnnotations.range())));
1628}
1629
1630TEST(LocateSymbol, WithPreamble) {
1631 // Test stragety: AST should always use the latest preamble instead of last
1632 // good preamble.
1633 MockFS FS;
1634 MockCompilationDatabase CDB;
1635 ClangdServer Server(CDB, FS, ClangdServer::optsForTest());
1636
1637 auto FooCpp = testPath("foo.cpp");
1638 // The trigger locations must be the same.
1639 Annotations FooWithHeader(R"cpp(#include "fo^o.h")cpp");
1640 Annotations FooWithoutHeader(R"cpp(double [[fo^o]]();)cpp");
1641
1642 FS.Files[FooCpp] = std::string(FooWithHeader.code());
1643
1644 auto FooH = testPath("foo.h");
1645 Annotations FooHeader(R"cpp([[]])cpp");
1646 FS.Files[FooH] = std::string(FooHeader.code());
1647
1648 runAddDocument(Server, FooCpp, FooWithHeader.code());
1649 // LocateSymbol goes to a #include file: the result comes from the preamble.
1650 EXPECT_THAT(
1651 cantFail(runLocateSymbolAt(Server, FooCpp, FooWithHeader.point())),
1652 ElementsAre(sym("foo.h", FooHeader.range(), FooHeader.range())));
1653
1654 // Only preamble is built, and no AST is built in this request.
1655 Server.addDocument(FooCpp, FooWithoutHeader.code(), "null",
1657 // We build AST here, and it should use the latest preamble rather than the
1658 // stale one.
1659 EXPECT_THAT(
1660 cantFail(runLocateSymbolAt(Server, FooCpp, FooWithoutHeader.point())),
1661 ElementsAre(sym("foo", FooWithoutHeader.range(), std::nullopt)));
1662
1663 // Reset test environment.
1664 runAddDocument(Server, FooCpp, FooWithHeader.code());
1665 // Both preamble and AST are built in this request.
1666 Server.addDocument(FooCpp, FooWithoutHeader.code(), "null",
1668 // Use the AST being built in above request.
1669 EXPECT_THAT(
1670 cantFail(runLocateSymbolAt(Server, FooCpp, FooWithoutHeader.point())),
1671 ElementsAre(sym("foo", FooWithoutHeader.range(), std::nullopt)));
1672}
1673
1674TEST(LocateSymbol, NearbyTokenSmoke) {
1675 auto T = Annotations(R"cpp(
1676 // prints e^rr and crashes
1677 void die(const char* [[err]]);
1678 )cpp");
1679 auto AST = TestTU::withCode(T.code()).build();
1680 // We don't pass an index, so can't hit index-based fallback.
1681 EXPECT_THAT(locateSymbolAt(AST, T.point()),
1682 ElementsAre(sym("err", T.range(), T.range())));
1683}
1684
1685TEST(LocateSymbol, NearbyIdentifier) {
1686 const char *Tests[] = {
1687 R"cpp(
1688 // regular identifiers (won't trigger)
1689 int hello;
1690 int y = he^llo;
1691 )cpp",
1692 R"cpp(
1693 // disabled preprocessor sections
1694 int [[hello]];
1695 #if 0
1696 int y = ^hello;
1697 #endif
1698 )cpp",
1699 R"cpp(
1700 // comments
1701 // he^llo, world
1702 int [[hello]];
1703 )cpp",
1704 R"cpp(
1705 // not triggered by string literals
1706 int hello;
1707 const char* greeting = "h^ello, world";
1708 )cpp",
1709
1710 R"cpp(
1711 // can refer to macro invocations
1712 #define INT int
1713 [[INT]] x;
1714 // I^NT
1715 )cpp",
1716
1717 R"cpp(
1718 // can refer to macro invocations (even if they expand to nothing)
1719 #define EMPTY
1720 [[EMPTY]] int x;
1721 // E^MPTY
1722 )cpp",
1723
1724 R"cpp(
1725 // prefer nearest occurrence, backwards is worse than forwards
1726 int hello;
1727 int x = hello;
1728 // h^ello
1729 int y = [[hello]];
1730 int z = hello;
1731 )cpp",
1732
1733 R"cpp(
1734 // short identifiers find near results
1735 int [[hi]];
1736 // h^i
1737 )cpp",
1738 R"cpp(
1739 // short identifiers don't find far results
1740 int hi;
1741
1742
1743
1744 // h^i
1745
1746
1747
1748
1749 int x = hi;
1750 )cpp",
1751 R"cpp(
1752 // prefer nearest occurrence even if several matched tokens
1753 // have the same value of `floor(log2(<token line> - <word line>))`.
1754 int hello;
1755 int x = hello, y = hello;
1756 int z = [[hello]];
1757 // h^ello
1758 )cpp"};
1759 for (const char *Test : Tests) {
1760 Annotations T(Test);
1761 auto AST = TestTU::withCode(T.code()).build();
1762 const auto &SM = AST.getSourceManager();
1763 std::optional<Range> Nearby;
1764 auto Word =
1765 SpelledWord::touching(cantFail(sourceLocationInMainFile(SM, T.point())),
1766 AST.getTokens(), AST.getLangOpts());
1767 if (!Word) {
1768 ADD_FAILURE() << "No word at point! " << Test;
1769 continue;
1770 }
1771 if (const auto *Tok = findNearbyIdentifier(*Word, AST.getTokens()))
1772 Nearby = halfOpenToRange(SM, CharSourceRange::getCharRange(
1773 Tok->location(), Tok->endLocation()));
1774 if (T.ranges().empty())
1775 EXPECT_THAT(Nearby, Eq(std::nullopt)) << Test;
1776 else
1777 EXPECT_EQ(Nearby, T.range()) << Test;
1778 }
1779}
1780
1781TEST(FindImplementations, Inheritance) {
1782 llvm::StringRef Test = R"cpp(
1783 struct $0^Base {
1784 virtual void F$1^oo();
1785 void C$4^oncrete();
1786 };
1787 struct $0[[Child1]] : Base {
1788 void $1[[Fo$3^o]]() override;
1789 virtual void B$2^ar();
1790 void Concrete(); // No implementations for concrete methods.
1791 };
1792 struct Child2 : Child1 {
1793 void $3[[Foo]]() override;
1794 void $2[[Bar]]() override;
1795 };
1796 void FromReference() {
1797 $0^Base* B;
1798 B->Fo$1^o();
1799 B->C$4^oncrete();
1800 &Base::Fo$1^o;
1801 Child1 * C1;
1802 C1->B$2^ar();
1803 C1->Fo$3^o();
1804 }
1805 // CRTP should work.
1806 template<typename T>
1807 struct $5^TemplateBase {};
1808 struct $5[[Child3]] : public TemplateBase<Child3> {};
1809
1810 // Local classes.
1811 void LocationFunction() {
1812 struct $0[[LocalClass1]] : Base {
1813 void $1[[Foo]]() override;
1814 };
1815 struct $6^LocalBase {
1816 virtual void $7^Bar();
1817 };
1818 struct $6[[LocalClass2]]: LocalBase {
1819 void $7[[Bar]]() override;
1820 };
1821 }
1822 )cpp";
1823
1824 Annotations Code(Test);
1825 auto TU = TestTU::withCode(Code.code());
1826 auto AST = TU.build();
1827 auto Index = TU.index();
1828 for (StringRef Label : {"0", "1", "2", "3", "4", "5", "6", "7"}) {
1829 for (const auto &Point : Code.points(Label)) {
1830 EXPECT_THAT(findImplementations(AST, Point, Index.get()),
1831 UnorderedPointwise(declRange(), Code.ranges(Label)))
1832 << Code.code() << " at " << Point << " for Label " << Label;
1833 }
1834 }
1835}
1836
1837TEST(FindImplementations, CaptureDefinition) {
1838 llvm::StringRef Test = R"cpp(
1839 struct Base {
1840 virtual void F^oo();
1841 };
1842 struct Child1 : Base {
1843 void $Decl[[Foo]]() override;
1844 };
1845 struct Child2 : Base {
1846 void $Child2[[Foo]]() override;
1847 };
1848 void Child1::$Def[[Foo]]() { /* Definition */ }
1849 )cpp";
1850 Annotations Code(Test);
1851 auto TU = TestTU::withCode(Code.code());
1852 auto AST = TU.build();
1853 EXPECT_THAT(
1854 findImplementations(AST, Code.point(), TU.index().get()),
1855 UnorderedElementsAre(sym("Foo", Code.range("Decl"), Code.range("Def")),
1856 sym("Foo", Code.range("Child2"), std::nullopt)))
1857 << Test;
1858}
1859
1860TEST(FindType, All) {
1861 Annotations HeaderA(R"cpp(
1862 struct $Target[[Target]] { operator int() const; };
1863 struct Aggregate { Target a, b; };
1864 Target t;
1865 Target make();
1866
1867 template <typename T> struct $smart_ptr[[smart_ptr]] {
1868 T& operator*();
1869 T* operator->();
1870 T* get();
1871 };
1872 )cpp");
1873 auto TU = TestTU::withHeaderCode(HeaderA.code());
1874 for (const llvm::StringRef Case : {
1875 "str^uct Target;",
1876 "T^arget x;",
1877 "Target ^x;",
1878 "a^uto x = Target{};",
1879 "namespace m { Target tgt; } auto x = m^::tgt;",
1880 "Target funcCall(); auto x = ^funcCall();",
1881 "Aggregate a = { {}, ^{} };",
1882 "Aggregate a = { ^.a=t, };",
1883 "struct X { Target a; X() : ^a() {} };",
1884 "^using T = Target; ^T foo();",
1885 "^template <int> Target foo();",
1886 "void x() { try {} ^catch(Target e) {} }",
1887 "void x() { ^throw t; }",
1888 "int x() { ^return t; }",
1889 "void x() { ^switch(t) {} }",
1890 "void x() { ^delete (Target*)nullptr; }",
1891 "Target& ^tref = t;",
1892 "void x() { ^if (t) {} }",
1893 "void x() { ^while (t) {} }",
1894 "void x() { ^do { } while (t); }",
1895 "void x() { ^make(); }",
1896 "void x(smart_ptr<Target> &t) { t.^get(); }",
1897 "^auto x = []() { return t; };",
1898 "Target* ^tptr = &t;",
1899 "Target ^tarray[3];",
1900 }) {
1901 Annotations A(Case);
1902 TU.Code = A.code().str();
1903 ParsedAST AST = TU.build();
1904
1905 ASSERT_GT(A.points().size(), 0u) << Case;
1906 for (auto Pos : A.points())
1907 EXPECT_THAT(findType(AST, Pos, nullptr),
1908 ElementsAre(
1909 sym("Target", HeaderA.range("Target"), HeaderA.range("Target"))))
1910 << Case;
1911 }
1912
1913 for (const llvm::StringRef Case : {
1914 "smart_ptr<Target> ^tsmart;",
1915 }) {
1916 Annotations A(Case);
1917 TU.Code = A.code().str();
1918 ParsedAST AST = TU.build();
1919
1920 EXPECT_THAT(findType(AST, A.point(), nullptr),
1921 UnorderedElementsAre(
1922 sym("Target", HeaderA.range("Target"), HeaderA.range("Target")),
1923 sym("smart_ptr", HeaderA.range("smart_ptr"), HeaderA.range("smart_ptr"))
1924 ))
1925 << Case;
1926 }
1927}
1928
1929TEST(FindType, Definition) {
1930 Annotations A(R"cpp(
1931 class $decl[[X]];
1932 X *^x;
1933 class $def[[X]] {};
1934 )cpp");
1935 auto TU = TestTU::withCode(A.code().str());
1936 ParsedAST AST = TU.build();
1937
1938 EXPECT_THAT(findType(AST, A.point(), nullptr),
1939 ElementsAre(sym("X", A.range("decl"), A.range("def"))));
1940}
1941
1942TEST(FindType, Index) {
1943 Annotations Def(R"cpp(
1944 // This definition is only available through the index.
1945 class [[X]] {};
1946 )cpp");
1947 TestTU DefTU = TestTU::withHeaderCode(Def.code());
1948 DefTU.HeaderFilename = "def.h";
1949 auto DefIdx = DefTU.index();
1950
1951 Annotations A(R"cpp(
1952 class [[X]];
1953 X *^x;
1954 )cpp");
1955 auto TU = TestTU::withCode(A.code().str());
1956 ParsedAST AST = TU.build();
1957
1958 EXPECT_THAT(findType(AST, A.point(), DefIdx.get()),
1959 ElementsAre(sym("X", A.range(), Def.range())));
1960}
1961
1962void checkFindRefs(llvm::StringRef Test, bool UseIndex = false) {
1963 Annotations T(Test);
1964 auto TU = TestTU::withCode(T.code());
1965 TU.ExtraArgs.push_back("-std=c++20");
1966
1967 auto AST = TU.build();
1968 std::vector<Matcher<ReferencesResult::Reference>> ExpectedLocations;
1969 for (const auto &[R, Context] : T.rangesWithPayload())
1970 ExpectedLocations.push_back(
1971 AllOf(rangeIs(R), containerIs(Context), attrsAre(0u)));
1972 // $def is actually shorthand for both definition and declaration.
1973 // If we have cases that are definition-only, we should change this.
1974 for (const auto &[R, Context] : T.rangesWithPayload("def"))
1975 ExpectedLocations.push_back(AllOf(rangeIs(R), containerIs(Context),
1978 for (const auto &[R, Context] : T.rangesWithPayload("decl"))
1979 ExpectedLocations.push_back(AllOf(rangeIs(R), containerIs(Context),
1981 for (const auto &[R, Context] : T.rangesWithPayload("overridedecl"))
1982 ExpectedLocations.push_back(AllOf(
1983 rangeIs(R), containerIs(Context),
1985 for (const auto &[R, Context] : T.rangesWithPayload("overridedef"))
1986 ExpectedLocations.push_back(AllOf(rangeIs(R), containerIs(Context),
1990 for (const auto &P : T.points()) {
1991 EXPECT_THAT(findReferences(AST, P, 0, UseIndex ? TU.index().get() : nullptr,
1992 /*AddContext*/ true)
1993 .References,
1994 UnorderedElementsAreArray(ExpectedLocations))
1995 << "Failed for Refs at " << P << "\n"
1996 << Test;
1997 }
1998}
1999
2000TEST(FindReferences, WithinAST) {
2001 const char *Tests[] = {
2002 R"cpp(// Local variable
2003 int main() {
2004 int $def(main)[[foo]];
2005 $(main)[[^foo]] = 2;
2006 int test1 = $(main)[[foo]];
2007 }
2008 )cpp",
2009
2010 R"cpp(// Struct
2011 namespace ns1 {
2012 struct $def(ns1)[[Foo]] {};
2013 } // namespace ns1
2014 int main() {
2015 ns1::$(main)[[Fo^o]]* Params;
2016 }
2017 )cpp",
2018
2019 R"cpp(// Forward declaration
2020 class $decl[[Foo]];
2021 class $def[[Foo]] {};
2022 int main() {
2023 $(main)[[Fo^o]] foo;
2024 }
2025 )cpp",
2026
2027 R"cpp(// Function
2028 int $def[[foo]](int) {}
2029 int main() {
2030 auto *X = &$(main)[[^foo]];
2031 $(main)[[foo]](42);
2032 }
2033 )cpp",
2034
2035 R"cpp(// Field
2036 struct Foo {
2037 int $def(Foo)[[foo]];
2038 Foo() : $(Foo::Foo)[[foo]](0) {}
2039 };
2040 int main() {
2041 Foo f;
2042 f.$(main)[[f^oo]] = 1;
2043 }
2044 )cpp",
2045
2046 R"cpp(// Method call
2047 struct Foo { int $decl(Foo)[[foo]](); };
2048 int Foo::$def(Foo)[[foo]]() {}
2049 int main() {
2050 Foo f;
2051 f.$(main)[[^foo]]();
2052 }
2053 )cpp",
2054
2055 R"cpp(// Constructor
2056 struct Foo {
2057 $decl(Foo)[[F^oo]](int);
2058 };
2059 void foo() {
2060 Foo f = $(foo)[[Foo]](42);
2061 }
2062 )cpp",
2063
2064 R"cpp(// Typedef
2065 typedef int $def[[Foo]];
2066 int main() {
2067 $(main)[[^Foo]] bar;
2068 }
2069 )cpp",
2070
2071 R"cpp(// Namespace
2072 namespace $decl[[ns]] { // FIXME: def?
2073 struct Foo {};
2074 } // namespace ns
2075 int main() { $(main)[[^ns]]::Foo foo; }
2076 )cpp",
2077
2078 R"cpp(// Macros
2079 #define TYPE(X) X
2080 #define FOO Foo
2081 #define CAT(X, Y) X##Y
2082 class $def[[Fo^o]] {};
2083 void test() {
2084 TYPE($(test)[[Foo]]) foo;
2085 $(test)[[FOO]] foo2;
2086 TYPE(TYPE($(test)[[Foo]])) foo3;
2087 $(test)[[CAT]](Fo, o) foo4;
2088 }
2089 )cpp",
2090
2091 R"cpp(// Macros
2092 #define $def[[MA^CRO]](X) (X+1)
2093 void test() {
2094 int x = $[[MACRO]]($[[MACRO]](1));
2095 }
2096 )cpp",
2097
2098 R"cpp(// Macro outside preamble
2099 int breakPreamble;
2100 #define $def[[MA^CRO]](X) (X+1)
2101 void test() {
2102 int x = $[[MACRO]]($[[MACRO]](1));
2103 }
2104 )cpp",
2105
2106 R"cpp(
2107 int $def[[v^ar]] = 0;
2108 void foo(int s = $(foo)[[var]]);
2109 )cpp",
2110
2111 R"cpp(
2112 template <typename T>
2113 class $def[[Fo^o]] {};
2114 void func($(func)[[Foo]]<int>);
2115 )cpp",
2116
2117 R"cpp(
2118 template <typename T>
2119 class $def[[Foo]] {};
2120 void func($(func)[[Fo^o]]<int>);
2121 )cpp",
2122 R"cpp(// Not touching any identifiers.
2123 struct Foo {
2124 $def(Foo)[[~]]Foo() {};
2125 };
2126 void foo() {
2127 Foo f;
2128 f.$(foo)[[^~]]Foo();
2129 }
2130 )cpp",
2131 R"cpp(// Lambda capture initializer
2132 void foo() {
2133 int $def(foo)[[w^aldo]] = 42;
2134 auto lambda = [x = $(foo)[[waldo]]](){};
2135 }
2136 )cpp",
2137 R"cpp(// Renaming alias
2138 template <typename> class Vector {};
2139 using $def[[^X]] = Vector<int>;
2140 $(x1)[[X]] x1;
2141 Vector<int> x2;
2142 Vector<double> y;
2143 )cpp",
2144 R"cpp(// Dependent code
2145 template <typename T> void $decl[[foo]](T t);
2146 template <typename T> void bar(T t) { $(bar)[[foo]](t); } // foo in bar is uninstantiated.
2147 void baz(int x) { $(baz)[[f^oo]](x); }
2148 )cpp",
2149 R"cpp(
2150 namespace ns {
2151 struct S{};
2152 void $decl(ns)[[foo]](S s);
2153 } // namespace ns
2154 template <typename T> void foo(T t);
2155 // FIXME: Maybe report this foo as a ref to ns::foo (because of ADL)
2156 // when bar<ns::S> is instantiated?
2157 template <typename T> void bar(T t) { foo(t); }
2158 void baz(int x) {
2159 ns::S s;
2160 bar<ns::S>(s);
2161 $(baz)[[f^oo]](s);
2162 }
2163 )cpp",
2164 R"cpp(// unresolved member expression
2165 struct Foo {
2166 template <typename T> void $decl(Foo)[[b^ar]](T t);
2167 };
2168 template <typename T> void test(Foo F, T t) {
2169 F.$(test)[[bar]](t);
2170 }
2171 )cpp",
2172
2173 // Enum base
2174 R"cpp(
2175 typedef int $def[[MyTypeD^ef]];
2176 enum MyEnum : $(MyEnum)[[MyTy^peDef]] { };
2177 )cpp",
2178 R"cpp(
2179 typedef int $def[[MyType^Def]];
2180 enum MyEnum : $(MyEnum)[[MyTypeD^ef]];
2181 )cpp",
2182 R"cpp(
2183 using $def[[MyTypeD^ef]] = int;
2184 enum MyEnum : $(MyEnum)[[MyTy^peDef]] { };
2185 )cpp",
2186 // UDL
2187 R"cpp(
2188 bool $decl[[operator]]"" _u^dl(unsigned long long value);
2189 bool x = $(x)[[1_udl]];
2190 )cpp",
2191 };
2192 for (const char *Test : Tests)
2193 checkFindRefs(Test);
2194}
2195
2196TEST(FindReferences, ConceptsWithinAST) {
2197 constexpr llvm::StringLiteral Code = R"cpp(
2198 template <class T>
2199 concept $def[[IsSmal^l]] = sizeof(T) <= 8;
2200
2201 template <class T>
2202 concept IsSmallPtr = requires(T x) {
2203 { *x } -> $(IsSmallPtr)[[IsSmal^l]];
2204 };
2205
2206 $(i)[[IsSmall]] auto i = 'c';
2207 template<$(foo)[[IsSmal^l]] U> void foo();
2208 template<class U> void bar() requires $(bar)[[IsSmal^l]]<U>;
2209 template<class U> requires $(baz)[[IsSmal^l]]<U> void baz();
2210 static_assert([[IsSma^ll]]<char>);
2211 )cpp";
2212 checkFindRefs(Code);
2213}
2214
2215TEST(FindReferences, ConceptReq) {
2216 constexpr llvm::StringLiteral Code = R"cpp(
2217 template <class T>
2218 concept $def[[IsSmal^l]] = sizeof(T) <= 8;
2219
2220 template <class T>
2221 concept IsSmallPtr = requires(T x) {
2222 { *x } -> $(IsSmallPtr)[[IsSmal^l]];
2223 };
2224 )cpp";
2225 checkFindRefs(Code);
2226}
2227
2228TEST(FindReferences, RequiresExprParameters) {
2229 constexpr llvm::StringLiteral Code = R"cpp(
2230 template <class T>
2231 concept IsSmall = sizeof(T) <= 8;
2232
2233 template <class T>
2234 concept IsSmallPtr = requires(T $def[[^x]]) {
2235 { *$(IsSmallPtr)[[^x]] } -> IsSmall;
2236 };
2237 )cpp";
2238 checkFindRefs(Code);
2239}
2240
2241TEST(FindReferences, IncludeOverrides) {
2242 llvm::StringRef Test =
2243 R"cpp(
2244 class Base {
2245 public:
2246 virtu^al void $decl(Base)[[f^unc]]() ^= ^0;
2247 };
2248 class Derived : public Base {
2249 public:
2250 void $overridedecl(Derived::func)[[func]]() override;
2251 };
2252 void Derived::$overridedef[[func]]() {}
2253 class Derived2 : public Base {
2254 void $overridedef(Derived2::func)[[func]]() override {}
2255 };
2256 void test(Derived* D, Base* B) {
2257 D->func(); // No references to the overrides.
2258 B->$(test)[[func]]();
2259 })cpp";
2260 checkFindRefs(Test, /*UseIndex=*/true);
2261}
2262
2263TEST(FindReferences, RefsToBaseMethod) {
2264 llvm::StringRef Test =
2265 R"cpp(
2266 class BaseBase {
2267 public:
2268 virtual void $(BaseBase)[[func]]();
2269 };
2270 class Base : public BaseBase {
2271 public:
2272 void $(Base)[[func]]() override;
2273 };
2274 class Derived : public Base {
2275 public:
2276 void $decl(Derived)[[fu^nc]]() over^ride;
2277 };
2278 void test(BaseBase* BB, Base* B, Derived* D) {
2279 // refs to overridden methods in complete type hierarchy are reported.
2280 BB->$(test)[[func]]();
2281 B->$(test)[[func]]();
2282 D->$(test)[[fu^nc]]();
2283 })cpp";
2284 checkFindRefs(Test, /*UseIndex=*/true);
2285}
2286
2287TEST(FindReferences, MainFileReferencesOnly) {
2288 llvm::StringRef Test =
2289 R"cpp(
2290 void test() {
2291 int [[fo^o]] = 1;
2292 // refs not from main file should not be included.
2293 #include "foo.inc"
2294 })cpp";
2295
2296 Annotations Code(Test);
2297 auto TU = TestTU::withCode(Code.code());
2298 TU.AdditionalFiles["foo.inc"] = R"cpp(
2299 foo = 3;
2300 )cpp";
2301 auto AST = TU.build();
2302
2303 std::vector<Matcher<ReferencesResult::Reference>> ExpectedLocations;
2304 for (const auto &R : Code.ranges())
2305 ExpectedLocations.push_back(rangeIs(R));
2306 EXPECT_THAT(findReferences(AST, Code.point(), 0).References,
2307 ElementsAreArray(ExpectedLocations))
2308 << Test;
2309}
2310
2311TEST(FindReferences, ExplicitSymbols) {
2312 const char *Tests[] = {
2313 R"cpp(
2314 struct Foo { Foo* $decl(Foo)[[self]]() const; };
2315 void f() {
2316 Foo foo;
2317 if (Foo* T = foo.$(f)[[^self]]()) {} // Foo member call expr.
2318 }
2319 )cpp",
2320
2321 R"cpp(
2322 struct Foo { Foo(int); };
2323 Foo f() {
2324 int $def(f)[[b]];
2325 return $(f)[[^b]]; // Foo constructor expr.
2326 }
2327 )cpp",
2328
2329 R"cpp(
2330 struct Foo {};
2331 void g(Foo);
2332 Foo $decl[[f]]();
2333 void call() {
2334 g($(call)[[^f]]()); // Foo constructor expr.
2335 }
2336 )cpp",
2337
2338 R"cpp(
2339 void $decl[[foo]](int);
2340 void $decl[[foo]](double);
2341
2342 namespace ns {
2343 using ::$decl(ns)[[fo^o]];
2344 }
2345 )cpp",
2346
2347 R"cpp(
2348 struct X {
2349 operator bool();
2350 };
2351
2352 int test() {
2353 X $def(test)[[a]];
2354 $(test)[[a]].operator bool();
2355 if ($(test)[[a^]]) {} // ignore implicit conversion-operator AST node
2356 }
2357 )cpp",
2358 };
2359 for (const char *Test : Tests)
2360 checkFindRefs(Test);
2361}
2362
2363TEST(FindReferences, UsedSymbolsFromInclude) {
2364 const char *Tests[] = {
2365 R"cpp( [[#include ^"bar.h"]]
2366 #include <vector>
2367 int fstBar = [[bar1]]();
2368 int sndBar = [[bar2]]();
2369 [[Bar]] bar;
2370 int macroBar = [[BAR]];
2371 std::vector<int> vec;
2372 )cpp",
2373
2374 R"cpp([[#in^clude <vector>]]
2375 std::[[vector]]<int> vec;
2376 )cpp",
2377
2378 R"cpp(
2379 [[#include ^"udl_header.h"]]
2380 auto x = [[1_b]];
2381 )cpp",
2382 };
2383 for (const char *Test : Tests) {
2384 Annotations T(Test);
2385 auto TU = TestTU::withCode(T.code());
2386 TU.ExtraArgs.push_back("-std=c++20");
2387 TU.AdditionalFiles["bar.h"] = guard(R"cpp(
2388 #define BAR 5
2389 int bar1();
2390 int bar2();
2391 class Bar {};
2392 )cpp");
2393 TU.AdditionalFiles["system/vector"] = guard(R"cpp(
2394 namespace std {
2395 template<typename>
2396 class vector{};
2397 }
2398 )cpp");
2399 TU.AdditionalFiles["udl_header.h"] = guard(R"cpp(
2400 bool operator"" _b(unsigned long long value);
2401 )cpp");
2402 TU.ExtraArgs.push_back("-isystem" + testPath("system"));
2403
2404 auto AST = TU.build();
2405 std::vector<Matcher<ReferencesResult::Reference>> ExpectedLocations;
2406 for (const auto &R : T.ranges())
2407 ExpectedLocations.push_back(AllOf(rangeIs(R), attrsAre(0u)));
2408 for (const auto &P : T.points())
2409 EXPECT_THAT(findReferences(AST, P, 0).References,
2410 UnorderedElementsAreArray(ExpectedLocations))
2411 << "Failed for Refs at " << P << "\n"
2412 << Test;
2413 }
2414}
2415
2416TEST(FindReferences, NeedsIndexForSymbols) {
2417 const char *Header = "int foo();";
2418 Annotations Main("int main() { [[f^oo]](); }");
2419 TestTU TU;
2420 TU.Code = std::string(Main.code());
2421 TU.HeaderCode = Header;
2422 auto AST = TU.build();
2423
2424 // References in main file are returned without index.
2425 EXPECT_THAT(
2426 findReferences(AST, Main.point(), 0, /*Index=*/nullptr).References,
2427 ElementsAre(rangeIs(Main.range())));
2428 Annotations IndexedMain(R"cpp(
2429 int $decl[[foo]]() { return 42; }
2430 void bar() { $bar(bar)[[foo]](); }
2431 struct S { void bar() { $S(S::bar)[[foo]](); } };
2432 namespace N { void bar() { $N(N::bar)[[foo]](); } }
2433 )cpp");
2434
2435 // References from indexed files are included.
2436 TestTU IndexedTU;
2437 IndexedTU.Code = std::string(IndexedMain.code());
2438 IndexedTU.Filename = "Indexed.cpp";
2439 IndexedTU.HeaderCode = Header;
2440 EXPECT_THAT(
2441 findReferences(AST, Main.point(), 0, IndexedTU.index().get(),
2442 /*AddContext*/ true)
2443 .References,
2444 ElementsAre(
2445 rangeIs(Main.range()),
2446 AllOf(rangeIs(IndexedMain.range("decl")),
2449 AllOf(rangeIs(IndexedMain.range("bar")), containerIs("bar")),
2450 AllOf(rangeIs(IndexedMain.range("S")), containerIs("S::bar")),
2451 AllOf(rangeIs(IndexedMain.range("N")), containerIs("N::bar"))));
2452 auto LimitRefs =
2453 findReferences(AST, Main.point(), /*Limit*/ 1, IndexedTU.index().get());
2454 EXPECT_EQ(1u, LimitRefs.References.size());
2455 EXPECT_TRUE(LimitRefs.HasMore);
2456
2457 // Avoid indexed results for the main file. Use AST for the mainfile.
2458 TU.Code = ("\n\n" + Main.code()).str();
2459 EXPECT_THAT(findReferences(AST, Main.point(), 0, TU.index().get()).References,
2460 ElementsAre(rangeIs(Main.range())));
2461}
2462
2463TEST(FindReferences, NeedsIndexForMacro) {
2464 const char *Header = "#define MACRO(X) (X+1)";
2465 Annotations Main(R"cpp(
2466 int main() {
2467 int a = [[MA^CRO]](1);
2468 }
2469 )cpp");
2470 TestTU TU;
2471 TU.Code = std::string(Main.code());
2472 TU.HeaderCode = Header;
2473 auto AST = TU.build();
2474
2475 // References in main file are returned without index.
2476 EXPECT_THAT(
2477 findReferences(AST, Main.point(), 0, /*Index=*/nullptr).References,
2478 ElementsAre(rangeIs(Main.range())));
2479
2480 Annotations IndexedMain(R"cpp(
2481 int indexed_main() {
2482 int a = [[MACRO]](1);
2483 }
2484 )cpp");
2485
2486 // References from indexed files are included.
2487 TestTU IndexedTU;
2488 IndexedTU.Code = std::string(IndexedMain.code());
2489 IndexedTU.Filename = "Indexed.cpp";
2490 IndexedTU.HeaderCode = Header;
2491 EXPECT_THAT(
2492 findReferences(AST, Main.point(), 0, IndexedTU.index().get()).References,
2493 ElementsAre(rangeIs(Main.range()), rangeIs(IndexedMain.range())));
2494 auto LimitRefs =
2495 findReferences(AST, Main.point(), /*Limit*/ 1, IndexedTU.index().get());
2496 EXPECT_EQ(1u, LimitRefs.References.size());
2497 EXPECT_TRUE(LimitRefs.HasMore);
2498}
2499
2500TEST(FindReferences, NoQueryForLocalSymbols) {
2501 struct RecordingIndex : public MemIndex {
2502 mutable std::optional<llvm::DenseSet<SymbolID>> RefIDs;
2503 bool refs(const RefsRequest &Req,
2504 llvm::function_ref<void(const Ref &)>) const override {
2505 RefIDs = Req.IDs;
2506 return false;
2507 }
2508 };
2509
2510 struct Test {
2511 StringRef AnnotatedCode;
2512 bool WantQuery;
2513 } Tests[] = {
2514 {"int ^x;", true},
2515 // For now we don't assume header structure which would allow skipping.
2516 {"namespace { int ^x; }", true},
2517 {"static int ^x;", true},
2518 // Anything in a function certainly can't be referenced though.
2519 {"void foo() { int ^x; }", false},
2520 {"void foo() { struct ^x{}; }", false},
2521 {"auto lambda = []{ int ^x; };", false},
2522 };
2523 for (Test T : Tests) {
2524 Annotations File(T.AnnotatedCode);
2525 RecordingIndex Rec;
2526 auto AST = TestTU::withCode(File.code()).build();
2527 findReferences(AST, File.point(), 0, &Rec);
2528 if (T.WantQuery)
2529 EXPECT_NE(Rec.RefIDs, std::nullopt) << T.AnnotatedCode;
2530 else
2531 EXPECT_EQ(Rec.RefIDs, std::nullopt) << T.AnnotatedCode;
2532 }
2533}
2534
2535TEST(GetNonLocalDeclRefs, All) {
2536 struct Case {
2537 llvm::StringRef AnnotatedCode;
2538 std::vector<std::string> ExpectedDecls;
2539 } Cases[] = {
2540 {
2541 // VarDecl and ParamVarDecl
2542 R"cpp(
2543 void bar();
2544 void ^foo(int baz) {
2545 int x = 10;
2546 bar();
2547 })cpp",
2548 {"bar"},
2549 },
2550 {
2551 // Method from class
2552 R"cpp(
2553 class Foo { public: void foo(); };
2554 class Bar {
2555 void foo();
2556 void bar();
2557 };
2558 void Bar::^foo() {
2559 Foo f;
2560 bar();
2561 f.foo();
2562 })cpp",
2563 {"Bar", "Bar::bar", "Foo", "Foo::foo"},
2564 },
2565 {
2566 // Local types
2567 R"cpp(
2568 void ^foo() {
2569 class Foo { public: void foo() {} };
2570 class Bar { public: void bar() {} };
2571 Foo f;
2572 Bar b;
2573 b.bar();
2574 f.foo();
2575 })cpp",
2576 {},
2577 },
2578 {
2579 // Template params
2580 R"cpp(
2581 template <typename T, template<typename> class Q>
2582 void ^foo() {
2583 T x;
2584 Q<T> y;
2585 })cpp",
2586 {},
2587 },
2588 };
2589 for (const Case &C : Cases) {
2590 Annotations File(C.AnnotatedCode);
2591 auto AST = TestTU::withCode(File.code()).build();
2592 SourceLocation SL = llvm::cantFail(
2593 sourceLocationInMainFile(AST.getSourceManager(), File.point()));
2594
2595 const FunctionDecl *FD =
2596 llvm::dyn_cast<FunctionDecl>(&findDecl(AST, [SL](const NamedDecl &ND) {
2597 return ND.getLocation() == SL && llvm::isa<FunctionDecl>(ND);
2598 }));
2599 ASSERT_NE(FD, nullptr);
2600
2601 auto NonLocalDeclRefs = getNonLocalDeclRefs(AST, FD);
2602 std::vector<std::string> Names;
2603 for (const Decl *D : NonLocalDeclRefs) {
2604 if (const auto *ND = llvm::dyn_cast<NamedDecl>(D))
2605 Names.push_back(ND->getQualifiedNameAsString());
2606 }
2607 EXPECT_THAT(Names, UnorderedElementsAreArray(C.ExpectedDecls))
2608 << File.code();
2609 }
2610}
2611
2612TEST(DocumentLinks, All) {
2613 Annotations MainCpp(R"cpp(
2614 #/*comments*/include /*comments*/ $foo[["foo.h"]] //more comments
2615 int end_of_preamble = 0;
2616 #include $bar[[<bar.h>]]
2617 )cpp");
2618
2619 TestTU TU;
2620 TU.Code = std::string(MainCpp.code());
2621 TU.AdditionalFiles = {{"foo.h", ""}, {"bar.h", ""}};
2622 TU.ExtraArgs = {"-isystem."};
2623 auto AST = TU.build();
2624
2625 EXPECT_THAT(
2627 ElementsAre(
2628 DocumentLink({MainCpp.range("foo"),
2629 URIForFile::canonicalize(testPath("foo.h"), "")}),
2630 DocumentLink({MainCpp.range("bar"),
2631 URIForFile::canonicalize(testPath("bar.h"), "")})));
2632}
2633
2634} // namespace
2635} // namespace clangd
2636} // namespace clang
const FunctionDecl * Decl
llvm::SmallString< 256U > Name
StringRef BuildDir
Definition: ClangTidy.cpp:305
std::vector< CodeCompletionResult > Results
std::string AnnotatedCode
const Criteria C
std::string Word
CharSourceRange Range
SourceRange for the file name.
std::vector< HeaderEntry > HeaderContents
Definition: Modularize.cpp:482
size_t Pos
std::vector< const char * > Expected
Kind K
Definition: Rename.cpp:474
static Options optsForTest()
Token::Index index(const Token &T) const
Returns the index of T within the stream.
SymbolID getSymbolID(const Decl *D)
Gets the symbol ID for a declaration. Returned SymbolID might be null.
Definition: AST.cpp:331
const NamedDecl & findDecl(ParsedAST &AST, llvm::StringRef QName)
Definition: TestTU.cpp:219
Range halfOpenToRange(const SourceManager &SM, CharSourceRange R)
Definition: SourceCode.cpp:472
std::vector< DocumentHighlight > findDocumentHighlights(ParsedAST &AST, Position Pos)
Returns highlights for all usages of a symbol at Pos.
Definition: XRefs.cpp:1218
Symbol sym(llvm::StringRef QName, index::SymbolKind Kind, llvm::StringRef USRFormat, llvm::StringRef Signature)
Definition: TestIndex.cpp:40
std::vector< LocatedSymbol > locateSymbolTextually(const SpelledWord &Word, ParsedAST &AST, const SymbolIndex *Index, llvm::StringRef MainFilePath, ASTNodeKind NodeKind)
Definition: XRefs.cpp:546
std::vector< DocumentLink > getDocumentLinks(ParsedAST &AST)
Get all document links.
Definition: XRefs.cpp:826
MATCHER_P2(hasFlag, Flag, Path, "")
std::vector< LocatedSymbol > findType(ParsedAST &AST, Position Pos, const SymbolIndex *Index)
Returns symbols for types referenced at Pos.
Definition: XRefs.cpp:2053
MATCHER_P(named, N, "")
ReferencesResult findReferences(ParsedAST &AST, Position Pos, uint32_t Limit, const SymbolIndex *Index, bool AddContext)
Returns references of the symbol at a specified Pos.
Definition: XRefs.cpp:1363
std::string testPath(PathRef File, llvm::sys::path::Style Style)
Definition: TestFS.cpp:93
std::vector< LocatedSymbol > locateSymbolAt(ParsedAST &AST, Position Pos, const SymbolIndex *Index)
Get definition of symbol at a specified Pos.
Definition: XRefs.cpp:747
TEST(BackgroundQueueTest, Priority)
const syntax::Token * findNearbyIdentifier(const SpelledWord &Word, const syntax::TokenBuffer &TB)
Definition: XRefs.cpp:656
void runAddDocument(ClangdServer &Server, PathRef File, llvm::StringRef Contents, llvm::StringRef Version, WantDiagnostics WantDiags, bool ForceRebuild)
Definition: SyncAPI.cpp:17
llvm::Expected< std::vector< LocatedSymbol > > runLocateSymbolAt(ClangdServer &Server, PathRef File, Position Pos)
Definition: SyncAPI.cpp:88
const Symbol & findSymbol(const SymbolSlab &Slab, llvm::StringRef QName)
Definition: TestTU.cpp:185
llvm::Expected< SourceLocation > sourceLocationInMainFile(const SourceManager &SM, Position P)
Return the file location, corresponding to P.
Definition: SourceCode.cpp:462
@ No
Diagnostics must be generated for this snapshot.
std::vector< LocatedSymbol > findImplementations(ParsedAST &AST, Position Pos, const SymbolIndex *Index)
Returns implementations at a specified Pos:
Definition: XRefs.cpp:1259
MATCHER(declared, "")
llvm::DenseSet< const Decl * > getNonLocalDeclRefs(ParsedAST &AST, const FunctionDecl *FD)
Returns all decls that are referenced in the FD except local symbols.
Definition: XRefs.cpp:2369
const char * testRoot()
Definition: TestFS.cpp:85
@ Alias
This declaration is an alias that was referred to.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
std::vector< Reference > References
Definition: XRefs.h:94
static std::optional< SpelledWord > touching(SourceLocation SpelledLoc, const syntax::TokenBuffer &TB, const LangOptions &LangOpts)
Definition: SourceCode.cpp:949
SymbolID ID
The ID of the symbol.
Definition: Symbol.h:41
ParsedAST build() const
Definition: TestTU.cpp:114
static TestTU withHeaderCode(llvm::StringRef HeaderCode)
Definition: TestTU.h:42
static TestTU withCode(llvm::StringRef Code)
Definition: TestTU.h:36
static URIForFile canonicalize(llvm::StringRef AbsPath, llvm::StringRef TUPath)
Canonicalizes AbsPath via URI.
Definition: Protocol.cpp:46