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(// Field in offsetof
605 struct Foo { int [[x]]; };
606 int y = __builtin_offsetof(Foo, ^x);
607 )cpp",
608
609 R"cpp(// Outer field in nested offsetof designator
610 struct Inner { int c; };
611 struct A { Inner [[B]]; };
612 int y = __builtin_offsetof(A, ^B.c);
613 )cpp",
614
615 R"cpp(// Inner field in nested offsetof designator
616 struct Inner { int [[c]]; };
617 struct A { Inner B; };
618 int y = __builtin_offsetof(A, B.^c);
619 )cpp",
620
621 R"cpp(// Field in offsetof macro form
622 #define offsetof(t, m) __builtin_offsetof(t, m)
623 struct Foo { int [[x]]; };
624 int y = offsetof(Foo, ^x);
625 )cpp",
626
627 R"cpp(// Inherited field in offsetof
628 struct B { int [[x]]; };
629 struct D : B {};
630 int y = __builtin_offsetof(D, ^x);
631 )cpp",
632
633 R"cpp(// Builtin offsetof name is not a field reference.
634 struct Foo { int x; };
635 int y = __builtin_o^ffsetof(Foo, x);
636 )cpp",
637
638 R"cpp(// Method call
639 struct Foo { int $decl[[x]](); };
640 int main() {
641 Foo bar;
642 bar.^x();
643 }
644 )cpp",
645
646 R"cpp(// Typedef
647 typedef int $decl[[Foo]];
648 int main() {
649 ^Foo bar;
650 }
651 )cpp",
652
653 R"cpp(// Template type parameter
654 template <typename [[T]]>
655 void foo() { ^T t; }
656 )cpp",
657
658 R"cpp(// Template template type parameter
659 template <template<typename> class [[T]]>
660 void foo() { ^T<int> t; }
661 )cpp",
662
663 R"cpp(// Namespace
664 namespace $decl[[ns]] {
665 struct Foo { static void bar(); };
666 } // namespace ns
667 int main() { ^ns::Foo::bar(); }
668 )cpp",
669
670 R"cpp(// Macro
671 class TTT { public: int a; };
672 #define [[FF]](S) if (int b = S.a) {}
673 void f() {
674 TTT t;
675 F^F(t);
676 }
677 )cpp",
678
679 R"cpp(// Macro argument
680 int [[i]];
681 #define ADDRESSOF(X) &X;
682 int *j = ADDRESSOF(^i);
683 )cpp",
684 R"cpp(// Macro argument appearing multiple times in expansion
685 #define VALIDATE_TYPE(x) (void)x;
686 #define ASSERT(expr) \
687 do { \
688 VALIDATE_TYPE(expr); \
689 if (!expr); \
690 } while (false)
691 bool [[waldo]]() { return true; }
692 void foo() {
693 ASSERT(wa^ldo());
694 }
695 )cpp",
696 R"cpp(// Symbol concatenated inside macro (not supported)
697 int *pi;
698 #define POINTER(X) p ## X;
699 int x = *POINTER(^i);
700 )cpp",
701
702 R"cpp(// Forward class declaration
703 class $decl[[Foo]];
704 class $def[[Foo]] {};
705 F^oo* foo();
706 )cpp",
707
708 R"cpp(// Function declaration
709 void $decl[[foo]]();
710 void g() { f^oo(); }
711 void $def[[foo]]() {}
712 )cpp",
713
714 R"cpp(
715 #define FF(name) class name##_Test {};
716 [[FF]](my);
717 void f() { my^_Test a; }
718 )cpp",
719
720 R"cpp(
721 #define FF() class [[Test]] {};
722 FF();
723 void f() { T^est a; }
724 )cpp",
725
726 R"cpp(// explicit template specialization
727 template <typename T>
728 struct Foo { void bar() {} };
729
730 template <>
731 struct [[Foo]]<int> { void bar() {} };
732
733 void foo() {
734 Foo<char> abc;
735 Fo^o<int> b;
736 }
737 )cpp",
738
739 R"cpp(// implicit template specialization
740 template <typename T>
741 struct [[Foo]] { void bar() {} };
742 template <>
743 struct Foo<int> { void bar() {} };
744 void foo() {
745 Fo^o<char> abc;
746 Foo<int> b;
747 }
748 )cpp",
749
750 R"cpp(// partial template specialization
751 template <typename T>
752 struct Foo { void bar() {} };
753 template <typename T>
754 struct [[Foo]]<T*> { void bar() {} };
755 ^Foo<int*> x;
756 )cpp",
757
758 R"cpp(// function template specializations
759 template <class T>
760 void foo(T) {}
761 template <>
762 void [[foo]](int) {}
763 void bar() {
764 fo^o(10);
765 }
766 )cpp",
767
768 R"cpp(// variable template decls
769 template <class T>
770 T var = T();
771
772 template <>
773 double [[var]]<int> = 10;
774
775 double y = va^r<int>;
776 )cpp",
777
778 R"cpp(// No implicit constructors
779 struct X {
780 X(X&& x) = default;
781 };
782 X $decl[[makeX]]();
783 void foo() {
784 auto x = m^akeX();
785 }
786 )cpp",
787
788 R"cpp(
789 struct X {
790 X& $decl[[operator]]++();
791 };
792 void foo(X& x) {
793 +^+x;
794 }
795 )cpp",
796
797 R"cpp(
798 struct S1 { void f(); };
799 struct S2 { S1 * $decl[[operator]]->(); };
800 void test(S2 s2) {
801 s2-^>f();
802 }
803 )cpp",
804
805 R"cpp(// Declaration of explicit template specialization
806 template <typename T>
807 struct $decl[[$def[[Foo]]]] {};
808
809 template <>
810 struct Fo^o<int> {};
811 )cpp",
812
813 R"cpp(// Declaration of partial template specialization
814 template <typename T>
815 struct $decl[[$def[[Foo]]]] {};
816
817 template <typename T>
818 struct Fo^o<T*> {};
819 )cpp",
820
821 R"cpp(// Definition on ClassTemplateDecl
822 namespace ns {
823 // Forward declaration.
824 template<typename T>
825 struct $decl[[Foo]];
826
827 template <typename T>
828 struct $def[[Foo]] {};
829 }
830
831 using ::ns::Fo^o;
832 )cpp",
833
834 R"cpp(// auto builtin type (not supported)
835 ^auto x = 42;
836 )cpp",
837
838 R"cpp(// auto on lambda
839 auto x = [[[]]]{};
840 ^auto y = x;
841 )cpp",
842
843 R"cpp(// auto on struct
844 namespace ns1 {
845 struct [[S1]] {};
846 } // namespace ns1
847
848 ^auto x = ns1::S1{};
849 )cpp",
850
851 R"cpp(// decltype on struct
852 namespace ns1 {
853 struct [[S1]] {};
854 } // namespace ns1
855
856 ns1::S1 i;
857 ^decltype(i) j;
858 )cpp",
859
860 R"cpp(// decltype(auto) on struct
861 namespace ns1 {
862 struct [[S1]] {};
863 } // namespace ns1
864
865 ns1::S1 i;
866 ns1::S1& j = i;
867 ^decltype(auto) k = j;
868 )cpp",
869
870 R"cpp(// auto on template class
871 template<typename T> class [[Foo]] {};
872
873 ^auto x = Foo<int>();
874 )cpp",
875
876 R"cpp(// auto on template class with forward declared class
877 template<typename T> class [[Foo]] {};
878 class X;
879
880 ^auto x = Foo<X>();
881 )cpp",
882
883 R"cpp(// auto on specialized template class
884 template<typename T> class Foo {};
885 template<> class [[Foo]]<int> {};
886
887 ^auto x = Foo<int>();
888 )cpp",
889
890 R"cpp(// auto on initializer list.
891 namespace std
892 {
893 template<class _E>
894 class [[initializer_list]] { const _E *a, *b; };
895 }
896
897 ^auto i = {1,2};
898 )cpp",
899
900 R"cpp(// auto function return with trailing type
901 struct [[Bar]] {};
902 ^auto test() -> decltype(Bar()) {
903 return Bar();
904 }
905 )cpp",
906
907 R"cpp(// decltype in trailing return type
908 struct [[Bar]] {};
909 auto test() -> ^decltype(Bar()) {
910 return Bar();
911 }
912 )cpp",
913
914 R"cpp(// auto in function return
915 struct [[Bar]] {};
916 ^auto test() {
917 return Bar();
918 }
919 )cpp",
920
921 R"cpp(// auto& in function return
922 struct [[Bar]] {};
923 ^auto& test() {
924 static Bar x;
925 return x;
926 }
927 )cpp",
928
929 R"cpp(// auto* in function return
930 struct [[Bar]] {};
931 ^auto* test() {
932 Bar* x;
933 return x;
934 }
935 )cpp",
936
937 R"cpp(// const auto& in function return
938 struct [[Bar]] {};
939 const ^auto& test() {
940 static Bar x;
941 return x;
942 }
943 )cpp",
944
945 R"cpp(// auto lambda param where there's a single instantiation
946 struct [[Bar]] {};
947 auto Lambda = [](^auto){ return 0; };
948 int x = Lambda(Bar{});
949 )cpp",
950
951 R"cpp(// decltype(auto) in function return
952 struct [[Bar]] {};
953 ^decltype(auto) test() {
954 return Bar();
955 }
956 )cpp",
957
958 R"cpp(// decltype of function with trailing return type.
959 struct [[Bar]] {};
960 auto test() -> decltype(Bar()) {
961 return Bar();
962 }
963 void foo() {
964 ^decltype(test()) i = test();
965 }
966 )cpp",
967
968 R"cpp(// auto with dependent type
969 template <typename>
970 struct [[A]] {};
971 template <typename T>
972 void foo(A<T> a) {
973 ^auto copy = a;
974 }
975 )cpp",
976
977 R"cpp(// Override specifier jumps to overridden method
978 class Y { virtual void $decl[[a]]() = 0; };
979 class X : Y { void a() ^override {} };
980 )cpp",
981 R"cpp(// Final specifier jumps to overridden method
982 class Y { virtual void $decl[[a]]() = 0; };
983 class X : Y { void a() ^final {} };
984 )cpp",
985
986 R"cpp(// Heuristic resolution of dependent method
987 template <typename T>
988 struct S {
989 void [[bar]]() {}
990 };
991
992 template <typename T>
993 void foo(S<T> arg) {
994 arg.ba^r();
995 }
996 )cpp",
997
998 R"cpp(// Heuristic resolution of dependent method via this->
999 template <typename T>
1000 struct S {
1001 void [[foo]]() {
1002 this->fo^o();
1003 }
1004 };
1005 )cpp",
1006
1007 R"cpp(// Heuristic resolution of dependent static method
1008 template <typename T>
1009 struct S {
1010 static void [[bar]]() {}
1011 };
1012
1013 template <typename T>
1014 void foo() {
1015 S<T>::ba^r();
1016 }
1017 )cpp",
1018
1019 R"cpp(// Heuristic resolution of dependent method
1020 // invoked via smart pointer
1021 template <typename> struct S { void [[foo]]() {} };
1022 template <typename T> struct unique_ptr {
1023 T* operator->();
1024 };
1025 template <typename T>
1026 void test(unique_ptr<S<T>>& V) {
1027 V->fo^o();
1028 }
1029 )cpp",
1030
1031 R"cpp(// Heuristic resolution of dependent enumerator
1032 template <typename T>
1033 struct Foo {
1034 enum class E { [[A]], B };
1035 E e = E::A^;
1036 };
1037 )cpp",
1038
1039 R"cpp(// Enum base
1040 typedef int $decl[[MyTypeDef]];
1041 enum Foo : My^TypeDef {};
1042 )cpp",
1043 R"cpp(// Enum base
1044 typedef int $decl[[MyTypeDef]];
1045 enum Foo : My^TypeDef;
1046 )cpp",
1047 R"cpp(// Enum base
1048 using $decl[[MyTypeDef]] = int;
1049 enum Foo : My^TypeDef {};
1050 )cpp",
1051
1052 R"objc(
1053 @protocol Dog;
1054 @protocol $decl[[Dog]]
1055 - (void)bark;
1056 @end
1057 id<Do^g> getDoggo() {
1058 return 0;
1059 }
1060 )objc",
1061
1062 R"objc(
1063 @interface Cat
1064 @end
1065 @implementation Cat
1066 @end
1067 @interface $decl[[Cat]] (Exte^nsion)
1068 - (void)meow;
1069 @end
1070 @implementation $def[[Cat]] (Extension)
1071 - (void)meow {}
1072 @end
1073 )objc",
1074
1075 R"objc(
1076 @class $decl[[Foo]];
1077 Fo^o * getFoo() {
1078 return 0;
1079 }
1080 )objc",
1081
1082 R"objc(// Prefer interface definition over forward declaration
1083 @class Foo;
1084 @interface $decl[[Foo]]
1085 @end
1086 Fo^o * getFoo() {
1087 return 0;
1088 }
1089 )objc",
1090
1091 R"objc(
1092 @class Foo;
1093 @interface $decl[[Foo]]
1094 @end
1095 @implementation $def[[Foo]]
1096 @end
1097 Fo^o * getFoo() {
1098 return 0;
1099 }
1100 )objc",
1101
1102 R"objc(// Method decl and definition for ObjC class.
1103 @interface Cat
1104 - (void)$decl[[meow]];
1105 @end
1106 @implementation Cat
1107 - (void)$def[[meow]] {}
1108 @end
1109 void makeNoise(Cat *kitty) {
1110 [kitty me^ow];
1111 }
1112 )objc",
1113
1114 R"objc(// Method decl and definition for ObjC category.
1115 @interface Dog
1116 @end
1117 @interface Dog (Play)
1118 - (void)$decl[[runAround]];
1119 @end
1120 @implementation Dog (Play)
1121 - (void)$def[[runAround]] {}
1122 @end
1123 void play(Dog *dog) {
1124 [dog run^Around];
1125 }
1126 )objc",
1127
1128 R"objc(// Method decl and definition for ObjC class extension.
1129 @interface Dog
1130 @end
1131 @interface Dog ()
1132 - (void)$decl[[howl]];
1133 @end
1134 @implementation Dog
1135 - (void)$def[[howl]] {}
1136 @end
1137 void play(Dog *dog) {
1138 [dog ho^wl];
1139 }
1140 )objc",
1141 R"cpp(
1142 struct PointerIntPairInfo {
1143 static void *$decl[[getPointer]](void *Value);
1144 };
1145
1146 template <typename Info = PointerIntPairInfo> struct PointerIntPair {
1147 void *Value;
1148 void *getPointer() const { return Info::get^Pointer(Value); }
1149 };
1150 )cpp",
1151 R"cpp(// Deducing this
1152 struct S {
1153 int bar(this S&);
1154 };
1155 void foo() {
1156 S [[waldo]];
1157 int x = wa^ldo.bar();
1158 }
1159 )cpp"};
1160 for (const char *Test : Tests) {
1161 Annotations T(Test);
1162 std::optional<Range> WantDecl;
1163 std::optional<Range> WantDef;
1164 if (!T.ranges().empty())
1165 WantDecl = WantDef = T.range();
1166 if (!T.ranges("decl").empty())
1167 WantDecl = T.range("decl");
1168 if (!T.ranges("def").empty())
1169 WantDef = T.range("def");
1170
1171 TestTU TU;
1172 TU.Code = std::string(T.code());
1173
1174 TU.ExtraArgs.push_back("-xobjective-c++");
1175 TU.ExtraArgs.push_back("-std=c++23");
1176
1177 auto AST = TU.build();
1178 auto Results = locateSymbolAt(AST, T.point());
1179
1180 if (!WantDecl) {
1181 EXPECT_THAT(Results, IsEmpty()) << Test;
1182 } else {
1183 ASSERT_THAT(Results, ::testing::SizeIs(1)) << Test;
1184 EXPECT_EQ(Results[0].PreferredDeclaration.range, *WantDecl) << Test;
1185 EXPECT_TRUE(Results[0].ID) << Test;
1186 std::optional<Range> GotDef;
1187 if (Results[0].Definition)
1188 GotDef = Results[0].Definition->range;
1189 EXPECT_EQ(WantDef, GotDef) << Test;
1190 }
1191 }
1192}
1193TEST(LocateSymbol, ValidSymbolID) {
1194 auto T = Annotations(R"cpp(
1195 #define MACRO(x, y) ((x) + (y))
1196 int add(int x, int y) { return $MACRO^MACRO(x, y); }
1197 int sum = $add^add(1, 2);
1198 )cpp");
1199
1200 TestTU TU = TestTU::withCode(T.code());
1201 auto AST = TU.build();
1202 auto Index = TU.index();
1203 EXPECT_THAT(locateSymbolAt(AST, T.point("add"), Index.get()),
1204 ElementsAre(AllOf(sym("add"),
1205 hasID(getSymbolID(&findDecl(AST, "add"))))));
1206 EXPECT_THAT(
1207 locateSymbolAt(AST, T.point("MACRO"), Index.get()),
1208 ElementsAre(AllOf(sym("MACRO"),
1209 hasID(findSymbol(TU.headerSymbols(), "MACRO").ID))));
1210}
1211
1212TEST(LocateSymbol, AllMulti) {
1213 // Ranges in tests:
1214 // $declN is the declaration location
1215 // $defN is the definition location (if absent, symbol has no definition)
1216 //
1217 // NOTE:
1218 // N starts at 0.
1219 struct ExpectedRanges {
1220 Range WantDecl;
1221 std::optional<Range> WantDef;
1222 };
1223 const char *Tests[] = {
1224 R"objc(
1225 @interface $decl0[[Cat]]
1226 @end
1227 @implementation $def0[[Cat]]
1228 @end
1229 @interface $decl1[[Ca^t]] (Extension)
1230 - (void)meow;
1231 @end
1232 @implementation $def1[[Cat]] (Extension)
1233 - (void)meow {}
1234 @end
1235 )objc",
1236
1237 R"objc(
1238 @interface $decl0[[Cat]]
1239 @end
1240 @implementation $def0[[Cat]]
1241 @end
1242 @interface $decl1[[Cat]] (Extension)
1243 - (void)meow;
1244 @end
1245 @implementation $def1[[Ca^t]] (Extension)
1246 - (void)meow {}
1247 @end
1248 )objc",
1249
1250 R"objc(
1251 @interface $decl0[[Cat]]
1252 @end
1253 @interface $decl1[[Ca^t]] ()
1254 - (void)meow;
1255 @end
1256 @implementation $def0[[$def1[[Cat]]]]
1257 - (void)meow {}
1258 @end
1259 )objc",
1260 };
1261 for (const char *Test : Tests) {
1262 Annotations T(Test);
1263 std::vector<ExpectedRanges> Ranges;
1264 for (int Idx = 0; true; Idx++) {
1265 bool HasDecl = !T.ranges("decl" + std::to_string(Idx)).empty();
1266 bool HasDef = !T.ranges("def" + std::to_string(Idx)).empty();
1267 if (!HasDecl && !HasDef)
1268 break;
1269 ExpectedRanges Range;
1270 if (HasDecl)
1271 Range.WantDecl = T.range("decl" + std::to_string(Idx));
1272 if (HasDef)
1273 Range.WantDef = T.range("def" + std::to_string(Idx));
1274 Ranges.push_back(Range);
1275 }
1276
1277 TestTU TU;
1278 TU.Code = std::string(T.code());
1279 TU.ExtraArgs.push_back("-xobjective-c++");
1280
1281 auto AST = TU.build();
1282 auto Results = locateSymbolAt(AST, T.point());
1283
1284 ASSERT_THAT(Results, ::testing::SizeIs(Ranges.size())) << Test;
1285 for (size_t Idx = 0; Idx < Ranges.size(); Idx++) {
1286 EXPECT_EQ(Results[Idx].PreferredDeclaration.range, Ranges[Idx].WantDecl)
1287 << "($decl" << Idx << ")" << Test;
1288 std::optional<Range> GotDef;
1289 if (Results[Idx].Definition)
1290 GotDef = Results[Idx].Definition->range;
1291 EXPECT_EQ(GotDef, Ranges[Idx].WantDef) << "($def" << Idx << ")" << Test;
1292 }
1293 }
1294}
1295
1296// LocateSymbol test cases that produce warnings.
1297// These are separated out from All so that in All we can assert
1298// that there are no diagnostics.
1299TEST(LocateSymbol, Warnings) {
1300 const char *Tests[] = {
1301 R"cpp(// Field, GNU old-style field designator
1302 struct Foo { int [[x]]; };
1303 int main() {
1304 Foo bar = { ^x : 1 };
1305 }
1306 )cpp",
1307
1308 R"cpp(// Macro
1309 #define MACRO 0
1310 #define [[MACRO]] 1
1311 int main() { return ^MACRO; }
1312 #define MACRO 2
1313 #undef macro
1314 )cpp",
1315 };
1316
1317 for (const char *Test : Tests) {
1318 Annotations T(Test);
1319 std::optional<Range> WantDecl;
1320 std::optional<Range> WantDef;
1321 if (!T.ranges().empty())
1322 WantDecl = WantDef = T.range();
1323 if (!T.ranges("decl").empty())
1324 WantDecl = T.range("decl");
1325 if (!T.ranges("def").empty())
1326 WantDef = T.range("def");
1327
1328 TestTU TU;
1329 TU.Code = std::string(T.code());
1330
1331 auto AST = TU.build();
1332 auto Results = locateSymbolAt(AST, T.point());
1333
1334 if (!WantDecl) {
1335 EXPECT_THAT(Results, IsEmpty()) << Test;
1336 } else {
1337 ASSERT_THAT(Results, ::testing::SizeIs(1)) << Test;
1338 EXPECT_EQ(Results[0].PreferredDeclaration.range, *WantDecl) << Test;
1339 std::optional<Range> GotDef;
1340 if (Results[0].Definition)
1341 GotDef = Results[0].Definition->range;
1342 EXPECT_EQ(WantDef, GotDef) << Test;
1343 }
1344 }
1345}
1346
1347TEST(LocateSymbol, TextualSmoke) {
1348 auto T = Annotations(
1349 R"cpp(
1350 struct [[MyClass]] {};
1351 // Comment mentioning M^yClass
1352 )cpp");
1353
1354 auto TU = TestTU::withCode(T.code());
1355 auto AST = TU.build();
1356 auto Index = TU.index();
1357 EXPECT_THAT(
1358 locateSymbolAt(AST, T.point(), Index.get()),
1359 ElementsAre(AllOf(sym("MyClass", T.range(), T.range()),
1360 hasID(getSymbolID(&findDecl(AST, "MyClass"))))));
1361}
1362
1363TEST(LocateSymbol, Textual) {
1364 const char *Tests[] = {
1365 R"cpp(// Comment
1366 struct [[MyClass]] {};
1367 // Comment mentioning M^yClass
1368 )cpp",
1369 R"cpp(// String
1370 struct MyClass {};
1371 // Not triggered for string literal tokens.
1372 const char* s = "String literal mentioning M^yClass";
1373 )cpp",
1374 R"cpp(// Ifdef'ed out code
1375 struct [[MyClass]] {};
1376 #ifdef WALDO
1377 M^yClass var;
1378 #endif
1379 )cpp",
1380 R"cpp(// Macro definition
1381 struct [[MyClass]] {};
1382 #define DECLARE_MYCLASS_OBJ(name) M^yClass name;
1383 )cpp",
1384 R"cpp(// Invalid code
1385 /*error-ok*/
1386 int myFunction(int);
1387 // Not triggered for token which survived preprocessing.
1388 int var = m^yFunction();
1389 )cpp"};
1390
1391 for (const char *Test : Tests) {
1392 Annotations T(Test);
1393 std::optional<Range> WantDecl;
1394 if (!T.ranges().empty())
1395 WantDecl = T.range();
1396
1397 auto TU = TestTU::withCode(T.code());
1398
1399 auto AST = TU.build();
1400 auto Index = TU.index();
1401 auto Word = SpelledWord::touching(
1402 cantFail(sourceLocationInMainFile(AST.getSourceManager(), T.point())),
1403 AST.getTokens(), AST.getLangOpts());
1404 if (!Word) {
1405 ADD_FAILURE() << "No word touching point!" << Test;
1406 continue;
1407 }
1408 auto Results = locateSymbolTextually(*Word, AST, Index.get(),
1409 testPath(TU.Filename), ASTNodeKind());
1410
1411 if (!WantDecl) {
1412 EXPECT_THAT(Results, IsEmpty()) << Test;
1413 } else {
1414 ASSERT_THAT(Results, ::testing::SizeIs(1)) << Test;
1415 EXPECT_EQ(Results[0].PreferredDeclaration.range, *WantDecl) << Test;
1416 }
1417 }
1418} // namespace
1419
1420TEST(LocateSymbol, Ambiguous) {
1421 auto T = Annotations(R"cpp(
1422 struct Foo {
1423 Foo();
1424 Foo(Foo&&);
1425 $ConstructorLoc[[Foo]](const char*);
1426 };
1427
1428 Foo f();
1429
1430 void g(Foo foo);
1431
1432 void call() {
1433 const char* str = "123";
1434 Foo a = $1^str;
1435 Foo b = Foo($2^str);
1436 Foo c = $3^f();
1437 $4^g($5^f());
1438 g($6^str);
1439 Foo ab$7^c;
1440 Foo ab$8^cd("asdf");
1441 Foo foox = Fo$9^o("asdf");
1442 Foo abcde$10^("asdf");
1443 Foo foox2 = Foo$11^("asdf");
1444 }
1445
1446 template <typename T>
1447 struct S {
1448 void $NonstaticOverload1[[bar]](int);
1449 void $NonstaticOverload2[[bar]](float);
1450
1451 static void $StaticOverload1[[baz]](int);
1452 static void $StaticOverload2[[baz]](float);
1453 };
1454
1455 template <typename T, typename U>
1456 void dependent_call(S<T> s, U u) {
1457 s.ba$12^r(u);
1458 S<T>::ba$13^z(u);
1459 }
1460 )cpp");
1461 auto TU = TestTU::withCode(T.code());
1462 // FIXME: Go-to-definition in a template requires disabling delayed template
1463 // parsing.
1464 TU.ExtraArgs.push_back("-fno-delayed-template-parsing");
1465 auto AST = TU.build();
1466 // Ordered assertions are deliberate: we expect a predictable order.
1467 EXPECT_THAT(locateSymbolAt(AST, T.point("1")), ElementsAre(sym("str")));
1468 EXPECT_THAT(locateSymbolAt(AST, T.point("2")), ElementsAre(sym("str")));
1469 EXPECT_THAT(locateSymbolAt(AST, T.point("3")), ElementsAre(sym("f")));
1470 EXPECT_THAT(locateSymbolAt(AST, T.point("4")), ElementsAre(sym("g")));
1471 EXPECT_THAT(locateSymbolAt(AST, T.point("5")), ElementsAre(sym("f")));
1472 EXPECT_THAT(locateSymbolAt(AST, T.point("6")), ElementsAre(sym("str")));
1473 // FIXME: Target the constructor as well.
1474 EXPECT_THAT(locateSymbolAt(AST, T.point("7")), ElementsAre(sym("abc")));
1475 // FIXME: Target the constructor as well.
1476 EXPECT_THAT(locateSymbolAt(AST, T.point("8")), ElementsAre(sym("abcd")));
1477 // FIXME: Target the constructor as well.
1478 EXPECT_THAT(locateSymbolAt(AST, T.point("9")), ElementsAre(sym("Foo")));
1479 EXPECT_THAT(locateSymbolAt(AST, T.point("10")),
1480 ElementsAre(sym("Foo", T.range("ConstructorLoc"), std::nullopt)));
1481 EXPECT_THAT(locateSymbolAt(AST, T.point("11")),
1482 ElementsAre(sym("Foo", T.range("ConstructorLoc"), std::nullopt)));
1483 // These assertions are unordered because the order comes from
1484 // CXXRecordDecl::lookupDependentName() which doesn't appear to provide
1485 // an order guarantee.
1486 EXPECT_THAT(locateSymbolAt(AST, T.point("12")),
1487 UnorderedElementsAre(
1488 sym("bar", T.range("NonstaticOverload1"), std::nullopt),
1489 sym("bar", T.range("NonstaticOverload2"), std::nullopt)));
1490 EXPECT_THAT(locateSymbolAt(AST, T.point("13")),
1491 UnorderedElementsAre(
1492 sym("baz", T.range("StaticOverload1"), std::nullopt),
1493 sym("baz", T.range("StaticOverload2"), std::nullopt)));
1494}
1495
1496TEST(LocateSymbol, TextualDependent) {
1497 // Put the declarations in the header to make sure we are
1498 // finding them via the index heuristic and not the
1499 // nearby-ident heuristic.
1500 Annotations Header(R"cpp(
1501 struct Foo {
1502 void $FooLoc[[uniqueMethodName]]();
1503 };
1504 struct Bar {
1505 void $BarLoc[[uniqueMethodName]]();
1506 };
1507 )cpp");
1508 Annotations Source(R"cpp(
1509 template <typename T>
1510 void f(T t) {
1511 t.u^niqueMethodName();
1512 }
1513 )cpp");
1514 TestTU TU;
1515 TU.Code = std::string(Source.code());
1516 TU.HeaderCode = std::string(Header.code());
1517 auto AST = TU.build();
1518 auto Index = TU.index();
1519 // Need to use locateSymbolAt() since we are testing an
1520 // interaction between locateASTReferent() and
1521 // locateSymbolNamedTextuallyAt().
1522 auto Results = locateSymbolAt(AST, Source.point(), Index.get());
1523 EXPECT_THAT(
1524 Results,
1525 UnorderedElementsAre(
1526 sym("uniqueMethodName", Header.range("FooLoc"), std::nullopt),
1527 sym("uniqueMethodName", Header.range("BarLoc"), std::nullopt)));
1528}
1529
1530TEST(LocateSymbol, Alias) {
1531 const char *Tests[] = {
1532 R"cpp(
1533 template <class T> struct function {};
1534 template <class T> using [[callback]] = function<T()>;
1535
1536 c^allback<int> foo;
1537 )cpp",
1538
1539 // triggered on non-definition of a renaming alias: should not give any
1540 // underlying decls.
1541 R"cpp(
1542 class Foo {};
1543 typedef Foo [[Bar]];
1544
1545 B^ar b;
1546 )cpp",
1547 R"cpp(
1548 class Foo {};
1549 using [[Bar]] = Foo; // definition
1550 Ba^r b;
1551 )cpp",
1552
1553 // triggered on the underlying decl of a renaming alias.
1554 R"cpp(
1555 class [[Foo]];
1556 using Bar = Fo^o;
1557 )cpp",
1558
1559 // triggered on definition of a non-renaming alias: should give underlying
1560 // decls.
1561 R"cpp(
1562 namespace ns { class [[Foo]] {}; }
1563 using ns::F^oo;
1564 )cpp",
1565
1566 R"cpp(
1567 namespace ns { int [[x]](char); int [[x]](double); }
1568 using ns::^x;
1569 )cpp",
1570
1571 R"cpp(
1572 namespace ns { int [[x]](char); int x(double); }
1573 using ns::[[x]];
1574 int y = ^x('a');
1575 )cpp",
1576
1577 R"cpp(
1578 namespace ns { class [[Foo]] {}; }
1579 using ns::[[Foo]];
1580 F^oo f;
1581 )cpp",
1582
1583 // other cases that don't matter much.
1584 R"cpp(
1585 class Foo {};
1586 typedef Foo [[Ba^r]];
1587 )cpp",
1588 R"cpp(
1589 class Foo {};
1590 using [[B^ar]] = Foo;
1591 )cpp",
1592
1593 // Member of dependent base
1594 R"cpp(
1595 template <typename T>
1596 struct Base {
1597 void [[waldo]]() {}
1598 };
1599 template <typename T>
1600 struct Derived : Base<T> {
1601 using Base<T>::w^aldo;
1602 };
1603 )cpp",
1604 };
1605
1606 for (const auto *Case : Tests) {
1607 SCOPED_TRACE(Case);
1608 auto T = Annotations(Case);
1609 auto AST = TestTU::withCode(T.code()).build();
1610 EXPECT_THAT(locateSymbolAt(AST, T.point()),
1611 UnorderedPointwise(declRange(), T.ranges()));
1612 }
1613}
1614
1615TEST(LocateSymbol, RelPathsInCompileCommand) {
1616 // The source is in "/clangd-test/src".
1617 // We build in "/clangd-test/build".
1618
1619 Annotations SourceAnnotations(R"cpp(
1620#include "header_in_preamble.h"
1621int [[foo]];
1622#include "header_not_in_preamble.h"
1623int baz = f$p1^oo + bar_pre$p2^amble + bar_not_pre$p3^amble;
1624)cpp");
1625
1626 Annotations HeaderInPreambleAnnotations(R"cpp(
1627int [[bar_preamble]];
1628)cpp");
1629
1630 Annotations HeaderNotInPreambleAnnotations(R"cpp(
1631int [[bar_not_preamble]];
1632)cpp");
1633
1634 // Make the compilation paths appear as ../src/foo.cpp in the compile
1635 // commands.
1636 SmallString<32> RelPathPrefix("..");
1637 llvm::sys::path::append(RelPathPrefix, "src");
1638 std::string BuildDir = testPath("build");
1639 MockCompilationDatabase CDB(BuildDir, RelPathPrefix);
1640
1641 MockFS FS;
1642 ClangdServer Server(CDB, FS, ClangdServer::optsForTest());
1643
1644 // Fill the filesystem.
1645 auto FooCpp = testPath("src/foo.cpp");
1646 FS.Files[FooCpp] = "";
1647 auto HeaderInPreambleH = testPath("src/header_in_preamble.h");
1648 FS.Files[HeaderInPreambleH] = std::string(HeaderInPreambleAnnotations.code());
1649 auto HeaderNotInPreambleH = testPath("src/header_not_in_preamble.h");
1650 FS.Files[HeaderNotInPreambleH] =
1651 std::string(HeaderNotInPreambleAnnotations.code());
1652
1653 runAddDocument(Server, FooCpp, SourceAnnotations.code());
1654
1655 // Go to a definition in main source file.
1656 auto Locations =
1657 runLocateSymbolAt(Server, FooCpp, SourceAnnotations.point("p1"));
1658 EXPECT_TRUE(bool(Locations)) << "findDefinitions returned an error";
1659 EXPECT_THAT(*Locations, ElementsAre(sym("foo", SourceAnnotations.range(),
1660 SourceAnnotations.range())));
1661
1662 // Go to a definition in header_in_preamble.h.
1663 Locations = runLocateSymbolAt(Server, FooCpp, SourceAnnotations.point("p2"));
1664 EXPECT_TRUE(bool(Locations)) << "findDefinitions returned an error";
1665 EXPECT_THAT(
1666 *Locations,
1667 ElementsAre(sym("bar_preamble", HeaderInPreambleAnnotations.range(),
1668 HeaderInPreambleAnnotations.range())));
1669
1670 // Go to a definition in header_not_in_preamble.h.
1671 Locations = runLocateSymbolAt(Server, FooCpp, SourceAnnotations.point("p3"));
1672 EXPECT_TRUE(bool(Locations)) << "findDefinitions returned an error";
1673 EXPECT_THAT(*Locations,
1674 ElementsAre(sym("bar_not_preamble",
1675 HeaderNotInPreambleAnnotations.range(),
1676 HeaderNotInPreambleAnnotations.range())));
1677}
1678
1679TEST(GoToInclude, All) {
1680 MockFS FS;
1682 ClangdServer Server(CDB, FS, ClangdServer::optsForTest());
1683
1684 auto FooCpp = testPath("foo.cpp");
1685 const char *SourceContents = R"cpp(
1686 #include ^"$2^foo.h$3^"
1687 #include "$4^invalid.h"
1688 int b = a;
1689 // test
1690 int foo;
1691 #in$5^clude "$6^foo.h"$7^
1692 )cpp";
1693 Annotations SourceAnnotations(SourceContents);
1694 FS.Files[FooCpp] = std::string(SourceAnnotations.code());
1695 auto FooH = testPath("foo.h");
1696
1697 const char *HeaderContents = R"cpp([[]]#pragma once
1698 int a;
1699 )cpp";
1700 Annotations HeaderAnnotations(HeaderContents);
1701 FS.Files[FooH] = std::string(HeaderAnnotations.code());
1702
1703 runAddDocument(Server, FooH, HeaderAnnotations.code());
1704 runAddDocument(Server, FooCpp, SourceAnnotations.code());
1705
1706 // Test include in preamble.
1707 auto Locations = runLocateSymbolAt(Server, FooCpp, SourceAnnotations.point());
1708 ASSERT_TRUE(bool(Locations)) << "locateSymbolAt returned an error";
1709 EXPECT_THAT(*Locations, ElementsAre(sym("foo.h", HeaderAnnotations.range(),
1710 HeaderAnnotations.range())));
1711
1712 // Test include in preamble, last char.
1713 Locations = runLocateSymbolAt(Server, FooCpp, SourceAnnotations.point("2"));
1714 ASSERT_TRUE(bool(Locations)) << "locateSymbolAt returned an error";
1715 EXPECT_THAT(*Locations, ElementsAre(sym("foo.h", HeaderAnnotations.range(),
1716 HeaderAnnotations.range())));
1717
1718 Locations = runLocateSymbolAt(Server, FooCpp, SourceAnnotations.point("3"));
1719 ASSERT_TRUE(bool(Locations)) << "locateSymbolAt returned an error";
1720 EXPECT_THAT(*Locations, ElementsAre(sym("foo.h", HeaderAnnotations.range(),
1721 HeaderAnnotations.range())));
1722
1723 // Test include outside of preamble.
1724 Locations = runLocateSymbolAt(Server, FooCpp, SourceAnnotations.point("6"));
1725 ASSERT_TRUE(bool(Locations)) << "locateSymbolAt returned an error";
1726 EXPECT_THAT(*Locations, ElementsAre(sym("foo.h", HeaderAnnotations.range(),
1727 HeaderAnnotations.range())));
1728
1729 // Test a few positions that do not result in Locations.
1730 Locations = runLocateSymbolAt(Server, FooCpp, SourceAnnotations.point("4"));
1731 ASSERT_TRUE(bool(Locations)) << "locateSymbolAt returned an error";
1732 EXPECT_THAT(*Locations, IsEmpty());
1733
1734 Locations = runLocateSymbolAt(Server, FooCpp, SourceAnnotations.point("5"));
1735 ASSERT_TRUE(bool(Locations)) << "locateSymbolAt returned an error";
1736 EXPECT_THAT(*Locations, ElementsAre(sym("foo.h", HeaderAnnotations.range(),
1737 HeaderAnnotations.range())));
1738
1739 Locations = runLocateSymbolAt(Server, FooCpp, SourceAnnotations.point("7"));
1740 ASSERT_TRUE(bool(Locations)) << "locateSymbolAt returned an error";
1741 EXPECT_THAT(*Locations, ElementsAre(sym("foo.h", HeaderAnnotations.range(),
1742 HeaderAnnotations.range())));
1743
1744 // Objective C #import directive.
1745 Annotations ObjC(R"objc(
1746 #import "^foo.h"
1747 )objc");
1748 auto FooM = testPath("foo.m");
1749 FS.Files[FooM] = std::string(ObjC.code());
1750
1751 runAddDocument(Server, FooM, ObjC.code());
1752 Locations = runLocateSymbolAt(Server, FooM, ObjC.point());
1753 ASSERT_TRUE(bool(Locations)) << "locateSymbolAt returned an error";
1754 EXPECT_THAT(*Locations, ElementsAre(sym("foo.h", HeaderAnnotations.range(),
1755 HeaderAnnotations.range())));
1756}
1757
1758TEST(LocateSymbol, WithPreamble) {
1759 // Test stragety: AST should always use the latest preamble instead of last
1760 // good preamble.
1761 MockFS FS;
1763 ClangdServer Server(CDB, FS, ClangdServer::optsForTest());
1764
1765 auto FooCpp = testPath("foo.cpp");
1766 // The trigger locations must be the same.
1767 Annotations FooWithHeader(R"cpp(#include "fo^o.h")cpp");
1768 Annotations FooWithoutHeader(R"cpp(double [[fo^o]]();)cpp");
1769
1770 FS.Files[FooCpp] = std::string(FooWithHeader.code());
1771
1772 auto FooH = testPath("foo.h");
1773 Annotations FooHeader(R"cpp([[]])cpp");
1774 FS.Files[FooH] = std::string(FooHeader.code());
1775
1776 runAddDocument(Server, FooCpp, FooWithHeader.code());
1777 // LocateSymbol goes to a #include file: the result comes from the preamble.
1778 EXPECT_THAT(
1779 cantFail(runLocateSymbolAt(Server, FooCpp, FooWithHeader.point())),
1780 ElementsAre(sym("foo.h", FooHeader.range(), FooHeader.range())));
1781
1782 // Only preamble is built, and no AST is built in this request.
1783 Server.addDocument(FooCpp, FooWithoutHeader.code(), "null",
1785 // We build AST here, and it should use the latest preamble rather than the
1786 // stale one.
1787 EXPECT_THAT(
1788 cantFail(runLocateSymbolAt(Server, FooCpp, FooWithoutHeader.point())),
1789 ElementsAre(sym("foo", FooWithoutHeader.range(), std::nullopt)));
1790
1791 // Reset test environment.
1792 runAddDocument(Server, FooCpp, FooWithHeader.code());
1793 // Both preamble and AST are built in this request.
1794 Server.addDocument(FooCpp, FooWithoutHeader.code(), "null",
1796 // Use the AST being built in above request.
1797 EXPECT_THAT(
1798 cantFail(runLocateSymbolAt(Server, FooCpp, FooWithoutHeader.point())),
1799 ElementsAre(sym("foo", FooWithoutHeader.range(), std::nullopt)));
1800}
1801
1802TEST(LocateSymbol, NearbyTokenSmoke) {
1803 auto T = Annotations(R"cpp(
1804 // prints e^rr and crashes
1805 void die(const char* [[err]]);
1806 )cpp");
1807 auto AST = TestTU::withCode(T.code()).build();
1808 // We don't pass an index, so can't hit index-based fallback.
1809 EXPECT_THAT(locateSymbolAt(AST, T.point()),
1810 ElementsAre(sym("err", T.range(), T.range())));
1811}
1812
1813TEST(LocateSymbol, NearbyIdentifier) {
1814 const char *Tests[] = {
1815 R"cpp(
1816 // regular identifiers (won't trigger)
1817 int hello;
1818 int y = he^llo;
1819 )cpp",
1820 R"cpp(
1821 // disabled preprocessor sections
1822 int [[hello]];
1823 #if 0
1824 int y = ^hello;
1825 #endif
1826 )cpp",
1827 R"cpp(
1828 // comments
1829 // he^llo, world
1830 int [[hello]];
1831 )cpp",
1832 R"cpp(
1833 // not triggered by string literals
1834 int hello;
1835 const char* greeting = "h^ello, world";
1836 )cpp",
1837
1838 R"cpp(
1839 // can refer to macro invocations
1840 #define INT int
1841 [[INT]] x;
1842 // I^NT
1843 )cpp",
1844
1845 R"cpp(
1846 // can refer to macro invocations (even if they expand to nothing)
1847 #define EMPTY
1848 [[EMPTY]] int x;
1849 // E^MPTY
1850 )cpp",
1851
1852 R"cpp(
1853 // prefer nearest occurrence, backwards is worse than forwards
1854 int hello;
1855 int x = hello;
1856 // h^ello
1857 int y = [[hello]];
1858 int z = hello;
1859 )cpp",
1860
1861 R"cpp(
1862 // short identifiers find near results
1863 int [[hi]];
1864 // h^i
1865 )cpp",
1866 R"cpp(
1867 // short identifiers don't find far results
1868 int hi;
1869
1870
1871
1872 // h^i
1873
1874
1875
1876
1877 int x = hi;
1878 )cpp",
1879 R"cpp(
1880 // prefer nearest occurrence even if several matched tokens
1881 // have the same value of `floor(log2(<token line> - <word line>))`.
1882 int hello;
1883 int x = hello, y = hello;
1884 int z = [[hello]];
1885 // h^ello
1886 )cpp"};
1887 for (const char *Test : Tests) {
1888 Annotations T(Test);
1889 auto AST = TestTU::withCode(T.code()).build();
1890 const auto &SM = AST.getSourceManager();
1891 std::optional<Range> Nearby;
1892 auto Word =
1893 SpelledWord::touching(cantFail(sourceLocationInMainFile(SM, T.point())),
1894 AST.getTokens(), AST.getLangOpts());
1895 if (!Word) {
1896 ADD_FAILURE() << "No word at point! " << Test;
1897 continue;
1898 }
1899 if (const auto *Tok = findNearbyIdentifier(*Word, AST.getTokens()))
1900 Nearby = halfOpenToRange(SM, CharSourceRange::getCharRange(
1901 Tok->location(), Tok->endLocation()));
1902 if (T.ranges().empty())
1903 EXPECT_THAT(Nearby, Eq(std::nullopt)) << Test;
1904 else
1905 EXPECT_EQ(Nearby, T.range()) << Test;
1906 }
1907}
1908
1909TEST(FindImplementations, Inheritance) {
1910 llvm::StringRef Test = R"cpp(
1911 struct $0^Base {
1912 virtual void F$1^oo();
1913 void C$4^oncrete();
1914 };
1915 struct $0[[Child1]] : Base {
1916 void $1[[Fo$3^o]]() override;
1917 virtual void B$2^ar();
1918 void Concrete(); // No implementations for concrete methods.
1919 };
1920 struct $0[[Child2]] : Child1 {
1921 void $1[[$3[[Foo]]]]() override;
1922 void $2[[Bar]]() override;
1923 };
1924 void FromReference() {
1925 $0^Base* B;
1926 B->Fo$1^o();
1927 B->C$4^oncrete();
1928 &Base::Fo$1^o;
1929 Child1 * C1;
1930 C1->B$2^ar();
1931 C1->Fo$3^o();
1932 }
1933 // CRTP should work.
1934 template<typename T>
1935 struct $5^TemplateBase {};
1936 struct $5[[Child3]] : public TemplateBase<Child3> {};
1937
1938 // Local classes.
1939 void LocationFunction() {
1940 struct $0[[LocalClass1]] : Base {
1941 void $1[[Foo]]() override;
1942 };
1943 struct $6^LocalBase {
1944 virtual void $7^Bar();
1945 };
1946 struct $6[[LocalClass2]]: LocalBase {
1947 void $7[[Bar]]() override;
1948 };
1949 }
1950 )cpp";
1951
1952 Annotations Code(Test);
1953 auto TU = TestTU::withCode(Code.code());
1954 auto AST = TU.build();
1955 auto Index = TU.index();
1956 for (StringRef Label : {"0", "1", "2", "3", "4", "5", "6", "7"}) {
1957 for (const auto &Point : Code.points(Label)) {
1958 EXPECT_THAT(findImplementations(AST, Point, Index.get()),
1959 UnorderedPointwise(declRange(), Code.ranges(Label)))
1960 << Code.code() << " at " << Point << " for Label " << Label;
1961 }
1962 }
1963}
1964
1965TEST(FindImplementations, InheritanceRecursion) {
1966 // Make sure inheritance is followed, but does not diverge.
1967 llvm::StringRef Test = R"cpp(
1968 template <int>
1969 struct Ev^en;
1970
1971 template <int>
1972 struct Odd;
1973
1974 template <>
1975 struct Even<0> {
1976 static const bool value = true;
1977 };
1978
1979 template <>
1980 struct Odd<0> {
1981 static const bool value = false;
1982 };
1983
1984 template <int I>
1985 struct [[Even]] : Odd<I - 1> {};
1986
1987 template <int I>
1988 struct [[Odd]] : Even<I - 1> {};
1989
1990 constexpr bool Answer = Even<42>::value;
1991 )cpp";
1992
1993 Annotations Code(Test);
1994 auto TU = TestTU::withCode(Code.code());
1995 auto AST = TU.build();
1996 auto Index = TU.index();
1997 EXPECT_THAT(findImplementations(AST, Code.point(), Index.get()),
1998 UnorderedPointwise(defRange(), Code.ranges()));
1999}
2000
2001TEST(FindImplementations, InheritanceObjC) {
2002 llvm::StringRef Test = R"objc(
2003 @interface $base^Base
2004 - (void)fo$foo^o;
2005 @end
2006 @protocol Protocol
2007 - (void)$protocol^protocol;
2008 @end
2009 @interface $ChildDecl[[Child]] : Base <Protocol>
2010 - (void)concrete;
2011 - (void)$fooDecl[[foo]];
2012 @end
2013 @implementation $ChildDef[[Child]]
2014 - (void)concrete {}
2015 - (void)$fooDef[[foo]] {}
2016 - (void)$protocolDef[[protocol]] {}
2017 @end
2018 )objc";
2019
2020 Annotations Code(Test);
2021 auto TU = TestTU::withCode(Code.code());
2022 TU.ExtraArgs.push_back("-xobjective-c++");
2023 auto AST = TU.build();
2024 auto Index = TU.index();
2025 EXPECT_THAT(findImplementations(AST, Code.point("base"), Index.get()),
2026 UnorderedElementsAre(sym("Child", Code.range("ChildDecl"),
2027 Code.range("ChildDef"))));
2028 EXPECT_THAT(findImplementations(AST, Code.point("foo"), Index.get()),
2029 UnorderedElementsAre(
2030 sym("foo", Code.range("fooDecl"), Code.range("fooDef"))));
2031 EXPECT_THAT(findImplementations(AST, Code.point("protocol"), Index.get()),
2032 UnorderedElementsAre(sym("protocol", Code.range("protocolDef"),
2033 Code.range("protocolDef"))));
2034}
2035
2036TEST(FindImplementations, CaptureDefinition) {
2037 llvm::StringRef Test = R"cpp(
2038 struct Base {
2039 virtual void F^oo();
2040 };
2041 struct Child1 : Base {
2042 void $Decl[[Foo]]() override;
2043 };
2044 struct Child2 : Base {
2045 void $Child2[[Foo]]() override;
2046 };
2047 void Child1::$Def[[Foo]]() { /* Definition */ }
2048 )cpp";
2049 Annotations Code(Test);
2050 auto TU = TestTU::withCode(Code.code());
2051 auto AST = TU.build();
2052 EXPECT_THAT(
2053 findImplementations(AST, Code.point(), TU.index().get()),
2054 UnorderedElementsAre(sym("Foo", Code.range("Decl"), Code.range("Def")),
2055 sym("Foo", Code.range("Child2"), std::nullopt)))
2056 << Test;
2057}
2058
2059TEST(FindType, All) {
2060 Annotations HeaderA(R"cpp(
2061 struct $Target[[Target]] { operator int() const; };
2062 struct Aggregate { Target a, b; };
2063 Target t;
2064 Target make();
2065
2066 template <typename T> struct $smart_ptr[[smart_ptr]] {
2067 T& operator*();
2068 T* operator->();
2069 T* get();
2070 };
2071 )cpp");
2072 auto TU = TestTU::withHeaderCode(HeaderA.code());
2073 for (const llvm::StringRef Case : {
2074 "str^uct Target;",
2075 "T^arget x;",
2076 "Target ^x;",
2077 "a^uto x = Target{};",
2078 "namespace m { Target tgt; } auto x = m^::tgt;",
2079 "Target funcCall(); auto x = ^funcCall();",
2080 "Aggregate a = { {}, ^{} };",
2081 "Aggregate a = { ^.a=t, };",
2082 "struct X { Target a; X() : ^a() {} };",
2083 "^using T = Target; ^T foo();",
2084 "^template <int> Target foo();",
2085 "void x() { try {} ^catch(Target e) {} }",
2086 "void x() { ^throw t; }",
2087 "int x() { ^return t; }",
2088 "void x() { ^switch(t) {} }",
2089 "void x() { ^delete (Target*)nullptr; }",
2090 "Target& ^tref = t;",
2091 "void x() { ^if (t) {} }",
2092 "void x() { ^while (t) {} }",
2093 "void x() { ^do { } while (t); }",
2094 "void x() { ^make(); }",
2095 "void x(smart_ptr<Target> &t) { t.^get(); }",
2096 "^auto x = []() { return t; };",
2097 "Target* ^tptr = &t;",
2098 "Target ^tarray[3];",
2099 }) {
2100 Annotations A(Case);
2101 TU.Code = A.code().str();
2102 ParsedAST AST = TU.build();
2103
2104 ASSERT_GT(A.points().size(), 0u) << Case;
2105 for (auto Pos : A.points())
2106 EXPECT_THAT(findType(AST, Pos, nullptr),
2107 ElementsAre(
2108 sym("Target", HeaderA.range("Target"), HeaderA.range("Target"))))
2109 << Case;
2110 }
2111
2112 for (const llvm::StringRef Case : {
2113 "smart_ptr<Target> ^tsmart;",
2114 }) {
2115 Annotations A(Case);
2116 TU.Code = A.code().str();
2117 ParsedAST AST = TU.build();
2118
2119 EXPECT_THAT(findType(AST, A.point(), nullptr),
2120 UnorderedElementsAre(
2121 sym("Target", HeaderA.range("Target"), HeaderA.range("Target")),
2122 sym("smart_ptr", HeaderA.range("smart_ptr"), HeaderA.range("smart_ptr"))
2123 ))
2124 << Case;
2125 }
2126}
2127
2128TEST(FindType, Definition) {
2129 Annotations A(R"cpp(
2130 class $decl[[X]];
2131 X *$x^x;
2132 class $def[[X]] {};
2133
2134 template <class T>
2135 concept $Concept^True = true;
2136 )cpp");
2137 auto TU = TestTU::withCode(A.code().str());
2138 TU.ExtraArgs.push_back("-std=c++20");
2139 ParsedAST AST = TU.build();
2140
2141 EXPECT_THAT(findType(AST, A.point("x"), nullptr),
2142 ElementsAre(sym("X", A.range("decl"), A.range("def"))));
2143 EXPECT_THAT(findType(AST, A.point("Concept"), nullptr), IsEmpty());
2144}
2145
2146TEST(FindType, Index) {
2147 Annotations Def(R"cpp(
2148 // This definition is only available through the index.
2149 class [[X]] {};
2150 )cpp");
2151 TestTU DefTU = TestTU::withHeaderCode(Def.code());
2152 DefTU.HeaderFilename = "def.h";
2153 auto DefIdx = DefTU.index();
2154
2155 Annotations A(R"cpp(
2156 class [[X]];
2157 X *^x;
2158 )cpp");
2159 auto TU = TestTU::withCode(A.code().str());
2160 ParsedAST AST = TU.build();
2161
2162 EXPECT_THAT(findType(AST, A.point(), DefIdx.get()),
2163 ElementsAre(sym("X", A.range(), Def.range())));
2164}
2165
2166void checkFindRefs(llvm::StringRef Test, bool UseIndex = false) {
2167 Annotations T(Test);
2168 auto TU = TestTU::withCode(T.code());
2169 TU.ExtraArgs.push_back("-std=c++20");
2170 TU.ExtraArgs.push_back("-xobjective-c++");
2171
2172 auto AST = TU.build();
2173 std::vector<Matcher<ReferencesResult::Reference>> ExpectedLocations;
2174 for (const auto &[R, Context] : T.rangesWithPayload())
2175 ExpectedLocations.push_back(
2176 AllOf(rangeIs(R), containerIs(Context), attrsAre(0u)));
2177 // $def is actually shorthand for both definition and declaration.
2178 // If we have cases that are definition-only, we should change this.
2179 for (const auto &[R, Context] : T.rangesWithPayload("def"))
2180 ExpectedLocations.push_back(AllOf(rangeIs(R), containerIs(Context),
2183 for (const auto &[R, Context] : T.rangesWithPayload("decl"))
2184 ExpectedLocations.push_back(AllOf(rangeIs(R), containerIs(Context),
2186 for (const auto &[R, Context] : T.rangesWithPayload("overridedecl"))
2187 ExpectedLocations.push_back(AllOf(
2188 rangeIs(R), containerIs(Context),
2190 for (const auto &[R, Context] : T.rangesWithPayload("overridedef"))
2191 ExpectedLocations.push_back(AllOf(rangeIs(R), containerIs(Context),
2195 for (const auto &P : T.points()) {
2196 EXPECT_THAT(findReferences(AST, P, 0, UseIndex ? TU.index().get() : nullptr,
2197 /*AddContext*/ true)
2198 .References,
2199 UnorderedElementsAreArray(ExpectedLocations))
2200 << "Failed for Refs at " << P << "\n"
2201 << Test;
2202 }
2203}
2204
2205TEST(FindReferences, WithinAST) {
2206 const char *Tests[] = {
2207 R"cpp(// Local variable
2208 int main() {
2209 int $def(main)[[foo]];
2210 $(main)[[^foo]] = 2;
2211 int test1 = $(main)[[foo]];
2212 }
2213 )cpp",
2214
2215 R"cpp(// Struct
2216 namespace ns1 {
2217 struct $def(ns1)[[Foo]] {};
2218 } // namespace ns1
2219 int main() {
2220 ns1::$(main)[[Fo^o]]* Params;
2221 }
2222 )cpp",
2223
2224 R"cpp(// Forward declaration
2225 class $decl[[Foo]];
2226 class $def[[Foo]] {};
2227 int main() {
2228 $(main)[[Fo^o]] foo;
2229 }
2230 )cpp",
2231
2232 R"cpp(// Function
2233 int $def[[foo]](int) { return 0; }
2234 int main() {
2235 auto *X = &$(main)[[^foo]];
2236 $(main)[[foo]](42);
2237 }
2238 )cpp",
2239
2240 R"cpp(// Field
2241 struct Foo {
2242 int $def(Foo)[[foo]];
2243 Foo() : $(Foo::Foo)[[foo]](0) {}
2244 };
2245 int main() {
2246 Foo f;
2247 f.$(main)[[f^oo]] = 1;
2248 }
2249 )cpp",
2250
2251 R"cpp(// Method call
2252 struct Foo { int $decl(Foo)[[foo]](); };
2253 int Foo::$def(Foo)[[foo]]() { return 0; }
2254 int main() {
2255 Foo f;
2256 f.$(main)[[^foo]]();
2257 }
2258 )cpp",
2259
2260 R"cpp(// Constructor
2261 struct Foo {
2262 $decl(Foo)[[F^oo]](int);
2263 };
2264 void foo() {
2265 Foo f = $(foo)[[Foo]](42);
2266 }
2267 )cpp",
2268
2269 R"cpp(// Typedef
2270 typedef int $def[[Foo]];
2271 int main() {
2272 $(main)[[^Foo]] bar;
2273 }
2274 )cpp",
2275
2276 R"cpp(// Namespace
2277 namespace $decl[[ns]] { // FIXME: def?
2278 struct Foo {};
2279 } // namespace ns
2280 int main() { $(main)[[^ns]]::Foo foo; }
2281 )cpp",
2282
2283 R"cpp(// Macros
2284 #define TYPE(X) X
2285 #define FOO Foo
2286 #define CAT(X, Y) X##Y
2287 class $def[[Fo^o]] {};
2288 void test() {
2289 TYPE($(test)[[Foo]]) foo;
2290 $(test)[[FOO]] foo2;
2291 TYPE(TYPE($(test)[[Foo]])) foo3;
2292 $(test)[[CAT]](Fo, o) foo4;
2293 }
2294 )cpp",
2295
2296 R"cpp(// Macros
2297 #define $def[[MA^CRO]](X) (X+1)
2298 void test() {
2299 int x = $[[MACRO]]($[[MACRO]](1));
2300 }
2301 )cpp",
2302
2303 R"cpp(// Macro outside preamble
2304 int breakPreamble;
2305 #define $def[[MA^CRO]](X) (X+1)
2306 void test() {
2307 int x = $[[MACRO]]($[[MACRO]](1));
2308 }
2309 )cpp",
2310
2311 R"cpp(
2312 int $def[[v^ar]] = 0;
2313 void foo(int s = $(foo)[[var]]);
2314 )cpp",
2315
2316 R"cpp(
2317 template <typename T>
2318 class $def[[Fo^o]] {};
2319 void func($(func)[[Foo]]<int>);
2320 )cpp",
2321
2322 R"cpp(
2323 template <typename T>
2324 class $def[[Foo]] {};
2325 void func($(func)[[Fo^o]]<int>);
2326 )cpp",
2327 R"cpp(// Not touching any identifiers.
2328 struct Foo {
2329 $def(Foo)[[~]]Foo() {};
2330 };
2331 void foo() {
2332 Foo f;
2333 f.$(foo)[[^~]]Foo();
2334 }
2335 )cpp",
2336 R"cpp(// Lambda capture initializer
2337 void foo() {
2338 int $def(foo)[[w^aldo]] = 42;
2339 auto lambda = [x = $(foo)[[waldo]]](){};
2340 }
2341 )cpp",
2342 R"cpp(// Renaming alias
2343 template <typename> class Vector {};
2344 using $def[[^X]] = Vector<int>;
2345 $(x1)[[X]] x1;
2346 Vector<int> x2;
2347 Vector<double> y;
2348 )cpp",
2349 R"cpp(// Dependent code
2350 template <typename T> void $decl[[foo]](T t);
2351 template <typename T> void bar(T t) { $(bar)[[foo]](t); } // foo in bar is uninstantiated.
2352 void baz(int x) { $(baz)[[f^oo]](x); }
2353 )cpp",
2354 R"cpp(
2355 namespace ns {
2356 struct S{};
2357 void $decl(ns)[[foo]](S s);
2358 } // namespace ns
2359 template <typename T> void foo(T t);
2360 // FIXME: Maybe report this foo as a ref to ns::foo (because of ADL)
2361 // when bar<ns::S> is instantiated?
2362 template <typename T> void bar(T t) { foo(t); }
2363 void baz(int x) {
2364 ns::S s;
2365 bar<ns::S>(s);
2366 $(baz)[[f^oo]](s);
2367 }
2368 )cpp",
2369 R"cpp(// unresolved member expression
2370 struct Foo {
2371 template <typename T> void $decl(Foo)[[b^ar]](T t);
2372 };
2373 template <typename T> void test(Foo F, T t) {
2374 F.$(test)[[bar]](t);
2375 }
2376 )cpp",
2377
2378 // Enum base
2379 R"cpp(
2380 typedef int $def[[MyTypeD^ef]];
2381 enum MyEnum : $(MyEnum)[[MyTy^peDef]] { };
2382 )cpp",
2383 R"cpp(
2384 typedef int $def[[MyType^Def]];
2385 enum MyEnum : $(MyEnum)[[MyTypeD^ef]];
2386 )cpp",
2387 R"cpp(
2388 using $def[[MyTypeD^ef]] = int;
2389 enum MyEnum : $(MyEnum)[[MyTy^peDef]] { };
2390 )cpp",
2391 // UDL
2392 R"cpp(
2393 bool $decl[[operator]]"" _u^dl(unsigned long long value);
2394 bool x = $(x)[[1_udl]];
2395 )cpp",
2396 R"cpp(
2397 struct S {
2398 public:
2399 static void $decl(S)[[operator]] delete(void *);
2400 static void deleteObject(S *S) {
2401 $(S::deleteObject)[[de^lete]] S;
2402 }
2403 };
2404 )cpp",
2405 // Array designators
2406 R"cpp(
2407 const int $def[[F^oo]] = 0;
2408 int Bar[] = {
2409 [$(Bar)[[F^oo]]...$(Bar)[[Fo^o]] + 1] = 0,
2410 [$(Bar)[[^Foo]] + 2] = 1
2411 };
2412 )cpp",
2413 // Field of pointer-to-member type
2414 R"cpp(
2415 struct S { void foo(); };
2416 struct A {
2417 void (S::*$def(A)[[fi^eld]])();
2418 };
2419 void bar(A& a, S& s) {
2420 (s.*(a.$(bar)[[field]]))();
2421 }
2422 )cpp"};
2423 for (const char *Test : Tests)
2424 checkFindRefs(Test);
2425}
2426
2427TEST(FindReferences, ConceptsWithinAST) {
2428 constexpr llvm::StringLiteral Code = R"cpp(
2429 template <class T>
2430 concept $def[[IsSmal^l]] = sizeof(T) <= 8;
2431
2432 template <class T>
2433 concept IsSmallPtr = requires(T x) {
2434 { *x } -> $(IsSmallPtr)[[IsSmal^l]];
2435 };
2436
2437 $(i)[[IsSmall]] auto i = 'c';
2438 template<$(foo)[[IsSmal^l]] U> void foo();
2439 template<class U> void bar() requires $(bar)[[IsSmal^l]]<U>;
2440 template<class U> requires $(baz)[[IsSmal^l]]<U> void baz();
2441 static_assert([[IsSma^ll]]<char>);
2442 )cpp";
2443 checkFindRefs(Code);
2444}
2445
2446TEST(FindReferences, ConceptReq) {
2447 constexpr llvm::StringLiteral Code = R"cpp(
2448 template <class T>
2449 concept $def[[IsSmal^l]] = sizeof(T) <= 8;
2450
2451 template <class T>
2452 concept IsSmallPtr = requires(T x) {
2453 { *x } -> $(IsSmallPtr)[[IsSmal^l]];
2454 };
2455 )cpp";
2456 checkFindRefs(Code);
2457}
2458
2459TEST(FindReferences, RequiresExprParameters) {
2460 constexpr llvm::StringLiteral Code = R"cpp(
2461 template <class T>
2462 concept IsSmall = sizeof(T) <= 8;
2463
2464 template <class T>
2465 concept IsSmallPtr = requires(T $def[[^x]]) {
2466 { *$(IsSmallPtr)[[^x]] } -> IsSmall;
2467 };
2468 )cpp";
2469 checkFindRefs(Code);
2470}
2471
2472TEST(FindReferences, IncludeOverrides) {
2473 llvm::StringRef Test =
2474 R"cpp(
2475 class Base {
2476 public:
2477 virtu^al void $decl(Base)[[f^unc]]() ^= ^0;
2478 };
2479 class Derived : public Base {
2480 public:
2481 void $overridedecl(Derived::func)[[func]]() override;
2482 };
2483 void Derived::$overridedef[[func]]() {}
2484 class Derived2 : public Base {
2485 void $overridedef(Derived2::func)[[func]]() override {}
2486 };
2487 void test(Derived* D, Base* B) {
2488 D->func(); // No references to the overrides.
2489 B->$(test)[[func]]();
2490 })cpp";
2491 checkFindRefs(Test, /*UseIndex=*/true);
2492}
2493
2494TEST(FindReferences, IncludeOverridesObjC) {
2495 llvm::StringRef Test =
2496 R"objc(
2497 @interface Base
2498 - (void)$decl(Base)[[f^unc]];
2499 @end
2500 @interface Derived : Base
2501 - (void)$overridedecl(Derived::func)[[func]];
2502 @end
2503 @implementation Derived
2504 - (void)$overridedef[[func]] {}
2505 @end
2506 void test(Derived *derived, Base *base) {
2507 [derived func]; // No references to the overrides.
2508 [base $(test)[[func]]];
2509 })objc";
2510 checkFindRefs(Test, /*UseIndex=*/true);
2511}
2512
2513TEST(FindReferences, RefsToBaseMethod) {
2514 llvm::StringRef Test =
2515 R"cpp(
2516 class BaseBase {
2517 public:
2518 virtual void $(BaseBase)[[func]]();
2519 };
2520 class Base : public BaseBase {
2521 public:
2522 void $(Base)[[func]]() override;
2523 };
2524 class Derived : public Base {
2525 public:
2526 void $decl(Derived)[[fu^nc]]() over^ride;
2527 };
2528 void test(BaseBase* BB, Base* B, Derived* D) {
2529 // refs to overridden methods in complete type hierarchy are reported.
2530 BB->$(test)[[func]]();
2531 B->$(test)[[func]]();
2532 D->$(test)[[fu^nc]]();
2533 })cpp";
2534 checkFindRefs(Test, /*UseIndex=*/true);
2535}
2536
2537TEST(FindReferences, RefsToBaseMethodObjC) {
2538 llvm::StringRef Test =
2539 R"objc(
2540 @interface BaseBase
2541 - (void)$(BaseBase)[[func]];
2542 @end
2543 @interface Base : BaseBase
2544 - (void)$(Base)[[func]];
2545 @end
2546 @interface Derived : Base
2547 - (void)$decl(Derived)[[fu^nc]];
2548 @end
2549 void test(BaseBase *bb, Base *b, Derived *d) {
2550 // refs to overridden methods in complete type hierarchy are reported.
2551 [bb $(test)[[func]]];
2552 [b $(test)[[func]]];
2553 [d $(test)[[fu^nc]]];
2554 })objc";
2555 checkFindRefs(Test, /*UseIndex=*/true);
2556}
2557
2558TEST(FindReferences, MainFileReferencesOnly) {
2559 llvm::StringRef Test =
2560 R"cpp(
2561 void test() {
2562 int [[fo^o]] = 1;
2563 // refs not from main file should not be included.
2564 #include "foo.inc"
2565 })cpp";
2566
2567 Annotations Code(Test);
2568 auto TU = TestTU::withCode(Code.code());
2569 TU.AdditionalFiles["foo.inc"] = R"cpp(
2570 foo = 3;
2571 )cpp";
2572 auto AST = TU.build();
2573
2574 std::vector<Matcher<ReferencesResult::Reference>> ExpectedLocations;
2575 for (const auto &R : Code.ranges())
2576 ExpectedLocations.push_back(rangeIs(R));
2577 EXPECT_THAT(findReferences(AST, Code.point(), 0).References,
2578 ElementsAreArray(ExpectedLocations))
2579 << Test;
2580}
2581
2582TEST(FindReferences, ExplicitSymbols) {
2583 const char *Tests[] = {
2584 R"cpp(
2585 struct Foo { Foo* $decl(Foo)[[self]]() const; };
2586 void f() {
2587 Foo foo;
2588 if (Foo* T = foo.$(f)[[^self]]()) {} // Foo member call expr.
2589 }
2590 )cpp",
2591
2592 R"cpp(
2593 struct Foo { Foo(int); };
2594 Foo f() {
2595 int $def(f)[[b]];
2596 return $(f)[[^b]]; // Foo constructor expr.
2597 }
2598 )cpp",
2599
2600 R"cpp(
2601 struct Foo {};
2602 void g(Foo);
2603 Foo $decl[[f]]();
2604 void call() {
2605 g($(call)[[^f]]()); // Foo constructor expr.
2606 }
2607 )cpp",
2608
2609 R"cpp(
2610 void $decl[[foo]](int);
2611 void $decl[[foo]](double);
2612
2613 namespace ns {
2614 using ::$decl(ns)[[fo^o]];
2615 }
2616 )cpp",
2617
2618 R"cpp(
2619 struct X {
2620 operator bool();
2621 };
2622
2623 int test() {
2624 X $def(test)[[a]];
2625 $(test)[[a]].operator bool();
2626 if ($(test)[[a^]]) {} // ignore implicit conversion-operator AST node
2627 return 0;
2628 }
2629 )cpp",
2630 };
2631 for (const char *Test : Tests)
2632 checkFindRefs(Test);
2633}
2634
2635TEST(FindReferences, UsedSymbolsFromInclude) {
2636 const char *Tests[] = {
2637 R"cpp( [[#include ^"bar.h"]]
2638 #include <vector>
2639 int fstBar = [[bar1]]();
2640 int sndBar = [[bar2]]();
2641 [[Bar]] bar;
2642 int macroBar = [[BAR]];
2643 std::vector<int> vec;
2644 )cpp",
2645
2646 R"cpp([[#in^clude <vector>]]
2647 std::[[vector]]<int> vec;
2648 )cpp",
2649
2650 R"cpp(
2651 [[#include ^"udl_header.h"]]
2652 auto x = [[1_b]];
2653 )cpp",
2654 };
2655 for (const char *Test : Tests) {
2656 Annotations T(Test);
2657 auto TU = TestTU::withCode(T.code());
2658 TU.ExtraArgs.push_back("-std=c++20");
2659 TU.AdditionalFiles["bar.h"] = guard(R"cpp(
2660 #define BAR 5
2661 int bar1();
2662 int bar2();
2663 class Bar {};
2664 )cpp");
2665 TU.AdditionalFiles["system/vector"] = guard(R"cpp(
2666 namespace std {
2667 template<typename>
2668 class vector{};
2669 }
2670 )cpp");
2671 TU.AdditionalFiles["udl_header.h"] = guard(R"cpp(
2672 bool operator"" _b(unsigned long long value);
2673 )cpp");
2674 TU.ExtraArgs.push_back("-isystem" + testPath("system"));
2675
2676 auto AST = TU.build();
2677 std::vector<Matcher<ReferencesResult::Reference>> ExpectedLocations;
2678 for (const auto &R : T.ranges())
2679 ExpectedLocations.push_back(AllOf(rangeIs(R), attrsAre(0u)));
2680 for (const auto &P : T.points())
2681 EXPECT_THAT(findReferences(AST, P, 0).References,
2682 UnorderedElementsAreArray(ExpectedLocations))
2683 << "Failed for Refs at " << P << "\n"
2684 << Test;
2685 }
2686}
2687
2688TEST(FindReferences, NeedsIndexForSymbols) {
2689 const char *Header = "int foo();";
2690 Annotations Main("int main() { [[f^oo]](); }");
2691 TestTU TU;
2692 TU.Code = std::string(Main.code());
2693 TU.HeaderCode = Header;
2694 auto AST = TU.build();
2695
2696 // References in main file are returned without index.
2697 EXPECT_THAT(
2698 findReferences(AST, Main.point(), 0, /*Index=*/nullptr).References,
2699 ElementsAre(rangeIs(Main.range())));
2700 Annotations IndexedMain(R"cpp(
2701 int $decl[[foo]]() { return 42; }
2702 void bar() { $bar(bar)[[foo]](); }
2703 struct S { void bar() { $S(S::bar)[[foo]](); } };
2704 namespace N { void bar() { $N(N::bar)[[foo]](); } }
2705 )cpp");
2706
2707 // References from indexed files are included.
2708 TestTU IndexedTU;
2709 IndexedTU.Code = std::string(IndexedMain.code());
2710 IndexedTU.Filename = "Indexed.cpp";
2711 IndexedTU.HeaderCode = Header;
2712 EXPECT_THAT(
2713 findReferences(AST, Main.point(), 0, IndexedTU.index().get(),
2714 /*AddContext*/ true)
2715 .References,
2716 ElementsAre(
2717 rangeIs(Main.range()),
2718 AllOf(rangeIs(IndexedMain.range("decl")),
2721 AllOf(rangeIs(IndexedMain.range("bar")), containerIs("bar")),
2722 AllOf(rangeIs(IndexedMain.range("S")), containerIs("S::bar")),
2723 AllOf(rangeIs(IndexedMain.range("N")), containerIs("N::bar"))));
2724 auto LimitRefs =
2725 findReferences(AST, Main.point(), /*Limit*/ 1, IndexedTU.index().get());
2726 EXPECT_EQ(1u, LimitRefs.References.size());
2727 EXPECT_TRUE(LimitRefs.HasMore);
2728
2729 // Avoid indexed results for the main file. Use AST for the mainfile.
2730 TU.Code = ("\n\n" + Main.code()).str();
2731 EXPECT_THAT(findReferences(AST, Main.point(), 0, TU.index().get()).References,
2732 ElementsAre(rangeIs(Main.range())));
2733}
2734
2735TEST(FindReferences, NeedsIndexForMacro) {
2736 const char *Header = "#define MACRO(X) (X+1)";
2737 Annotations Main(R"cpp(
2738 int main() {
2739 int a = [[MA^CRO]](1);
2740 }
2741 )cpp");
2742 TestTU TU;
2743 TU.Code = std::string(Main.code());
2744 TU.HeaderCode = Header;
2745 auto AST = TU.build();
2746
2747 // References in main file are returned without index.
2748 EXPECT_THAT(
2749 findReferences(AST, Main.point(), 0, /*Index=*/nullptr).References,
2750 ElementsAre(rangeIs(Main.range())));
2751
2752 Annotations IndexedMain(R"cpp(
2753 int indexed_main() {
2754 int a = [[MACRO]](1);
2755 return 0;
2756 }
2757 )cpp");
2758
2759 // References from indexed files are included.
2760 TestTU IndexedTU;
2761 IndexedTU.Code = std::string(IndexedMain.code());
2762 IndexedTU.Filename = "Indexed.cpp";
2763 IndexedTU.HeaderCode = Header;
2764 EXPECT_THAT(
2765 findReferences(AST, Main.point(), 0, IndexedTU.index().get()).References,
2766 ElementsAre(rangeIs(Main.range()), rangeIs(IndexedMain.range())));
2767 auto LimitRefs =
2768 findReferences(AST, Main.point(), /*Limit*/ 1, IndexedTU.index().get());
2769 EXPECT_EQ(1u, LimitRefs.References.size());
2770 EXPECT_TRUE(LimitRefs.HasMore);
2771}
2772
2773TEST(FindReferences, NoQueryForLocalSymbols) {
2774 struct RecordingIndex : public MemIndex {
2775 mutable std::optional<llvm::DenseSet<SymbolID>> RefIDs;
2776 bool refs(const RefsRequest &Req,
2777 llvm::function_ref<void(const Ref &)>) const override {
2778 RefIDs = Req.IDs;
2779 return false;
2780 }
2781 };
2782
2783 struct Test {
2784 StringRef AnnotatedCode;
2785 bool WantQuery;
2786 } Tests[] = {
2787 {"int ^x;", true},
2788 // For now we don't assume header structure which would allow skipping.
2789 {"namespace { int ^x; }", true},
2790 {"static int ^x;", true},
2791 // Anything in a function certainly can't be referenced though.
2792 {"void foo() { int ^x; }", false},
2793 {"void foo() { struct ^x{}; }", false},
2794 {"auto lambda = []{ int ^x; };", false},
2795 };
2796 for (Test T : Tests) {
2797 Annotations File(T.AnnotatedCode);
2798 RecordingIndex Rec;
2799 auto AST = TestTU::withCode(File.code()).build();
2800 findReferences(AST, File.point(), 0, &Rec);
2801 if (T.WantQuery)
2802 EXPECT_NE(Rec.RefIDs, std::nullopt) << T.AnnotatedCode;
2803 else
2804 EXPECT_EQ(Rec.RefIDs, std::nullopt) << T.AnnotatedCode;
2805 }
2806}
2807
2808TEST(FindReferences, ConstructorForwardingInAST) {
2809 Annotations Main(R"cpp(
2810 namespace std {
2811 template <class T> T &&forward(T &t);
2812 template <class T, class... Args> T *make_unique(Args &&...args) {
2813 return new T(std::forward<Args>(args)...);
2814 }
2815 }
2816
2817 struct Test {
2818 $Constructor[[T^est]](){}
2819 };
2820
2821 int main() {
2822 auto a = std::$Caller[[make_unique]]<Test>();
2823 }
2824 )cpp");
2825 TestTU TU;
2826 TU.Code = std::string(Main.code());
2827 auto AST = TU.build();
2828
2829 EXPECT_THAT(findReferences(AST, Main.point(), 0).References,
2830 ElementsAre(rangeIs(Main.range("Constructor")),
2831 rangeIs(Main.range("Caller"))));
2832}
2833
2834TEST(FindReferences, ConstructorForwardingInASTChained) {
2835 Annotations Main(R"cpp(
2836 namespace std {
2837 template <class T> T &&forward(T &t);
2838 template <class T, class... Args> T *make_unique(Args &&...args) {
2839 return new T(forward<Args>(args)...);
2840 }
2841 template <class T, class... Args> T *make_unique2(Args &&...args) {
2842 return make_unique<T>(forward<Args>(args)...);
2843 }
2844 template <class T, class... Args> T *make_unique3(Args &&...args) {
2845 return make_unique2<T>(forward<Args>(args)...);
2846 }
2847 }
2848
2849 struct Test {
2850 $Constructor[[T^est]](){}
2851 };
2852
2853 int main() {
2854 auto a = std::$Caller[[make_unique3]]<Test>();
2855 }
2856 )cpp");
2857 TestTU TU;
2858 TU.Code = std::string(Main.code());
2859 auto AST = TU.build();
2860
2861 EXPECT_THAT(findReferences(AST, Main.point(), 0).References,
2862 ElementsAre(rangeIs(Main.range("Constructor")),
2863 rangeIs(Main.range("Caller"))));
2864}
2865
2866TEST(FindReferences, ConstructorForwardingInIndex) {
2867 Annotations Header(R"cpp(
2868 namespace std {
2869 template <class T> T &&forward(T &t);
2870 template <class T, class... Args> T *make_unique(Args &&...args) {
2871 return new T(std::forward<Args>(args)...);
2872 }
2873 }
2874 struct Test {
2875 [[T^est]](){}
2876 };
2877 )cpp");
2878 Annotations Main(R"cpp(
2879 #include "header.hpp"
2880 int main() {
2881 auto a = std::[[make_unique]]<Test>();
2882 }
2883 )cpp");
2884 TestWorkspace TW;
2885 TW.addSource("header.hpp", Header.code());
2886 TW.addMainFile("main.cpp", Main.code());
2887 auto AST = TW.openFile("header.hpp").value();
2888 auto Index = TW.index();
2889
2890 EXPECT_THAT(
2891 findReferences(AST, Header.point(), 0, Index.get(),
2892 /*AddContext*/ true)
2893 .References,
2894 ElementsAre(
2895 AllOf(rangeIs(Header.range()), fileIs(testPath("header.hpp"))),
2896 AllOf(rangeIs(Main.range()), fileIs(testPath("main.cpp")))));
2897}
2898
2899TEST(FindReferences, TemplatedConstructorForwarding) {
2900 Annotations Main(R"cpp(
2901 namespace std {
2902 template <class T> T &&forward(T &t);
2903 template <class T, class... Args> T *make_unique(Args &&...args) {
2904 return new T(std::forward<Args>(args)...);
2905 }
2906 }
2907
2908 struct Waldo {
2909 template <typename T>
2910 $Constructor[[W$Waldo^aldo]](T);
2911 };
2912 template <typename T>
2913 struct Waldo2 {
2914 $Constructor2[[W$Waldo2^aldo2]](int);
2915 };
2916 struct S {};
2917
2918 int main() {
2919 S s;
2920 Waldo $Caller[[w]](s);
2921 std::$ForwardedCaller[[make_unique]]<Waldo>(s);
2922
2923 Waldo2<int> $Caller2[[w2]](42);
2924 std::$ForwardedCaller2[[make_unique]]<Waldo2<int>>(42);
2925 }
2926 )cpp");
2927 TestTU TU;
2928 TU.Code = std::string(Main.code());
2929 auto AST = TU.build();
2930
2931 EXPECT_THAT(findReferences(AST, Main.point("Waldo"), 0).References,
2932 ElementsAre(rangeIs(Main.range("Constructor")),
2933 rangeIs(Main.range("Caller")),
2934 rangeIs(Main.range("ForwardedCaller"))));
2935
2936 EXPECT_THAT(findReferences(AST, Main.point("Waldo2"), 0).References,
2937 ElementsAre(rangeIs(Main.range("Constructor2")),
2938 rangeIs(Main.range("Caller2")),
2939 rangeIs(Main.range("ForwardedCaller2"))));
2940}
2941
2942TEST(GetNonLocalDeclRefs, All) {
2943 struct Case {
2944 llvm::StringRef AnnotatedCode;
2945 std::vector<std::string> ExpectedDecls;
2946 } Cases[] = {
2947 {
2948 // VarDecl and ParamVarDecl
2949 R"cpp(
2950 void bar();
2951 void ^foo(int baz) {
2952 int x = 10;
2953 bar();
2954 })cpp",
2955 {"bar"},
2956 },
2957 {
2958 // Method from class
2959 R"cpp(
2960 class Foo { public: void foo(); };
2961 class Bar {
2962 void foo();
2963 void bar();
2964 };
2965 void Bar::^foo() {
2966 Foo f;
2967 bar();
2968 f.foo();
2969 })cpp",
2970 {"Bar", "Bar::bar", "Foo", "Foo::foo"},
2971 },
2972 {
2973 // Local types
2974 R"cpp(
2975 void ^foo() {
2976 class Foo { public: void foo() {} };
2977 class Bar { public: void bar() {} };
2978 Foo f;
2979 Bar b;
2980 b.bar();
2981 f.foo();
2982 })cpp",
2983 {},
2984 },
2985 {
2986 // Template params
2987 R"cpp(
2988 template <typename T, template<typename> class Q>
2989 void ^foo() {
2990 T x;
2991 Q<T> y;
2992 })cpp",
2993 {},
2994 },
2995 };
2996 for (const Case &C : Cases) {
2997 Annotations File(C.AnnotatedCode);
2998 auto AST = TestTU::withCode(File.code()).build();
2999 SourceLocation SL = llvm::cantFail(
3000 sourceLocationInMainFile(AST.getSourceManager(), File.point()));
3001
3002 const FunctionDecl *FD =
3003 llvm::dyn_cast<FunctionDecl>(&findDecl(AST, [SL](const NamedDecl &ND) {
3004 return ND.getLocation() == SL && llvm::isa<FunctionDecl>(ND);
3005 }));
3006 ASSERT_NE(FD, nullptr);
3007
3008 auto NonLocalDeclRefs = getNonLocalDeclRefs(AST, FD);
3009 std::vector<std::string> Names;
3010 for (const Decl *D : NonLocalDeclRefs) {
3011 if (const auto *ND = llvm::dyn_cast<NamedDecl>(D))
3012 Names.push_back(ND->getQualifiedNameAsString());
3013 }
3014 EXPECT_THAT(Names, UnorderedElementsAreArray(C.ExpectedDecls))
3015 << File.code();
3016 }
3017}
3018
3019TEST(DocumentLinks, All) {
3020 Annotations MainCpp(R"cpp(
3021 #define HEADER_AA "faa.h"
3022 #define HEADER_BB "fbb.h"
3023 #define GET_HEADER(X) HEADER_ ## X
3024
3025 #/*comments*/include /*comments*/ $foo[["foo.h"]] //more comments
3026 int end_of_preamble = 0;
3027 #include $bar[[<bar.h>]]
3028 #include $AA[[GET_HEADER]](AA) // Some comment !
3029 # /* What about */ \
3030 include /* multiple line */ \
3031 $BB[[GET_HEADER]]( /* statements ? */ \
3032 BB /* :) */ )
3033 )cpp");
3034
3035 TestTU TU;
3036 TU.Code = std::string(MainCpp.code());
3037 TU.AdditionalFiles = {
3038 {"faa.h", ""}, {"fbb.h", ""}, {"foo.h", ""}, {"bar.h", ""}};
3039 TU.ExtraArgs = {"-isystem."};
3040 auto AST = TU.build();
3041
3042 EXPECT_THAT(
3044 ElementsAre(
3045 DocumentLink({MainCpp.range("foo"),
3046 URIForFile::canonicalize(testPath("foo.h"), "")}),
3047 DocumentLink({MainCpp.range("bar"),
3048 URIForFile::canonicalize(testPath("bar.h"), "")}),
3049 DocumentLink({MainCpp.range("AA"),
3050 URIForFile::canonicalize(testPath("faa.h"), "")}),
3051 DocumentLink({MainCpp.range("BB"),
3052 URIForFile::canonicalize(testPath("fbb.h"), "")})));
3053}
3054
3055} // namespace
3056} // namespace clangd
3057} // 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:354
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:2191
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:94
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:2536
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