1 //===-- XRefsTests.cpp ---------------------------*- C++ -*--------------===//
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
7 //===----------------------------------------------------------------------===//
8 #include "Annotations.h"
10 #include "ParsedAST.h"
12 #include "SourceCode.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"
35 using ::testing::AllOf
;
36 using ::testing::Contains
;
37 using ::testing::ElementsAre
;
39 using ::testing::IsEmpty
;
40 using ::testing::Matcher
;
42 using ::testing::UnorderedElementsAre
;
43 using ::testing::UnorderedElementsAreArray
;
44 using ::testing::UnorderedPointwise
;
46 std::string
guard(llvm::StringRef Code
) {
47 return "#pragma once\n" + Code
.str();
50 MATCHER_P2(FileRange
, File
, Range
, "") {
51 return Location
{URIForFile::canonicalize(File
, testRoot()), Range
} == arg
;
53 MATCHER(declRange
, "") {
54 const LocatedSymbol
&Sym
= ::testing::get
<0>(arg
);
55 const Range
&Range
= ::testing::get
<1>(arg
);
56 return Sym
.PreferredDeclaration
.range
== Range
;
59 // Extracts ranges from an annotated example, and constructs a matcher for a
60 // highlight set. Ranges should be named $read/$write as appropriate.
61 Matcher
<const std::vector
<DocumentHighlight
> &>
62 highlightsFrom(const Annotations
&Test
) {
63 std::vector
<DocumentHighlight
> Expected
;
64 auto Add
= [&](const Range
&R
, DocumentHighlightKind K
) {
65 Expected
.emplace_back();
66 Expected
.back().range
= R
;
67 Expected
.back().kind
= K
;
69 for (const auto &Range
: Test
.ranges())
70 Add(Range
, DocumentHighlightKind::Text
);
71 for (const auto &Range
: Test
.ranges("read"))
72 Add(Range
, DocumentHighlightKind::Read
);
73 for (const auto &Range
: Test
.ranges("write"))
74 Add(Range
, DocumentHighlightKind::Write
);
75 return UnorderedElementsAreArray(Expected
);
78 TEST(HighlightsTest
, All
) {
79 const char *Tests
[] = {
80 R
"cpp(// Local variable
83 $write[[^bonjour]] = 2;
84 int test1 = $read[[bonjour]];
91 static void foo([[MyClass]]*) {}
95 ns1::[[My^Class]]* Params;
102 [[foo]]([[foo]](42));
107 R
"cpp(// Function parameter in decl
108 void foo(int [[^bar]]);
110 R
"cpp(// Not touching any identifiers.
119 R
"cpp(// ObjC methods with split selectors.
121 +(void) [[x]]:(int)a [[y]]:(int)b;
124 +(void) [[x]]:(int)a [[y]]:(int)b {}
127 [Foo [[x]]:2 [[^y]]:4];
131 for (const char *Test
: Tests
) {
133 auto TU
= TestTU::withCode(T
.code());
134 TU
.ExtraArgs
.push_back("-xobjective-c++");
135 auto AST
= TU
.build();
136 EXPECT_THAT(findDocumentHighlights(AST
, T
.point()), highlightsFrom(T
))
141 TEST(HighlightsTest
, ControlFlow
) {
142 const char *Tests
[] = {
144 // Highlight same-function returns.
145 int fib(unsigned n) {
146 if (n <= 1) [[ret^urn]] 1;
147 [[return]] fib(n - 1) + fib(n - 2);
149 // Returns from other functions not highlighted.
150 auto Lambda = [] { return; };
151 class LocalClass { void x() { return; } };
156 #define FAIL() return false
159 if (n < 0) [[FAIL]]();
165 // Highlight loop control flow
168 [[^for]] (char c : "fruit loops
!") {
169 if (c == ' ') [[continue]];
171 if (c == '!') [[break]];
172 if (c == '?') [[return]] -1;
179 // Highlight loop and same-loop control flow
182 if (false) [[bre^ak]];
190 // Highlight switch for break (but not other breaks).
191 void describe(unsigned n) {
202 // Highlight case and exits for switch-break (but not other cases).
203 void describe(unsigned n) {
216 // Highlight exits and switch for case
217 void describe(unsigned n) {
230 // Highlight nothing for switch.
231 void describe(unsigned n) {
244 // FIXME: match exception type against catch blocks
246 try { // wrong: highlight try with matching catch
247 try { // correct: has no matching catch
249 } catch (int) { } // correct: catch doesn't match type
250 [[return]] -1; // correct: exits the matching catch
251 } catch (const char*) { } // wrong: highlight matching catch
252 [[return]] 42; // wrong: throw doesn't exit function
257 // Loop highlights goto exiting the loop, but not jumping within it.
268 for (const char *Test
: Tests
) {
270 auto TU
= TestTU::withCode(T
.code());
271 TU
.ExtraArgs
.push_back("-fexceptions"); // FIXME: stop testing on PS4.
272 auto AST
= TU
.build();
273 EXPECT_THAT(findDocumentHighlights(AST
, T
.point()), highlightsFrom(T
))
278 MATCHER_P3(sym
, Name
, Decl
, DefOrNone
, "") {
279 std::optional
<Range
> Def
= DefOrNone
;
280 if (Name
!= arg
.Name
) {
281 *result_listener
<< "Name is " << arg
.Name
;
284 if (Decl
!= arg
.PreferredDeclaration
.range
) {
285 *result_listener
<< "Declaration is "
286 << llvm::to_string(arg
.PreferredDeclaration
);
289 if (!Def
&& !arg
.Definition
)
291 if (Def
&& !arg
.Definition
) {
292 *result_listener
<< "Has no definition";
295 if (!Def
&& arg
.Definition
) {
296 *result_listener
<< "Definition is " << llvm::to_string(*arg
.Definition
);
299 if (arg
.Definition
->range
!= *Def
) {
300 *result_listener
<< "Definition is " << llvm::to_string(*arg
.Definition
);
306 MATCHER_P(sym
, Name
, "") { return arg
.Name
== Name
; }
308 MATCHER_P(rangeIs
, R
, "") { return arg
.Loc
.range
== R
; }
309 MATCHER_P(containerIs
, C
, "") {
310 return arg
.Loc
.containerName
.value_or("") == C
;
312 MATCHER_P(attrsAre
, A
, "") { return arg
.Attributes
== A
; }
313 MATCHER_P(hasID
, ID
, "") { return arg
.ID
== ID
; }
315 TEST(LocateSymbol
, WithIndex
) {
316 Annotations
SymbolHeader(R
"cpp(
317 class $forward[[Forward]];
318 class $foo[[Foo]] {};
322 inline void $f2[[f2]]() {}
324 Annotations
SymbolCpp(R
"cpp(
325 class $forward[[forward]] {};
330 TU
.Code
= std::string(SymbolCpp
.code());
331 TU
.HeaderCode
= std::string(SymbolHeader
.code());
332 auto Index
= TU
.index();
333 auto LocateWithIndex
= [&Index
](const Annotations
&Main
) {
334 auto AST
= TestTU::withCode(Main
.code()).build();
335 return clangd::locateSymbolAt(AST
, Main
.point(), Index
.get());
338 Annotations
Test(R
"cpp(// only declaration in AST.
344 EXPECT_THAT(LocateWithIndex(Test
),
345 ElementsAre(sym("f1", Test
.range(), SymbolCpp
.range("f1"))));
347 Test
= Annotations(R
"cpp(// definition in AST.
353 EXPECT_THAT(LocateWithIndex(Test
),
354 ElementsAre(sym("f1", SymbolHeader
.range("f1"), Test
.range())));
356 Test
= Annotations(R
"cpp(// forward declaration in AST.
360 EXPECT_THAT(LocateWithIndex(Test
),
361 ElementsAre(sym("Foo", Test
.range(), SymbolHeader
.range("foo"))));
363 Test
= Annotations(R
"cpp(// definition in AST.
364 class [[Forward]] {};
368 LocateWithIndex(Test
),
369 ElementsAre(sym("Forward", SymbolHeader
.range("forward"), Test
.range())));
372 TEST(LocateSymbol
, AnonymousStructFields
) {
373 auto Code
= Annotations(R
"cpp(
375 struct { int $1[[x]]; };
377 // Make sure the implicit base is skipped.
381 // Check that we don't skip explicit bases.
384 TestTU TU
= TestTU::withCode(Code
.code());
385 auto AST
= TU
.build();
386 EXPECT_THAT(locateSymbolAt(AST
, Code
.point("1"), TU
.index().get()),
387 UnorderedElementsAre(sym("x", Code
.range("1"), Code
.range("1"))));
389 locateSymbolAt(AST
, Code
.point("2"), TU
.index().get()),
390 UnorderedElementsAre(sym("Foo", Code
.range("2"), Code
.range("2"))));
393 TEST(LocateSymbol
, FindOverrides
) {
394 auto Code
= Annotations(R
"cpp(
396 virtual void $1[[fo^o]]() = 0;
398 class Bar : public Foo {
399 void $2[[foo]]() override;
402 TestTU TU
= TestTU::withCode(Code
.code());
403 auto AST
= TU
.build();
404 EXPECT_THAT(locateSymbolAt(AST
, Code
.point(), TU
.index().get()),
405 UnorderedElementsAre(sym("foo", Code
.range("1"), std::nullopt
),
406 sym("foo", Code
.range("2"), std::nullopt
)));
409 TEST(LocateSymbol
, WithIndexPreferredLocation
) {
410 Annotations
SymbolHeader(R
"cpp(
411 class $p[[Proto]] {};
412 void $f[[func]]() {};
415 TU
.HeaderCode
= std::string(SymbolHeader
.code());
416 TU
.HeaderFilename
= "x.proto"; // Prefer locations in codegen files.
417 auto Index
= TU
.index();
419 Annotations
Test(R
"cpp(// only declaration in AST.
420 // Shift to make range different.
429 auto AST
= TestTU::withCode(Test
.code()).build();
431 auto Locs
= clangd::locateSymbolAt(AST
, Test
.point("p"), Index
.get());
432 auto CodeGenLoc
= SymbolHeader
.range("p");
433 EXPECT_THAT(Locs
, ElementsAre(sym("Proto", CodeGenLoc
, CodeGenLoc
)));
436 auto Locs
= clangd::locateSymbolAt(AST
, Test
.point("f"), Index
.get());
437 auto CodeGenLoc
= SymbolHeader
.range("f");
438 EXPECT_THAT(Locs
, ElementsAre(sym("func", CodeGenLoc
, CodeGenLoc
)));
442 TEST(LocateSymbol
, All
) {
444 // $decl is the declaration location (if absent, no symbol is located)
445 // $def is the definition location (if absent, symbol has no definition)
446 // unnamed range becomes both $decl and $def.
447 const char *Tests
[] = {
460 R
"cpp(// Local variable
470 struct [[MyClass]] {};
473 ns1::My^Class* Params;
477 R
"cpp(// Function definition via pointer
484 R
"cpp(// Function declaration via call
485 int $decl[[foo]](int);
492 struct Foo { int [[x]]; };
499 R
"cpp(// Field, member initializer
506 R
"cpp(// Field, field designator
507 struct Foo { int [[x]]; };
509 Foo bar = { .^x = 2 };
514 struct Foo { int $decl[[x]](); };
522 typedef int $decl[[Foo]];
528 R
"cpp(// Template type parameter
529 template <typename [[T]]>
533 R
"cpp(// Template template type parameter
534 template <template<typename> class [[T]]>
535 void foo() { ^T<int> t; }
539 namespace $decl[[ns]] {
540 struct Foo { static void bar(); };
542 int main() { ^ns::Foo::bar(); }
546 class TTT { public: int a; };
547 #define [[FF]](S) if (int b = S.a) {}
554 R
"cpp(// Macro argument
556 #define ADDRESSOF(X) &X;
557 int *j = ADDRESSOF(^i);
559 R
"cpp(// Macro argument appearing multiple times in expansion
560 #define VALIDATE_TYPE(x) (void)x;
561 #define ASSERT(expr) \
563 VALIDATE_TYPE(expr); \
566 bool [[waldo]]() { return true; }
571 R
"cpp(// Symbol concatenated inside macro (not supported)
573 #define POINTER(X) p ## X;
574 int x = *POINTER(^i);
577 R
"cpp(// Forward class declaration
579 class $def[[Foo]] {};
583 R
"cpp(// Function declaration
586 void $def[[foo]]() {}
590 #define FF(name) class name##_Test {};
592 void f() { my^_Test a; }
596 #define FF() class [[Test]] {};
598 void f() { T^est a; }
601 R
"cpp(// explicit template specialization
602 template <typename T>
603 struct Foo { void bar() {} };
606 struct [[Foo]]<int> { void bar() {} };
614 R
"cpp(// implicit template specialization
615 template <typename T>
616 struct [[Foo]] { void bar() {} };
618 struct Foo<int> { void bar() {} };
625 R
"cpp(// partial template specialization
626 template <typename T>
627 struct Foo { void bar() {} };
628 template <typename T>
629 struct [[Foo]]<T*> { void bar() {} };
633 R
"cpp(// function template specializations
643 R
"cpp(// variable template decls
648 double [[var]]<int> = 10;
650 double y = va^r<int>;
653 R
"cpp(// No implicit constructors
665 X& $decl[[operator]]++();
673 struct S1 { void f(); };
674 struct S2 { S1 * $decl[[operator]]->(); };
680 R
"cpp(// Declaration of explicit template specialization
681 template <typename T>
682 struct $decl[[$def[[Foo]]]] {};
688 R
"cpp(// Declaration of partial template specialization
689 template <typename T>
690 struct $decl[[$def[[Foo]]]] {};
692 template <typename T>
696 R
"cpp(// Definition on ClassTemplateDecl
698 // Forward declaration.
702 template <typename T>
703 struct $def[[Foo]] {};
709 R
"cpp(// auto builtin type (not supported)
713 R
"cpp(// auto on lambda
718 R
"cpp(// auto on struct
726 R
"cpp(// decltype on struct
735 R
"cpp(// decltype(auto) on struct
742 ^decltype(auto) k = j;
745 R
"cpp(// auto on template class
746 template<typename T> class [[Foo]] {};
748 ^auto x = Foo<int>();
751 R
"cpp(// auto on template class with forward declared class
752 template<typename T> class [[Foo]] {};
758 R
"cpp(// auto on specialized template class
759 template<typename T> class Foo {};
760 template<> class [[Foo]]<int> {};
762 ^auto x = Foo<int>();
765 R
"cpp(// auto on initializer list.
769 class [[initializer_list]] {};
775 R
"cpp(// auto function return with trailing type
777 ^auto test() -> decltype(Bar()) {
782 R
"cpp(// decltype in trailing return type
784 auto test() -> ^decltype(Bar()) {
789 R
"cpp(// auto in function return
796 R
"cpp(// auto& in function return
804 R
"cpp(// auto* in function return
812 R
"cpp(// const auto& in function return
814 const ^auto& test() {
820 R
"cpp(// auto lambda param where there's a single instantiation
822 auto Lambda = [](^auto){ return 0; };
823 int x = Lambda(Bar{});
826 R
"cpp(// decltype(auto) in function return
828 ^decltype(auto) test() {
833 R
"cpp(// decltype of function with trailing return type.
835 auto test() -> decltype(Bar()) {
839 ^decltype(test()) i = test();
843 R
"cpp(// Override specifier jumps to overridden method
844 class Y { virtual void $decl[[a]]() = 0; };
845 class X : Y { void a() ^override {} };
848 R
"cpp(// Final specifier jumps to overridden method
849 class Y { virtual void $decl[[a]]() = 0; };
850 class X : Y { void a() ^final {} };
853 R
"cpp(// Heuristic resolution of dependent method
854 template <typename T>
859 template <typename T>
865 R
"cpp(// Heuristic resolution of dependent method via this->
866 template <typename T>
874 R
"cpp(// Heuristic resolution of dependent static method
875 template <typename T>
877 static void [[bar]]() {}
880 template <typename T>
886 R
"cpp(// Heuristic resolution of dependent method
887 // invoked via smart pointer
888 template <typename> struct S { void [[foo]]() {} };
889 template <typename T> struct unique_ptr {
892 template <typename T>
893 void test(unique_ptr<S<T>>& V) {
898 R
"cpp(// Heuristic resolution of dependent enumerator
899 template <typename T>
901 enum class E { [[A]], B };
907 typedef int $decl[[MyTypeDef]];
908 enum Foo : My^TypeDef {};
911 typedef int $decl[[MyTypeDef]];
912 enum Foo : My^TypeDef;
915 using $decl[[MyTypeDef]] = int;
916 enum Foo : My^TypeDef {};
921 @protocol $decl[[Dog]]
924 id<Do^g> getDoggo() {
934 @interface $decl[[Cat]] (Exte^nsion)
937 @implementation $def[[Cat]] (Extension)
949 R
"objc(// Prefer interface definition over forward declaration
951 @interface $decl[[Foo]]
960 @interface $decl[[Foo]]
962 @implementation $def[[Foo]]
969 R
"objc(// Method decl and definition for ObjC class.
971 - (void)$decl[[meow]];
974 - (void)$def[[meow]] {}
976 void makeNoise(Cat *kitty) {
981 R
"objc(// Method decl and definition for ObjC category.
984 @interface Dog (Play)
985 - (void)$decl[[runAround]];
987 @implementation Dog (Play)
988 - (void)$def[[runAround]] {}
990 void play(Dog *dog) {
995 R
"objc(// Method decl and definition for ObjC class extension.
999 - (void)$decl[[howl]];
1002 - (void)$def[[howl]] {}
1004 void play(Dog *dog) {
1008 for (const char *Test
: Tests
) {
1009 Annotations
T(Test
);
1010 std::optional
<Range
> WantDecl
;
1011 std::optional
<Range
> WantDef
;
1012 if (!T
.ranges().empty())
1013 WantDecl
= WantDef
= T
.range();
1014 if (!T
.ranges("decl").empty())
1015 WantDecl
= T
.range("decl");
1016 if (!T
.ranges("def").empty())
1017 WantDef
= T
.range("def");
1020 TU
.Code
= std::string(T
.code());
1022 TU
.ExtraArgs
.push_back("-xobjective-c++");
1024 auto AST
= TU
.build();
1025 auto Results
= locateSymbolAt(AST
, T
.point());
1028 EXPECT_THAT(Results
, IsEmpty()) << Test
;
1030 ASSERT_THAT(Results
, ::testing::SizeIs(1)) << Test
;
1031 EXPECT_EQ(Results
[0].PreferredDeclaration
.range
, *WantDecl
) << Test
;
1032 EXPECT_TRUE(Results
[0].ID
) << Test
;
1033 std::optional
<Range
> GotDef
;
1034 if (Results
[0].Definition
)
1035 GotDef
= Results
[0].Definition
->range
;
1036 EXPECT_EQ(WantDef
, GotDef
) << Test
;
1040 TEST(LocateSymbol
, ValidSymbolID
) {
1041 auto T
= Annotations(R
"cpp(
1042 #define MACRO(x, y) ((x) + (y))
1043 int add(int x, int y) { return $MACRO^MACRO(x, y); }
1044 int sum = $add^add(1, 2);
1047 TestTU TU
= TestTU::withCode(T
.code());
1048 auto AST
= TU
.build();
1049 auto Index
= TU
.index();
1050 EXPECT_THAT(locateSymbolAt(AST
, T
.point("add"), Index
.get()),
1051 ElementsAre(AllOf(sym("add"),
1052 hasID(getSymbolID(&findDecl(AST
, "add"))))));
1054 locateSymbolAt(AST
, T
.point("MACRO"), Index
.get()),
1055 ElementsAre(AllOf(sym("MACRO"),
1056 hasID(findSymbol(TU
.headerSymbols(), "MACRO").ID
))));
1059 TEST(LocateSymbol
, AllMulti
) {
1061 // $declN is the declaration location
1062 // $defN is the definition location (if absent, symbol has no definition)
1066 struct ExpectedRanges
{
1068 std::optional
<Range
> WantDef
;
1070 const char *Tests
[] = {
1072 @interface $decl0[[Cat]]
1074 @implementation $def0[[Cat]]
1076 @interface $decl1[[Ca^t]] (Extension)
1079 @implementation $def1[[Cat]] (Extension)
1085 @interface $decl0[[Cat]]
1087 @implementation $def0[[Cat]]
1089 @interface $decl1[[Cat]] (Extension)
1092 @implementation $def1[[Ca^t]] (Extension)
1098 @interface $decl0[[Cat]]
1100 @interface $decl1[[Ca^t]] ()
1103 @implementation $def0[[$def1[[Cat]]]]
1108 for (const char *Test
: Tests
) {
1109 Annotations
T(Test
);
1110 std::vector
<ExpectedRanges
> Ranges
;
1111 for (int Idx
= 0; true; Idx
++) {
1112 bool HasDecl
= !T
.ranges("decl" + std::to_string(Idx
)).empty();
1113 bool HasDef
= !T
.ranges("def" + std::to_string(Idx
)).empty();
1114 if (!HasDecl
&& !HasDef
)
1116 ExpectedRanges Range
;
1118 Range
.WantDecl
= T
.range("decl" + std::to_string(Idx
));
1120 Range
.WantDef
= T
.range("def" + std::to_string(Idx
));
1121 Ranges
.push_back(Range
);
1125 TU
.Code
= std::string(T
.code());
1126 TU
.ExtraArgs
.push_back("-xobjective-c++");
1128 auto AST
= TU
.build();
1129 auto Results
= locateSymbolAt(AST
, T
.point());
1131 ASSERT_THAT(Results
, ::testing::SizeIs(Ranges
.size())) << Test
;
1132 for (size_t Idx
= 0; Idx
< Ranges
.size(); Idx
++) {
1133 EXPECT_EQ(Results
[Idx
].PreferredDeclaration
.range
, Ranges
[Idx
].WantDecl
)
1134 << "($decl" << Idx
<< ")" << Test
;
1135 std::optional
<Range
> GotDef
;
1136 if (Results
[Idx
].Definition
)
1137 GotDef
= Results
[Idx
].Definition
->range
;
1138 EXPECT_EQ(GotDef
, Ranges
[Idx
].WantDef
) << "($def" << Idx
<< ")" << Test
;
1143 // LocateSymbol test cases that produce warnings.
1144 // These are separated out from All so that in All we can assert
1145 // that there are no diagnostics.
1146 TEST(LocateSymbol
, Warnings
) {
1147 const char *Tests
[] = {
1148 R
"cpp(// Field, GNU old-style field designator
1149 struct Foo { int [[x]]; };
1151 Foo bar = { ^x : 1 };
1158 int main() { return ^MACRO; }
1164 for (const char *Test
: Tests
) {
1165 Annotations
T(Test
);
1166 std::optional
<Range
> WantDecl
;
1167 std::optional
<Range
> WantDef
;
1168 if (!T
.ranges().empty())
1169 WantDecl
= WantDef
= T
.range();
1170 if (!T
.ranges("decl").empty())
1171 WantDecl
= T
.range("decl");
1172 if (!T
.ranges("def").empty())
1173 WantDef
= T
.range("def");
1176 TU
.Code
= std::string(T
.code());
1178 auto AST
= TU
.build();
1179 auto Results
= locateSymbolAt(AST
, T
.point());
1182 EXPECT_THAT(Results
, IsEmpty()) << Test
;
1184 ASSERT_THAT(Results
, ::testing::SizeIs(1)) << Test
;
1185 EXPECT_EQ(Results
[0].PreferredDeclaration
.range
, *WantDecl
) << Test
;
1186 std::optional
<Range
> GotDef
;
1187 if (Results
[0].Definition
)
1188 GotDef
= Results
[0].Definition
->range
;
1189 EXPECT_EQ(WantDef
, GotDef
) << Test
;
1194 TEST(LocateSymbol
, TextualSmoke
) {
1195 auto T
= Annotations(
1197 struct [[MyClass]] {};
1198 // Comment mentioning M^yClass
1201 auto TU
= TestTU::withCode(T
.code());
1202 auto AST
= TU
.build();
1203 auto Index
= TU
.index();
1205 locateSymbolAt(AST
, T
.point(), Index
.get()),
1206 ElementsAre(AllOf(sym("MyClass", T
.range(), T
.range()),
1207 hasID(getSymbolID(&findDecl(AST
, "MyClass"))))));
1210 TEST(LocateSymbol
, Textual
) {
1211 const char *Tests
[] = {
1213 struct [[MyClass]] {};
1214 // Comment mentioning M^yClass
1218 // Not triggered for string literal tokens.
1219 const char* s = "String literal mentioning M
^yClass
";
1221 R
"cpp(// Ifdef'ed out code
1222 struct [[MyClass]] {};
1227 R
"cpp(// Macro definition
1228 struct [[MyClass]] {};
1229 #define DECLARE_MYCLASS_OBJ(name) M^yClass name;
1231 R
"cpp(// Invalid code
1233 int myFunction(int);
1234 // Not triggered for token which survived preprocessing.
1235 int var = m^yFunction();
1238 for (const char *Test
: Tests
) {
1239 Annotations
T(Test
);
1240 std::optional
<Range
> WantDecl
;
1241 if (!T
.ranges().empty())
1242 WantDecl
= T
.range();
1244 auto TU
= TestTU::withCode(T
.code());
1246 auto AST
= TU
.build();
1247 auto Index
= TU
.index();
1248 auto Word
= SpelledWord::touching(
1249 cantFail(sourceLocationInMainFile(AST
.getSourceManager(), T
.point())),
1250 AST
.getTokens(), AST
.getLangOpts());
1252 ADD_FAILURE() << "No word touching point!" << Test
;
1255 auto Results
= locateSymbolTextually(*Word
, AST
, Index
.get(),
1256 testPath(TU
.Filename
), ASTNodeKind());
1259 EXPECT_THAT(Results
, IsEmpty()) << Test
;
1261 ASSERT_THAT(Results
, ::testing::SizeIs(1)) << Test
;
1262 EXPECT_EQ(Results
[0].PreferredDeclaration
.range
, *WantDecl
) << Test
;
1267 TEST(LocateSymbol
, Ambiguous
) {
1268 auto T
= Annotations(R
"cpp(
1272 $ConstructorLoc[[Foo]](const char*);
1280 const char* str = "123";
1282 Foo b = Foo($2^str);
1287 Foo ab$8^cd("asdf
");
1288 Foo foox = Fo$9^o("asdf
");
1289 Foo abcde$10^("asdf
");
1290 Foo foox2 = Foo$11^("asdf
");
1293 template <typename T>
1295 void $NonstaticOverload1[[bar]](int);
1296 void $NonstaticOverload2[[bar]](float);
1298 static void $StaticOverload1[[baz]](int);
1299 static void $StaticOverload2[[baz]](float);
1302 template <typename T, typename U>
1303 void dependent_call(S<T> s, U u) {
1308 auto TU
= TestTU::withCode(T
.code());
1309 // FIXME: Go-to-definition in a template requires disabling delayed template
1311 TU
.ExtraArgs
.push_back("-fno-delayed-template-parsing");
1312 auto AST
= TU
.build();
1313 // Ordered assertions are deliberate: we expect a predictable order.
1314 EXPECT_THAT(locateSymbolAt(AST
, T
.point("1")), ElementsAre(sym("str")));
1315 EXPECT_THAT(locateSymbolAt(AST
, T
.point("2")), ElementsAre(sym("str")));
1316 EXPECT_THAT(locateSymbolAt(AST
, T
.point("3")), ElementsAre(sym("f")));
1317 EXPECT_THAT(locateSymbolAt(AST
, T
.point("4")), ElementsAre(sym("g")));
1318 EXPECT_THAT(locateSymbolAt(AST
, T
.point("5")), ElementsAre(sym("f")));
1319 EXPECT_THAT(locateSymbolAt(AST
, T
.point("6")), ElementsAre(sym("str")));
1320 // FIXME: Target the constructor as well.
1321 EXPECT_THAT(locateSymbolAt(AST
, T
.point("7")), ElementsAre(sym("abc")));
1322 // FIXME: Target the constructor as well.
1323 EXPECT_THAT(locateSymbolAt(AST
, T
.point("8")), ElementsAre(sym("abcd")));
1324 // FIXME: Target the constructor as well.
1325 EXPECT_THAT(locateSymbolAt(AST
, T
.point("9")), ElementsAre(sym("Foo")));
1326 EXPECT_THAT(locateSymbolAt(AST
, T
.point("10")),
1327 ElementsAre(sym("Foo", T
.range("ConstructorLoc"), std::nullopt
)));
1328 EXPECT_THAT(locateSymbolAt(AST
, T
.point("11")),
1329 ElementsAre(sym("Foo", T
.range("ConstructorLoc"), std::nullopt
)));
1330 // These assertions are unordered because the order comes from
1331 // CXXRecordDecl::lookupDependentName() which doesn't appear to provide
1332 // an order guarantee.
1333 EXPECT_THAT(locateSymbolAt(AST
, T
.point("12")),
1334 UnorderedElementsAre(
1335 sym("bar", T
.range("NonstaticOverload1"), std::nullopt
),
1336 sym("bar", T
.range("NonstaticOverload2"), std::nullopt
)));
1337 EXPECT_THAT(locateSymbolAt(AST
, T
.point("13")),
1338 UnorderedElementsAre(
1339 sym("baz", T
.range("StaticOverload1"), std::nullopt
),
1340 sym("baz", T
.range("StaticOverload2"), std::nullopt
)));
1343 TEST(LocateSymbol
, TextualDependent
) {
1344 // Put the declarations in the header to make sure we are
1345 // finding them via the index heuristic and not the
1346 // nearby-ident heuristic.
1347 Annotations
Header(R
"cpp(
1349 void $FooLoc[[uniqueMethodName]]();
1352 void $BarLoc[[uniqueMethodName]]();
1355 Annotations
Source(R
"cpp(
1356 template <typename T>
1358 t.u^niqueMethodName();
1362 TU
.Code
= std::string(Source
.code());
1363 TU
.HeaderCode
= std::string(Header
.code());
1364 auto AST
= TU
.build();
1365 auto Index
= TU
.index();
1366 // Need to use locateSymbolAt() since we are testing an
1367 // interaction between locateASTReferent() and
1368 // locateSymbolNamedTextuallyAt().
1369 auto Results
= locateSymbolAt(AST
, Source
.point(), Index
.get());
1372 UnorderedElementsAre(
1373 sym("uniqueMethodName", Header
.range("FooLoc"), std::nullopt
),
1374 sym("uniqueMethodName", Header
.range("BarLoc"), std::nullopt
)));
1377 TEST(LocateSymbol
, Alias
) {
1378 const char *Tests
[] = {
1380 template <class T> struct function {};
1381 template <class T> using [[callback]] = function<T()>;
1386 // triggered on non-definition of a renaming alias: should not give any
1387 // underlying decls.
1390 typedef Foo [[Bar]];
1396 using [[Bar]] = Foo; // definition
1400 // triggered on the underlying decl of a renaming alias.
1406 // triggered on definition of a non-renaming alias: should give underlying
1409 namespace ns { class [[Foo]] {}; }
1414 namespace ns { int [[x]](char); int [[x]](double); }
1419 namespace ns { int [[x]](char); int x(double); }
1425 namespace ns { class [[Foo]] {}; }
1430 // other cases that don't matter much.
1433 typedef Foo [[Ba^r]];
1437 using [[B^ar]] = Foo;
1440 // Member of dependent base
1442 template <typename T>
1446 template <typename T>
1447 struct Derived : Base<T> {
1448 using Base<T>::w^aldo;
1453 for (const auto *Case
: Tests
) {
1455 auto T
= Annotations(Case
);
1456 auto AST
= TestTU::withCode(T
.code()).build();
1457 EXPECT_THAT(locateSymbolAt(AST
, T
.point()),
1458 UnorderedPointwise(declRange(), T
.ranges()));
1462 TEST(LocateSymbol
, RelPathsInCompileCommand
) {
1463 // The source is in "/clangd-test/src".
1464 // We build in "/clangd-test/build".
1466 Annotations
SourceAnnotations(R
"cpp(
1467 #include "header_in_preamble
.h
"
1469 #include "header_not_in_preamble
.h
"
1470 int baz = f$p1^oo + bar_pre$p2^amble + bar_not_pre$p3^amble;
1473 Annotations
HeaderInPreambleAnnotations(R
"cpp(
1474 int [[bar_preamble]];
1477 Annotations
HeaderNotInPreambleAnnotations(R
"cpp(
1478 int [[bar_not_preamble]];
1481 // Make the compilation paths appear as ../src/foo.cpp in the compile
1483 SmallString
<32> RelPathPrefix("..");
1484 llvm::sys::path::append(RelPathPrefix
, "src");
1485 std::string BuildDir
= testPath("build");
1486 MockCompilationDatabase
CDB(BuildDir
, RelPathPrefix
);
1489 ClangdServer
Server(CDB
, FS
, ClangdServer::optsForTest());
1491 // Fill the filesystem.
1492 auto FooCpp
= testPath("src/foo.cpp");
1493 FS
.Files
[FooCpp
] = "";
1494 auto HeaderInPreambleH
= testPath("src/header_in_preamble.h");
1495 FS
.Files
[HeaderInPreambleH
] = std::string(HeaderInPreambleAnnotations
.code());
1496 auto HeaderNotInPreambleH
= testPath("src/header_not_in_preamble.h");
1497 FS
.Files
[HeaderNotInPreambleH
] =
1498 std::string(HeaderNotInPreambleAnnotations
.code());
1500 runAddDocument(Server
, FooCpp
, SourceAnnotations
.code());
1502 // Go to a definition in main source file.
1504 runLocateSymbolAt(Server
, FooCpp
, SourceAnnotations
.point("p1"));
1505 EXPECT_TRUE(bool(Locations
)) << "findDefinitions returned an error";
1506 EXPECT_THAT(*Locations
, ElementsAre(sym("foo", SourceAnnotations
.range(),
1507 SourceAnnotations
.range())));
1509 // Go to a definition in header_in_preamble.h.
1510 Locations
= runLocateSymbolAt(Server
, FooCpp
, SourceAnnotations
.point("p2"));
1511 EXPECT_TRUE(bool(Locations
)) << "findDefinitions returned an error";
1514 ElementsAre(sym("bar_preamble", HeaderInPreambleAnnotations
.range(),
1515 HeaderInPreambleAnnotations
.range())));
1517 // Go to a definition in header_not_in_preamble.h.
1518 Locations
= runLocateSymbolAt(Server
, FooCpp
, SourceAnnotations
.point("p3"));
1519 EXPECT_TRUE(bool(Locations
)) << "findDefinitions returned an error";
1520 EXPECT_THAT(*Locations
,
1521 ElementsAre(sym("bar_not_preamble",
1522 HeaderNotInPreambleAnnotations
.range(),
1523 HeaderNotInPreambleAnnotations
.range())));
1526 TEST(GoToInclude
, All
) {
1528 MockCompilationDatabase CDB
;
1529 ClangdServer
Server(CDB
, FS
, ClangdServer::optsForTest());
1531 auto FooCpp
= testPath("foo.cpp");
1532 const char *SourceContents
= R
"cpp(
1533 #include ^"$
2^foo
.h$
3^"
1534 #include "$
4^invalid
.h
"
1538 #in$5^clude "$
6^foo
.h
"$7^
1540 Annotations
SourceAnnotations(SourceContents
);
1541 FS
.Files
[FooCpp
] = std::string(SourceAnnotations
.code());
1542 auto FooH
= testPath("foo.h");
1544 const char *HeaderContents
= R
"cpp([[]]#pragma once
1547 Annotations
HeaderAnnotations(HeaderContents
);
1548 FS
.Files
[FooH
] = std::string(HeaderAnnotations
.code());
1550 runAddDocument(Server
, FooH
, HeaderAnnotations
.code());
1551 runAddDocument(Server
, FooCpp
, SourceAnnotations
.code());
1553 // Test include in preamble.
1554 auto Locations
= runLocateSymbolAt(Server
, FooCpp
, SourceAnnotations
.point());
1555 ASSERT_TRUE(bool(Locations
)) << "locateSymbolAt returned an error";
1556 EXPECT_THAT(*Locations
, ElementsAre(sym("foo.h", HeaderAnnotations
.range(),
1557 HeaderAnnotations
.range())));
1559 // Test include in preamble, last char.
1560 Locations
= runLocateSymbolAt(Server
, FooCpp
, SourceAnnotations
.point("2"));
1561 ASSERT_TRUE(bool(Locations
)) << "locateSymbolAt returned an error";
1562 EXPECT_THAT(*Locations
, ElementsAre(sym("foo.h", HeaderAnnotations
.range(),
1563 HeaderAnnotations
.range())));
1565 Locations
= runLocateSymbolAt(Server
, FooCpp
, SourceAnnotations
.point("3"));
1566 ASSERT_TRUE(bool(Locations
)) << "locateSymbolAt returned an error";
1567 EXPECT_THAT(*Locations
, ElementsAre(sym("foo.h", HeaderAnnotations
.range(),
1568 HeaderAnnotations
.range())));
1570 // Test include outside of preamble.
1571 Locations
= runLocateSymbolAt(Server
, FooCpp
, SourceAnnotations
.point("6"));
1572 ASSERT_TRUE(bool(Locations
)) << "locateSymbolAt returned an error";
1573 EXPECT_THAT(*Locations
, ElementsAre(sym("foo.h", HeaderAnnotations
.range(),
1574 HeaderAnnotations
.range())));
1576 // Test a few positions that do not result in Locations.
1577 Locations
= runLocateSymbolAt(Server
, FooCpp
, SourceAnnotations
.point("4"));
1578 ASSERT_TRUE(bool(Locations
)) << "locateSymbolAt returned an error";
1579 EXPECT_THAT(*Locations
, IsEmpty());
1581 Locations
= runLocateSymbolAt(Server
, FooCpp
, SourceAnnotations
.point("5"));
1582 ASSERT_TRUE(bool(Locations
)) << "locateSymbolAt returned an error";
1583 EXPECT_THAT(*Locations
, ElementsAre(sym("foo.h", HeaderAnnotations
.range(),
1584 HeaderAnnotations
.range())));
1586 Locations
= runLocateSymbolAt(Server
, FooCpp
, SourceAnnotations
.point("7"));
1587 ASSERT_TRUE(bool(Locations
)) << "locateSymbolAt returned an error";
1588 EXPECT_THAT(*Locations
, ElementsAre(sym("foo.h", HeaderAnnotations
.range(),
1589 HeaderAnnotations
.range())));
1591 // Objective C #import directive.
1592 Annotations
ObjC(R
"objc(
1595 auto FooM
= testPath("foo.m");
1596 FS
.Files
[FooM
] = std::string(ObjC
.code());
1598 runAddDocument(Server
, FooM
, ObjC
.code());
1599 Locations
= runLocateSymbolAt(Server
, FooM
, ObjC
.point());
1600 ASSERT_TRUE(bool(Locations
)) << "locateSymbolAt returned an error";
1601 EXPECT_THAT(*Locations
, ElementsAre(sym("foo.h", HeaderAnnotations
.range(),
1602 HeaderAnnotations
.range())));
1605 TEST(LocateSymbol
, WithPreamble
) {
1606 // Test stragety: AST should always use the latest preamble instead of last
1609 MockCompilationDatabase CDB
;
1610 ClangdServer
Server(CDB
, FS
, ClangdServer::optsForTest());
1612 auto FooCpp
= testPath("foo.cpp");
1613 // The trigger locations must be the same.
1614 Annotations
FooWithHeader(R
"cpp(#include "fo
^o
.h
")cpp");
1615 Annotations
FooWithoutHeader(R
"cpp(double [[fo^o]]();)cpp");
1617 FS
.Files
[FooCpp
] = std::string(FooWithHeader
.code());
1619 auto FooH
= testPath("foo.h");
1620 Annotations
FooHeader(R
"cpp([[]])cpp");
1621 FS
.Files
[FooH
] = std::string(FooHeader
.code());
1623 runAddDocument(Server
, FooCpp
, FooWithHeader
.code());
1624 // LocateSymbol goes to a #include file: the result comes from the preamble.
1626 cantFail(runLocateSymbolAt(Server
, FooCpp
, FooWithHeader
.point())),
1627 ElementsAre(sym("foo.h", FooHeader
.range(), FooHeader
.range())));
1629 // Only preamble is built, and no AST is built in this request.
1630 Server
.addDocument(FooCpp
, FooWithoutHeader
.code(), "null",
1631 WantDiagnostics::No
);
1632 // We build AST here, and it should use the latest preamble rather than the
1635 cantFail(runLocateSymbolAt(Server
, FooCpp
, FooWithoutHeader
.point())),
1636 ElementsAre(sym("foo", FooWithoutHeader
.range(), std::nullopt
)));
1638 // Reset test environment.
1639 runAddDocument(Server
, FooCpp
, FooWithHeader
.code());
1640 // Both preamble and AST are built in this request.
1641 Server
.addDocument(FooCpp
, FooWithoutHeader
.code(), "null",
1642 WantDiagnostics::Yes
);
1643 // Use the AST being built in above request.
1645 cantFail(runLocateSymbolAt(Server
, FooCpp
, FooWithoutHeader
.point())),
1646 ElementsAre(sym("foo", FooWithoutHeader
.range(), std::nullopt
)));
1649 TEST(LocateSymbol
, NearbyTokenSmoke
) {
1650 auto T
= Annotations(R
"cpp(
1651 // prints e^rr and crashes
1652 void die(const char* [[err]]);
1654 auto AST
= TestTU::withCode(T
.code()).build();
1655 // We don't pass an index, so can't hit index-based fallback.
1656 EXPECT_THAT(locateSymbolAt(AST
, T
.point()),
1657 ElementsAre(sym("err", T
.range(), T
.range())));
1660 TEST(LocateSymbol
, NearbyIdentifier
) {
1661 const char *Tests
[] = {
1663 // regular identifiers (won't trigger)
1668 // disabled preprocessor sections
1680 // not triggered by string literals
1682 const char* greeting = "h
^ello
, world
";
1686 // can refer to macro invocations
1693 // can refer to macro invocations (even if they expand to nothing)
1700 // prefer nearest occurrence, backwards is worse than forwards
1709 // short identifiers find near results
1714 // short identifiers don't find far results
1727 // prefer nearest occurrence even if several matched tokens
1728 // have the same value of `floor(log2(<token line> - <word line>))`.
1730 int x = hello, y = hello;
1734 for (const char *Test
: Tests
) {
1735 Annotations
T(Test
);
1736 auto AST
= TestTU::withCode(T
.code()).build();
1737 const auto &SM
= AST
.getSourceManager();
1738 std::optional
<Range
> Nearby
;
1740 SpelledWord::touching(cantFail(sourceLocationInMainFile(SM
, T
.point())),
1741 AST
.getTokens(), AST
.getLangOpts());
1743 ADD_FAILURE() << "No word at point! " << Test
;
1746 if (const auto *Tok
= findNearbyIdentifier(*Word
, AST
.getTokens()))
1747 Nearby
= halfOpenToRange(SM
, CharSourceRange::getCharRange(
1748 Tok
->location(), Tok
->endLocation()));
1749 if (T
.ranges().empty())
1750 EXPECT_THAT(Nearby
, Eq(std::nullopt
)) << Test
;
1752 EXPECT_EQ(Nearby
, T
.range()) << Test
;
1756 TEST(FindImplementations
, Inheritance
) {
1757 llvm::StringRef Test
= R
"cpp(
1759 virtual void F$1^oo();
1762 struct $0[[Child1]] : Base {
1763 void $1[[Fo$3^o]]() override;
1764 virtual void B$2^ar();
1765 void Concrete(); // No implementations for concrete methods.
1767 struct Child2 : Child1 {
1768 void $3[[Foo]]() override;
1769 void $2[[Bar]]() override;
1771 void FromReference() {
1780 // CRTP should work.
1781 template<typename T>
1782 struct $5^TemplateBase {};
1783 struct $5[[Child3]] : public TemplateBase<Child3> {};
1786 void LocationFunction() {
1787 struct $0[[LocalClass1]] : Base {
1788 void $1[[Foo]]() override;
1790 struct $6^LocalBase {
1791 virtual void $7^Bar();
1793 struct $6[[LocalClass2]]: LocalBase {
1794 void $7[[Bar]]() override;
1799 Annotations
Code(Test
);
1800 auto TU
= TestTU::withCode(Code
.code());
1801 auto AST
= TU
.build();
1802 auto Index
= TU
.index();
1803 for (StringRef Label
: {"0", "1", "2", "3", "4", "5", "6", "7"}) {
1804 for (const auto &Point
: Code
.points(Label
)) {
1805 EXPECT_THAT(findImplementations(AST
, Point
, Index
.get()),
1806 UnorderedPointwise(declRange(), Code
.ranges(Label
)))
1807 << Code
.code() << " at " << Point
<< " for Label " << Label
;
1812 TEST(FindImplementations
, CaptureDefinition
) {
1813 llvm::StringRef Test
= R
"cpp(
1815 virtual void F^oo();
1817 struct Child1 : Base {
1818 void $Decl[[Foo]]() override;
1820 struct Child2 : Base {
1821 void $Child2[[Foo]]() override;
1823 void Child1::$Def[[Foo]]() { /* Definition */ }
1825 Annotations
Code(Test
);
1826 auto TU
= TestTU::withCode(Code
.code());
1827 auto AST
= TU
.build();
1829 findImplementations(AST
, Code
.point(), TU
.index().get()),
1830 UnorderedElementsAre(sym("Foo", Code
.range("Decl"), Code
.range("Def")),
1831 sym("Foo", Code
.range("Child2"), std::nullopt
)))
1835 TEST(FindType
, All
) {
1836 Annotations
HeaderA(R
"cpp(
1837 struct $Target[[Target]] { operator int() const; };
1838 struct Aggregate { Target a, b; };
1842 template <typename T> struct $smart_ptr[[smart_ptr]] {
1848 auto TU
= TestTU::withHeaderCode(HeaderA
.code());
1849 for (const llvm::StringRef Case
: {
1853 "a^uto x = Target{};",
1854 "namespace m { Target tgt; } auto x = m^::tgt;",
1855 "Target funcCall(); auto x = ^funcCall();",
1856 "Aggregate a = { {}, ^{} };",
1857 "Aggregate a = { ^.a=t, };",
1858 "struct X { Target a; X() : ^a() {} };",
1859 "^using T = Target; ^T foo();",
1860 "^template <int> Target foo();",
1861 "void x() { try {} ^catch(Target e) {} }",
1862 "void x() { ^throw t; }",
1863 "int x() { ^return t; }",
1864 "void x() { ^switch(t) {} }",
1865 "void x() { ^delete (Target*)nullptr; }",
1866 "Target& ^tref = t;",
1867 "void x() { ^if (t) {} }",
1868 "void x() { ^while (t) {} }",
1869 "void x() { ^do { } while (t); }",
1870 "void x() { ^make(); }",
1871 "void x(smart_ptr<Target> &t) { t.^get(); }",
1872 "^auto x = []() { return t; };",
1873 "Target* ^tptr = &t;",
1874 "Target ^tarray[3];",
1876 Annotations
A(Case
);
1877 TU
.Code
= A
.code().str();
1878 ParsedAST AST
= TU
.build();
1880 ASSERT_GT(A
.points().size(), 0u) << Case
;
1881 for (auto Pos
: A
.points())
1882 EXPECT_THAT(findType(AST
, Pos
),
1884 sym("Target", HeaderA
.range("Target"), HeaderA
.range("Target"))))
1888 for (const llvm::StringRef Case
: {
1889 "smart_ptr<Target> ^tsmart;",
1891 Annotations
A(Case
);
1892 TU
.Code
= A
.code().str();
1893 ParsedAST AST
= TU
.build();
1895 EXPECT_THAT(findType(AST
, A
.point()),
1896 UnorderedElementsAre(
1897 sym("Target", HeaderA
.range("Target"), HeaderA
.range("Target")),
1898 sym("smart_ptr", HeaderA
.range("smart_ptr"), HeaderA
.range("smart_ptr"))
1904 void checkFindRefs(llvm::StringRef Test
, bool UseIndex
= false) {
1905 Annotations
T(Test
);
1906 auto TU
= TestTU::withCode(T
.code());
1907 TU
.ExtraArgs
.push_back("-std=c++20");
1909 auto AST
= TU
.build();
1910 std::vector
<Matcher
<ReferencesResult::Reference
>> ExpectedLocations
;
1911 for (const auto &[R
, Context
] : T
.rangesWithPayload())
1912 ExpectedLocations
.push_back(
1913 AllOf(rangeIs(R
), containerIs(Context
), attrsAre(0u)));
1914 // $def is actually shorthand for both definition and declaration.
1915 // If we have cases that are definition-only, we should change this.
1916 for (const auto &[R
, Context
] : T
.rangesWithPayload("def"))
1917 ExpectedLocations
.push_back(AllOf(rangeIs(R
), containerIs(Context
),
1918 attrsAre(ReferencesResult::Definition
|
1919 ReferencesResult::Declaration
)));
1920 for (const auto &[R
, Context
] : T
.rangesWithPayload("decl"))
1921 ExpectedLocations
.push_back(AllOf(rangeIs(R
), containerIs(Context
),
1922 attrsAre(ReferencesResult::Declaration
)));
1923 for (const auto &[R
, Context
] : T
.rangesWithPayload("overridedecl"))
1924 ExpectedLocations
.push_back(AllOf(
1925 rangeIs(R
), containerIs(Context
),
1926 attrsAre(ReferencesResult::Declaration
| ReferencesResult::Override
)));
1927 for (const auto &[R
, Context
] : T
.rangesWithPayload("overridedef"))
1928 ExpectedLocations
.push_back(AllOf(rangeIs(R
), containerIs(Context
),
1929 attrsAre(ReferencesResult::Declaration
|
1930 ReferencesResult::Definition
|
1931 ReferencesResult::Override
)));
1932 for (const auto &P
: T
.points()) {
1933 EXPECT_THAT(findReferences(AST
, P
, 0, UseIndex
? TU
.index().get() : nullptr,
1934 /*AddContext*/ true)
1936 UnorderedElementsAreArray(ExpectedLocations
))
1937 << "Failed for Refs at " << P
<< "\n"
1942 TEST(FindReferences
, WithinAST
) {
1943 const char *Tests
[] = {
1944 R
"cpp(// Local variable
1946 int $def(main)[[foo]];
1947 $(main)[[^foo]] = 2;
1948 int test1 = $(main)[[foo]];
1954 struct $def(ns1)[[Foo]] {};
1957 ns1::$(main)[[Fo^o]]* Params;
1961 R
"cpp(// Forward declaration
1963 class $def[[Foo]] {};
1965 $(main)[[Fo^o]] foo;
1970 int $def[[foo]](int) {}
1972 auto *X = &$(main)[[^foo]];
1979 int $def(Foo)[[foo]];
1980 Foo() : $(Foo::Foo)[[foo]](0) {}
1984 f.$(main)[[f^oo]] = 1;
1988 R
"cpp(// Method call
1989 struct Foo { int $decl(Foo)[[foo]](); };
1990 int Foo::$def(Foo)[[foo]]() {}
1993 f.$(main)[[^foo]]();
1997 R
"cpp(// Constructor
1999 $decl(Foo)[[F^oo]](int);
2002 Foo f = $(foo)[[Foo]](42);
2007 typedef int $def[[Foo]];
2009 $(main)[[^Foo]] bar;
2014 namespace $decl[[ns]] { // FIXME: def?
2017 int main() { $(main)[[^ns]]::Foo foo; }
2023 #define CAT(X, Y) X##Y
2024 class $def[[Fo^o]] {};
2026 TYPE($(test)[[Foo]]) foo;
2027 $(test)[[FOO]] foo2;
2028 TYPE(TYPE($(test)[[Foo]])) foo3;
2029 $(test)[[CAT]](Fo, o) foo4;
2034 #define $def[[MA^CRO]](X) (X+1)
2036 int x = $[[MACRO]]($[[MACRO]](1));
2040 R
"cpp(// Macro outside preamble
2042 #define $def[[MA^CRO]](X) (X+1)
2044 int x = $[[MACRO]]($[[MACRO]](1));
2049 int $def[[v^ar]] = 0;
2050 void foo(int s = $(foo)[[var]]);
2054 template <typename T>
2055 class $def[[Fo^o]] {};
2056 void func($(func)[[Foo]]<int>);
2060 template <typename T>
2061 class $def[[Foo]] {};
2062 void func($(func)[[Fo^o]]<int>);
2064 R
"cpp(// Not touching any identifiers.
2066 $def(Foo)[[~]]Foo() {};
2070 f.$(foo)[[^~]]Foo();
2073 R
"cpp(// Lambda capture initializer
2075 int $def(foo)[[w^aldo]] = 42;
2076 auto lambda = [x = $(foo)[[waldo]]](){};
2079 R
"cpp(// Renaming alias
2080 template <typename> class Vector {};
2081 using $def[[^X]] = Vector<int>;
2086 R
"cpp(// Dependent code
2087 template <typename T> void $decl[[foo]](T t);
2088 template <typename T> void bar(T t) { $(bar)[[foo]](t); } // foo in bar is uninstantiated.
2089 void baz(int x) { $(baz)[[f^oo]](x); }
2094 void $decl(ns)[[foo]](S s);
2096 template <typename T> void foo(T t);
2097 // FIXME: Maybe report this foo as a ref to ns::foo (because of ADL)
2098 // when bar<ns::S> is instantiated?
2099 template <typename T> void bar(T t) { foo(t); }
2106 R
"cpp(// unresolved member expression
2108 template <typename T> void $decl(Foo)[[b^ar]](T t);
2110 template <typename T> void test(Foo F, T t) {
2111 F.$(test)[[bar]](t);
2117 typedef int $def[[MyTypeD^ef]];
2118 enum MyEnum : $(MyEnum)[[MyTy^peDef]] { };
2121 typedef int $def[[MyType^Def]];
2122 enum MyEnum : $(MyEnum)[[MyTypeD^ef]];
2125 using $def[[MyTypeD^ef]] = int;
2126 enum MyEnum : $(MyEnum)[[MyTy^peDef]] { };
2129 for (const char *Test
: Tests
)
2130 checkFindRefs(Test
);
2133 TEST(FindReferences
, ConceptsWithinAST
) {
2134 constexpr llvm::StringLiteral Code
= R
"cpp(
2136 concept $def[[IsSmal^l]] = sizeof(T) <= 8;
2139 concept IsSmallPtr = requires(T x) {
2140 { *x } -> $(IsSmallPtr)[[IsSmal^l]];
2143 $(i)[[IsSmall]] auto i = 'c';
2144 template<$(foo)[[IsSmal^l]] U> void foo();
2145 template<class U> void bar() requires $(bar)[[IsSmal^l]]<U>;
2146 template<class U> requires $(baz)[[IsSmal^l]]<U> void baz();
2147 static_assert([[IsSma^ll]]<char>);
2149 checkFindRefs(Code
);
2152 TEST(FindReferences
, ConceptReq
) {
2153 constexpr llvm::StringLiteral Code
= R
"cpp(
2155 concept $def[[IsSmal^l]] = sizeof(T) <= 8;
2158 concept IsSmallPtr = requires(T x) {
2159 { *x } -> $(IsSmallPtr)[[IsSmal^l]];
2162 checkFindRefs(Code
);
2165 TEST(FindReferences
, RequiresExprParameters
) {
2166 constexpr llvm::StringLiteral Code
= R
"cpp(
2168 concept IsSmall = sizeof(T) <= 8;
2171 concept IsSmallPtr = requires(T $def[[^x]]) {
2172 { *$(IsSmallPtr)[[^x]] } -> IsSmall;
2175 checkFindRefs(Code
);
2178 TEST(FindReferences
, IncludeOverrides
) {
2179 llvm::StringRef Test
=
2183 virtu^al void $decl(Base)[[f^unc]]() ^= ^0;
2185 class Derived : public Base {
2187 void $overridedecl(Derived::func)[[func]]() override;
2189 void Derived::$overridedef[[func]]() {}
2190 class Derived2 : public Base {
2191 void $overridedef(Derived2::func)[[func]]() override {}
2193 void test(Derived* D, Base* B) {
2194 D->func(); // No references to the overrides.
2195 B->$(test)[[func]]();
2197 checkFindRefs(Test
, /*UseIndex=*/true);
2200 TEST(FindReferences
, RefsToBaseMethod
) {
2201 llvm::StringRef Test
=
2205 virtual void $(BaseBase)[[func]]();
2207 class Base : public BaseBase {
2209 void $(Base)[[func]]() override;
2211 class Derived : public Base {
2213 void $decl(Derived)[[fu^nc]]() over^ride;
2215 void test(BaseBase* BB, Base* B, Derived* D) {
2216 // refs to overridden methods in complete type hierarchy are reported.
2217 BB->$(test)[[func]]();
2218 B->$(test)[[func]]();
2219 D->$(test)[[fu^nc]]();
2221 checkFindRefs(Test
, /*UseIndex=*/true);
2224 TEST(FindReferences
, MainFileReferencesOnly
) {
2225 llvm::StringRef Test
=
2229 // refs not from main file should not be included.
2233 Annotations
Code(Test
);
2234 auto TU
= TestTU::withCode(Code
.code());
2235 TU
.AdditionalFiles
["foo.inc"] = R
"cpp(
2238 auto AST
= TU
.build();
2240 std::vector
<Matcher
<ReferencesResult::Reference
>> ExpectedLocations
;
2241 for (const auto &R
: Code
.ranges())
2242 ExpectedLocations
.push_back(rangeIs(R
));
2243 EXPECT_THAT(findReferences(AST
, Code
.point(), 0).References
,
2244 ElementsAreArray(ExpectedLocations
))
2248 TEST(FindReferences
, ExplicitSymbols
) {
2249 const char *Tests
[] = {
2251 struct Foo { Foo* $decl(Foo)[[self]]() const; };
2254 if (Foo* T = foo.$(f)[[^self]]()) {} // Foo member call expr.
2259 struct Foo { Foo(int); };
2262 return $(f)[[^b]]; // Foo constructor expr.
2271 g($(call)[[^f]]()); // Foo constructor expr.
2276 void $decl[[foo]](int);
2277 void $decl[[foo]](double);
2280 using ::$decl(ns)[[fo^o]];
2291 $(test)[[a]].operator bool();
2292 if ($(test)[[a^]]) {} // ignore implicit conversion-operator AST node
2296 for (const char *Test
: Tests
)
2297 checkFindRefs(Test
);
2300 TEST(FindReferences
, UsedSymbolsFromInclude
) {
2301 const char *Tests
[] = {
2302 R
"cpp([[#include ^"bar
.h
"]]
2304 int fstBar = [[bar1]]();
2305 int sndBar = [[bar2]]();
2307 int macroBar = [[BAR]];
2308 std::vector<int> vec;
2311 R
"cpp([[#in^clude <vector>]]
2312 std::[[vector]]<int> vec;
2314 for (const char *Test
: Tests
) {
2315 Annotations
T(Test
);
2316 auto TU
= TestTU::withCode(T
.code());
2317 TU
.ExtraArgs
.push_back("-std=c++20");
2318 TU
.AdditionalFiles
["bar.h"] = guard(R
"cpp(
2324 TU
.AdditionalFiles
["system/vector"] = guard(R
"cpp(
2330 TU
.ExtraArgs
.push_back("-isystem" + testPath("system"));
2332 auto AST
= TU
.build();
2333 std::vector
<Matcher
<ReferencesResult::Reference
>> ExpectedLocations
;
2334 for (const auto &R
: T
.ranges())
2335 ExpectedLocations
.push_back(AllOf(rangeIs(R
), attrsAre(0u)));
2336 for (const auto &P
: T
.points())
2337 EXPECT_THAT(findReferences(AST
, P
, 0).References
,
2338 UnorderedElementsAreArray(ExpectedLocations
))
2339 << "Failed for Refs at " << P
<< "\n"
2344 TEST(FindReferences
, NeedsIndexForSymbols
) {
2345 const char *Header
= "int foo();";
2346 Annotations
Main("int main() { [[f^oo]](); }");
2348 TU
.Code
= std::string(Main
.code());
2349 TU
.HeaderCode
= Header
;
2350 auto AST
= TU
.build();
2352 // References in main file are returned without index.
2354 findReferences(AST
, Main
.point(), 0, /*Index=*/nullptr).References
,
2355 ElementsAre(rangeIs(Main
.range())));
2356 Annotations
IndexedMain(R
"cpp(
2357 int $decl[[foo]]() { return 42; }
2358 void bar() { $bar(bar)[[foo]](); }
2359 struct S { void bar() { $S(S::bar)[[foo]](); } };
2360 namespace N { void bar() { $N(N::bar)[[foo]](); } }
2363 // References from indexed files are included.
2365 IndexedTU
.Code
= std::string(IndexedMain
.code());
2366 IndexedTU
.Filename
= "Indexed.cpp";
2367 IndexedTU
.HeaderCode
= Header
;
2369 findReferences(AST
, Main
.point(), 0, IndexedTU
.index().get(),
2370 /*AddContext*/ true)
2373 rangeIs(Main
.range()),
2374 AllOf(rangeIs(IndexedMain
.range("decl")),
2375 attrsAre(ReferencesResult::Declaration
|
2376 ReferencesResult::Definition
)),
2377 AllOf(rangeIs(IndexedMain
.range("bar")), containerIs("bar")),
2378 AllOf(rangeIs(IndexedMain
.range("S")), containerIs("S::bar")),
2379 AllOf(rangeIs(IndexedMain
.range("N")), containerIs("N::bar"))));
2381 findReferences(AST
, Main
.point(), /*Limit*/ 1, IndexedTU
.index().get());
2382 EXPECT_EQ(1u, LimitRefs
.References
.size());
2383 EXPECT_TRUE(LimitRefs
.HasMore
);
2385 // Avoid indexed results for the main file. Use AST for the mainfile.
2386 TU
.Code
= ("\n\n" + Main
.code()).str();
2387 EXPECT_THAT(findReferences(AST
, Main
.point(), 0, TU
.index().get()).References
,
2388 ElementsAre(rangeIs(Main
.range())));
2391 TEST(FindReferences
, NeedsIndexForMacro
) {
2392 const char *Header
= "#define MACRO(X) (X+1)";
2393 Annotations
Main(R
"cpp(
2395 int a = [[MA^CRO]](1);
2399 TU
.Code
= std::string(Main
.code());
2400 TU
.HeaderCode
= Header
;
2401 auto AST
= TU
.build();
2403 // References in main file are returned without index.
2405 findReferences(AST
, Main
.point(), 0, /*Index=*/nullptr).References
,
2406 ElementsAre(rangeIs(Main
.range())));
2408 Annotations
IndexedMain(R
"cpp(
2409 int indexed_main() {
2410 int a = [[MACRO]](1);
2414 // References from indexed files are included.
2416 IndexedTU
.Code
= std::string(IndexedMain
.code());
2417 IndexedTU
.Filename
= "Indexed.cpp";
2418 IndexedTU
.HeaderCode
= Header
;
2420 findReferences(AST
, Main
.point(), 0, IndexedTU
.index().get()).References
,
2421 ElementsAre(rangeIs(Main
.range()), rangeIs(IndexedMain
.range())));
2423 findReferences(AST
, Main
.point(), /*Limit*/ 1, IndexedTU
.index().get());
2424 EXPECT_EQ(1u, LimitRefs
.References
.size());
2425 EXPECT_TRUE(LimitRefs
.HasMore
);
2428 TEST(FindReferences
, NoQueryForLocalSymbols
) {
2429 struct RecordingIndex
: public MemIndex
{
2430 mutable std::optional
<llvm::DenseSet
<SymbolID
>> RefIDs
;
2431 bool refs(const RefsRequest
&Req
,
2432 llvm::function_ref
<void(const Ref
&)>) const override
{
2439 StringRef AnnotatedCode
;
2443 // For now we don't assume header structure which would allow skipping.
2444 {"namespace { int ^x; }", true},
2445 {"static int ^x;", true},
2446 // Anything in a function certainly can't be referenced though.
2447 {"void foo() { int ^x; }", false},
2448 {"void foo() { struct ^x{}; }", false},
2449 {"auto lambda = []{ int ^x; };", false},
2451 for (Test T
: Tests
) {
2452 Annotations
File(T
.AnnotatedCode
);
2454 auto AST
= TestTU::withCode(File
.code()).build();
2455 findReferences(AST
, File
.point(), 0, &Rec
);
2457 EXPECT_NE(Rec
.RefIDs
, std::nullopt
) << T
.AnnotatedCode
;
2459 EXPECT_EQ(Rec
.RefIDs
, std::nullopt
) << T
.AnnotatedCode
;
2463 TEST(GetNonLocalDeclRefs
, All
) {
2465 llvm::StringRef AnnotatedCode
;
2466 std::vector
<std::string
> ExpectedDecls
;
2469 // VarDecl and ParamVarDecl
2472 void ^foo(int baz) {
2479 // Method from class
2481 class Foo { public: void foo(); };
2491 {"Bar", "Bar::bar", "Foo", "Foo::foo"},
2497 class Foo { public: void foo() {} };
2498 class Bar { public: void bar() {} };
2509 template <typename T, template<typename> class Q>
2517 for (const Case
&C
: Cases
) {
2518 Annotations
File(C
.AnnotatedCode
);
2519 auto AST
= TestTU::withCode(File
.code()).build();
2520 SourceLocation SL
= llvm::cantFail(
2521 sourceLocationInMainFile(AST
.getSourceManager(), File
.point()));
2523 const FunctionDecl
*FD
=
2524 llvm::dyn_cast
<FunctionDecl
>(&findDecl(AST
, [SL
](const NamedDecl
&ND
) {
2525 return ND
.getLocation() == SL
&& llvm::isa
<FunctionDecl
>(ND
);
2527 ASSERT_NE(FD
, nullptr);
2529 auto NonLocalDeclRefs
= getNonLocalDeclRefs(AST
, FD
);
2530 std::vector
<std::string
> Names
;
2531 for (const Decl
*D
: NonLocalDeclRefs
) {
2532 if (const auto *ND
= llvm::dyn_cast
<NamedDecl
>(D
))
2533 Names
.push_back(ND
->getQualifiedNameAsString());
2535 EXPECT_THAT(Names
, UnorderedElementsAreArray(C
.ExpectedDecls
))
2540 TEST(DocumentLinks
, All
) {
2541 Annotations
MainCpp(R
"cpp(
2542 #/*comments*/include /*comments*/ $foo[["foo
.h
"]] //more comments
2543 int end_of_preamble = 0;
2544 #include $bar[[<bar.h>]]
2548 TU
.Code
= std::string(MainCpp
.code());
2549 TU
.AdditionalFiles
= {{"foo.h", ""}, {"bar.h", ""}};
2550 TU
.ExtraArgs
= {"-isystem."};
2551 auto AST
= TU
.build();
2554 clangd::getDocumentLinks(AST
),
2556 DocumentLink({MainCpp
.range("foo"),
2557 URIForFile::canonicalize(testPath("foo.h"), "")}),
2558 DocumentLink({MainCpp
.range("bar"),
2559 URIForFile::canonicalize(testPath("bar.h"), "")})));
2563 } // namespace clangd
2564 } // namespace clang