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