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