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::ElementsAre
;
38 using ::testing::IsEmpty
;
39 using ::testing::Matcher
;
40 using ::testing::UnorderedElementsAre
;
41 using ::testing::UnorderedElementsAreArray
;
42 using ::testing::UnorderedPointwise
;
44 std::string
guard(llvm::StringRef Code
) {
45 return "#pragma once\n" + Code
.str();
48 MATCHER_P2(FileRange
, File
, Range
, "") {
49 return Location
{URIForFile::canonicalize(File
, testRoot()), Range
} == arg
;
51 MATCHER(declRange
, "") {
52 const LocatedSymbol
&Sym
= ::testing::get
<0>(arg
);
53 const Range
&Range
= ::testing::get
<1>(arg
);
54 return Sym
.PreferredDeclaration
.range
== Range
;
57 // Extracts ranges from an annotated example, and constructs a matcher for a
58 // highlight set. Ranges should be named $read/$write as appropriate.
59 Matcher
<const std::vector
<DocumentHighlight
> &>
60 highlightsFrom(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
;
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
);
76 TEST(HighlightsTest
, All
) {
77 const char *Tests
[] = {
78 R
"cpp(// Local variable
81 $write[[^bonjour]] = 2;
82 int test1 = $read[[bonjour]];
89 static void foo([[MyClass]]*) {}
93 ns1::[[My^Class]]* Params;
100 [[foo]]([[foo]](42));
105 R
"cpp(// Function parameter in decl
106 void foo(int [[^bar]]);
108 R
"cpp(// Not touching any identifiers.
117 R
"cpp(// ObjC methods with split selectors.
119 +(void) [[x]]:(int)a [[y]]:(int)b;
122 +(void) [[x]]:(int)a [[y]]:(int)b {}
125 [Foo [[x]]:2 [[^y]]:4];
136 for (const char *Test
: Tests
) {
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
))
146 TEST(HighlightsTest
, ControlFlow
) {
147 const char *Tests
[] = {
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);
154 // Returns from other functions not highlighted.
155 auto Lambda = [] { return; };
156 class LocalClass { void x() { return; } };
161 #define FAIL() return false
164 if (n < 0) [[FAIL]]();
170 // Highlight loop control flow
173 [[^for]] (char c : "fruit loops
!") {
174 if (c == ' ') [[continue]];
176 if (c == '!') [[break]];
177 if (c == '?') [[return]] -1;
184 // Highlight loop and same-loop control flow
187 if (false) [[bre^ak]];
195 // Highlight switch for break (but not other breaks).
196 void describe(unsigned n) {
207 // Highlight case and exits for switch-break (but not other cases).
208 void describe(unsigned n) {
221 // Highlight exits and switch for case
222 void describe(unsigned n) {
235 // Highlight nothing for switch.
236 void describe(unsigned n) {
249 // FIXME: match exception type against catch blocks
251 try { // wrong: highlight try with matching catch
252 try { // correct: has no matching catch
254 } catch (int) { } // correct: catch doesn't match type
255 [[return]] -1; // correct: exits the matching catch
256 } catch (const char*) { } // wrong: highlight matching catch
257 [[return]] 42; // wrong: throw doesn't exit function
262 // Loop highlights goto exiting the loop, but not jumping within it.
273 for (const char *Test
: Tests
) {
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
))
283 MATCHER_P3(sym
, Name
, Decl
, DefOrNone
, "") {
284 std::optional
<Range
> Def
= DefOrNone
;
285 if (Name
!= arg
.Name
) {
286 *result_listener
<< "Name is " << arg
.Name
;
289 if (Decl
!= arg
.PreferredDeclaration
.range
) {
290 *result_listener
<< "Declaration is "
291 << llvm::to_string(arg
.PreferredDeclaration
);
294 if (!Def
&& !arg
.Definition
)
296 if (Def
&& !arg
.Definition
) {
297 *result_listener
<< "Has no definition";
300 if (!Def
&& arg
.Definition
) {
301 *result_listener
<< "Definition is " << llvm::to_string(*arg
.Definition
);
304 if (arg
.Definition
->range
!= *Def
) {
305 *result_listener
<< "Definition is " << llvm::to_string(*arg
.Definition
);
311 MATCHER_P(sym
, Name
, "") { return arg
.Name
== Name
; }
313 MATCHER_P(rangeIs
, R
, "") { return arg
.Loc
.range
== R
; }
314 MATCHER_P(containerIs
, C
, "") {
315 return arg
.Loc
.containerName
.value_or("") == C
;
317 MATCHER_P(attrsAre
, A
, "") { return arg
.Attributes
== A
; }
318 MATCHER_P(hasID
, ID
, "") { return arg
.ID
== ID
; }
320 TEST(LocateSymbol
, WithIndex
) {
321 Annotations
SymbolHeader(R
"cpp(
322 class $forward[[Forward]];
323 class $foo[[Foo]] {};
327 inline void $f2[[f2]]() {}
329 Annotations
SymbolCpp(R
"cpp(
330 class $forward[[forward]] {};
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());
343 Annotations
Test(R
"cpp(// only declaration in AST.
349 EXPECT_THAT(LocateWithIndex(Test
),
350 ElementsAre(sym("f1", Test
.range(), SymbolCpp
.range("f1"))));
352 Test
= Annotations(R
"cpp(// definition in AST.
358 EXPECT_THAT(LocateWithIndex(Test
),
359 ElementsAre(sym("f1", SymbolHeader
.range("f1"), Test
.range())));
361 Test
= Annotations(R
"cpp(// forward declaration in AST.
365 EXPECT_THAT(LocateWithIndex(Test
),
366 ElementsAre(sym("Foo", Test
.range(), SymbolHeader
.range("foo"))));
368 Test
= Annotations(R
"cpp(// definition in AST.
369 class [[Forward]] {};
373 LocateWithIndex(Test
),
374 ElementsAre(sym("Forward", SymbolHeader
.range("forward"), Test
.range())));
377 TEST(LocateSymbol
, AnonymousStructFields
) {
378 auto Code
= Annotations(R
"cpp(
380 struct { int $1[[x]]; };
382 // Make sure the implicit base is skipped.
386 // Check that we don't skip explicit bases.
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"))));
394 locateSymbolAt(AST
, Code
.point("2"), TU
.index().get()),
395 UnorderedElementsAre(sym("Foo", Code
.range("2"), Code
.range("2"))));
398 TEST(LocateSymbol
, FindOverrides
) {
399 auto Code
= Annotations(R
"cpp(
401 virtual void $1[[fo^o]]() = 0;
403 class Bar : public Foo {
404 void $2[[foo]]() override;
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
)));
414 TEST(LocateSymbol
, WithIndexPreferredLocation
) {
415 Annotations
SymbolHeader(R
"cpp(
416 class $p[[Proto]] {};
417 void $f[[func]]() {};
420 TU
.HeaderCode
= std::string(SymbolHeader
.code());
421 TU
.HeaderFilename
= "x.proto"; // Prefer locations in codegen files.
422 auto Index
= TU
.index();
424 Annotations
Test(R
"cpp(// only declaration in AST.
425 // Shift to make range different.
434 auto AST
= TestTU::withCode(Test
.code()).build();
436 auto Locs
= clangd::locateSymbolAt(AST
, Test
.point("p"), Index
.get());
437 auto CodeGenLoc
= SymbolHeader
.range("p");
438 EXPECT_THAT(Locs
, ElementsAre(sym("Proto", CodeGenLoc
, CodeGenLoc
)));
441 auto Locs
= clangd::locateSymbolAt(AST
, Test
.point("f"), Index
.get());
442 auto CodeGenLoc
= SymbolHeader
.range("f");
443 EXPECT_THAT(Locs
, ElementsAre(sym("func", CodeGenLoc
, CodeGenLoc
)));
447 TEST(LocateSymbol
, All
) {
449 // $decl is the declaration location (if absent, no symbol is located)
450 // $def is the definition location (if absent, symbol has no definition)
451 // unnamed range becomes both $decl and $def.
452 const char *Tests
[] = {
465 R
"cpp(// Local variable
475 struct [[MyClass]] {};
478 ns1::My^Class* Params;
482 R
"cpp(// Function definition via pointer
489 R
"cpp(// Function declaration via call
490 int $decl[[foo]](int);
497 struct Foo { int [[x]]; };
504 R
"cpp(// Field, member initializer
511 R
"cpp(// Field, field designator
512 struct Foo { int [[x]]; };
514 Foo bar = { .^x = 2 };
519 struct Foo { int $decl[[x]](); };
527 typedef int $decl[[Foo]];
533 R
"cpp(// Template type parameter
534 template <typename [[T]]>
538 R
"cpp(// Template template type parameter
539 template <template<typename> class [[T]]>
540 void foo() { ^T<int> t; }
544 namespace $decl[[ns]] {
545 struct Foo { static void bar(); };
547 int main() { ^ns::Foo::bar(); }
551 class TTT { public: int a; };
552 #define [[FF]](S) if (int b = S.a) {}
559 R
"cpp(// Macro argument
561 #define ADDRESSOF(X) &X;
562 int *j = ADDRESSOF(^i);
564 R
"cpp(// Macro argument appearing multiple times in expansion
565 #define VALIDATE_TYPE(x) (void)x;
566 #define ASSERT(expr) \
568 VALIDATE_TYPE(expr); \
571 bool [[waldo]]() { return true; }
576 R
"cpp(// Symbol concatenated inside macro (not supported)
578 #define POINTER(X) p ## X;
579 int x = *POINTER(^i);
582 R
"cpp(// Forward class declaration
584 class $def[[Foo]] {};
588 R
"cpp(// Function declaration
591 void $def[[foo]]() {}
595 #define FF(name) class name##_Test {};
597 void f() { my^_Test a; }
601 #define FF() class [[Test]] {};
603 void f() { T^est a; }
606 R
"cpp(// explicit template specialization
607 template <typename T>
608 struct Foo { void bar() {} };
611 struct [[Foo]]<int> { void bar() {} };
619 R
"cpp(// implicit template specialization
620 template <typename T>
621 struct [[Foo]] { void bar() {} };
623 struct Foo<int> { void bar() {} };
630 R
"cpp(// partial template specialization
631 template <typename T>
632 struct Foo { void bar() {} };
633 template <typename T>
634 struct [[Foo]]<T*> { void bar() {} };
638 R
"cpp(// function template specializations
648 R
"cpp(// variable template decls
653 double [[var]]<int> = 10;
655 double y = va^r<int>;
658 R
"cpp(// No implicit constructors
670 X& $decl[[operator]]++();
678 struct S1 { void f(); };
679 struct S2 { S1 * $decl[[operator]]->(); };
685 R
"cpp(// Declaration of explicit template specialization
686 template <typename T>
687 struct $decl[[$def[[Foo]]]] {};
693 R
"cpp(// Declaration of partial template specialization
694 template <typename T>
695 struct $decl[[$def[[Foo]]]] {};
697 template <typename T>
701 R
"cpp(// Definition on ClassTemplateDecl
703 // Forward declaration.
707 template <typename T>
708 struct $def[[Foo]] {};
714 R
"cpp(// auto builtin type (not supported)
718 R
"cpp(// auto on lambda
723 R
"cpp(// auto on struct
731 R
"cpp(// decltype on struct
740 R
"cpp(// decltype(auto) on struct
747 ^decltype(auto) k = j;
750 R
"cpp(// auto on template class
751 template<typename T> class [[Foo]] {};
753 ^auto x = Foo<int>();
756 R
"cpp(// auto on template class with forward declared class
757 template<typename T> class [[Foo]] {};
763 R
"cpp(// auto on specialized template class
764 template<typename T> class Foo {};
765 template<> class [[Foo]]<int> {};
767 ^auto x = Foo<int>();
770 R
"cpp(// auto on initializer list.
774 class [[initializer_list]] { const _E *a, *b; };
780 R
"cpp(// auto function return with trailing type
782 ^auto test() -> decltype(Bar()) {
787 R
"cpp(// decltype in trailing return type
789 auto test() -> ^decltype(Bar()) {
794 R
"cpp(// auto in function return
801 R
"cpp(// auto& in function return
809 R
"cpp(// auto* in function return
817 R
"cpp(// const auto& in function return
819 const ^auto& test() {
825 R
"cpp(// auto lambda param where there's a single instantiation
827 auto Lambda = [](^auto){ return 0; };
828 int x = Lambda(Bar{});
831 R
"cpp(// decltype(auto) in function return
833 ^decltype(auto) test() {
838 R
"cpp(// decltype of function with trailing return type.
840 auto test() -> decltype(Bar()) {
844 ^decltype(test()) i = test();
848 R
"cpp(// Override specifier jumps to overridden method
849 class Y { virtual void $decl[[a]]() = 0; };
850 class X : Y { void a() ^override {} };
853 R
"cpp(// Final specifier jumps to overridden method
854 class Y { virtual void $decl[[a]]() = 0; };
855 class X : Y { void a() ^final {} };
858 R
"cpp(// Heuristic resolution of dependent method
859 template <typename T>
864 template <typename T>
870 R
"cpp(// Heuristic resolution of dependent method via this->
871 template <typename T>
879 R
"cpp(// Heuristic resolution of dependent static method
880 template <typename T>
882 static void [[bar]]() {}
885 template <typename T>
891 R
"cpp(// Heuristic resolution of dependent method
892 // invoked via smart pointer
893 template <typename> struct S { void [[foo]]() {} };
894 template <typename T> struct unique_ptr {
897 template <typename T>
898 void test(unique_ptr<S<T>>& V) {
903 R
"cpp(// Heuristic resolution of dependent enumerator
904 template <typename T>
906 enum class E { [[A]], B };
912 typedef int $decl[[MyTypeDef]];
913 enum Foo : My^TypeDef {};
916 typedef int $decl[[MyTypeDef]];
917 enum Foo : My^TypeDef;
920 using $decl[[MyTypeDef]] = int;
921 enum Foo : My^TypeDef {};
926 @protocol $decl[[Dog]]
929 id<Do^g> getDoggo() {
939 @interface $decl[[Cat]] (Exte^nsion)
942 @implementation $def[[Cat]] (Extension)
954 R
"objc(// Prefer interface definition over forward declaration
956 @interface $decl[[Foo]]
965 @interface $decl[[Foo]]
967 @implementation $def[[Foo]]
974 R
"objc(// Method decl and definition for ObjC class.
976 - (void)$decl[[meow]];
979 - (void)$def[[meow]] {}
981 void makeNoise(Cat *kitty) {
986 R
"objc(// Method decl and definition for ObjC category.
989 @interface Dog (Play)
990 - (void)$decl[[runAround]];
992 @implementation Dog (Play)
993 - (void)$def[[runAround]] {}
995 void play(Dog *dog) {
1000 R
"objc(// Method decl and definition for ObjC class extension.
1004 - (void)$decl[[howl]];
1007 - (void)$def[[howl]] {}
1009 void play(Dog *dog) {
1014 struct PointerIntPairInfo {
1015 static void *getPointer(void *Value);
1018 template <typename Info = PointerIntPairInfo> struct PointerIntPair {
1020 void *getPointer() const { return Info::get^Pointer(Value); }
1023 R
"cpp(// Deducing this
1029 int x = wa^ldo.bar();
1032 for (const char *Test
: Tests
) {
1033 Annotations
T(Test
);
1034 std::optional
<Range
> WantDecl
;
1035 std::optional
<Range
> WantDef
;
1036 if (!T
.ranges().empty())
1037 WantDecl
= WantDef
= T
.range();
1038 if (!T
.ranges("decl").empty())
1039 WantDecl
= T
.range("decl");
1040 if (!T
.ranges("def").empty())
1041 WantDef
= T
.range("def");
1044 TU
.Code
= std::string(T
.code());
1046 TU
.ExtraArgs
.push_back("-xobjective-c++");
1047 TU
.ExtraArgs
.push_back("-std=c++23");
1049 auto AST
= TU
.build();
1050 auto Results
= locateSymbolAt(AST
, T
.point());
1053 EXPECT_THAT(Results
, IsEmpty()) << Test
;
1055 ASSERT_THAT(Results
, ::testing::SizeIs(1)) << Test
;
1056 EXPECT_EQ(Results
[0].PreferredDeclaration
.range
, *WantDecl
) << Test
;
1057 EXPECT_TRUE(Results
[0].ID
) << Test
;
1058 std::optional
<Range
> GotDef
;
1059 if (Results
[0].Definition
)
1060 GotDef
= Results
[0].Definition
->range
;
1061 EXPECT_EQ(WantDef
, GotDef
) << Test
;
1065 TEST(LocateSymbol
, ValidSymbolID
) {
1066 auto T
= Annotations(R
"cpp(
1067 #define MACRO(x, y) ((x) + (y))
1068 int add(int x, int y) { return $MACRO^MACRO(x, y); }
1069 int sum = $add^add(1, 2);
1072 TestTU TU
= TestTU::withCode(T
.code());
1073 auto AST
= TU
.build();
1074 auto Index
= TU
.index();
1075 EXPECT_THAT(locateSymbolAt(AST
, T
.point("add"), Index
.get()),
1076 ElementsAre(AllOf(sym("add"),
1077 hasID(getSymbolID(&findDecl(AST
, "add"))))));
1079 locateSymbolAt(AST
, T
.point("MACRO"), Index
.get()),
1080 ElementsAre(AllOf(sym("MACRO"),
1081 hasID(findSymbol(TU
.headerSymbols(), "MACRO").ID
))));
1084 TEST(LocateSymbol
, AllMulti
) {
1086 // $declN is the declaration location
1087 // $defN is the definition location (if absent, symbol has no definition)
1091 struct ExpectedRanges
{
1093 std::optional
<Range
> WantDef
;
1095 const char *Tests
[] = {
1097 @interface $decl0[[Cat]]
1099 @implementation $def0[[Cat]]
1101 @interface $decl1[[Ca^t]] (Extension)
1104 @implementation $def1[[Cat]] (Extension)
1110 @interface $decl0[[Cat]]
1112 @implementation $def0[[Cat]]
1114 @interface $decl1[[Cat]] (Extension)
1117 @implementation $def1[[Ca^t]] (Extension)
1123 @interface $decl0[[Cat]]
1125 @interface $decl1[[Ca^t]] ()
1128 @implementation $def0[[$def1[[Cat]]]]
1133 for (const char *Test
: Tests
) {
1134 Annotations
T(Test
);
1135 std::vector
<ExpectedRanges
> Ranges
;
1136 for (int Idx
= 0; true; Idx
++) {
1137 bool HasDecl
= !T
.ranges("decl" + std::to_string(Idx
)).empty();
1138 bool HasDef
= !T
.ranges("def" + std::to_string(Idx
)).empty();
1139 if (!HasDecl
&& !HasDef
)
1141 ExpectedRanges Range
;
1143 Range
.WantDecl
= T
.range("decl" + std::to_string(Idx
));
1145 Range
.WantDef
= T
.range("def" + std::to_string(Idx
));
1146 Ranges
.push_back(Range
);
1150 TU
.Code
= std::string(T
.code());
1151 TU
.ExtraArgs
.push_back("-xobjective-c++");
1153 auto AST
= TU
.build();
1154 auto Results
= locateSymbolAt(AST
, T
.point());
1156 ASSERT_THAT(Results
, ::testing::SizeIs(Ranges
.size())) << Test
;
1157 for (size_t Idx
= 0; Idx
< Ranges
.size(); Idx
++) {
1158 EXPECT_EQ(Results
[Idx
].PreferredDeclaration
.range
, Ranges
[Idx
].WantDecl
)
1159 << "($decl" << Idx
<< ")" << Test
;
1160 std::optional
<Range
> GotDef
;
1161 if (Results
[Idx
].Definition
)
1162 GotDef
= Results
[Idx
].Definition
->range
;
1163 EXPECT_EQ(GotDef
, Ranges
[Idx
].WantDef
) << "($def" << Idx
<< ")" << Test
;
1168 // LocateSymbol test cases that produce warnings.
1169 // These are separated out from All so that in All we can assert
1170 // that there are no diagnostics.
1171 TEST(LocateSymbol
, Warnings
) {
1172 const char *Tests
[] = {
1173 R
"cpp(// Field, GNU old-style field designator
1174 struct Foo { int [[x]]; };
1176 Foo bar = { ^x : 1 };
1183 int main() { return ^MACRO; }
1189 for (const char *Test
: Tests
) {
1190 Annotations
T(Test
);
1191 std::optional
<Range
> WantDecl
;
1192 std::optional
<Range
> WantDef
;
1193 if (!T
.ranges().empty())
1194 WantDecl
= WantDef
= T
.range();
1195 if (!T
.ranges("decl").empty())
1196 WantDecl
= T
.range("decl");
1197 if (!T
.ranges("def").empty())
1198 WantDef
= T
.range("def");
1201 TU
.Code
= std::string(T
.code());
1203 auto AST
= TU
.build();
1204 auto Results
= locateSymbolAt(AST
, T
.point());
1207 EXPECT_THAT(Results
, IsEmpty()) << Test
;
1209 ASSERT_THAT(Results
, ::testing::SizeIs(1)) << Test
;
1210 EXPECT_EQ(Results
[0].PreferredDeclaration
.range
, *WantDecl
) << Test
;
1211 std::optional
<Range
> GotDef
;
1212 if (Results
[0].Definition
)
1213 GotDef
= Results
[0].Definition
->range
;
1214 EXPECT_EQ(WantDef
, GotDef
) << Test
;
1219 TEST(LocateSymbol
, TextualSmoke
) {
1220 auto T
= Annotations(
1222 struct [[MyClass]] {};
1223 // Comment mentioning M^yClass
1226 auto TU
= TestTU::withCode(T
.code());
1227 auto AST
= TU
.build();
1228 auto Index
= TU
.index();
1230 locateSymbolAt(AST
, T
.point(), Index
.get()),
1231 ElementsAre(AllOf(sym("MyClass", T
.range(), T
.range()),
1232 hasID(getSymbolID(&findDecl(AST
, "MyClass"))))));
1235 TEST(LocateSymbol
, Textual
) {
1236 const char *Tests
[] = {
1238 struct [[MyClass]] {};
1239 // Comment mentioning M^yClass
1243 // Not triggered for string literal tokens.
1244 const char* s = "String literal mentioning M
^yClass
";
1246 R
"cpp(// Ifdef'ed out code
1247 struct [[MyClass]] {};
1252 R
"cpp(// Macro definition
1253 struct [[MyClass]] {};
1254 #define DECLARE_MYCLASS_OBJ(name) M^yClass name;
1256 R
"cpp(// Invalid code
1258 int myFunction(int);
1259 // Not triggered for token which survived preprocessing.
1260 int var = m^yFunction();
1263 for (const char *Test
: Tests
) {
1264 Annotations
T(Test
);
1265 std::optional
<Range
> WantDecl
;
1266 if (!T
.ranges().empty())
1267 WantDecl
= T
.range();
1269 auto TU
= TestTU::withCode(T
.code());
1271 auto AST
= TU
.build();
1272 auto Index
= TU
.index();
1273 auto Word
= SpelledWord::touching(
1274 cantFail(sourceLocationInMainFile(AST
.getSourceManager(), T
.point())),
1275 AST
.getTokens(), AST
.getLangOpts());
1277 ADD_FAILURE() << "No word touching point!" << Test
;
1280 auto Results
= locateSymbolTextually(*Word
, AST
, Index
.get(),
1281 testPath(TU
.Filename
), ASTNodeKind());
1284 EXPECT_THAT(Results
, IsEmpty()) << Test
;
1286 ASSERT_THAT(Results
, ::testing::SizeIs(1)) << Test
;
1287 EXPECT_EQ(Results
[0].PreferredDeclaration
.range
, *WantDecl
) << Test
;
1292 TEST(LocateSymbol
, Ambiguous
) {
1293 auto T
= Annotations(R
"cpp(
1297 $ConstructorLoc[[Foo]](const char*);
1305 const char* str = "123";
1307 Foo b = Foo($2^str);
1312 Foo ab$8^cd("asdf
");
1313 Foo foox = Fo$9^o("asdf
");
1314 Foo abcde$10^("asdf
");
1315 Foo foox2 = Foo$11^("asdf
");
1318 template <typename T>
1320 void $NonstaticOverload1[[bar]](int);
1321 void $NonstaticOverload2[[bar]](float);
1323 static void $StaticOverload1[[baz]](int);
1324 static void $StaticOverload2[[baz]](float);
1327 template <typename T, typename U>
1328 void dependent_call(S<T> s, U u) {
1333 auto TU
= TestTU::withCode(T
.code());
1334 // FIXME: Go-to-definition in a template requires disabling delayed template
1336 TU
.ExtraArgs
.push_back("-fno-delayed-template-parsing");
1337 auto AST
= TU
.build();
1338 // Ordered assertions are deliberate: we expect a predictable order.
1339 EXPECT_THAT(locateSymbolAt(AST
, T
.point("1")), ElementsAre(sym("str")));
1340 EXPECT_THAT(locateSymbolAt(AST
, T
.point("2")), ElementsAre(sym("str")));
1341 EXPECT_THAT(locateSymbolAt(AST
, T
.point("3")), ElementsAre(sym("f")));
1342 EXPECT_THAT(locateSymbolAt(AST
, T
.point("4")), ElementsAre(sym("g")));
1343 EXPECT_THAT(locateSymbolAt(AST
, T
.point("5")), ElementsAre(sym("f")));
1344 EXPECT_THAT(locateSymbolAt(AST
, T
.point("6")), ElementsAre(sym("str")));
1345 // FIXME: Target the constructor as well.
1346 EXPECT_THAT(locateSymbolAt(AST
, T
.point("7")), ElementsAre(sym("abc")));
1347 // FIXME: Target the constructor as well.
1348 EXPECT_THAT(locateSymbolAt(AST
, T
.point("8")), ElementsAre(sym("abcd")));
1349 // FIXME: Target the constructor as well.
1350 EXPECT_THAT(locateSymbolAt(AST
, T
.point("9")), ElementsAre(sym("Foo")));
1351 EXPECT_THAT(locateSymbolAt(AST
, T
.point("10")),
1352 ElementsAre(sym("Foo", T
.range("ConstructorLoc"), std::nullopt
)));
1353 EXPECT_THAT(locateSymbolAt(AST
, T
.point("11")),
1354 ElementsAre(sym("Foo", T
.range("ConstructorLoc"), std::nullopt
)));
1355 // These assertions are unordered because the order comes from
1356 // CXXRecordDecl::lookupDependentName() which doesn't appear to provide
1357 // an order guarantee.
1358 EXPECT_THAT(locateSymbolAt(AST
, T
.point("12")),
1359 UnorderedElementsAre(
1360 sym("bar", T
.range("NonstaticOverload1"), std::nullopt
),
1361 sym("bar", T
.range("NonstaticOverload2"), std::nullopt
)));
1362 EXPECT_THAT(locateSymbolAt(AST
, T
.point("13")),
1363 UnorderedElementsAre(
1364 sym("baz", T
.range("StaticOverload1"), std::nullopt
),
1365 sym("baz", T
.range("StaticOverload2"), std::nullopt
)));
1368 TEST(LocateSymbol
, TextualDependent
) {
1369 // Put the declarations in the header to make sure we are
1370 // finding them via the index heuristic and not the
1371 // nearby-ident heuristic.
1372 Annotations
Header(R
"cpp(
1374 void $FooLoc[[uniqueMethodName]]();
1377 void $BarLoc[[uniqueMethodName]]();
1380 Annotations
Source(R
"cpp(
1381 template <typename T>
1383 t.u^niqueMethodName();
1387 TU
.Code
= std::string(Source
.code());
1388 TU
.HeaderCode
= std::string(Header
.code());
1389 auto AST
= TU
.build();
1390 auto Index
= TU
.index();
1391 // Need to use locateSymbolAt() since we are testing an
1392 // interaction between locateASTReferent() and
1393 // locateSymbolNamedTextuallyAt().
1394 auto Results
= locateSymbolAt(AST
, Source
.point(), Index
.get());
1397 UnorderedElementsAre(
1398 sym("uniqueMethodName", Header
.range("FooLoc"), std::nullopt
),
1399 sym("uniqueMethodName", Header
.range("BarLoc"), std::nullopt
)));
1402 TEST(LocateSymbol
, Alias
) {
1403 const char *Tests
[] = {
1405 template <class T> struct function {};
1406 template <class T> using [[callback]] = function<T()>;
1411 // triggered on non-definition of a renaming alias: should not give any
1412 // underlying decls.
1415 typedef Foo [[Bar]];
1421 using [[Bar]] = Foo; // definition
1425 // triggered on the underlying decl of a renaming alias.
1431 // triggered on definition of a non-renaming alias: should give underlying
1434 namespace ns { class [[Foo]] {}; }
1439 namespace ns { int [[x]](char); int [[x]](double); }
1444 namespace ns { int [[x]](char); int x(double); }
1450 namespace ns { class [[Foo]] {}; }
1455 // other cases that don't matter much.
1458 typedef Foo [[Ba^r]];
1462 using [[B^ar]] = Foo;
1465 // Member of dependent base
1467 template <typename T>
1471 template <typename T>
1472 struct Derived : Base<T> {
1473 using Base<T>::w^aldo;
1478 for (const auto *Case
: Tests
) {
1480 auto T
= Annotations(Case
);
1481 auto AST
= TestTU::withCode(T
.code()).build();
1482 EXPECT_THAT(locateSymbolAt(AST
, T
.point()),
1483 UnorderedPointwise(declRange(), T
.ranges()));
1487 TEST(LocateSymbol
, RelPathsInCompileCommand
) {
1488 // The source is in "/clangd-test/src".
1489 // We build in "/clangd-test/build".
1491 Annotations
SourceAnnotations(R
"cpp(
1492 #include "header_in_preamble
.h
"
1494 #include "header_not_in_preamble
.h
"
1495 int baz = f$p1^oo + bar_pre$p2^amble + bar_not_pre$p3^amble;
1498 Annotations
HeaderInPreambleAnnotations(R
"cpp(
1499 int [[bar_preamble]];
1502 Annotations
HeaderNotInPreambleAnnotations(R
"cpp(
1503 int [[bar_not_preamble]];
1506 // Make the compilation paths appear as ../src/foo.cpp in the compile
1508 SmallString
<32> RelPathPrefix("..");
1509 llvm::sys::path::append(RelPathPrefix
, "src");
1510 std::string BuildDir
= testPath("build");
1511 MockCompilationDatabase
CDB(BuildDir
, RelPathPrefix
);
1514 ClangdServer
Server(CDB
, FS
, ClangdServer::optsForTest());
1516 // Fill the filesystem.
1517 auto FooCpp
= testPath("src/foo.cpp");
1518 FS
.Files
[FooCpp
] = "";
1519 auto HeaderInPreambleH
= testPath("src/header_in_preamble.h");
1520 FS
.Files
[HeaderInPreambleH
] = std::string(HeaderInPreambleAnnotations
.code());
1521 auto HeaderNotInPreambleH
= testPath("src/header_not_in_preamble.h");
1522 FS
.Files
[HeaderNotInPreambleH
] =
1523 std::string(HeaderNotInPreambleAnnotations
.code());
1525 runAddDocument(Server
, FooCpp
, SourceAnnotations
.code());
1527 // Go to a definition in main source file.
1529 runLocateSymbolAt(Server
, FooCpp
, SourceAnnotations
.point("p1"));
1530 EXPECT_TRUE(bool(Locations
)) << "findDefinitions returned an error";
1531 EXPECT_THAT(*Locations
, ElementsAre(sym("foo", SourceAnnotations
.range(),
1532 SourceAnnotations
.range())));
1534 // Go to a definition in header_in_preamble.h.
1535 Locations
= runLocateSymbolAt(Server
, FooCpp
, SourceAnnotations
.point("p2"));
1536 EXPECT_TRUE(bool(Locations
)) << "findDefinitions returned an error";
1539 ElementsAre(sym("bar_preamble", HeaderInPreambleAnnotations
.range(),
1540 HeaderInPreambleAnnotations
.range())));
1542 // Go to a definition in header_not_in_preamble.h.
1543 Locations
= runLocateSymbolAt(Server
, FooCpp
, SourceAnnotations
.point("p3"));
1544 EXPECT_TRUE(bool(Locations
)) << "findDefinitions returned an error";
1545 EXPECT_THAT(*Locations
,
1546 ElementsAre(sym("bar_not_preamble",
1547 HeaderNotInPreambleAnnotations
.range(),
1548 HeaderNotInPreambleAnnotations
.range())));
1551 TEST(GoToInclude
, All
) {
1553 MockCompilationDatabase CDB
;
1554 ClangdServer
Server(CDB
, FS
, ClangdServer::optsForTest());
1556 auto FooCpp
= testPath("foo.cpp");
1557 const char *SourceContents
= R
"cpp(
1558 #include ^"$
2^foo
.h$
3^"
1559 #include "$
4^invalid
.h
"
1563 #in$5^clude "$
6^foo
.h
"$7^
1565 Annotations
SourceAnnotations(SourceContents
);
1566 FS
.Files
[FooCpp
] = std::string(SourceAnnotations
.code());
1567 auto FooH
= testPath("foo.h");
1569 const char *HeaderContents
= R
"cpp([[]]#pragma once
1572 Annotations
HeaderAnnotations(HeaderContents
);
1573 FS
.Files
[FooH
] = std::string(HeaderAnnotations
.code());
1575 runAddDocument(Server
, FooH
, HeaderAnnotations
.code());
1576 runAddDocument(Server
, FooCpp
, SourceAnnotations
.code());
1578 // Test include in preamble.
1579 auto Locations
= runLocateSymbolAt(Server
, FooCpp
, SourceAnnotations
.point());
1580 ASSERT_TRUE(bool(Locations
)) << "locateSymbolAt returned an error";
1581 EXPECT_THAT(*Locations
, ElementsAre(sym("foo.h", HeaderAnnotations
.range(),
1582 HeaderAnnotations
.range())));
1584 // Test include in preamble, last char.
1585 Locations
= runLocateSymbolAt(Server
, FooCpp
, SourceAnnotations
.point("2"));
1586 ASSERT_TRUE(bool(Locations
)) << "locateSymbolAt returned an error";
1587 EXPECT_THAT(*Locations
, ElementsAre(sym("foo.h", HeaderAnnotations
.range(),
1588 HeaderAnnotations
.range())));
1590 Locations
= runLocateSymbolAt(Server
, FooCpp
, SourceAnnotations
.point("3"));
1591 ASSERT_TRUE(bool(Locations
)) << "locateSymbolAt returned an error";
1592 EXPECT_THAT(*Locations
, ElementsAre(sym("foo.h", HeaderAnnotations
.range(),
1593 HeaderAnnotations
.range())));
1595 // Test include outside of preamble.
1596 Locations
= runLocateSymbolAt(Server
, FooCpp
, SourceAnnotations
.point("6"));
1597 ASSERT_TRUE(bool(Locations
)) << "locateSymbolAt returned an error";
1598 EXPECT_THAT(*Locations
, ElementsAre(sym("foo.h", HeaderAnnotations
.range(),
1599 HeaderAnnotations
.range())));
1601 // Test a few positions that do not result in Locations.
1602 Locations
= runLocateSymbolAt(Server
, FooCpp
, SourceAnnotations
.point("4"));
1603 ASSERT_TRUE(bool(Locations
)) << "locateSymbolAt returned an error";
1604 EXPECT_THAT(*Locations
, IsEmpty());
1606 Locations
= runLocateSymbolAt(Server
, FooCpp
, SourceAnnotations
.point("5"));
1607 ASSERT_TRUE(bool(Locations
)) << "locateSymbolAt returned an error";
1608 EXPECT_THAT(*Locations
, ElementsAre(sym("foo.h", HeaderAnnotations
.range(),
1609 HeaderAnnotations
.range())));
1611 Locations
= runLocateSymbolAt(Server
, FooCpp
, SourceAnnotations
.point("7"));
1612 ASSERT_TRUE(bool(Locations
)) << "locateSymbolAt returned an error";
1613 EXPECT_THAT(*Locations
, ElementsAre(sym("foo.h", HeaderAnnotations
.range(),
1614 HeaderAnnotations
.range())));
1616 // Objective C #import directive.
1617 Annotations
ObjC(R
"objc(
1620 auto FooM
= testPath("foo.m");
1621 FS
.Files
[FooM
] = std::string(ObjC
.code());
1623 runAddDocument(Server
, FooM
, ObjC
.code());
1624 Locations
= runLocateSymbolAt(Server
, FooM
, ObjC
.point());
1625 ASSERT_TRUE(bool(Locations
)) << "locateSymbolAt returned an error";
1626 EXPECT_THAT(*Locations
, ElementsAre(sym("foo.h", HeaderAnnotations
.range(),
1627 HeaderAnnotations
.range())));
1630 TEST(LocateSymbol
, WithPreamble
) {
1631 // Test stragety: AST should always use the latest preamble instead of last
1634 MockCompilationDatabase CDB
;
1635 ClangdServer
Server(CDB
, FS
, ClangdServer::optsForTest());
1637 auto FooCpp
= testPath("foo.cpp");
1638 // The trigger locations must be the same.
1639 Annotations
FooWithHeader(R
"cpp(#include "fo
^o
.h
")cpp");
1640 Annotations
FooWithoutHeader(R
"cpp(double [[fo^o]]();)cpp");
1642 FS
.Files
[FooCpp
] = std::string(FooWithHeader
.code());
1644 auto FooH
= testPath("foo.h");
1645 Annotations
FooHeader(R
"cpp([[]])cpp");
1646 FS
.Files
[FooH
] = std::string(FooHeader
.code());
1648 runAddDocument(Server
, FooCpp
, FooWithHeader
.code());
1649 // LocateSymbol goes to a #include file: the result comes from the preamble.
1651 cantFail(runLocateSymbolAt(Server
, FooCpp
, FooWithHeader
.point())),
1652 ElementsAre(sym("foo.h", FooHeader
.range(), FooHeader
.range())));
1654 // Only preamble is built, and no AST is built in this request.
1655 Server
.addDocument(FooCpp
, FooWithoutHeader
.code(), "null",
1656 WantDiagnostics::No
);
1657 // We build AST here, and it should use the latest preamble rather than the
1660 cantFail(runLocateSymbolAt(Server
, FooCpp
, FooWithoutHeader
.point())),
1661 ElementsAre(sym("foo", FooWithoutHeader
.range(), std::nullopt
)));
1663 // Reset test environment.
1664 runAddDocument(Server
, FooCpp
, FooWithHeader
.code());
1665 // Both preamble and AST are built in this request.
1666 Server
.addDocument(FooCpp
, FooWithoutHeader
.code(), "null",
1667 WantDiagnostics::Yes
);
1668 // Use the AST being built in above request.
1670 cantFail(runLocateSymbolAt(Server
, FooCpp
, FooWithoutHeader
.point())),
1671 ElementsAre(sym("foo", FooWithoutHeader
.range(), std::nullopt
)));
1674 TEST(LocateSymbol
, NearbyTokenSmoke
) {
1675 auto T
= Annotations(R
"cpp(
1676 // prints e^rr and crashes
1677 void die(const char* [[err]]);
1679 auto AST
= TestTU::withCode(T
.code()).build();
1680 // We don't pass an index, so can't hit index-based fallback.
1681 EXPECT_THAT(locateSymbolAt(AST
, T
.point()),
1682 ElementsAre(sym("err", T
.range(), T
.range())));
1685 TEST(LocateSymbol
, NearbyIdentifier
) {
1686 const char *Tests
[] = {
1688 // regular identifiers (won't trigger)
1693 // disabled preprocessor sections
1705 // not triggered by string literals
1707 const char* greeting = "h
^ello
, world
";
1711 // can refer to macro invocations
1718 // can refer to macro invocations (even if they expand to nothing)
1725 // prefer nearest occurrence, backwards is worse than forwards
1734 // short identifiers find near results
1739 // short identifiers don't find far results
1752 // prefer nearest occurrence even if several matched tokens
1753 // have the same value of `floor(log2(<token line> - <word line>))`.
1755 int x = hello, y = hello;
1759 for (const char *Test
: Tests
) {
1760 Annotations
T(Test
);
1761 auto AST
= TestTU::withCode(T
.code()).build();
1762 const auto &SM
= AST
.getSourceManager();
1763 std::optional
<Range
> Nearby
;
1765 SpelledWord::touching(cantFail(sourceLocationInMainFile(SM
, T
.point())),
1766 AST
.getTokens(), AST
.getLangOpts());
1768 ADD_FAILURE() << "No word at point! " << Test
;
1771 if (const auto *Tok
= findNearbyIdentifier(*Word
, AST
.getTokens()))
1772 Nearby
= halfOpenToRange(SM
, CharSourceRange::getCharRange(
1773 Tok
->location(), Tok
->endLocation()));
1774 if (T
.ranges().empty())
1775 EXPECT_THAT(Nearby
, Eq(std::nullopt
)) << Test
;
1777 EXPECT_EQ(Nearby
, T
.range()) << Test
;
1781 TEST(FindImplementations
, Inheritance
) {
1782 llvm::StringRef Test
= R
"cpp(
1784 virtual void F$1^oo();
1787 struct $0[[Child1]] : Base {
1788 void $1[[Fo$3^o]]() override;
1789 virtual void B$2^ar();
1790 void Concrete(); // No implementations for concrete methods.
1792 struct Child2 : Child1 {
1793 void $3[[Foo]]() override;
1794 void $2[[Bar]]() override;
1796 void FromReference() {
1805 // CRTP should work.
1806 template<typename T>
1807 struct $5^TemplateBase {};
1808 struct $5[[Child3]] : public TemplateBase<Child3> {};
1811 void LocationFunction() {
1812 struct $0[[LocalClass1]] : Base {
1813 void $1[[Foo]]() override;
1815 struct $6^LocalBase {
1816 virtual void $7^Bar();
1818 struct $6[[LocalClass2]]: LocalBase {
1819 void $7[[Bar]]() override;
1824 Annotations
Code(Test
);
1825 auto TU
= TestTU::withCode(Code
.code());
1826 auto AST
= TU
.build();
1827 auto Index
= TU
.index();
1828 for (StringRef Label
: {"0", "1", "2", "3", "4", "5", "6", "7"}) {
1829 for (const auto &Point
: Code
.points(Label
)) {
1830 EXPECT_THAT(findImplementations(AST
, Point
, Index
.get()),
1831 UnorderedPointwise(declRange(), Code
.ranges(Label
)))
1832 << Code
.code() << " at " << Point
<< " for Label " << Label
;
1837 TEST(FindImplementations
, CaptureDefinition
) {
1838 llvm::StringRef Test
= R
"cpp(
1840 virtual void F^oo();
1842 struct Child1 : Base {
1843 void $Decl[[Foo]]() override;
1845 struct Child2 : Base {
1846 void $Child2[[Foo]]() override;
1848 void Child1::$Def[[Foo]]() { /* Definition */ }
1850 Annotations
Code(Test
);
1851 auto TU
= TestTU::withCode(Code
.code());
1852 auto AST
= TU
.build();
1854 findImplementations(AST
, Code
.point(), TU
.index().get()),
1855 UnorderedElementsAre(sym("Foo", Code
.range("Decl"), Code
.range("Def")),
1856 sym("Foo", Code
.range("Child2"), std::nullopt
)))
1860 TEST(FindType
, All
) {
1861 Annotations
HeaderA(R
"cpp(
1862 struct $Target[[Target]] { operator int() const; };
1863 struct Aggregate { Target a, b; };
1867 template <typename T> struct $smart_ptr[[smart_ptr]] {
1873 auto TU
= TestTU::withHeaderCode(HeaderA
.code());
1874 for (const llvm::StringRef Case
: {
1878 "a^uto x = Target{};",
1879 "namespace m { Target tgt; } auto x = m^::tgt;",
1880 "Target funcCall(); auto x = ^funcCall();",
1881 "Aggregate a = { {}, ^{} };",
1882 "Aggregate a = { ^.a=t, };",
1883 "struct X { Target a; X() : ^a() {} };",
1884 "^using T = Target; ^T foo();",
1885 "^template <int> Target foo();",
1886 "void x() { try {} ^catch(Target e) {} }",
1887 "void x() { ^throw t; }",
1888 "int x() { ^return t; }",
1889 "void x() { ^switch(t) {} }",
1890 "void x() { ^delete (Target*)nullptr; }",
1891 "Target& ^tref = t;",
1892 "void x() { ^if (t) {} }",
1893 "void x() { ^while (t) {} }",
1894 "void x() { ^do { } while (t); }",
1895 "void x() { ^make(); }",
1896 "void x(smart_ptr<Target> &t) { t.^get(); }",
1897 "^auto x = []() { return t; };",
1898 "Target* ^tptr = &t;",
1899 "Target ^tarray[3];",
1901 Annotations
A(Case
);
1902 TU
.Code
= A
.code().str();
1903 ParsedAST AST
= TU
.build();
1905 ASSERT_GT(A
.points().size(), 0u) << Case
;
1906 for (auto Pos
: A
.points())
1907 EXPECT_THAT(findType(AST
, Pos
, nullptr),
1909 sym("Target", HeaderA
.range("Target"), HeaderA
.range("Target"))))
1913 for (const llvm::StringRef Case
: {
1914 "smart_ptr<Target> ^tsmart;",
1916 Annotations
A(Case
);
1917 TU
.Code
= A
.code().str();
1918 ParsedAST AST
= TU
.build();
1920 EXPECT_THAT(findType(AST
, A
.point(), nullptr),
1921 UnorderedElementsAre(
1922 sym("Target", HeaderA
.range("Target"), HeaderA
.range("Target")),
1923 sym("smart_ptr", HeaderA
.range("smart_ptr"), HeaderA
.range("smart_ptr"))
1929 TEST(FindType
, Definition
) {
1930 Annotations
A(R
"cpp(
1935 auto TU
= TestTU::withCode(A
.code().str());
1936 ParsedAST AST
= TU
.build();
1938 EXPECT_THAT(findType(AST
, A
.point(), nullptr),
1939 ElementsAre(sym("X", A
.range("decl"), A
.range("def"))));
1942 TEST(FindType
, Index
) {
1943 Annotations
Def(R
"cpp(
1944 // This definition is only available through the index.
1947 TestTU DefTU
= TestTU::withHeaderCode(Def
.code());
1948 DefTU
.HeaderFilename
= "def.h";
1949 auto DefIdx
= DefTU
.index();
1951 Annotations
A(R
"cpp(
1955 auto TU
= TestTU::withCode(A
.code().str());
1956 ParsedAST AST
= TU
.build();
1958 EXPECT_THAT(findType(AST
, A
.point(), DefIdx
.get()),
1959 ElementsAre(sym("X", A
.range(), Def
.range())));
1962 void checkFindRefs(llvm::StringRef Test
, bool UseIndex
= false) {
1963 Annotations
T(Test
);
1964 auto TU
= TestTU::withCode(T
.code());
1965 TU
.ExtraArgs
.push_back("-std=c++20");
1967 auto AST
= TU
.build();
1968 std::vector
<Matcher
<ReferencesResult::Reference
>> ExpectedLocations
;
1969 for (const auto &[R
, Context
] : T
.rangesWithPayload())
1970 ExpectedLocations
.push_back(
1971 AllOf(rangeIs(R
), containerIs(Context
), attrsAre(0u)));
1972 // $def is actually shorthand for both definition and declaration.
1973 // If we have cases that are definition-only, we should change this.
1974 for (const auto &[R
, Context
] : T
.rangesWithPayload("def"))
1975 ExpectedLocations
.push_back(AllOf(rangeIs(R
), containerIs(Context
),
1976 attrsAre(ReferencesResult::Definition
|
1977 ReferencesResult::Declaration
)));
1978 for (const auto &[R
, Context
] : T
.rangesWithPayload("decl"))
1979 ExpectedLocations
.push_back(AllOf(rangeIs(R
), containerIs(Context
),
1980 attrsAre(ReferencesResult::Declaration
)));
1981 for (const auto &[R
, Context
] : T
.rangesWithPayload("overridedecl"))
1982 ExpectedLocations
.push_back(AllOf(
1983 rangeIs(R
), containerIs(Context
),
1984 attrsAre(ReferencesResult::Declaration
| ReferencesResult::Override
)));
1985 for (const auto &[R
, Context
] : T
.rangesWithPayload("overridedef"))
1986 ExpectedLocations
.push_back(AllOf(rangeIs(R
), containerIs(Context
),
1987 attrsAre(ReferencesResult::Declaration
|
1988 ReferencesResult::Definition
|
1989 ReferencesResult::Override
)));
1990 for (const auto &P
: T
.points()) {
1991 EXPECT_THAT(findReferences(AST
, P
, 0, UseIndex
? TU
.index().get() : nullptr,
1992 /*AddContext*/ true)
1994 UnorderedElementsAreArray(ExpectedLocations
))
1995 << "Failed for Refs at " << P
<< "\n"
2000 TEST(FindReferences
, WithinAST
) {
2001 const char *Tests
[] = {
2002 R
"cpp(// Local variable
2004 int $def(main)[[foo]];
2005 $(main)[[^foo]] = 2;
2006 int test1 = $(main)[[foo]];
2012 struct $def(ns1)[[Foo]] {};
2015 ns1::$(main)[[Fo^o]]* Params;
2019 R
"cpp(// Forward declaration
2021 class $def[[Foo]] {};
2023 $(main)[[Fo^o]] foo;
2028 int $def[[foo]](int) {}
2030 auto *X = &$(main)[[^foo]];
2037 int $def(Foo)[[foo]];
2038 Foo() : $(Foo::Foo)[[foo]](0) {}
2042 f.$(main)[[f^oo]] = 1;
2046 R
"cpp(// Method call
2047 struct Foo { int $decl(Foo)[[foo]](); };
2048 int Foo::$def(Foo)[[foo]]() {}
2051 f.$(main)[[^foo]]();
2055 R
"cpp(// Constructor
2057 $decl(Foo)[[F^oo]](int);
2060 Foo f = $(foo)[[Foo]](42);
2065 typedef int $def[[Foo]];
2067 $(main)[[^Foo]] bar;
2072 namespace $decl[[ns]] { // FIXME: def?
2075 int main() { $(main)[[^ns]]::Foo foo; }
2081 #define CAT(X, Y) X##Y
2082 class $def[[Fo^o]] {};
2084 TYPE($(test)[[Foo]]) foo;
2085 $(test)[[FOO]] foo2;
2086 TYPE(TYPE($(test)[[Foo]])) foo3;
2087 $(test)[[CAT]](Fo, o) foo4;
2092 #define $def[[MA^CRO]](X) (X+1)
2094 int x = $[[MACRO]]($[[MACRO]](1));
2098 R
"cpp(// Macro outside preamble
2100 #define $def[[MA^CRO]](X) (X+1)
2102 int x = $[[MACRO]]($[[MACRO]](1));
2107 int $def[[v^ar]] = 0;
2108 void foo(int s = $(foo)[[var]]);
2112 template <typename T>
2113 class $def[[Fo^o]] {};
2114 void func($(func)[[Foo]]<int>);
2118 template <typename T>
2119 class $def[[Foo]] {};
2120 void func($(func)[[Fo^o]]<int>);
2122 R
"cpp(// Not touching any identifiers.
2124 $def(Foo)[[~]]Foo() {};
2128 f.$(foo)[[^~]]Foo();
2131 R
"cpp(// Lambda capture initializer
2133 int $def(foo)[[w^aldo]] = 42;
2134 auto lambda = [x = $(foo)[[waldo]]](){};
2137 R
"cpp(// Renaming alias
2138 template <typename> class Vector {};
2139 using $def[[^X]] = Vector<int>;
2144 R
"cpp(// Dependent code
2145 template <typename T> void $decl[[foo]](T t);
2146 template <typename T> void bar(T t) { $(bar)[[foo]](t); } // foo in bar is uninstantiated.
2147 void baz(int x) { $(baz)[[f^oo]](x); }
2152 void $decl(ns)[[foo]](S s);
2154 template <typename T> void foo(T t);
2155 // FIXME: Maybe report this foo as a ref to ns::foo (because of ADL)
2156 // when bar<ns::S> is instantiated?
2157 template <typename T> void bar(T t) { foo(t); }
2164 R
"cpp(// unresolved member expression
2166 template <typename T> void $decl(Foo)[[b^ar]](T t);
2168 template <typename T> void test(Foo F, T t) {
2169 F.$(test)[[bar]](t);
2175 typedef int $def[[MyTypeD^ef]];
2176 enum MyEnum : $(MyEnum)[[MyTy^peDef]] { };
2179 typedef int $def[[MyType^Def]];
2180 enum MyEnum : $(MyEnum)[[MyTypeD^ef]];
2183 using $def[[MyTypeD^ef]] = int;
2184 enum MyEnum : $(MyEnum)[[MyTy^peDef]] { };
2188 bool $decl[[operator]]"" _u^dl(unsigned long long value);
2189 bool x = $(x)[[1_udl]];
2192 for (const char *Test
: Tests
)
2193 checkFindRefs(Test
);
2196 TEST(FindReferences
, ConceptsWithinAST
) {
2197 constexpr llvm::StringLiteral Code
= R
"cpp(
2199 concept $def[[IsSmal^l]] = sizeof(T) <= 8;
2202 concept IsSmallPtr = requires(T x) {
2203 { *x } -> $(IsSmallPtr)[[IsSmal^l]];
2206 $(i)[[IsSmall]] auto i = 'c';
2207 template<$(foo)[[IsSmal^l]] U> void foo();
2208 template<class U> void bar() requires $(bar)[[IsSmal^l]]<U>;
2209 template<class U> requires $(baz)[[IsSmal^l]]<U> void baz();
2210 static_assert([[IsSma^ll]]<char>);
2212 checkFindRefs(Code
);
2215 TEST(FindReferences
, ConceptReq
) {
2216 constexpr llvm::StringLiteral Code
= R
"cpp(
2218 concept $def[[IsSmal^l]] = sizeof(T) <= 8;
2221 concept IsSmallPtr = requires(T x) {
2222 { *x } -> $(IsSmallPtr)[[IsSmal^l]];
2225 checkFindRefs(Code
);
2228 TEST(FindReferences
, RequiresExprParameters
) {
2229 constexpr llvm::StringLiteral Code
= R
"cpp(
2231 concept IsSmall = sizeof(T) <= 8;
2234 concept IsSmallPtr = requires(T $def[[^x]]) {
2235 { *$(IsSmallPtr)[[^x]] } -> IsSmall;
2238 checkFindRefs(Code
);
2241 TEST(FindReferences
, IncludeOverrides
) {
2242 llvm::StringRef Test
=
2246 virtu^al void $decl(Base)[[f^unc]]() ^= ^0;
2248 class Derived : public Base {
2250 void $overridedecl(Derived::func)[[func]]() override;
2252 void Derived::$overridedef[[func]]() {}
2253 class Derived2 : public Base {
2254 void $overridedef(Derived2::func)[[func]]() override {}
2256 void test(Derived* D, Base* B) {
2257 D->func(); // No references to the overrides.
2258 B->$(test)[[func]]();
2260 checkFindRefs(Test
, /*UseIndex=*/true);
2263 TEST(FindReferences
, RefsToBaseMethod
) {
2264 llvm::StringRef Test
=
2268 virtual void $(BaseBase)[[func]]();
2270 class Base : public BaseBase {
2272 void $(Base)[[func]]() override;
2274 class Derived : public Base {
2276 void $decl(Derived)[[fu^nc]]() over^ride;
2278 void test(BaseBase* BB, Base* B, Derived* D) {
2279 // refs to overridden methods in complete type hierarchy are reported.
2280 BB->$(test)[[func]]();
2281 B->$(test)[[func]]();
2282 D->$(test)[[fu^nc]]();
2284 checkFindRefs(Test
, /*UseIndex=*/true);
2287 TEST(FindReferences
, MainFileReferencesOnly
) {
2288 llvm::StringRef Test
=
2292 // refs not from main file should not be included.
2296 Annotations
Code(Test
);
2297 auto TU
= TestTU::withCode(Code
.code());
2298 TU
.AdditionalFiles
["foo.inc"] = R
"cpp(
2301 auto AST
= TU
.build();
2303 std::vector
<Matcher
<ReferencesResult::Reference
>> ExpectedLocations
;
2304 for (const auto &R
: Code
.ranges())
2305 ExpectedLocations
.push_back(rangeIs(R
));
2306 EXPECT_THAT(findReferences(AST
, Code
.point(), 0).References
,
2307 ElementsAreArray(ExpectedLocations
))
2311 TEST(FindReferences
, ExplicitSymbols
) {
2312 const char *Tests
[] = {
2314 struct Foo { Foo* $decl(Foo)[[self]]() const; };
2317 if (Foo* T = foo.$(f)[[^self]]()) {} // Foo member call expr.
2322 struct Foo { Foo(int); };
2325 return $(f)[[^b]]; // Foo constructor expr.
2334 g($(call)[[^f]]()); // Foo constructor expr.
2339 void $decl[[foo]](int);
2340 void $decl[[foo]](double);
2343 using ::$decl(ns)[[fo^o]];
2354 $(test)[[a]].operator bool();
2355 if ($(test)[[a^]]) {} // ignore implicit conversion-operator AST node
2359 for (const char *Test
: Tests
)
2360 checkFindRefs(Test
);
2363 TEST(FindReferences
, UsedSymbolsFromInclude
) {
2364 const char *Tests
[] = {
2365 R
"cpp( [[#include ^"bar
.h
"]]
2367 int fstBar = [[bar1]]();
2368 int sndBar = [[bar2]]();
2370 int macroBar = [[BAR]];
2371 std::vector<int> vec;
2374 R
"cpp([[#in^clude <vector>]]
2375 std::[[vector]]<int> vec;
2379 [[#include ^"udl_header
.h
"]]
2383 for (const char *Test
: Tests
) {
2384 Annotations
T(Test
);
2385 auto TU
= TestTU::withCode(T
.code());
2386 TU
.ExtraArgs
.push_back("-std=c++20");
2387 TU
.AdditionalFiles
["bar.h"] = guard(R
"cpp(
2393 TU
.AdditionalFiles
["system/vector"] = guard(R
"cpp(
2399 TU
.AdditionalFiles
["udl_header.h"] = guard(R
"cpp(
2400 bool operator"" _b(unsigned long long value);
2402 TU
.ExtraArgs
.push_back("-isystem" + testPath("system"));
2404 auto AST
= TU
.build();
2405 std::vector
<Matcher
<ReferencesResult::Reference
>> ExpectedLocations
;
2406 for (const auto &R
: T
.ranges())
2407 ExpectedLocations
.push_back(AllOf(rangeIs(R
), attrsAre(0u)));
2408 for (const auto &P
: T
.points())
2409 EXPECT_THAT(findReferences(AST
, P
, 0).References
,
2410 UnorderedElementsAreArray(ExpectedLocations
))
2411 << "Failed for Refs at " << P
<< "\n"
2416 TEST(FindReferences
, NeedsIndexForSymbols
) {
2417 const char *Header
= "int foo();";
2418 Annotations
Main("int main() { [[f^oo]](); }");
2420 TU
.Code
= std::string(Main
.code());
2421 TU
.HeaderCode
= Header
;
2422 auto AST
= TU
.build();
2424 // References in main file are returned without index.
2426 findReferences(AST
, Main
.point(), 0, /*Index=*/nullptr).References
,
2427 ElementsAre(rangeIs(Main
.range())));
2428 Annotations
IndexedMain(R
"cpp(
2429 int $decl[[foo]]() { return 42; }
2430 void bar() { $bar(bar)[[foo]](); }
2431 struct S { void bar() { $S(S::bar)[[foo]](); } };
2432 namespace N { void bar() { $N(N::bar)[[foo]](); } }
2435 // References from indexed files are included.
2437 IndexedTU
.Code
= std::string(IndexedMain
.code());
2438 IndexedTU
.Filename
= "Indexed.cpp";
2439 IndexedTU
.HeaderCode
= Header
;
2441 findReferences(AST
, Main
.point(), 0, IndexedTU
.index().get(),
2442 /*AddContext*/ true)
2445 rangeIs(Main
.range()),
2446 AllOf(rangeIs(IndexedMain
.range("decl")),
2447 attrsAre(ReferencesResult::Declaration
|
2448 ReferencesResult::Definition
)),
2449 AllOf(rangeIs(IndexedMain
.range("bar")), containerIs("bar")),
2450 AllOf(rangeIs(IndexedMain
.range("S")), containerIs("S::bar")),
2451 AllOf(rangeIs(IndexedMain
.range("N")), containerIs("N::bar"))));
2453 findReferences(AST
, Main
.point(), /*Limit*/ 1, IndexedTU
.index().get());
2454 EXPECT_EQ(1u, LimitRefs
.References
.size());
2455 EXPECT_TRUE(LimitRefs
.HasMore
);
2457 // Avoid indexed results for the main file. Use AST for the mainfile.
2458 TU
.Code
= ("\n\n" + Main
.code()).str();
2459 EXPECT_THAT(findReferences(AST
, Main
.point(), 0, TU
.index().get()).References
,
2460 ElementsAre(rangeIs(Main
.range())));
2463 TEST(FindReferences
, NeedsIndexForMacro
) {
2464 const char *Header
= "#define MACRO(X) (X+1)";
2465 Annotations
Main(R
"cpp(
2467 int a = [[MA^CRO]](1);
2471 TU
.Code
= std::string(Main
.code());
2472 TU
.HeaderCode
= Header
;
2473 auto AST
= TU
.build();
2475 // References in main file are returned without index.
2477 findReferences(AST
, Main
.point(), 0, /*Index=*/nullptr).References
,
2478 ElementsAre(rangeIs(Main
.range())));
2480 Annotations
IndexedMain(R
"cpp(
2481 int indexed_main() {
2482 int a = [[MACRO]](1);
2486 // References from indexed files are included.
2488 IndexedTU
.Code
= std::string(IndexedMain
.code());
2489 IndexedTU
.Filename
= "Indexed.cpp";
2490 IndexedTU
.HeaderCode
= Header
;
2492 findReferences(AST
, Main
.point(), 0, IndexedTU
.index().get()).References
,
2493 ElementsAre(rangeIs(Main
.range()), rangeIs(IndexedMain
.range())));
2495 findReferences(AST
, Main
.point(), /*Limit*/ 1, IndexedTU
.index().get());
2496 EXPECT_EQ(1u, LimitRefs
.References
.size());
2497 EXPECT_TRUE(LimitRefs
.HasMore
);
2500 TEST(FindReferences
, NoQueryForLocalSymbols
) {
2501 struct RecordingIndex
: public MemIndex
{
2502 mutable std::optional
<llvm::DenseSet
<SymbolID
>> RefIDs
;
2503 bool refs(const RefsRequest
&Req
,
2504 llvm::function_ref
<void(const Ref
&)>) const override
{
2511 StringRef AnnotatedCode
;
2515 // For now we don't assume header structure which would allow skipping.
2516 {"namespace { int ^x; }", true},
2517 {"static int ^x;", true},
2518 // Anything in a function certainly can't be referenced though.
2519 {"void foo() { int ^x; }", false},
2520 {"void foo() { struct ^x{}; }", false},
2521 {"auto lambda = []{ int ^x; };", false},
2523 for (Test T
: Tests
) {
2524 Annotations
File(T
.AnnotatedCode
);
2526 auto AST
= TestTU::withCode(File
.code()).build();
2527 findReferences(AST
, File
.point(), 0, &Rec
);
2529 EXPECT_NE(Rec
.RefIDs
, std::nullopt
) << T
.AnnotatedCode
;
2531 EXPECT_EQ(Rec
.RefIDs
, std::nullopt
) << T
.AnnotatedCode
;
2535 TEST(GetNonLocalDeclRefs
, All
) {
2537 llvm::StringRef AnnotatedCode
;
2538 std::vector
<std::string
> ExpectedDecls
;
2541 // VarDecl and ParamVarDecl
2544 void ^foo(int baz) {
2551 // Method from class
2553 class Foo { public: void foo(); };
2563 {"Bar", "Bar::bar", "Foo", "Foo::foo"},
2569 class Foo { public: void foo() {} };
2570 class Bar { public: void bar() {} };
2581 template <typename T, template<typename> class Q>
2589 for (const Case
&C
: Cases
) {
2590 Annotations
File(C
.AnnotatedCode
);
2591 auto AST
= TestTU::withCode(File
.code()).build();
2592 SourceLocation SL
= llvm::cantFail(
2593 sourceLocationInMainFile(AST
.getSourceManager(), File
.point()));
2595 const FunctionDecl
*FD
=
2596 llvm::dyn_cast
<FunctionDecl
>(&findDecl(AST
, [SL
](const NamedDecl
&ND
) {
2597 return ND
.getLocation() == SL
&& llvm::isa
<FunctionDecl
>(ND
);
2599 ASSERT_NE(FD
, nullptr);
2601 auto NonLocalDeclRefs
= getNonLocalDeclRefs(AST
, FD
);
2602 std::vector
<std::string
> Names
;
2603 for (const Decl
*D
: NonLocalDeclRefs
) {
2604 if (const auto *ND
= llvm::dyn_cast
<NamedDecl
>(D
))
2605 Names
.push_back(ND
->getQualifiedNameAsString());
2607 EXPECT_THAT(Names
, UnorderedElementsAreArray(C
.ExpectedDecls
))
2612 TEST(DocumentLinks
, All
) {
2613 Annotations
MainCpp(R
"cpp(
2614 #/*comments*/include /*comments*/ $foo[["foo
.h
"]] //more comments
2615 int end_of_preamble = 0;
2616 #include $bar[[<bar.h>]]
2620 TU
.Code
= std::string(MainCpp
.code());
2621 TU
.AdditionalFiles
= {{"foo.h", ""}, {"bar.h", ""}};
2622 TU
.ExtraArgs
= {"-isystem."};
2623 auto AST
= TU
.build();
2626 clangd::getDocumentLinks(AST
),
2628 DocumentLink({MainCpp
.range("foo"),
2629 URIForFile::canonicalize(testPath("foo.h"), "")}),
2630 DocumentLink({MainCpp
.range("bar"),
2631 URIForFile::canonicalize(testPath("bar.h"), "")})));
2635 } // namespace clangd
2636 } // namespace clang