19#include "clang/AST/Decl.h"
20#include "clang/Basic/SourceLocation.h"
21#include "llvm/ADT/StringRef.h"
22#include "llvm/Support/Casting.h"
23#include "llvm/Support/Error.h"
24#include "llvm/Support/Path.h"
25#include "llvm/Support/ScopedPrinter.h"
26#include "gmock/gmock.h"
27#include "gtest/gtest.h"
36using ::testing::AllOf;
37using ::testing::ElementsAre;
39using ::testing::IsEmpty;
40using ::testing::Matcher;
41using ::testing::UnorderedElementsAre;
42using ::testing::UnorderedElementsAreArray;
43using ::testing::UnorderedPointwise;
45std::string guard(llvm::StringRef Code) {
46 return "#pragma once\n" + Code.str();
52 return Sym.PreferredDeclaration.range ==
Range;
57 return Sym.Definition.value_or(Sym.PreferredDeclaration).range ==
Range;
62Matcher<const std::vector<DocumentHighlight> &>
64 std::vector<DocumentHighlight> Expected;
66 Expected.emplace_back();
67 Expected.back().range = R;
68 Expected.back().kind = K;
70 for (
const auto &
Range : Test.ranges())
72 for (
const auto &
Range : Test.ranges(
"read"))
74 for (
const auto &
Range : Test.ranges(
"write"))
76 return UnorderedElementsAreArray(Expected);
80 const char *Tests[] = {
81 R
"cpp(// Local variable
84 $write[[^bonjour]] = 2;
85 int test1 = $read[[bonjour]];
92 static void foo([[MyClass]]*) {}
96 ns1::[[My^Class]]* Params;
101 int [[^foo]](int) { return 0; }
103 [[foo]]([[foo]](42));
108 R"cpp(// Function parameter in decl
109 void foo(int [[^bar]]);
111 R"cpp(// Not touching any identifiers.
120 R"cpp(// ObjC methods with split selectors.
122 +(void) [[x]]:(int)a [[y]]:(int)b;
125 +(void) [[x]]:(int)a [[y]]:(int)b {}
128 [Foo [[x]]:2 [[^y]]:4];
138 R"cpp(// Overloaded operator: the whole name, not just `operator`, is highlighted.
139 using size_t = decltype(sizeof(0));
141 static void *[[operator]] [[n^ew]](size_t);
142 static void operator delete(void *);
145 R"cpp(// Same, with the cursor on the operator keyword itself.
146 using size_t = decltype(sizeof(0));
148 static void *[[^operator]] [[new]](size_t);
149 static void operator delete(void *);
152 R"cpp(// Same, for operator delete.
153 using size_t = decltype(sizeof(0));
155 static void *operator new(size_t);
156 static void [[operator]] [[del^ete]](void *);
159 R"cpp(// Overloaded operator spanning multiple tokens.
161 void [[operator]] [[^(]][[)]](int);
164 R"cpp(// Explicit operator-call syntax also highlights the whole name.
166 S [[operator]] [[+]](S);
169 a.[[operator]] [[^+]](a);
172 R"cpp(// Literal operator: the suffix is lexed together with the preceding
173 // `""` as a single token, so the whole thing is highlighted.
174 long double [[operator]] [[""_te^st]](long double);
176 R"cpp(// Conversion operator: the target type name is highlighted too.
177 // (Clicking on `int` itself doesn't resolve to the declaration at
178 // all, a separate limitation.)
180 [[^operator]] [[int]]();
183 R"cpp(// Regression: an operator name coming from a macro expansion must not
184 // crash. Since a macro location isn't something we can safely treat
185 // as spelled tokens, we fall back to highlighting just `operator`.
187 struct S { void [[operator]] PLU^S(int); };
189 R"cpp(// Regression: an overloaded operator called with dependent arguments
190 // (so overload resolution is deferred, producing an
191 // UnresolvedMemberExpr with several candidates at one location)
192 // should still have its whole name highlighted, not just `operator`.
195 void [[operat^or]] [[+]](double);
197 template <typename T>
199 s.[[operator]] [[+]](t);
203 for (
const char *Test : Tests) {
206 TU.ExtraArgs.push_back(
"-xobjective-c++");
207 auto AST = TU.build();
213TEST(HighlightsTest, ControlFlow) {
214 const char *Tests[] = {
216 // Highlight same-function returns.
217 int fib(unsigned n) {
218 if (n <= 1) [[ret^urn]] 1;
219 [[return]] fib(n - 1) + fib(n - 2);
221 // Returns from other functions not highlighted.
222 auto Lambda = [] { return; };
223 class LocalClass { void x() { return; } };
228 #define FAIL() return false
231 if (n < 0) [[FAIL]]();
237 // Highlight loop control flow
240 [[^for]] (char c : "fruit loops!") {
241 if (c == ' ') [[continue]];
243 if (c == '!') [[break]];
244 if (c == '?') [[return]] -1;
251 // Highlight loop and same-loop control flow
254 if (false) [[bre^ak]];
262 // Highlight switch for break (but not other breaks).
263 void describe(unsigned n) {
274 // Highlight case and exits for switch-break (but not other cases).
275 void describe(unsigned n) {
288 // Highlight exits and switch for case
289 void describe(unsigned n) {
302 // Highlight nothing for switch.
303 void describe(unsigned n) {
316 // FIXME: match exception type against catch blocks
318 try { // wrong: highlight try with matching catch
319 try { // correct: has no matching catch
321 } catch (int) { } // correct: catch doesn't match type
322 [[return]] -1; // correct: exits the matching catch
323 } catch (const char*) { } // wrong: highlight matching catch
324 [[return]] 42; // wrong: throw doesn't exit function
329 // Loop highlights goto exiting the loop, but not jumping within it.
340 for (
const char *Test : Tests) {
343 TU.ExtraArgs.push_back(
"-fexceptions");
344 auto AST = TU.build();
350MATCHER_P3(
sym, Name, Decl, DefOrNone,
"") {
351 std::optional<Range> Def = DefOrNone;
352 if (Name != arg.Name) {
353 *result_listener <<
"Name is " << arg.Name;
356 if (Decl != arg.PreferredDeclaration.range) {
357 *result_listener <<
"Declaration is "
358 << llvm::to_string(arg.PreferredDeclaration);
361 if (!Def && !arg.Definition)
363 if (Def && !arg.Definition) {
364 *result_listener <<
"Has no definition";
367 if (!Def && arg.Definition) {
368 *result_listener <<
"Definition is " << llvm::to_string(*arg.Definition);
371 if (arg.Definition->range != *Def) {
372 *result_listener <<
"Definition is " << llvm::to_string(*arg.Definition);
380MATCHER_P(rangeIs, R,
"") {
return arg.Loc.range == R; }
381MATCHER_P(fileIs, F,
"") {
return arg.Loc.uri.file() == F; }
383 return arg.Loc.containerName.value_or(
"") ==
C;
385MATCHER_P(attrsAre, A,
"") {
return arg.Attributes ==
A; }
386MATCHER_P(hasID, ID,
"") {
return arg.ID == ID; }
388TEST(LocateSymbol, WithIndex) {
390 class $forward[[Forward]];
391 class $foo[[Foo]] {};
395 inline void $f2[[f2]]() {}
398 class $forward[[forward]] {};
403 TU.Code = std::string(SymbolCpp.code());
404 TU.HeaderCode = std::string(SymbolHeader.code());
405 auto Index = TU.index();
406 auto LocateWithIndex = [&Index](
const Annotations &Main) {
417 EXPECT_THAT(LocateWithIndex(Test),
418 ElementsAre(sym("f1", Test.range(), SymbolCpp.range(
"f1"))));
426 EXPECT_THAT(LocateWithIndex(Test),
427 ElementsAre(sym("f1", SymbolHeader.range(
"f1"), Test.range())));
429 Test =
Annotations(R
"cpp(// forward declaration in AST.
433 EXPECT_THAT(LocateWithIndex(Test),
434 ElementsAre(sym("Foo", Test.range(), SymbolHeader.range(
"foo"))));
437 class [[Forward]] {};
441 LocateWithIndex(Test),
442 ElementsAre(sym("Forward", SymbolHeader.range(
"forward"), Test.range())));
445TEST(LocateSymbol, AnonymousStructFields) {
448 struct { int $1[[x]]; };
450 // Make sure the implicit base is skipped.
454 // Check that we don't skip explicit bases.
458 auto AST = TU.build();
460 UnorderedElementsAre(
sym(
"x", Code.range(
"1"), Code.range(
"1"))));
463 UnorderedElementsAre(
sym(
"Foo", Code.range(
"2"), Code.range(
"2"))));
466TEST(LocateSymbol, FindOverrides) {
469 virtual void $1[[fo^o]]() = 0;
471 class Bar : public Foo {
472 void $2[[foo]]() override;
476 auto AST = TU.build();
478 UnorderedElementsAre(
sym(
"foo", Code.range(
"1"), std::nullopt),
479 sym(
"foo", Code.range(
"2"), std::nullopt)));
482TEST(LocateSymbol, FindOverridesFromDefObjC) {
490 @interface Foo : Base<Fooey>
498 - (void)$3[[fo^o]] {}
502 TU.ExtraArgs.push_back("-xobjective-c++");
503 auto AST = TU.build();
506 UnorderedElementsAre(
sym(
"foo", Code.range(
"1"), std::nullopt),
507 sym(
"foo", Code.range(
"2"), Code.range(
"3"))));
510TEST(LocateSymbol, NoOverridesFromDeclObjC) {
518 @interface Foo : Base<Fooey>
530 TU.ExtraArgs.push_back("-xobjective-c++");
531 auto AST = TU.build();
534 UnorderedElementsAre(
sym(
"foo", Code.range(
"2"), Code.range(
"3"))));
537TEST(LocateSymbol, ObjCNoOverridesOnUsage) {
549 void doSomething(Bar *bar) {
554 TU.ExtraArgs.push_back("-xobjective-c++");
555 auto AST = TU.build();
558 UnorderedElementsAre(
sym(
"foo", Code.range(
"1"), Code.range(
"2"))));
561TEST(LocateSymbol, WithIndexPreferredLocation) {
563 class $p[[Proto]] {};
564 void $f[[func]]() {};
567 TU.HeaderCode = std::string(SymbolHeader.code());
568 TU.HeaderFilename = "x.proto";
569 auto Index = TU.index();
572 // Shift to make range different.
584 auto CodeGenLoc = SymbolHeader.range(
"p");
585 EXPECT_THAT(Locs, ElementsAre(
sym(
"Proto", CodeGenLoc, CodeGenLoc)));
589 auto CodeGenLoc = SymbolHeader.range(
"f");
590 EXPECT_THAT(Locs, ElementsAre(
sym(
"func", CodeGenLoc, CodeGenLoc)));
599 const char *Tests[] = {
612 R"cpp(// Local variable
622 struct [[MyClass]] {};
625 ns1::My^Class* Params;
629 R"cpp(// Function definition via pointer
636 R"cpp(// Function declaration via call
637 int $decl[[foo]](int);
644 struct Foo { int [[x]]; };
651 R"cpp(// Field, member initializer
658 R"cpp(// Field, field designator
659 struct Foo { int [[x]]; };
661 Foo bar = { .^x = 2 };
665 R"cpp(// Field in offsetof
666 struct Foo { int [[x]]; };
667 int y = __builtin_offsetof(Foo, ^x);
670 R"cpp(// Outer field in nested offsetof designator
671 struct Inner { int c; };
672 struct A { Inner [[B]]; };
673 int y = __builtin_offsetof(A, ^B.c);
676 R"cpp(// Inner field in nested offsetof designator
677 struct Inner { int [[c]]; };
678 struct A { Inner B; };
679 int y = __builtin_offsetof(A, B.^c);
682 R"cpp(// Field in offsetof macro form
683 #define offsetof(t, m) __builtin_offsetof(t, m)
684 struct Foo { int [[x]]; };
685 int y = offsetof(Foo, ^x);
688 R"cpp(// Inherited field in offsetof
689 struct B { int [[x]]; };
691 int y = __builtin_offsetof(D, ^x);
694 R"cpp(// Builtin offsetof name is not a field reference.
695 struct Foo { int x; };
696 int y = __builtin_o^ffsetof(Foo, x);
700 struct Foo { int $decl[[x]](); };
708 typedef int $decl[[Foo]];
714 R"cpp(// Template type parameter
715 template <typename [[T]]>
719 R"cpp(// Template template type parameter
720 template <template<typename> class [[T]]>
721 void foo() { ^T<int> t; }
725 namespace $decl[[ns]] {
726 struct Foo { static void bar(); };
728 int main() { ^ns::Foo::bar(); }
732 class TTT { public: int a; };
733 #define [[FF]](S) if (int b = S.a) {}
740 R"cpp(// Macro argument
742 #define ADDRESSOF(X) &X;
743 int *j = ADDRESSOF(^i);
745 R"cpp(// Macro argument appearing multiple times in expansion
746 #define VALIDATE_TYPE(x) (void)x;
747 #define ASSERT(expr) \
749 VALIDATE_TYPE(expr); \
752 bool [[waldo]]() { return true; }
757 R"cpp(// Symbol concatenated inside macro (not supported)
759 #define POINTER(X) p ## X;
760 int x = *POINTER(^i);
763 R"cpp(// Forward class declaration
765 class $def[[Foo]] {};
769 R"cpp(// Function declaration
772 void $def[[foo]]() {}
776 #define FF(name) class name##_Test {};
778 void f() { my^_Test a; }
782 #define FF() class [[Test]] {};
784 void f() { T^est a; }
787 R"cpp(// explicit template specialization
788 template <typename T>
789 struct Foo { void bar() {} };
792 struct [[Foo]]<int> { void bar() {} };
800 R"cpp(// implicit template specialization
801 template <typename T>
802 struct [[Foo]] { void bar() {} };
804 struct Foo<int> { void bar() {} };
811 R"cpp(// partial template specialization
812 template <typename T>
813 struct Foo { void bar() {} };
814 template <typename T>
815 struct [[Foo]]<T*> { void bar() {} };
819 R"cpp(// function template specializations
829 R"cpp(// variable template decls
834 double [[var]]<int> = 10;
836 double y = va^r<int>;
839 R"cpp(// No implicit constructors
851 X& $decl[[operator]]++();
859 struct S1 { void f(); };
860 struct S2 { S1 * $decl[[operator]]->(); };
866 R"cpp(// Declaration of explicit template specialization
867 template <typename T>
868 struct $decl[[$def[[Foo]]]] {};
874 R"cpp(// Declaration of partial template specialization
875 template <typename T>
876 struct $decl[[$def[[Foo]]]] {};
878 template <typename T>
882 R"cpp(// Definition on ClassTemplateDecl
884 // Forward declaration.
888 template <typename T>
889 struct $def[[Foo]] {};
895 R"cpp(// auto builtin type (not supported)
899 R"cpp(// auto on lambda
904 R"cpp(// auto on struct
912 R"cpp(// decltype on struct
921 R"cpp(// decltype(auto) on struct
928 ^decltype(auto) k = j;
931 R"cpp(// auto on template class
932 template<typename T> class [[Foo]] {};
934 ^auto x = Foo<int>();
937 R"cpp(// auto on template class with forward declared class
938 template<typename T> class [[Foo]] {};
944 R"cpp(// auto on specialized template class
945 template<typename T> class Foo {};
946 template<> class [[Foo]]<int> {};
948 ^auto x = Foo<int>();
951 R"cpp(// auto on initializer list.
955 class [[initializer_list]] { const _E *a, *b; };
961 R"cpp(// auto function return with trailing type
963 ^auto test() -> decltype(Bar()) {
968 R"cpp(// decltype in trailing return type
970 auto test() -> ^decltype(Bar()) {
975 R"cpp(// auto in function return
982 R"cpp(// auto& in function return
990 R"cpp(// auto* in function return
998 R"cpp(// const auto& in function return
1000 const ^auto& test() {
1006 R"cpp(// auto lambda param where there's a single instantiation
1008 auto Lambda = [](^auto){ return 0; };
1009 int x = Lambda(Bar{});
1012 R"cpp(// decltype(auto) in function return
1014 ^decltype(auto) test() {
1019 R"cpp(// decltype of function with trailing return type.
1021 auto test() -> decltype(Bar()) {
1025 ^decltype(test()) i = test();
1029 R"cpp(// auto with dependent type
1032 template <typename T>
1038 R"cpp(// Override specifier jumps to overridden method
1039 class Y { virtual void $decl[[a]]() = 0; };
1040 class X : Y { void a() ^override {} };
1042 R"cpp(// Final specifier jumps to overridden method
1043 class Y { virtual void $decl[[a]]() = 0; };
1044 class X : Y { void a() ^final {} };
1047 R"cpp(// Heuristic resolution of dependent method
1048 template <typename T>
1053 template <typename T>
1054 void foo(S<T> arg) {
1059 R"cpp(// Heuristic resolution of dependent method via this->
1060 template <typename T>
1068 R"cpp(// Heuristic resolution of dependent static method
1069 template <typename T>
1071 static void [[bar]]() {}
1074 template <typename T>
1080 R"cpp(// Heuristic resolution of dependent method
1081 // invoked via smart pointer
1082 template <typename> struct S { void [[foo]]() {} };
1083 template <typename T> struct unique_ptr {
1086 template <typename T>
1087 void test(unique_ptr<S<T>>& V) {
1092 R"cpp(// Heuristic resolution of dependent enumerator
1093 template <typename T>
1095 enum class E { [[A]], B };
1101 typedef int $decl[[MyTypeDef]];
1102 enum Foo : My^TypeDef {};
1105 typedef int $decl[[MyTypeDef]];
1106 enum Foo : My^TypeDef;
1109 using $decl[[MyTypeDef]] = int;
1110 enum Foo : My^TypeDef {};
1115 @protocol $decl[[Dog]]
1118 id<Do^g> getDoggo() {
1128 @interface $decl[[Cat]] (Exte^nsion)
1131 @implementation $def[[Cat]] (Extension)
1137 @class $decl[[Foo]];
1143 R"objc(// Prefer interface definition over forward declaration
1145 @interface $decl[[Foo]]
1154 @interface $decl[[Foo]]
1156 @implementation $def[[Foo]]
1163 R"objc(// Method decl and definition for ObjC class.
1165 - (void)$decl[[meow]];
1168 - (void)$def[[meow]] {}
1170 void makeNoise(Cat *kitty) {
1175 R"objc(// Method decl and definition for ObjC category.
1178 @interface Dog (Play)
1179 - (void)$decl[[runAround]];
1181 @implementation Dog (Play)
1182 - (void)$def[[runAround]] {}
1184 void play(Dog *dog) {
1189 R"objc(// Method decl and definition for ObjC class extension.
1193 - (void)$decl[[howl]];
1196 - (void)$def[[howl]] {}
1198 void play(Dog *dog) {
1203 struct PointerIntPairInfo {
1204 static void *$decl[[getPointer]](void *Value);
1207 template <typename Info = PointerIntPairInfo> struct PointerIntPair {
1209 void *getPointer() const { return Info::get^Pointer(Value); }
1212 R"cpp(// Deducing this
1218 int x = wa^ldo.bar();
1221 for (
const char *Test : Tests) {
1223 std::optional<Range> WantDecl;
1224 std::optional<Range> WantDef;
1225 if (!
T.ranges().empty())
1226 WantDecl = WantDef =
T.range();
1227 if (!
T.ranges(
"decl").empty())
1228 WantDecl =
T.range(
"decl");
1229 if (!
T.ranges(
"def").empty())
1230 WantDef =
T.range(
"def");
1233 TU.
Code = std::string(
T.code());
1235 TU.ExtraArgs.push_back(
"-xobjective-c++");
1236 TU.ExtraArgs.push_back(
"-std=c++23");
1238 auto AST = TU.build();
1242 EXPECT_THAT(Results, IsEmpty()) << Test;
1244 ASSERT_THAT(Results, ::testing::SizeIs(1)) << Test;
1245 EXPECT_EQ(Results[0].PreferredDeclaration.range, *WantDecl) << Test;
1246 EXPECT_TRUE(Results[0].ID) << Test;
1247 std::optional<Range> GotDef;
1249 GotDef = Results[0].Definition->range;
1250 EXPECT_EQ(WantDef, GotDef) << Test;
1254TEST(LocateSymbol, ValidSymbolID) {
1256 #define MACRO(x, y) ((x) + (y))
1257 int add(int x, int y) { return $MACRO^MACRO(x, y); }
1258 int sum = $add^add(1, 2);
1262 auto AST = TU.build();
1263 auto Index = TU.index();
1265 ElementsAre(AllOf(
sym(
"add"),
1269 ElementsAre(AllOf(
sym(
"MACRO"),
1273TEST(LocateSymbol, AllMulti) {
1280 struct ExpectedRanges {
1282 std::optional<Range> WantDef;
1284 const char *Tests[] = {
1286 @interface $decl0[[Cat]]
1288 @implementation $def0[[Cat]]
1290 @interface $decl1[[Ca^t]] (Extension)
1293 @implementation $def1[[Cat]] (Extension)
1299 @interface $decl0[[Cat]]
1301 @implementation $def0[[Cat]]
1303 @interface $decl1[[Cat]] (Extension)
1306 @implementation $def1[[Ca^t]] (Extension)
1312 @interface $decl0[[Cat]]
1314 @interface $decl1[[Ca^t]] ()
1317 @implementation $def0[[$def1[[Cat]]]]
1322 for (
const char *Test : Tests) {
1324 std::vector<ExpectedRanges> Ranges;
1325 for (
int Idx = 0;
true; Idx++) {
1326 bool HasDecl = !
T.ranges(
"decl" + std::to_string(Idx)).empty();
1327 bool HasDef = !
T.ranges(
"def" + std::to_string(Idx)).empty();
1328 if (!HasDecl && !HasDef)
1330 ExpectedRanges
Range;
1332 Range.WantDecl =
T.range(
"decl" + std::to_string(Idx));
1334 Range.WantDef =
T.range(
"def" + std::to_string(Idx));
1335 Ranges.push_back(
Range);
1339 TU.
Code = std::string(
T.code());
1340 TU.ExtraArgs.push_back(
"-xobjective-c++");
1342 auto AST = TU.build();
1345 ASSERT_THAT(Results, ::testing::SizeIs(Ranges.size())) << Test;
1346 for (
size_t Idx = 0; Idx < Ranges.size(); Idx++) {
1347 EXPECT_EQ(Results[Idx].PreferredDeclaration.range, Ranges[Idx].WantDecl)
1348 <<
"($decl" << Idx <<
")" << Test;
1349 std::optional<Range> GotDef;
1351 GotDef = Results[Idx].Definition->range;
1352 EXPECT_EQ(GotDef, Ranges[Idx].WantDef) <<
"($def" << Idx <<
")" << Test;
1360TEST(LocateSymbol, Warnings) {
1361 const char *Tests[] = {
1362 R
"cpp(// Field, GNU old-style field designator
1363 struct Foo { int [[x]]; };
1365 Foo bar = { ^x : 1 };
1372 int main() { return ^MACRO; }
1378 for (
const char *Test : Tests) {
1380 std::optional<Range> WantDecl;
1381 std::optional<Range> WantDef;
1382 if (!
T.ranges().empty())
1383 WantDecl = WantDef =
T.range();
1384 if (!
T.ranges(
"decl").empty())
1385 WantDecl =
T.range(
"decl");
1386 if (!
T.ranges(
"def").empty())
1387 WantDef =
T.range(
"def");
1390 TU.
Code = std::string(
T.code());
1392 auto AST = TU.build();
1396 EXPECT_THAT(Results, IsEmpty()) << Test;
1398 ASSERT_THAT(Results, ::testing::SizeIs(1)) << Test;
1399 EXPECT_EQ(Results[0].PreferredDeclaration.range, *WantDecl) << Test;
1400 std::optional<Range> GotDef;
1402 GotDef = Results[0].Definition->range;
1403 EXPECT_EQ(WantDef, GotDef) << Test;
1408TEST(LocateSymbol, TextualSmoke) {
1411 struct [[MyClass]] {};
1412 // Comment mentioning M^yClass
1416 auto AST = TU.build();
1417 auto Index = TU.index();
1420 ElementsAre(AllOf(
sym(
"MyClass",
T.range(),
T.range()),
1424TEST(LocateSymbol, Textual) {
1425 const char *Tests[] = {
1427 struct [[MyClass]] {};
1428 // Comment mentioning M^yClass
1432 // Not triggered for string literal tokens.
1433 const char* s = "String literal mentioning M^yClass";
1435 R"cpp(// Ifdef'ed out code
1436 struct [[MyClass]] {};
1441 R"cpp(// Macro definition
1442 struct [[MyClass]] {};
1443 #define DECLARE_MYCLASS_OBJ(name) M^yClass name;
1445 R"cpp(// Invalid code
1447 int myFunction(int);
1448 // Not triggered for token which survived preprocessing.
1449 int var = m^yFunction();
1452 for (
const char *Test : Tests) {
1454 std::optional<Range> WantDecl;
1455 if (!
T.ranges().empty())
1456 WantDecl =
T.range();
1460 auto AST = TU.build();
1461 auto Index = TU.index();
1464 AST.getTokens(),
AST.getLangOpts());
1466 ADD_FAILURE() <<
"No word touching point!" << Test;
1470 testPath(TU.Filename), ASTNodeKind());
1473 EXPECT_THAT(Results, IsEmpty()) << Test;
1475 ASSERT_THAT(Results, ::testing::SizeIs(1)) << Test;
1476 EXPECT_EQ(Results[0].PreferredDeclaration.range, *WantDecl) << Test;
1481TEST(LocateSymbol, Ambiguous) {
1486 $ConstructorLoc[[Foo]](const char*);
1494 const char* str = "123";
1496 Foo b = Foo($2^str);
1501 Foo ab$8^cd("asdf");
1502 Foo foox = Fo$9^o("asdf");
1503 Foo abcde$10^("asdf");
1504 Foo foox2 = Foo$11^("asdf");
1507 template <typename T>
1509 void $NonstaticOverload1[[bar]](int);
1510 void $NonstaticOverload2[[bar]](float);
1512 static void $StaticOverload1[[baz]](int);
1513 static void $StaticOverload2[[baz]](float);
1516 template <typename T, typename U>
1517 void dependent_call(S<T> s, U u) {
1525 TU.ExtraArgs.push_back(
"-fno-delayed-template-parsing");
1526 auto AST = TU.build();
1541 ElementsAre(
sym(
"Foo",
T.range(
"ConstructorLoc"), std::nullopt)));
1543 ElementsAre(
sym(
"Foo",
T.range(
"ConstructorLoc"), std::nullopt)));
1548 UnorderedElementsAre(
1549 sym(
"bar",
T.range(
"NonstaticOverload1"), std::nullopt),
1550 sym(
"bar",
T.range(
"NonstaticOverload2"), std::nullopt)));
1552 UnorderedElementsAre(
1553 sym(
"baz",
T.range(
"StaticOverload1"), std::nullopt),
1554 sym(
"baz",
T.range(
"StaticOverload2"), std::nullopt)));
1557TEST(LocateSymbol, TextualDependent) {
1563 void $FooLoc[[uniqueMethodName]]();
1566 void $BarLoc[[uniqueMethodName]]();
1570 template <typename T>
1572 t.u^niqueMethodName();
1576 TU.Code = std::string(Source.code());
1577 TU.HeaderCode = std::string(Header.code());
1578 auto AST = TU.build();
1579 auto Index = TU.index();
1586 UnorderedElementsAre(
1587 sym(
"uniqueMethodName", Header.range(
"FooLoc"), std::nullopt),
1588 sym(
"uniqueMethodName", Header.range(
"BarLoc"), std::nullopt)));
1592 const char *Tests[] = {
1594 template <class T> struct function {};
1595 template <class T> using [[callback]] = function<T()>;
1604 typedef Foo [[Bar]];
1610 using [[Bar]] = Foo; // definition
1623 namespace ns { class [[Foo]] {}; }
1628 namespace ns { int [[x]](char); int [[x]](double); }
1633 namespace ns { int [[x]](char); int x(double); }
1639 namespace ns { class [[Foo]] {}; }
1647 typedef Foo [[Ba^r]];
1651 using [[B^ar]] = Foo;
1656 template <typename T>
1660 template <typename T>
1661 struct Derived : Base<T> {
1662 using Base<T>::w^aldo;
1667 for (
const auto *Case : Tests) {
1672 UnorderedPointwise(declRange(),
T.ranges()));
1676TEST(LocateSymbol, RelPathsInCompileCommand) {
1681#include "header_in_preamble.h"
1683#include "header_not_in_preamble.h"
1684int baz = f$p1^oo + bar_pre$p2^amble + bar_not_pre$p3^amble;
1688int [[bar_preamble]];
1692int [[bar_not_preamble]];
1697 SmallString<32> RelPathPrefix(
"..");
1698 llvm::sys::path::append(RelPathPrefix,
"src");
1699 std::string BuildDir =
testPath(
"build");
1706 auto FooCpp =
testPath(
"src/foo.cpp");
1707 FS.Files[FooCpp] =
"";
1708 auto HeaderInPreambleH =
testPath(
"src/header_in_preamble.h");
1709 FS.Files[HeaderInPreambleH] = std::string(HeaderInPreambleAnnotations.code());
1710 auto HeaderNotInPreambleH =
testPath(
"src/header_not_in_preamble.h");
1711 FS.Files[HeaderNotInPreambleH] =
1712 std::string(HeaderNotInPreambleAnnotations.code());
1719 EXPECT_TRUE(
bool(Locations)) <<
"findDefinitions returned an error";
1720 EXPECT_THAT(*Locations, ElementsAre(
sym(
"foo", SourceAnnotations.range(),
1721 SourceAnnotations.range())));
1725 EXPECT_TRUE(
bool(Locations)) <<
"findDefinitions returned an error";
1728 ElementsAre(
sym(
"bar_preamble", HeaderInPreambleAnnotations.range(),
1729 HeaderInPreambleAnnotations.range())));
1733 EXPECT_TRUE(
bool(Locations)) <<
"findDefinitions returned an error";
1734 EXPECT_THAT(*Locations,
1735 ElementsAre(
sym(
"bar_not_preamble",
1736 HeaderNotInPreambleAnnotations.range(),
1737 HeaderNotInPreambleAnnotations.range())));
1746 const char *SourceContents = R
"cpp(
1747 #include ^"$2^foo.h$3^"
1748 #include "$4^invalid.h"
1752 #in$5^clude "$6^foo.h"$7^
1755 FS.Files[FooCpp] = std::string(SourceAnnotations.code());
1762 FS.Files[FooH] = std::string(HeaderAnnotations.code());
1769 ASSERT_TRUE(
bool(Locations)) <<
"locateSymbolAt returned an error";
1770 EXPECT_THAT(*Locations, ElementsAre(
sym(
"foo.h", HeaderAnnotations.range(),
1771 HeaderAnnotations.range())));
1775 ASSERT_TRUE(
bool(Locations)) <<
"locateSymbolAt returned an error";
1776 EXPECT_THAT(*Locations, ElementsAre(
sym(
"foo.h", HeaderAnnotations.range(),
1777 HeaderAnnotations.range())));
1780 ASSERT_TRUE(
bool(Locations)) <<
"locateSymbolAt returned an error";
1781 EXPECT_THAT(*Locations, ElementsAre(
sym(
"foo.h", HeaderAnnotations.range(),
1782 HeaderAnnotations.range())));
1786 ASSERT_TRUE(
bool(Locations)) <<
"locateSymbolAt returned an error";
1787 EXPECT_THAT(*Locations, ElementsAre(
sym(
"foo.h", HeaderAnnotations.range(),
1788 HeaderAnnotations.range())));
1792 ASSERT_TRUE(
bool(Locations)) <<
"locateSymbolAt returned an error";
1793 EXPECT_THAT(*Locations, IsEmpty());
1796 ASSERT_TRUE(
bool(Locations)) <<
"locateSymbolAt returned an error";
1797 EXPECT_THAT(*Locations, ElementsAre(
sym(
"foo.h", HeaderAnnotations.range(),
1798 HeaderAnnotations.range())));
1801 ASSERT_TRUE(
bool(Locations)) <<
"locateSymbolAt returned an error";
1802 EXPECT_THAT(*Locations, ElementsAre(
sym(
"foo.h", HeaderAnnotations.range(),
1803 HeaderAnnotations.range())));
1810 FS.Files[FooM] = std::string(ObjC.code());
1814 ASSERT_TRUE(
bool(Locations)) <<
"locateSymbolAt returned an error";
1815 EXPECT_THAT(*Locations, ElementsAre(
sym(
"foo.h", HeaderAnnotations.range(),
1816 HeaderAnnotations.range())));
1819TEST(LocateSymbol, WithPreamble) {
1828 Annotations FooWithHeader(R
"cpp(#include "fo^o.h")cpp");
1829 Annotations FooWithoutHeader(R"cpp(double [[fo^o]]();)cpp");
1831 FS.Files[FooCpp] = std::string(FooWithHeader.code());
1835 FS.Files[FooH] = std::string(FooHeader.code());
1841 ElementsAre(
sym(
"foo.h", FooHeader.range(), FooHeader.range())));
1844 Server.addDocument(FooCpp, FooWithoutHeader.code(),
"null",
1850 ElementsAre(
sym(
"foo", FooWithoutHeader.range(), std::nullopt)));
1855 Server.addDocument(FooCpp, FooWithoutHeader.code(),
"null",
1860 ElementsAre(
sym(
"foo", FooWithoutHeader.range(), std::nullopt)));
1863TEST(LocateSymbol, NearbyTokenSmoke) {
1865 // prints e^rr and crashes
1866 void die(const char* [[err]]);
1871 ElementsAre(
sym(
"err",
T.range(),
T.range())));
1874TEST(LocateSymbol, NearbyIdentifier) {
1875 const char *Tests[] = {
1877 // regular identifiers (won't trigger)
1882 // disabled preprocessor sections
1894 // not triggered by string literals
1896 const char* greeting = "h^ello, world";
1900 // can refer to macro invocations
1907 // can refer to macro invocations (even if they expand to nothing)
1914 // prefer nearest occurrence, backwards is worse than forwards
1923 // short identifiers find near results
1928 // short identifiers don't find far results
1941 // prefer nearest occurrence even if several matched tokens
1942 // have the same value of `floor(log2(<token line> - <word line>))`.
1944 int x = hello, y = hello;
1948 for (
const char *Test : Tests) {
1951 const auto &SM =
AST.getSourceManager();
1952 std::optional<Range> Nearby;
1955 AST.getTokens(),
AST.getLangOpts());
1957 ADD_FAILURE() <<
"No word at point! " << Test;
1962 Tok->location(), Tok->endLocation()));
1963 if (
T.ranges().empty())
1964 EXPECT_THAT(Nearby, Eq(std::nullopt)) << Test;
1966 EXPECT_EQ(Nearby,
T.range()) << Test;
1970TEST(FindImplementations, Inheritance) {
1971 llvm::StringRef Test = R
"cpp(
1973 virtual void F$1^oo();
1976 struct $0[[Child1]] : Base {
1977 void $1[[Fo$3^o]]() override;
1978 virtual void B$2^ar();
1979 void Concrete(); // No implementations for concrete methods.
1981 struct $0[[Child2]] : Child1 {
1982 void $1[[$3[[Foo]]]]() override;
1983 void $2[[Bar]]() override;
1985 void FromReference() {
1994 // CRTP should work.
1995 template<typename T>
1996 struct $5^TemplateBase {};
1997 struct $5[[Child3]] : public TemplateBase<Child3> {};
2000 void LocationFunction() {
2001 struct $0[[LocalClass1]] : Base {
2002 void $1[[Foo]]() override;
2004 struct $6^LocalBase {
2005 virtual void $7^Bar();
2007 struct $6[[LocalClass2]]: LocalBase {
2008 void $7[[Bar]]() override;
2015 auto AST = TU.build();
2016 auto Index = TU.index();
2017 for (StringRef
Label : {
"0",
"1",
"2",
"3",
"4",
"5",
"6",
"7"}) {
2018 for (
const auto &Point : Code.points(
Label)) {
2020 UnorderedPointwise(declRange(), Code.ranges(
Label)))
2021 << Code.code() <<
" at " << Point <<
" for Label " <<
Label;
2026TEST(FindImplementations, InheritanceRecursion) {
2028 llvm::StringRef Test = R
"cpp(
2037 static const bool value = true;
2042 static const bool value = false;
2046 struct [[Even]] : Odd<I - 1> {};
2049 struct [[Odd]] : Even<I - 1> {};
2051 constexpr bool Answer = Even<42>::value;
2056 auto AST = TU.build();
2057 auto Index = TU.index();
2059 UnorderedPointwise(defRange(), Code.ranges()));
2062TEST(FindImplementations, InheritanceObjC) {
2063 llvm::StringRef Test = R
"objc(
2064 @interface $base^Base
2068 - (void)$protocol^protocol;
2070 @interface $ChildDecl[[Child]] : Base <Protocol>
2072 - (void)$fooDecl[[foo]];
2074 @implementation $ChildDef[[Child]]
2076 - (void)$fooDef[[foo]] {}
2077 - (void)$protocolDef[[protocol]] {}
2083 TU.ExtraArgs.push_back(
"-xobjective-c++");
2084 auto AST = TU.build();
2085 auto Index = TU.index();
2087 UnorderedElementsAre(
sym(
"Child", Code.range(
"ChildDecl"),
2088 Code.range(
"ChildDef"))));
2090 UnorderedElementsAre(
2091 sym(
"foo", Code.range(
"fooDecl"), Code.range(
"fooDef"))));
2093 UnorderedElementsAre(
sym(
"protocol", Code.range(
"protocolDef"),
2094 Code.range(
"protocolDef"))));
2097TEST(FindImplementations, CaptureDefinition) {
2098 llvm::StringRef Test = R
"cpp(
2100 virtual void F^oo();
2102 struct Child1 : Base {
2103 void $Decl[[Foo]]() override;
2105 struct Child2 : Base {
2106 void $Child2[[Foo]]() override;
2108 void Child1::$Def[[Foo]]() { /* Definition */ }
2112 auto AST = TU.build();
2115 UnorderedElementsAre(
sym(
"Foo", Code.range(
"Decl"), Code.range(
"Def")),
2116 sym(
"Foo", Code.range(
"Child2"), std::nullopt)))
2122 struct $Target[[Target]] { operator int() const; };
2123 struct Aggregate { Target a, b; };
2127 template <typename T> struct $smart_ptr[[smart_ptr]] {
2134 for (
const llvm::StringRef Case : {
2138 "a^uto x = Target{};",
2139 "namespace m { Target tgt; } auto x = m^::tgt;",
2140 "Target funcCall(); auto x = ^funcCall();",
2141 "Aggregate a = { {}, ^{} };",
2142 "Aggregate a = { ^.a=t, };",
2143 "struct X { Target a; X() : ^a() {} };",
2144 "^using T = Target; ^T foo();",
2145 "^template <int> Target foo();",
2146 "void x() { try {} ^catch(Target e) {} }",
2147 "void x() { ^throw t; }",
2148 "int x() { ^return t; }",
2149 "void x() { ^switch(t) {} }",
2150 "void x() { ^delete (Target*)nullptr; }",
2151 "Target& ^tref = t;",
2152 "void x() { ^if (t) {} }",
2153 "void x() { ^while (t) {} }",
2154 "void x() { ^do { } while (t); }",
2155 "void x() { ^make(); }",
2156 "void x(smart_ptr<Target> &t) { t.^get(); }",
2157 "^auto x = []() { return t; };",
2158 "Target* ^tptr = &t;",
2159 "Target ^tarray[3];",
2162 TU.Code =
A.code().str();
2165 ASSERT_GT(
A.points().size(), 0u) << Case;
2166 for (
auto Pos :
A.points())
2169 sym(
"Target", HeaderA.range(
"Target"), HeaderA.range(
"Target"))))
2173 for (
const llvm::StringRef Case : {
2174 "smart_ptr<Target> ^tsmart;",
2177 TU.Code =
A.code().str();
2181 UnorderedElementsAre(
2182 sym(
"Target", HeaderA.range(
"Target"), HeaderA.range(
"Target")),
2183 sym(
"smart_ptr", HeaderA.range(
"smart_ptr"), HeaderA.range(
"smart_ptr"))
2196 concept $Concept^True = true;
2199 TU.ExtraArgs.push_back(
"-std=c++20");
2203 ElementsAre(
sym(
"X",
A.range(
"decl"),
A.range(
"def"))));
2204 EXPECT_THAT(
findType(
AST,
A.point(
"Concept"),
nullptr), IsEmpty());
2207TEST(FindType, Index) {
2209 // This definition is only available through the index.
2213 DefTU.HeaderFilename = "def.h";
2214 auto DefIdx = DefTU.index();
2224 ElementsAre(
sym(
"X",
A.range(), Def.range())));
2227void checkFindRefs(llvm::StringRef Test,
bool UseIndex =
false) {
2230 TU.ExtraArgs.push_back(
"-std=c++20");
2231 TU.ExtraArgs.push_back(
"-xobjective-c++");
2233 auto AST = TU.build();
2234 std::vector<Matcher<ReferencesResult::Reference>> ExpectedLocations;
2235 for (
const auto &[R,
Context] :
T.rangesWithPayload())
2236 ExpectedLocations.push_back(
2237 AllOf(rangeIs(R), containerIs(
Context), attrsAre(0u)));
2240 for (
const auto &[R,
Context] :
T.rangesWithPayload(
"def"))
2241 ExpectedLocations.push_back(AllOf(rangeIs(R), containerIs(
Context),
2244 for (
const auto &[R,
Context] :
T.rangesWithPayload(
"decl"))
2245 ExpectedLocations.push_back(AllOf(rangeIs(R), containerIs(
Context),
2247 for (
const auto &[R,
Context] :
T.rangesWithPayload(
"overridedecl"))
2248 ExpectedLocations.push_back(AllOf(
2249 rangeIs(R), containerIs(
Context),
2251 for (
const auto &[R,
Context] :
T.rangesWithPayload(
"overridedef"))
2252 ExpectedLocations.push_back(AllOf(rangeIs(R), containerIs(
Context),
2256 for (
const auto &P :
T.points()) {
2260 UnorderedElementsAreArray(ExpectedLocations))
2261 <<
"Failed for Refs at " <<
P <<
"\n"
2266TEST(FindReferences, WithinAST) {
2267 const char *Tests[] = {
2268 R
"cpp(// Local variable
2270 int $def(main)[[foo]];
2271 $(main)[[^foo]] = 2;
2272 int test1 = $(main)[[foo]];
2278 struct $def(ns1)[[Foo]] {};
2281 ns1::$(main)[[Fo^o]]* Params;
2285 R"cpp(// Forward declaration
2287 class $def[[Foo]] {};
2289 $(main)[[Fo^o]] foo;
2294 int $def[[foo]](int) { return 0; }
2296 auto *X = &$(main)[[^foo]];
2303 int $def(Foo)[[foo]];
2304 Foo() : $(Foo::Foo)[[foo]](0) {}
2308 f.$(main)[[f^oo]] = 1;
2312 R"cpp(// Method call
2313 struct Foo { int $decl(Foo)[[foo]](); };
2314 int Foo::$def(Foo)[[foo]]() { return 0; }
2317 f.$(main)[[^foo]]();
2321 R"cpp(// Constructor
2323 $decl(Foo)[[F^oo]](int);
2326 Foo f = $(foo)[[Foo]](42);
2331 typedef int $def[[Foo]];
2333 $(main)[[^Foo]] bar;
2338 namespace $decl[[ns]] { // FIXME: def?
2341 int main() { $(main)[[^ns]]::Foo foo; }
2347 #define CAT(X, Y) X##Y
2348 class $def[[Fo^o]] {};
2350 TYPE($(test)[[Foo]]) foo;
2351 $(test)[[FOO]] foo2;
2352 TYPE(TYPE($(test)[[Foo]])) foo3;
2353 $(test)[[CAT]](Fo, o) foo4;
2358 #define $def[[MA^CRO]](X) (X+1)
2360 int x = $[[MACRO]]($[[MACRO]](1));
2364 R"cpp(// Macro outside preamble
2366 #define $def[[MA^CRO]](X) (X+1)
2368 int x = $[[MACRO]]($[[MACRO]](1));
2373 int $def[[v^ar]] = 0;
2374 void foo(int s = $(foo)[[var]]);
2378 template <typename T>
2379 class $def[[Fo^o]] {};
2380 void func($(func)[[Foo]]<int>);
2384 template <typename T>
2385 class $def[[Foo]] {};
2386 void func($(func)[[Fo^o]]<int>);
2388 R"cpp(// Not touching any identifiers.
2390 $def(Foo)[[~]]Foo() {};
2394 f.$(foo)[[^~]]Foo();
2397 R"cpp(// Lambda capture initializer
2399 int $def(foo)[[w^aldo]] = 42;
2400 auto lambda = [x = $(foo)[[waldo]]](){};
2403 R"cpp(// Renaming alias
2404 template <typename> class Vector {};
2405 using $def[[^X]] = Vector<int>;
2410 R"cpp(// Dependent code
2411 template <typename T> void $decl[[foo]](T t);
2412 template <typename T> void bar(T t) { $(bar)[[foo]](t); } // foo in bar is uninstantiated.
2413 void baz(int x) { $(baz)[[f^oo]](x); }
2418 void $decl(ns)[[foo]](S s);
2420 template <typename T> void foo(T t);
2421 // FIXME: Maybe report this foo as a ref to ns::foo (because of ADL)
2422 // when bar<ns::S> is instantiated?
2423 template <typename T> void bar(T t) { foo(t); }
2430 R"cpp(// unresolved member expression
2432 template <typename T> void $decl(Foo)[[b^ar]](T t);
2434 template <typename T> void test(Foo F, T t) {
2435 F.$(test)[[bar]](t);
2441 typedef int $def[[MyTypeD^ef]];
2442 enum MyEnum : $(MyEnum)[[MyTy^peDef]] { };
2445 typedef int $def[[MyType^Def]];
2446 enum MyEnum : $(MyEnum)[[MyTypeD^ef]];
2449 using $def[[MyTypeD^ef]] = int;
2450 enum MyEnum : $(MyEnum)[[MyTy^peDef]] { };
2454 bool $decl[[operator]]"" _u^dl(unsigned long long value);
2455 bool x = $(x)[[1_udl]];
2460 static void $decl(S)[[operator]] delete(void *);
2461 static void deleteObject(S *S) {
2462 $(S::deleteObject)[[de^lete]] S;
2468 const int $def[[F^oo]] = 0;
2470 [$(Bar)[[F^oo]]...$(Bar)[[Fo^o]] + 1] = 0,
2471 [$(Bar)[[^Foo]] + 2] = 1
2476 struct S { void foo(); };
2478 void (S::*$def(A)[[fi^eld]])();
2480 void bar(A& a, S& s) {
2481 (s.*(a.$(bar)[[field]]))();
2484 for (
const char *Test : Tests)
2485 checkFindRefs(Test);
2488TEST(FindReferences, ConceptsWithinAST) {
2489 constexpr llvm::StringLiteral Code = R
"cpp(
2491 concept $def[[IsSmal^l]] = sizeof(T) <= 8;
2494 concept IsSmallPtr = requires(T x) {
2495 { *x } -> $(IsSmallPtr)[[IsSmal^l]];
2498 $(i)[[IsSmall]] auto i = 'c';
2499 template<$(foo)[[IsSmal^l]] U> void foo();
2500 template<class U> void bar() requires $(bar)[[IsSmal^l]]<U>;
2501 template<class U> requires $(baz)[[IsSmal^l]]<U> void baz();
2502 static_assert([[IsSma^ll]]<char>);
2504 checkFindRefs(Code);
2507TEST(FindReferences, ConceptReq) {
2508 constexpr llvm::StringLiteral Code = R
"cpp(
2510 concept $def[[IsSmal^l]] = sizeof(T) <= 8;
2513 concept IsSmallPtr = requires(T x) {
2514 { *x } -> $(IsSmallPtr)[[IsSmal^l]];
2517 checkFindRefs(Code);
2520TEST(FindReferences, RequiresExprParameters) {
2521 constexpr llvm::StringLiteral Code = R
"cpp(
2523 concept IsSmall = sizeof(T) <= 8;
2526 concept IsSmallPtr = requires(T $def[[^x]]) {
2527 { *$(IsSmallPtr)[[^x]] } -> IsSmall;
2530 checkFindRefs(Code);
2533TEST(FindReferences, IncludeOverrides) {
2534 llvm::StringRef Test =
2538 virtu^al void $decl(Base)[[f^unc]]() ^= ^0;
2540 class Derived : public Base {
2542 void $overridedecl(Derived::func)[[func]]() override;
2544 void Derived::$overridedef[[func]]() {}
2545 class Derived2 : public Base {
2546 void $overridedef(Derived2::func)[[func]]() override {}
2548 void test(Derived* D, Base* B) {
2549 D->func(); // No references to the overrides.
2550 B->$(test)[[func]]();
2552 checkFindRefs(Test, true);
2555TEST(FindReferences, IncludeOverridesObjC) {
2556 llvm::StringRef Test =
2559 - (void)$decl(Base)[[f^unc]];
2561 @interface Derived : Base
2562 - (void)$overridedecl(Derived::func)[[func]];
2564 @implementation Derived
2565 - (void)$overridedef[[func]] {}
2567 void test(Derived *derived, Base *base) {
2568 [derived func]; // No references to the overrides.
2569 [base $(test)[[func]]];
2571 checkFindRefs(Test, true);
2574TEST(FindReferences, RefsToBaseMethod) {
2575 llvm::StringRef Test =
2579 virtual void $(BaseBase)[[func]]();
2581 class Base : public BaseBase {
2583 void $(Base)[[func]]() override;
2585 class Derived : public Base {
2587 void $decl(Derived)[[fu^nc]]() over^ride;
2589 void test(BaseBase* BB, Base* B, Derived* D) {
2590 // refs to overridden methods in complete type hierarchy are reported.
2591 BB->$(test)[[func]]();
2592 B->$(test)[[func]]();
2593 D->$(test)[[fu^nc]]();
2595 checkFindRefs(Test, true);
2598TEST(FindReferences, RefsToBaseMethodObjC) {
2599 llvm::StringRef Test =
2602 - (void)$(BaseBase)[[func]];
2604 @interface Base : BaseBase
2605 - (void)$(Base)[[func]];
2607 @interface Derived : Base
2608 - (void)$decl(Derived)[[fu^nc]];
2610 void test(BaseBase *bb, Base *b, Derived *d) {
2611 // refs to overridden methods in complete type hierarchy are reported.
2612 [bb $(test)[[func]]];
2613 [b $(test)[[func]]];
2614 [d $(test)[[fu^nc]]];
2616 checkFindRefs(Test, true);
2619TEST(FindReferences, MainFileReferencesOnly) {
2620 llvm::StringRef Test =
2624 // refs not from main file should not be included.
2630 TU.AdditionalFiles[
"foo.inc"] = R
"cpp(
2633 auto AST = TU.build();
2635 std::vector<Matcher<ReferencesResult::Reference>> ExpectedLocations;
2636 for (
const auto &R : Code.ranges())
2637 ExpectedLocations.push_back(rangeIs(R));
2639 ElementsAreArray(ExpectedLocations))
2643TEST(FindReferences, ExplicitSymbols) {
2644 const char *Tests[] = {
2646 struct Foo { Foo* $decl(Foo)[[self]]() const; };
2649 if (Foo* T = foo.$(f)[[^self]]()) {} // Foo member call expr.
2654 struct Foo { Foo(int); };
2657 return $(f)[[^b]]; // Foo constructor expr.
2666 g($(call)[[^f]]()); // Foo constructor expr.
2671 void $decl[[foo]](int);
2672 void $decl[[foo]](double);
2675 using ::$decl(ns)[[fo^o]];
2686 $(test)[[a]].operator bool();
2687 if ($(test)[[a^]]) {} // ignore implicit conversion-operator AST node
2692 for (
const char *Test : Tests)
2693 checkFindRefs(Test);
2696TEST(FindReferences, UsedSymbolsFromInclude) {
2697 const char *Tests[] = {
2698 R
"cpp( [[#include ^"bar.h"]]
2700 int fstBar = [[bar1]]();
2701 int sndBar = [[bar2]]();
2703 int macroBar = [[BAR]];
2704 std::vector<int> vec;
2707 R"cpp([[#in^clude <vector>]]
2708 std::[[vector]]<int> vec;
2712 [[#include ^"udl_header.h"]]
2716 for (
const char *Test : Tests) {
2719 TU.ExtraArgs.push_back(
"-std=c++20");
2720 TU.AdditionalFiles[
"bar.h"] = guard(R
"cpp(
2726 TU.AdditionalFiles["system/vector"] = guard(R
"cpp(
2732 TU.AdditionalFiles["udl_header.h"] = guard(R
"cpp(
2733 bool operator"" _b(unsigned long long value);
2735 TU.ExtraArgs.push_back("-isystem" +
testPath(
"system"));
2737 auto AST = TU.build();
2738 std::vector<Matcher<ReferencesResult::Reference>> ExpectedLocations;
2739 for (
const auto &R :
T.ranges())
2740 ExpectedLocations.push_back(AllOf(rangeIs(R), attrsAre(0u)));
2741 for (
const auto &P :
T.points())
2743 UnorderedElementsAreArray(ExpectedLocations))
2744 <<
"Failed for Refs at " <<
P <<
"\n"
2749TEST(FindReferences, NeedsIndexForSymbols) {
2750 const char *Header =
"int foo();";
2753 TU.
Code = std::string(Main.code());
2754 TU.HeaderCode = Header;
2755 auto AST = TU.build();
2760 ElementsAre(rangeIs(Main.range())));
2762 int $decl[[foo]]() { return 42; }
2763 void bar() { $bar(bar)[[foo]](); }
2764 struct S { void bar() { $S(S::bar)[[foo]](); } };
2765 namespace N { void bar() { $N(N::bar)[[foo]](); } }
2770 IndexedTU.
Code = std::string(IndexedMain.code());
2771 IndexedTU.Filename =
"Indexed.cpp";
2772 IndexedTU.HeaderCode = Header;
2778 rangeIs(Main.range()),
2779 AllOf(rangeIs(IndexedMain.range(
"decl")),
2782 AllOf(rangeIs(IndexedMain.range(
"bar")), containerIs(
"bar")),
2783 AllOf(rangeIs(IndexedMain.range(
"S")), containerIs(
"S::bar")),
2784 AllOf(rangeIs(IndexedMain.range(
"N")), containerIs(
"N::bar"))));
2787 EXPECT_EQ(1u, LimitRefs.References.size());
2788 EXPECT_TRUE(LimitRefs.HasMore);
2791 TU.Code = (
"\n\n" + Main.code()).str();
2793 ElementsAre(rangeIs(Main.range())));
2796TEST(FindReferences, NeedsIndexForMacro) {
2797 const char *Header =
"#define MACRO(X) (X+1)";
2800 int a = [[MA^CRO]](1);
2804 TU.Code = std::string(Main.code());
2805 TU.HeaderCode = Header;
2806 auto AST = TU.build();
2811 ElementsAre(rangeIs(Main.range())));
2814 int indexed_main() {
2815 int a = [[MACRO]](1);
2822 IndexedTU.
Code = std::string(IndexedMain.code());
2823 IndexedTU.Filename =
"Indexed.cpp";
2824 IndexedTU.HeaderCode = Header;
2827 ElementsAre(rangeIs(Main.range()), rangeIs(IndexedMain.range())));
2830 EXPECT_EQ(1u, LimitRefs.References.size());
2831 EXPECT_TRUE(LimitRefs.HasMore);
2834TEST(FindReferences, NoQueryForLocalSymbols) {
2835 struct RecordingIndex :
public MemIndex {
2836 mutable std::optional<llvm::DenseSet<SymbolID>> RefIDs;
2837 bool refs(
const RefsRequest &Req,
2838 llvm::function_ref<
void(
const Ref &)>)
const override {
2845 StringRef AnnotatedCode;
2850 {
"namespace { int ^x; }",
true},
2851 {
"static int ^x;",
true},
2853 {
"void foo() { int ^x; }",
false},
2854 {
"void foo() { struct ^x{}; }",
false},
2855 {
"auto lambda = []{ int ^x; };",
false},
2857 for (Test T : Tests) {
2863 EXPECT_NE(Rec.RefIDs, std::nullopt) <<
T.AnnotatedCode;
2865 EXPECT_EQ(Rec.RefIDs, std::nullopt) <<
T.AnnotatedCode;
2869TEST(FindReferences, ConstructorForwardingInAST) {
2872 template <class T> T &&forward(T &t);
2873 template <class T, class... Args> T *make_unique(Args &&...args) {
2874 return new T(std::forward<Args>(args)...);
2879 $Constructor[[T^est]](){}
2883 auto a = std::$Caller[[make_unique]]<Test>();
2887 TU.Code = std::string(Main.code());
2888 auto AST = TU.build();
2891 ElementsAre(rangeIs(Main.range(
"Constructor")),
2892 rangeIs(Main.range(
"Caller"))));
2895TEST(FindReferences, ConstructorForwardingInASTChained) {
2898 template <class T> T &&forward(T &t);
2899 template <class T, class... Args> T *make_unique(Args &&...args) {
2900 return new T(forward<Args>(args)...);
2902 template <class T, class... Args> T *make_unique2(Args &&...args) {
2903 return make_unique<T>(forward<Args>(args)...);
2905 template <class T, class... Args> T *make_unique3(Args &&...args) {
2906 return make_unique2<T>(forward<Args>(args)...);
2911 $Constructor[[T^est]](){}
2915 auto a = std::$Caller[[make_unique3]]<Test>();
2919 TU.Code = std::string(Main.code());
2920 auto AST = TU.build();
2923 ElementsAre(rangeIs(Main.range(
"Constructor")),
2924 rangeIs(Main.range(
"Caller"))));
2927TEST(FindReferences, ConstructorForwardingInIndex) {
2930 template <class T> T &&forward(T &t);
2931 template <class T, class... Args> T *make_unique(Args &&...args) {
2932 return new T(std::forward<Args>(args)...);
2940 #include "header.hpp"
2942 auto a = std::[[make_unique]]<Test>();
2946 TW.addSource("header.hpp", Header.code());
2947 TW.addMainFile(
"main.cpp", Main.code());
2948 auto AST = TW.openFile(
"header.hpp").value();
2949 auto Index = TW.index();
2956 AllOf(rangeIs(Header.range()), fileIs(
testPath(
"header.hpp"))),
2957 AllOf(rangeIs(Main.range()), fileIs(
testPath(
"main.cpp")))));
2960TEST(FindReferences, TemplatedConstructorForwarding) {
2963 template <class T> T &&forward(T &t);
2964 template <class T, class... Args> T *make_unique(Args &&...args) {
2965 return new T(std::forward<Args>(args)...);
2970 template <typename T>
2971 $Constructor[[W$Waldo^aldo]](T);
2973 template <typename T>
2975 $Constructor2[[W$Waldo2^aldo2]](int);
2981 Waldo $Caller[[w]](s);
2982 std::$ForwardedCaller[[make_unique]]<Waldo>(s);
2984 Waldo2<int> $Caller2[[w2]](42);
2985 std::$ForwardedCaller2[[make_unique]]<Waldo2<int>>(42);
2989 TU.Code = std::string(Main.code());
2990 auto AST = TU.build();
2993 ElementsAre(rangeIs(Main.range(
"Constructor")),
2994 rangeIs(Main.range(
"Caller")),
2995 rangeIs(Main.range(
"ForwardedCaller"))));
2998 ElementsAre(rangeIs(Main.range(
"Constructor2")),
2999 rangeIs(Main.range(
"Caller2")),
3000 rangeIs(Main.range(
"ForwardedCaller2"))));
3003TEST(LocateSymbol, ConstructorForwarding) {
3010 template <class T> T &&forward(T &t);
3011 template <class T, class... Args>
3012 T *$MakeUnique[[make_unique]](Args &&...args) {
3013 return new T(std::forward<Args>(args)...);
3015 template <class T, class... Args> T *make_unique2(Args &&...args) {
3016 return make_unique<T>(forward<Args>(args)...);
3018 template <class T, class... Args> T *make_unique3(Args &&...args) {
3019 return make_unique2<T>(forward<Args>(args)...);
3021 template <class T> struct shared_ptr {
3024 template <class T, class... Args>
3025 shared_ptr<T> make_shared(Args &&...args) {
3026 return shared_ptr<T>(new T(std::forward<Args>(args)...));
3030 // Non-forwarding template: a call to it should fall through to itself.
3031 template <class T> T *$Make[[make]]() { return nullptr; }
3034 $DefaultCtor[[Test]]() {}
3035 $IntCtor[[Test]](int) {}
3036 Test(const char *) {}
3040 // Caret on parens -> Test default ctor.
3041 auto a = std::make_unique<Test>$ParenMU^();
3042 // Caret on the wrapper identifier -> make_unique itself.
3043 auto b = std::ma$IdentMU^ke_unique<Test>();
3044 // make_shared works the same way; overload resolution picks Test(int).
3045 auto c = std::make_shared<Test>$MakeShared^(1);
3046 // Chained forwarding (three wrappers deep).
3047 auto d = std::make_unique3<Test>$Chained^();
3048 // Overload resolution inside the instantiated body picks Test(int).
3049 auto e = std::make_unique<Test>$Overload^(42);
3050 // Non-forwarding template call: no constructor target.
3051 auto f = make<Test>$NonFwd^();
3055 auto AST = TU.build();
3058 ElementsAre(
sym(
"Test", Code.range(
"DefaultCtor"),
3059 Code.range(
"DefaultCtor"))));
3061 ElementsAre(
sym(
"make_unique", Code.range(
"MakeUnique"),
3062 Code.range(
"MakeUnique"))));
3065 ElementsAre(
sym(
"Test", Code.range(
"IntCtor"), Code.range(
"IntCtor"))));
3067 ElementsAre(
sym(
"Test", Code.range(
"DefaultCtor"),
3068 Code.range(
"DefaultCtor"))));
3071 ElementsAre(
sym(
"Test", Code.range(
"IntCtor"), Code.range(
"IntCtor"))));
3073 ElementsAre(
sym(
"make", Code.range(
"Make"), Code.range(
"Make"))));
3076TEST(GetNonLocalDeclRefs,
All) {
3078 llvm::StringRef AnnotatedCode;
3079 std::vector<std::string> ExpectedDecls;
3085 void ^foo(int baz) {
3094 class Foo { public: void foo(); };
3104 {"Bar",
"Bar::bar",
"Foo",
"Foo::foo"},
3110 class Foo { public: void foo() {} };
3111 class Bar { public: void bar() {} };
3122 template <typename T, template<typename> class Q>
3130 for (
const Case &C : Cases) {
3133 SourceLocation SL = llvm::cantFail(
3136 const FunctionDecl *FD =
3137 llvm::dyn_cast<FunctionDecl>(&
findDecl(
AST, [SL](
const NamedDecl &ND) {
3138 return ND.getLocation() == SL && llvm::isa<FunctionDecl>(ND);
3140 ASSERT_NE(FD,
nullptr);
3143 std::vector<std::string> Names;
3144 for (
const Decl *D : NonLocalDeclRefs) {
3145 if (
const auto *ND = llvm::dyn_cast<NamedDecl>(D))
3146 Names.push_back(ND->getQualifiedNameAsString());
3148 EXPECT_THAT(Names, UnorderedElementsAreArray(
C.ExpectedDecls))
3155 #define HEADER_AA "faa.h"
3156 #define HEADER_BB "fbb.h"
3157 #define GET_HEADER(X) HEADER_ ## X
3159 #/*comments*/include /*comments*/ $foo[["foo.h"]] //more comments
3160 int end_of_preamble = 0;
3161 #include $bar[[<bar.h>]]
3162 #include $AA[[GET_HEADER]](AA) // Some comment !
3163 # /* What about */ \
3164 include /* multiple line */ \
3165 $BB[[GET_HEADER]]( /* statements ? */ \
3170 TU.Code = std::string(MainCpp.code());
3171 TU.AdditionalFiles = {
3172 {"faa.h",
""}, {
"fbb.h",
""}, {
"foo.h",
""}, {
"bar.h",
""}};
3173 TU.ExtraArgs = {
"-isystem."};
3174 auto AST = TU.build();
std::vector< HeaderEntry > HeaderContents
Same as llvm::Annotations, but adjusts functions to LSP-specific types for positions and ranges.
Manages a collection of source files and derived data (ASTs, indexes), and provides language-aware fe...
static Options optsForTest()
A context is an immutable container for per-request data that must be propagated through layers that ...
MemIndex is a naive in-memory index suitable for a small set of symbols.
Stores and provides access to parsed AST.
void addSource(llvm::StringRef Filename, llvm::StringRef Code)
FIXME: Skip testing on windows temporarily due to the different escaping code mode.
SymbolID getSymbolID(const Decl *D)
Gets the symbol ID for a declaration. Returned SymbolID might be null.
const NamedDecl & findDecl(ParsedAST &AST, llvm::StringRef QName)
Range halfOpenToRange(const SourceManager &SM, CharSourceRange R)
std::vector< DocumentHighlight > findDocumentHighlights(ParsedAST &AST, Position Pos)
Returns highlights for all usages of a symbol at Pos.
Symbol sym(llvm::StringRef QName, index::SymbolKind Kind, llvm::StringRef USRFormat, llvm::StringRef Signature)
std::vector< LocatedSymbol > locateSymbolTextually(const SpelledWord &Word, ParsedAST &AST, const SymbolIndex *Index, llvm::StringRef MainFilePath, ASTNodeKind NodeKind)
std::vector< DocumentLink > getDocumentLinks(ParsedAST &AST)
Get all document links.
std::vector< LocatedSymbol > findType(ParsedAST &AST, Position Pos, const SymbolIndex *Index)
Returns symbols for types referenced at Pos.
ReferencesResult findReferences(ParsedAST &AST, Position Pos, uint32_t Limit, const SymbolIndex *Index, bool AddContext)
Returns references of the symbol at a specified Pos.
std::string testPath(PathRef File, llvm::sys::path::Style Style)
std::vector< LocatedSymbol > locateSymbolAt(ParsedAST &AST, Position Pos, const SymbolIndex *Index)
Get definition of symbol at a specified Pos.
TEST(BackgroundQueueTest, Priority)
const syntax::Token * findNearbyIdentifier(const SpelledWord &Word, const syntax::TokenBuffer &TB)
void runAddDocument(ClangdServer &Server, PathRef File, llvm::StringRef Contents, llvm::StringRef Version, WantDiagnostics WantDiags, bool ForceRebuild)
llvm::Expected< std::vector< LocatedSymbol > > runLocateSymbolAt(ClangdServer &Server, PathRef File, Position Pos)
const Symbol & findSymbol(const SymbolSlab &Slab, llvm::StringRef QName)
llvm::Expected< SourceLocation > sourceLocationInMainFile(const SourceManager &SM, Position P)
Return the file location, corresponding to P.
@ No
Diagnostics must be generated for this snapshot.
std::vector< LocatedSymbol > findImplementations(ParsedAST &AST, Position Pos, const SymbolIndex *Index)
Returns implementations at a specified Pos:
llvm::DenseSet< const Decl * > getNonLocalDeclRefs(ParsedAST &AST, const FunctionDecl *FD)
Returns all decls that are referenced in the FD except local symbols.
@ Alias
This declaration is an alias that was referred to.
cppcoreguidelines::ProBoundsAvoidUncheckedContainerAccessCheck P
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
A range in a text document that links to an internal or external resource, like another text document...
std::vector< Reference > References
static std::optional< SpelledWord > touching(SourceLocation SpelledLoc, const syntax::TokenBuffer &TB, const LangOptions &LangOpts)
SymbolID ID
The ID of the symbol.
static TestTU withHeaderCode(llvm::StringRef HeaderCode)
static TestTU withCode(llvm::StringRef Code)
static URIForFile canonicalize(llvm::StringRef AbsPath, llvm::StringRef TUPath)
Canonicalizes AbsPath via URI.