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