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();
55 return Sym.PreferredDeclaration.range ==
Range;
60 return Sym.Definition.value_or(Sym.PreferredDeclaration).range ==
Range;
65Matcher<const std::vector<DocumentHighlight> &>
67 std::vector<DocumentHighlight> Expected;
69 Expected.emplace_back();
70 Expected.back().range = R;
71 Expected.back().kind = K;
73 for (
const auto &
Range : Test.ranges())
75 for (
const auto &
Range : Test.ranges(
"read"))
77 for (
const auto &
Range : Test.ranges(
"write"))
79 return UnorderedElementsAreArray(Expected);
83 const char *Tests[] = {
84 R
"cpp(// Local variable
87 $write[[^bonjour]] = 2;
88 int test1 = $read[[bonjour]];
95 static void foo([[MyClass]]*) {}
99 ns1::[[My^Class]]* Params;
104 int [[^foo]](int) { return 0; }
106 [[foo]]([[foo]](42));
111 R"cpp(// Function parameter in decl
112 void foo(int [[^bar]]);
114 R"cpp(// Not touching any identifiers.
123 R"cpp(// ObjC methods with split selectors.
125 +(void) [[x]]:(int)a [[y]]:(int)b;
128 +(void) [[x]]:(int)a [[y]]:(int)b {}
131 [Foo [[x]]:2 [[^y]]:4];
142 for (
const char *Test : Tests) {
145 TU.ExtraArgs.push_back(
"-xobjective-c++");
146 auto AST = TU.build();
152TEST(HighlightsTest, ControlFlow) {
153 const char *Tests[] = {
155 // Highlight same-function returns.
156 int fib(unsigned n) {
157 if (n <= 1) [[ret^urn]] 1;
158 [[return]] fib(n - 1) + fib(n - 2);
160 // Returns from other functions not highlighted.
161 auto Lambda = [] { return; };
162 class LocalClass { void x() { return; } };
167 #define FAIL() return false
170 if (n < 0) [[FAIL]]();
176 // Highlight loop control flow
179 [[^for]] (char c : "fruit loops!") {
180 if (c == ' ') [[continue]];
182 if (c == '!') [[break]];
183 if (c == '?') [[return]] -1;
190 // Highlight loop and same-loop control flow
193 if (false) [[bre^ak]];
201 // Highlight switch for break (but not other breaks).
202 void describe(unsigned n) {
213 // Highlight case and exits for switch-break (but not other cases).
214 void describe(unsigned n) {
227 // Highlight exits and switch for case
228 void describe(unsigned n) {
241 // Highlight nothing for switch.
242 void describe(unsigned n) {
255 // FIXME: match exception type against catch blocks
257 try { // wrong: highlight try with matching catch
258 try { // correct: has no matching catch
260 } catch (int) { } // correct: catch doesn't match type
261 [[return]] -1; // correct: exits the matching catch
262 } catch (const char*) { } // wrong: highlight matching catch
263 [[return]] 42; // wrong: throw doesn't exit function
268 // Loop highlights goto exiting the loop, but not jumping within it.
279 for (
const char *Test : Tests) {
282 TU.ExtraArgs.push_back(
"-fexceptions");
283 auto AST = TU.build();
289MATCHER_P3(
sym, Name, Decl, DefOrNone,
"") {
290 std::optional<Range> Def = DefOrNone;
291 if (Name != arg.Name) {
292 *result_listener <<
"Name is " << arg.Name;
295 if (Decl != arg.PreferredDeclaration.range) {
296 *result_listener <<
"Declaration is "
297 << llvm::to_string(arg.PreferredDeclaration);
300 if (!Def && !arg.Definition)
302 if (Def && !arg.Definition) {
303 *result_listener <<
"Has no definition";
306 if (!Def && arg.Definition) {
307 *result_listener <<
"Definition is " << llvm::to_string(*arg.Definition);
310 if (arg.Definition->range != *Def) {
311 *result_listener <<
"Definition is " << llvm::to_string(*arg.Definition);
319MATCHER_P(rangeIs, R,
"") {
return arg.Loc.range == R; }
320MATCHER_P(fileIs, F,
"") {
return arg.Loc.uri.file() == F; }
322 return arg.Loc.containerName.value_or(
"") ==
C;
324MATCHER_P(attrsAre, A,
"") {
return arg.Attributes ==
A; }
325MATCHER_P(hasID, ID,
"") {
return arg.ID == ID; }
327TEST(LocateSymbol, WithIndex) {
329 class $forward[[Forward]];
330 class $foo[[Foo]] {};
334 inline void $f2[[f2]]() {}
337 class $forward[[forward]] {};
342 TU.Code = std::string(SymbolCpp.code());
343 TU.HeaderCode = std::string(SymbolHeader.code());
344 auto Index = TU.index();
345 auto LocateWithIndex = [&Index](
const Annotations &Main) {
356 EXPECT_THAT(LocateWithIndex(Test),
357 ElementsAre(sym("f1", Test.range(), SymbolCpp.range(
"f1"))));
365 EXPECT_THAT(LocateWithIndex(Test),
366 ElementsAre(sym("f1", SymbolHeader.range(
"f1"), Test.range())));
368 Test =
Annotations(R
"cpp(// forward declaration in AST.
372 EXPECT_THAT(LocateWithIndex(Test),
373 ElementsAre(sym("Foo", Test.range(), SymbolHeader.range(
"foo"))));
376 class [[Forward]] {};
380 LocateWithIndex(Test),
381 ElementsAre(sym("Forward", SymbolHeader.range(
"forward"), Test.range())));
384TEST(LocateSymbol, AnonymousStructFields) {
387 struct { int $1[[x]]; };
389 // Make sure the implicit base is skipped.
393 // Check that we don't skip explicit bases.
397 auto AST = TU.build();
399 UnorderedElementsAre(
sym(
"x", Code.range(
"1"), Code.range(
"1"))));
402 UnorderedElementsAre(
sym(
"Foo", Code.range(
"2"), Code.range(
"2"))));
405TEST(LocateSymbol, FindOverrides) {
408 virtual void $1[[fo^o]]() = 0;
410 class Bar : public Foo {
411 void $2[[foo]]() override;
415 auto AST = TU.build();
417 UnorderedElementsAre(
sym(
"foo", Code.range(
"1"), std::nullopt),
418 sym(
"foo", Code.range(
"2"), std::nullopt)));
421TEST(LocateSymbol, FindOverridesFromDefObjC) {
429 @interface Foo : Base<Fooey>
437 - (void)$3[[fo^o]] {}
441 TU.ExtraArgs.push_back("-xobjective-c++");
442 auto AST = TU.build();
445 UnorderedElementsAre(
sym(
"foo", Code.range(
"1"), std::nullopt),
446 sym(
"foo", Code.range(
"2"), Code.range(
"3"))));
449TEST(LocateSymbol, NoOverridesFromDeclObjC) {
457 @interface Foo : Base<Fooey>
469 TU.ExtraArgs.push_back("-xobjective-c++");
470 auto AST = TU.build();
473 UnorderedElementsAre(
sym(
"foo", Code.range(
"2"), Code.range(
"3"))));
476TEST(LocateSymbol, ObjCNoOverridesOnUsage) {
488 void doSomething(Bar *bar) {
493 TU.ExtraArgs.push_back("-xobjective-c++");
494 auto AST = TU.build();
497 UnorderedElementsAre(
sym(
"foo", Code.range(
"1"), Code.range(
"2"))));
500TEST(LocateSymbol, WithIndexPreferredLocation) {
502 class $p[[Proto]] {};
503 void $f[[func]]() {};
506 TU.HeaderCode = std::string(SymbolHeader.code());
507 TU.HeaderFilename = "x.proto";
508 auto Index = TU.index();
511 // Shift to make range different.
523 auto CodeGenLoc = SymbolHeader.range(
"p");
524 EXPECT_THAT(Locs, ElementsAre(
sym(
"Proto", CodeGenLoc, CodeGenLoc)));
528 auto CodeGenLoc = SymbolHeader.range(
"f");
529 EXPECT_THAT(Locs, ElementsAre(
sym(
"func", CodeGenLoc, CodeGenLoc)));
538 const char *Tests[] = {
551 R"cpp(// Local variable
561 struct [[MyClass]] {};
564 ns1::My^Class* Params;
568 R"cpp(// Function definition via pointer
575 R"cpp(// Function declaration via call
576 int $decl[[foo]](int);
583 struct Foo { int [[x]]; };
590 R"cpp(// Field, member initializer
597 R"cpp(// Field, field designator
598 struct Foo { int [[x]]; };
600 Foo bar = { .^x = 2 };
604 R"cpp(// Field in offsetof
605 struct Foo { int [[x]]; };
606 int y = __builtin_offsetof(Foo, ^x);
609 R"cpp(// Outer field in nested offsetof designator
610 struct Inner { int c; };
611 struct A { Inner [[B]]; };
612 int y = __builtin_offsetof(A, ^B.c);
615 R"cpp(// Inner field in nested offsetof designator
616 struct Inner { int [[c]]; };
617 struct A { Inner B; };
618 int y = __builtin_offsetof(A, B.^c);
621 R"cpp(// Field in offsetof macro form
622 #define offsetof(t, m) __builtin_offsetof(t, m)
623 struct Foo { int [[x]]; };
624 int y = offsetof(Foo, ^x);
627 R"cpp(// Inherited field in offsetof
628 struct B { int [[x]]; };
630 int y = __builtin_offsetof(D, ^x);
633 R"cpp(// Builtin offsetof name is not a field reference.
634 struct Foo { int x; };
635 int y = __builtin_o^ffsetof(Foo, x);
639 struct Foo { int $decl[[x]](); };
647 typedef int $decl[[Foo]];
653 R"cpp(// Template type parameter
654 template <typename [[T]]>
658 R"cpp(// Template template type parameter
659 template <template<typename> class [[T]]>
660 void foo() { ^T<int> t; }
664 namespace $decl[[ns]] {
665 struct Foo { static void bar(); };
667 int main() { ^ns::Foo::bar(); }
671 class TTT { public: int a; };
672 #define [[FF]](S) if (int b = S.a) {}
679 R"cpp(// Macro argument
681 #define ADDRESSOF(X) &X;
682 int *j = ADDRESSOF(^i);
684 R"cpp(// Macro argument appearing multiple times in expansion
685 #define VALIDATE_TYPE(x) (void)x;
686 #define ASSERT(expr) \
688 VALIDATE_TYPE(expr); \
691 bool [[waldo]]() { return true; }
696 R"cpp(// Symbol concatenated inside macro (not supported)
698 #define POINTER(X) p ## X;
699 int x = *POINTER(^i);
702 R"cpp(// Forward class declaration
704 class $def[[Foo]] {};
708 R"cpp(// Function declaration
711 void $def[[foo]]() {}
715 #define FF(name) class name##_Test {};
717 void f() { my^_Test a; }
721 #define FF() class [[Test]] {};
723 void f() { T^est a; }
726 R"cpp(// explicit template specialization
727 template <typename T>
728 struct Foo { void bar() {} };
731 struct [[Foo]]<int> { void bar() {} };
739 R"cpp(// implicit template specialization
740 template <typename T>
741 struct [[Foo]] { void bar() {} };
743 struct Foo<int> { void bar() {} };
750 R"cpp(// partial template specialization
751 template <typename T>
752 struct Foo { void bar() {} };
753 template <typename T>
754 struct [[Foo]]<T*> { void bar() {} };
758 R"cpp(// function template specializations
768 R"cpp(// variable template decls
773 double [[var]]<int> = 10;
775 double y = va^r<int>;
778 R"cpp(// No implicit constructors
790 X& $decl[[operator]]++();
798 struct S1 { void f(); };
799 struct S2 { S1 * $decl[[operator]]->(); };
805 R"cpp(// Declaration of explicit template specialization
806 template <typename T>
807 struct $decl[[$def[[Foo]]]] {};
813 R"cpp(// Declaration of partial template specialization
814 template <typename T>
815 struct $decl[[$def[[Foo]]]] {};
817 template <typename T>
821 R"cpp(// Definition on ClassTemplateDecl
823 // Forward declaration.
827 template <typename T>
828 struct $def[[Foo]] {};
834 R"cpp(// auto builtin type (not supported)
838 R"cpp(// auto on lambda
843 R"cpp(// auto on struct
851 R"cpp(// decltype on struct
860 R"cpp(// decltype(auto) on struct
867 ^decltype(auto) k = j;
870 R"cpp(// auto on template class
871 template<typename T> class [[Foo]] {};
873 ^auto x = Foo<int>();
876 R"cpp(// auto on template class with forward declared class
877 template<typename T> class [[Foo]] {};
883 R"cpp(// auto on specialized template class
884 template<typename T> class Foo {};
885 template<> class [[Foo]]<int> {};
887 ^auto x = Foo<int>();
890 R"cpp(// auto on initializer list.
894 class [[initializer_list]] { const _E *a, *b; };
900 R"cpp(// auto function return with trailing type
902 ^auto test() -> decltype(Bar()) {
907 R"cpp(// decltype in trailing return type
909 auto test() -> ^decltype(Bar()) {
914 R"cpp(// auto in function return
921 R"cpp(// auto& in function return
929 R"cpp(// auto* in function return
937 R"cpp(// const auto& in function return
939 const ^auto& test() {
945 R"cpp(// auto lambda param where there's a single instantiation
947 auto Lambda = [](^auto){ return 0; };
948 int x = Lambda(Bar{});
951 R"cpp(// decltype(auto) in function return
953 ^decltype(auto) test() {
958 R"cpp(// decltype of function with trailing return type.
960 auto test() -> decltype(Bar()) {
964 ^decltype(test()) i = test();
968 R"cpp(// auto with dependent type
971 template <typename T>
977 R"cpp(// Override specifier jumps to overridden method
978 class Y { virtual void $decl[[a]]() = 0; };
979 class X : Y { void a() ^override {} };
981 R"cpp(// Final specifier jumps to overridden method
982 class Y { virtual void $decl[[a]]() = 0; };
983 class X : Y { void a() ^final {} };
986 R"cpp(// Heuristic resolution of dependent method
987 template <typename T>
992 template <typename T>
998 R"cpp(// Heuristic resolution of dependent method via this->
999 template <typename T>
1007 R"cpp(// Heuristic resolution of dependent static method
1008 template <typename T>
1010 static void [[bar]]() {}
1013 template <typename T>
1019 R"cpp(// Heuristic resolution of dependent method
1020 // invoked via smart pointer
1021 template <typename> struct S { void [[foo]]() {} };
1022 template <typename T> struct unique_ptr {
1025 template <typename T>
1026 void test(unique_ptr<S<T>>& V) {
1031 R"cpp(// Heuristic resolution of dependent enumerator
1032 template <typename T>
1034 enum class E { [[A]], B };
1040 typedef int $decl[[MyTypeDef]];
1041 enum Foo : My^TypeDef {};
1044 typedef int $decl[[MyTypeDef]];
1045 enum Foo : My^TypeDef;
1048 using $decl[[MyTypeDef]] = int;
1049 enum Foo : My^TypeDef {};
1054 @protocol $decl[[Dog]]
1057 id<Do^g> getDoggo() {
1067 @interface $decl[[Cat]] (Exte^nsion)
1070 @implementation $def[[Cat]] (Extension)
1076 @class $decl[[Foo]];
1082 R"objc(// Prefer interface definition over forward declaration
1084 @interface $decl[[Foo]]
1093 @interface $decl[[Foo]]
1095 @implementation $def[[Foo]]
1102 R"objc(// Method decl and definition for ObjC class.
1104 - (void)$decl[[meow]];
1107 - (void)$def[[meow]] {}
1109 void makeNoise(Cat *kitty) {
1114 R"objc(// Method decl and definition for ObjC category.
1117 @interface Dog (Play)
1118 - (void)$decl[[runAround]];
1120 @implementation Dog (Play)
1121 - (void)$def[[runAround]] {}
1123 void play(Dog *dog) {
1128 R"objc(// Method decl and definition for ObjC class extension.
1132 - (void)$decl[[howl]];
1135 - (void)$def[[howl]] {}
1137 void play(Dog *dog) {
1142 struct PointerIntPairInfo {
1143 static void *$decl[[getPointer]](void *Value);
1146 template <typename Info = PointerIntPairInfo> struct PointerIntPair {
1148 void *getPointer() const { return Info::get^Pointer(Value); }
1151 R"cpp(// Deducing this
1157 int x = wa^ldo.bar();
1160 for (
const char *Test : Tests) {
1162 std::optional<Range> WantDecl;
1163 std::optional<Range> WantDef;
1164 if (!
T.ranges().empty())
1165 WantDecl = WantDef =
T.range();
1166 if (!
T.ranges(
"decl").empty())
1167 WantDecl =
T.range(
"decl");
1168 if (!
T.ranges(
"def").empty())
1169 WantDef =
T.range(
"def");
1172 TU.
Code = std::string(
T.code());
1174 TU.ExtraArgs.push_back(
"-xobjective-c++");
1175 TU.ExtraArgs.push_back(
"-std=c++23");
1177 auto AST = TU.build();
1181 EXPECT_THAT(Results, IsEmpty()) << Test;
1183 ASSERT_THAT(Results, ::testing::SizeIs(1)) << Test;
1184 EXPECT_EQ(Results[0].PreferredDeclaration.range, *WantDecl) << Test;
1185 EXPECT_TRUE(Results[0].ID) << Test;
1186 std::optional<Range> GotDef;
1188 GotDef = Results[0].Definition->range;
1189 EXPECT_EQ(WantDef, GotDef) << Test;
1193TEST(LocateSymbol, ValidSymbolID) {
1195 #define MACRO(x, y) ((x) + (y))
1196 int add(int x, int y) { return $MACRO^MACRO(x, y); }
1197 int sum = $add^add(1, 2);
1201 auto AST = TU.build();
1202 auto Index = TU.index();
1204 ElementsAre(AllOf(
sym(
"add"),
1208 ElementsAre(AllOf(
sym(
"MACRO"),
1212TEST(LocateSymbol, AllMulti) {
1219 struct ExpectedRanges {
1221 std::optional<Range> WantDef;
1223 const char *Tests[] = {
1225 @interface $decl0[[Cat]]
1227 @implementation $def0[[Cat]]
1229 @interface $decl1[[Ca^t]] (Extension)
1232 @implementation $def1[[Cat]] (Extension)
1238 @interface $decl0[[Cat]]
1240 @implementation $def0[[Cat]]
1242 @interface $decl1[[Cat]] (Extension)
1245 @implementation $def1[[Ca^t]] (Extension)
1251 @interface $decl0[[Cat]]
1253 @interface $decl1[[Ca^t]] ()
1256 @implementation $def0[[$def1[[Cat]]]]
1261 for (
const char *Test : Tests) {
1263 std::vector<ExpectedRanges> Ranges;
1264 for (
int Idx = 0;
true; Idx++) {
1265 bool HasDecl = !
T.ranges(
"decl" + std::to_string(Idx)).empty();
1266 bool HasDef = !
T.ranges(
"def" + std::to_string(Idx)).empty();
1267 if (!HasDecl && !HasDef)
1269 ExpectedRanges
Range;
1271 Range.WantDecl =
T.range(
"decl" + std::to_string(Idx));
1273 Range.WantDef =
T.range(
"def" + std::to_string(Idx));
1274 Ranges.push_back(
Range);
1278 TU.
Code = std::string(
T.code());
1279 TU.ExtraArgs.push_back(
"-xobjective-c++");
1281 auto AST = TU.build();
1284 ASSERT_THAT(Results, ::testing::SizeIs(Ranges.size())) << Test;
1285 for (
size_t Idx = 0; Idx < Ranges.size(); Idx++) {
1286 EXPECT_EQ(Results[Idx].PreferredDeclaration.range, Ranges[Idx].WantDecl)
1287 <<
"($decl" << Idx <<
")" << Test;
1288 std::optional<Range> GotDef;
1290 GotDef = Results[Idx].Definition->range;
1291 EXPECT_EQ(GotDef, Ranges[Idx].WantDef) <<
"($def" << Idx <<
")" << Test;
1299TEST(LocateSymbol, Warnings) {
1300 const char *Tests[] = {
1301 R
"cpp(// Field, GNU old-style field designator
1302 struct Foo { int [[x]]; };
1304 Foo bar = { ^x : 1 };
1311 int main() { return ^MACRO; }
1317 for (
const char *Test : Tests) {
1319 std::optional<Range> WantDecl;
1320 std::optional<Range> WantDef;
1321 if (!
T.ranges().empty())
1322 WantDecl = WantDef =
T.range();
1323 if (!
T.ranges(
"decl").empty())
1324 WantDecl =
T.range(
"decl");
1325 if (!
T.ranges(
"def").empty())
1326 WantDef =
T.range(
"def");
1329 TU.
Code = std::string(
T.code());
1331 auto AST = TU.build();
1335 EXPECT_THAT(Results, IsEmpty()) << Test;
1337 ASSERT_THAT(Results, ::testing::SizeIs(1)) << Test;
1338 EXPECT_EQ(Results[0].PreferredDeclaration.range, *WantDecl) << Test;
1339 std::optional<Range> GotDef;
1341 GotDef = Results[0].Definition->range;
1342 EXPECT_EQ(WantDef, GotDef) << Test;
1347TEST(LocateSymbol, TextualSmoke) {
1350 struct [[MyClass]] {};
1351 // Comment mentioning M^yClass
1355 auto AST = TU.build();
1356 auto Index = TU.index();
1359 ElementsAre(AllOf(
sym(
"MyClass",
T.range(),
T.range()),
1363TEST(LocateSymbol, Textual) {
1364 const char *Tests[] = {
1366 struct [[MyClass]] {};
1367 // Comment mentioning M^yClass
1371 // Not triggered for string literal tokens.
1372 const char* s = "String literal mentioning M^yClass";
1374 R"cpp(// Ifdef'ed out code
1375 struct [[MyClass]] {};
1380 R"cpp(// Macro definition
1381 struct [[MyClass]] {};
1382 #define DECLARE_MYCLASS_OBJ(name) M^yClass name;
1384 R"cpp(// Invalid code
1386 int myFunction(int);
1387 // Not triggered for token which survived preprocessing.
1388 int var = m^yFunction();
1391 for (
const char *Test : Tests) {
1393 std::optional<Range> WantDecl;
1394 if (!
T.ranges().empty())
1395 WantDecl =
T.range();
1399 auto AST = TU.build();
1400 auto Index = TU.index();
1403 AST.getTokens(),
AST.getLangOpts());
1405 ADD_FAILURE() <<
"No word touching point!" << Test;
1409 testPath(TU.Filename), ASTNodeKind());
1412 EXPECT_THAT(Results, IsEmpty()) << Test;
1414 ASSERT_THAT(Results, ::testing::SizeIs(1)) << Test;
1415 EXPECT_EQ(Results[0].PreferredDeclaration.range, *WantDecl) << Test;
1420TEST(LocateSymbol, Ambiguous) {
1425 $ConstructorLoc[[Foo]](const char*);
1433 const char* str = "123";
1435 Foo b = Foo($2^str);
1440 Foo ab$8^cd("asdf");
1441 Foo foox = Fo$9^o("asdf");
1442 Foo abcde$10^("asdf");
1443 Foo foox2 = Foo$11^("asdf");
1446 template <typename T>
1448 void $NonstaticOverload1[[bar]](int);
1449 void $NonstaticOverload2[[bar]](float);
1451 static void $StaticOverload1[[baz]](int);
1452 static void $StaticOverload2[[baz]](float);
1455 template <typename T, typename U>
1456 void dependent_call(S<T> s, U u) {
1464 TU.ExtraArgs.push_back(
"-fno-delayed-template-parsing");
1465 auto AST = TU.build();
1480 ElementsAre(
sym(
"Foo",
T.range(
"ConstructorLoc"), std::nullopt)));
1482 ElementsAre(
sym(
"Foo",
T.range(
"ConstructorLoc"), std::nullopt)));
1487 UnorderedElementsAre(
1488 sym(
"bar",
T.range(
"NonstaticOverload1"), std::nullopt),
1489 sym(
"bar",
T.range(
"NonstaticOverload2"), std::nullopt)));
1491 UnorderedElementsAre(
1492 sym(
"baz",
T.range(
"StaticOverload1"), std::nullopt),
1493 sym(
"baz",
T.range(
"StaticOverload2"), std::nullopt)));
1496TEST(LocateSymbol, TextualDependent) {
1502 void $FooLoc[[uniqueMethodName]]();
1505 void $BarLoc[[uniqueMethodName]]();
1509 template <typename T>
1511 t.u^niqueMethodName();
1515 TU.Code = std::string(Source.code());
1516 TU.HeaderCode = std::string(Header.code());
1517 auto AST = TU.build();
1518 auto Index = TU.index();
1525 UnorderedElementsAre(
1526 sym(
"uniqueMethodName", Header.range(
"FooLoc"), std::nullopt),
1527 sym(
"uniqueMethodName", Header.range(
"BarLoc"), std::nullopt)));
1531 const char *Tests[] = {
1533 template <class T> struct function {};
1534 template <class T> using [[callback]] = function<T()>;
1543 typedef Foo [[Bar]];
1549 using [[Bar]] = Foo; // definition
1562 namespace ns { class [[Foo]] {}; }
1567 namespace ns { int [[x]](char); int [[x]](double); }
1572 namespace ns { int [[x]](char); int x(double); }
1578 namespace ns { class [[Foo]] {}; }
1586 typedef Foo [[Ba^r]];
1590 using [[B^ar]] = Foo;
1595 template <typename T>
1599 template <typename T>
1600 struct Derived : Base<T> {
1601 using Base<T>::w^aldo;
1606 for (
const auto *Case : Tests) {
1611 UnorderedPointwise(declRange(),
T.ranges()));
1615TEST(LocateSymbol, RelPathsInCompileCommand) {
1620#include "header_in_preamble.h"
1622#include "header_not_in_preamble.h"
1623int baz = f$p1^oo + bar_pre$p2^amble + bar_not_pre$p3^amble;
1627int [[bar_preamble]];
1631int [[bar_not_preamble]];
1636 SmallString<32> RelPathPrefix(
"..");
1637 llvm::sys::path::append(RelPathPrefix,
"src");
1638 std::string BuildDir =
testPath(
"build");
1645 auto FooCpp =
testPath(
"src/foo.cpp");
1646 FS.Files[FooCpp] =
"";
1647 auto HeaderInPreambleH =
testPath(
"src/header_in_preamble.h");
1648 FS.Files[HeaderInPreambleH] = std::string(HeaderInPreambleAnnotations.code());
1649 auto HeaderNotInPreambleH =
testPath(
"src/header_not_in_preamble.h");
1650 FS.Files[HeaderNotInPreambleH] =
1651 std::string(HeaderNotInPreambleAnnotations.code());
1658 EXPECT_TRUE(
bool(Locations)) <<
"findDefinitions returned an error";
1659 EXPECT_THAT(*Locations, ElementsAre(
sym(
"foo", SourceAnnotations.range(),
1660 SourceAnnotations.range())));
1664 EXPECT_TRUE(
bool(Locations)) <<
"findDefinitions returned an error";
1667 ElementsAre(
sym(
"bar_preamble", HeaderInPreambleAnnotations.range(),
1668 HeaderInPreambleAnnotations.range())));
1672 EXPECT_TRUE(
bool(Locations)) <<
"findDefinitions returned an error";
1673 EXPECT_THAT(*Locations,
1674 ElementsAre(
sym(
"bar_not_preamble",
1675 HeaderNotInPreambleAnnotations.range(),
1676 HeaderNotInPreambleAnnotations.range())));
1685 const char *SourceContents = R
"cpp(
1686 #include ^"$2^foo.h$3^"
1687 #include "$4^invalid.h"
1691 #in$5^clude "$6^foo.h"$7^
1694 FS.Files[FooCpp] = std::string(SourceAnnotations.code());
1701 FS.Files[FooH] = std::string(HeaderAnnotations.code());
1708 ASSERT_TRUE(
bool(Locations)) <<
"locateSymbolAt returned an error";
1709 EXPECT_THAT(*Locations, ElementsAre(
sym(
"foo.h", HeaderAnnotations.range(),
1710 HeaderAnnotations.range())));
1714 ASSERT_TRUE(
bool(Locations)) <<
"locateSymbolAt returned an error";
1715 EXPECT_THAT(*Locations, ElementsAre(
sym(
"foo.h", HeaderAnnotations.range(),
1716 HeaderAnnotations.range())));
1719 ASSERT_TRUE(
bool(Locations)) <<
"locateSymbolAt returned an error";
1720 EXPECT_THAT(*Locations, ElementsAre(
sym(
"foo.h", HeaderAnnotations.range(),
1721 HeaderAnnotations.range())));
1725 ASSERT_TRUE(
bool(Locations)) <<
"locateSymbolAt returned an error";
1726 EXPECT_THAT(*Locations, ElementsAre(
sym(
"foo.h", HeaderAnnotations.range(),
1727 HeaderAnnotations.range())));
1731 ASSERT_TRUE(
bool(Locations)) <<
"locateSymbolAt returned an error";
1732 EXPECT_THAT(*Locations, IsEmpty());
1735 ASSERT_TRUE(
bool(Locations)) <<
"locateSymbolAt returned an error";
1736 EXPECT_THAT(*Locations, ElementsAre(
sym(
"foo.h", HeaderAnnotations.range(),
1737 HeaderAnnotations.range())));
1740 ASSERT_TRUE(
bool(Locations)) <<
"locateSymbolAt returned an error";
1741 EXPECT_THAT(*Locations, ElementsAre(
sym(
"foo.h", HeaderAnnotations.range(),
1742 HeaderAnnotations.range())));
1749 FS.Files[FooM] = std::string(ObjC.code());
1753 ASSERT_TRUE(
bool(Locations)) <<
"locateSymbolAt returned an error";
1754 EXPECT_THAT(*Locations, ElementsAre(
sym(
"foo.h", HeaderAnnotations.range(),
1755 HeaderAnnotations.range())));
1758TEST(LocateSymbol, WithPreamble) {
1767 Annotations FooWithHeader(R
"cpp(#include "fo^o.h")cpp");
1768 Annotations FooWithoutHeader(R"cpp(double [[fo^o]]();)cpp");
1770 FS.Files[FooCpp] = std::string(FooWithHeader.code());
1774 FS.Files[FooH] = std::string(FooHeader.code());
1780 ElementsAre(
sym(
"foo.h", FooHeader.range(), FooHeader.range())));
1783 Server.addDocument(FooCpp, FooWithoutHeader.code(),
"null",
1789 ElementsAre(
sym(
"foo", FooWithoutHeader.range(), std::nullopt)));
1794 Server.addDocument(FooCpp, FooWithoutHeader.code(),
"null",
1799 ElementsAre(
sym(
"foo", FooWithoutHeader.range(), std::nullopt)));
1802TEST(LocateSymbol, NearbyTokenSmoke) {
1804 // prints e^rr and crashes
1805 void die(const char* [[err]]);
1810 ElementsAre(
sym(
"err",
T.range(),
T.range())));
1813TEST(LocateSymbol, NearbyIdentifier) {
1814 const char *Tests[] = {
1816 // regular identifiers (won't trigger)
1821 // disabled preprocessor sections
1833 // not triggered by string literals
1835 const char* greeting = "h^ello, world";
1839 // can refer to macro invocations
1846 // can refer to macro invocations (even if they expand to nothing)
1853 // prefer nearest occurrence, backwards is worse than forwards
1862 // short identifiers find near results
1867 // short identifiers don't find far results
1880 // prefer nearest occurrence even if several matched tokens
1881 // have the same value of `floor(log2(<token line> - <word line>))`.
1883 int x = hello, y = hello;
1887 for (
const char *Test : Tests) {
1890 const auto &SM =
AST.getSourceManager();
1891 std::optional<Range> Nearby;
1894 AST.getTokens(),
AST.getLangOpts());
1896 ADD_FAILURE() <<
"No word at point! " << Test;
1901 Tok->location(), Tok->endLocation()));
1902 if (
T.ranges().empty())
1903 EXPECT_THAT(Nearby, Eq(std::nullopt)) << Test;
1905 EXPECT_EQ(Nearby,
T.range()) << Test;
1909TEST(FindImplementations, Inheritance) {
1910 llvm::StringRef Test = R
"cpp(
1912 virtual void F$1^oo();
1915 struct $0[[Child1]] : Base {
1916 void $1[[Fo$3^o]]() override;
1917 virtual void B$2^ar();
1918 void Concrete(); // No implementations for concrete methods.
1920 struct $0[[Child2]] : Child1 {
1921 void $1[[$3[[Foo]]]]() override;
1922 void $2[[Bar]]() override;
1924 void FromReference() {
1933 // CRTP should work.
1934 template<typename T>
1935 struct $5^TemplateBase {};
1936 struct $5[[Child3]] : public TemplateBase<Child3> {};
1939 void LocationFunction() {
1940 struct $0[[LocalClass1]] : Base {
1941 void $1[[Foo]]() override;
1943 struct $6^LocalBase {
1944 virtual void $7^Bar();
1946 struct $6[[LocalClass2]]: LocalBase {
1947 void $7[[Bar]]() override;
1954 auto AST = TU.build();
1955 auto Index = TU.index();
1956 for (StringRef
Label : {
"0",
"1",
"2",
"3",
"4",
"5",
"6",
"7"}) {
1957 for (
const auto &Point : Code.points(
Label)) {
1959 UnorderedPointwise(declRange(), Code.ranges(
Label)))
1960 << Code.code() <<
" at " << Point <<
" for Label " <<
Label;
1965TEST(FindImplementations, InheritanceRecursion) {
1967 llvm::StringRef Test = R
"cpp(
1976 static const bool value = true;
1981 static const bool value = false;
1985 struct [[Even]] : Odd<I - 1> {};
1988 struct [[Odd]] : Even<I - 1> {};
1990 constexpr bool Answer = Even<42>::value;
1995 auto AST = TU.build();
1996 auto Index = TU.index();
1998 UnorderedPointwise(defRange(), Code.ranges()));
2001TEST(FindImplementations, InheritanceObjC) {
2002 llvm::StringRef Test = R
"objc(
2003 @interface $base^Base
2007 - (void)$protocol^protocol;
2009 @interface $ChildDecl[[Child]] : Base <Protocol>
2011 - (void)$fooDecl[[foo]];
2013 @implementation $ChildDef[[Child]]
2015 - (void)$fooDef[[foo]] {}
2016 - (void)$protocolDef[[protocol]] {}
2022 TU.ExtraArgs.push_back(
"-xobjective-c++");
2023 auto AST = TU.build();
2024 auto Index = TU.index();
2026 UnorderedElementsAre(
sym(
"Child", Code.range(
"ChildDecl"),
2027 Code.range(
"ChildDef"))));
2029 UnorderedElementsAre(
2030 sym(
"foo", Code.range(
"fooDecl"), Code.range(
"fooDef"))));
2032 UnorderedElementsAre(
sym(
"protocol", Code.range(
"protocolDef"),
2033 Code.range(
"protocolDef"))));
2036TEST(FindImplementations, CaptureDefinition) {
2037 llvm::StringRef Test = R
"cpp(
2039 virtual void F^oo();
2041 struct Child1 : Base {
2042 void $Decl[[Foo]]() override;
2044 struct Child2 : Base {
2045 void $Child2[[Foo]]() override;
2047 void Child1::$Def[[Foo]]() { /* Definition */ }
2051 auto AST = TU.build();
2054 UnorderedElementsAre(
sym(
"Foo", Code.range(
"Decl"), Code.range(
"Def")),
2055 sym(
"Foo", Code.range(
"Child2"), std::nullopt)))
2061 struct $Target[[Target]] { operator int() const; };
2062 struct Aggregate { Target a, b; };
2066 template <typename T> struct $smart_ptr[[smart_ptr]] {
2073 for (
const llvm::StringRef Case : {
2077 "a^uto x = Target{};",
2078 "namespace m { Target tgt; } auto x = m^::tgt;",
2079 "Target funcCall(); auto x = ^funcCall();",
2080 "Aggregate a = { {}, ^{} };",
2081 "Aggregate a = { ^.a=t, };",
2082 "struct X { Target a; X() : ^a() {} };",
2083 "^using T = Target; ^T foo();",
2084 "^template <int> Target foo();",
2085 "void x() { try {} ^catch(Target e) {} }",
2086 "void x() { ^throw t; }",
2087 "int x() { ^return t; }",
2088 "void x() { ^switch(t) {} }",
2089 "void x() { ^delete (Target*)nullptr; }",
2090 "Target& ^tref = t;",
2091 "void x() { ^if (t) {} }",
2092 "void x() { ^while (t) {} }",
2093 "void x() { ^do { } while (t); }",
2094 "void x() { ^make(); }",
2095 "void x(smart_ptr<Target> &t) { t.^get(); }",
2096 "^auto x = []() { return t; };",
2097 "Target* ^tptr = &t;",
2098 "Target ^tarray[3];",
2101 TU.Code =
A.code().str();
2104 ASSERT_GT(
A.points().size(), 0u) << Case;
2105 for (
auto Pos :
A.points())
2108 sym(
"Target", HeaderA.range(
"Target"), HeaderA.range(
"Target"))))
2112 for (
const llvm::StringRef Case : {
2113 "smart_ptr<Target> ^tsmart;",
2116 TU.Code =
A.code().str();
2120 UnorderedElementsAre(
2121 sym(
"Target", HeaderA.range(
"Target"), HeaderA.range(
"Target")),
2122 sym(
"smart_ptr", HeaderA.range(
"smart_ptr"), HeaderA.range(
"smart_ptr"))
2135 concept $Concept^True = true;
2138 TU.ExtraArgs.push_back(
"-std=c++20");
2142 ElementsAre(
sym(
"X",
A.range(
"decl"),
A.range(
"def"))));
2143 EXPECT_THAT(
findType(
AST,
A.point(
"Concept"),
nullptr), IsEmpty());
2146TEST(FindType, Index) {
2148 // This definition is only available through the index.
2152 DefTU.HeaderFilename = "def.h";
2153 auto DefIdx = DefTU.index();
2163 ElementsAre(
sym(
"X",
A.range(), Def.range())));
2166void checkFindRefs(llvm::StringRef Test,
bool UseIndex =
false) {
2169 TU.ExtraArgs.push_back(
"-std=c++20");
2170 TU.ExtraArgs.push_back(
"-xobjective-c++");
2172 auto AST = TU.build();
2173 std::vector<Matcher<ReferencesResult::Reference>> ExpectedLocations;
2174 for (
const auto &[R,
Context] :
T.rangesWithPayload())
2175 ExpectedLocations.push_back(
2176 AllOf(rangeIs(R), containerIs(
Context), attrsAre(0u)));
2179 for (
const auto &[R,
Context] :
T.rangesWithPayload(
"def"))
2180 ExpectedLocations.push_back(AllOf(rangeIs(R), containerIs(
Context),
2183 for (
const auto &[R,
Context] :
T.rangesWithPayload(
"decl"))
2184 ExpectedLocations.push_back(AllOf(rangeIs(R), containerIs(
Context),
2186 for (
const auto &[R,
Context] :
T.rangesWithPayload(
"overridedecl"))
2187 ExpectedLocations.push_back(AllOf(
2188 rangeIs(R), containerIs(
Context),
2190 for (
const auto &[R,
Context] :
T.rangesWithPayload(
"overridedef"))
2191 ExpectedLocations.push_back(AllOf(rangeIs(R), containerIs(
Context),
2195 for (
const auto &P :
T.points()) {
2199 UnorderedElementsAreArray(ExpectedLocations))
2200 <<
"Failed for Refs at " <<
P <<
"\n"
2205TEST(FindReferences, WithinAST) {
2206 const char *Tests[] = {
2207 R
"cpp(// Local variable
2209 int $def(main)[[foo]];
2210 $(main)[[^foo]] = 2;
2211 int test1 = $(main)[[foo]];
2217 struct $def(ns1)[[Foo]] {};
2220 ns1::$(main)[[Fo^o]]* Params;
2224 R"cpp(// Forward declaration
2226 class $def[[Foo]] {};
2228 $(main)[[Fo^o]] foo;
2233 int $def[[foo]](int) { return 0; }
2235 auto *X = &$(main)[[^foo]];
2242 int $def(Foo)[[foo]];
2243 Foo() : $(Foo::Foo)[[foo]](0) {}
2247 f.$(main)[[f^oo]] = 1;
2251 R"cpp(// Method call
2252 struct Foo { int $decl(Foo)[[foo]](); };
2253 int Foo::$def(Foo)[[foo]]() { return 0; }
2256 f.$(main)[[^foo]]();
2260 R"cpp(// Constructor
2262 $decl(Foo)[[F^oo]](int);
2265 Foo f = $(foo)[[Foo]](42);
2270 typedef int $def[[Foo]];
2272 $(main)[[^Foo]] bar;
2277 namespace $decl[[ns]] { // FIXME: def?
2280 int main() { $(main)[[^ns]]::Foo foo; }
2286 #define CAT(X, Y) X##Y
2287 class $def[[Fo^o]] {};
2289 TYPE($(test)[[Foo]]) foo;
2290 $(test)[[FOO]] foo2;
2291 TYPE(TYPE($(test)[[Foo]])) foo3;
2292 $(test)[[CAT]](Fo, o) foo4;
2297 #define $def[[MA^CRO]](X) (X+1)
2299 int x = $[[MACRO]]($[[MACRO]](1));
2303 R"cpp(// Macro outside preamble
2305 #define $def[[MA^CRO]](X) (X+1)
2307 int x = $[[MACRO]]($[[MACRO]](1));
2312 int $def[[v^ar]] = 0;
2313 void foo(int s = $(foo)[[var]]);
2317 template <typename T>
2318 class $def[[Fo^o]] {};
2319 void func($(func)[[Foo]]<int>);
2323 template <typename T>
2324 class $def[[Foo]] {};
2325 void func($(func)[[Fo^o]]<int>);
2327 R"cpp(// Not touching any identifiers.
2329 $def(Foo)[[~]]Foo() {};
2333 f.$(foo)[[^~]]Foo();
2336 R"cpp(// Lambda capture initializer
2338 int $def(foo)[[w^aldo]] = 42;
2339 auto lambda = [x = $(foo)[[waldo]]](){};
2342 R"cpp(// Renaming alias
2343 template <typename> class Vector {};
2344 using $def[[^X]] = Vector<int>;
2349 R"cpp(// Dependent code
2350 template <typename T> void $decl[[foo]](T t);
2351 template <typename T> void bar(T t) { $(bar)[[foo]](t); } // foo in bar is uninstantiated.
2352 void baz(int x) { $(baz)[[f^oo]](x); }
2357 void $decl(ns)[[foo]](S s);
2359 template <typename T> void foo(T t);
2360 // FIXME: Maybe report this foo as a ref to ns::foo (because of ADL)
2361 // when bar<ns::S> is instantiated?
2362 template <typename T> void bar(T t) { foo(t); }
2369 R"cpp(// unresolved member expression
2371 template <typename T> void $decl(Foo)[[b^ar]](T t);
2373 template <typename T> void test(Foo F, T t) {
2374 F.$(test)[[bar]](t);
2380 typedef int $def[[MyTypeD^ef]];
2381 enum MyEnum : $(MyEnum)[[MyTy^peDef]] { };
2384 typedef int $def[[MyType^Def]];
2385 enum MyEnum : $(MyEnum)[[MyTypeD^ef]];
2388 using $def[[MyTypeD^ef]] = int;
2389 enum MyEnum : $(MyEnum)[[MyTy^peDef]] { };
2393 bool $decl[[operator]]"" _u^dl(unsigned long long value);
2394 bool x = $(x)[[1_udl]];
2399 static void $decl(S)[[operator]] delete(void *);
2400 static void deleteObject(S *S) {
2401 $(S::deleteObject)[[de^lete]] S;
2407 const int $def[[F^oo]] = 0;
2409 [$(Bar)[[F^oo]]...$(Bar)[[Fo^o]] + 1] = 0,
2410 [$(Bar)[[^Foo]] + 2] = 1
2415 struct S { void foo(); };
2417 void (S::*$def(A)[[fi^eld]])();
2419 void bar(A& a, S& s) {
2420 (s.*(a.$(bar)[[field]]))();
2423 for (
const char *Test : Tests)
2424 checkFindRefs(Test);
2427TEST(FindReferences, ConceptsWithinAST) {
2428 constexpr llvm::StringLiteral Code = R
"cpp(
2430 concept $def[[IsSmal^l]] = sizeof(T) <= 8;
2433 concept IsSmallPtr = requires(T x) {
2434 { *x } -> $(IsSmallPtr)[[IsSmal^l]];
2437 $(i)[[IsSmall]] auto i = 'c';
2438 template<$(foo)[[IsSmal^l]] U> void foo();
2439 template<class U> void bar() requires $(bar)[[IsSmal^l]]<U>;
2440 template<class U> requires $(baz)[[IsSmal^l]]<U> void baz();
2441 static_assert([[IsSma^ll]]<char>);
2443 checkFindRefs(Code);
2446TEST(FindReferences, ConceptReq) {
2447 constexpr llvm::StringLiteral Code = R
"cpp(
2449 concept $def[[IsSmal^l]] = sizeof(T) <= 8;
2452 concept IsSmallPtr = requires(T x) {
2453 { *x } -> $(IsSmallPtr)[[IsSmal^l]];
2456 checkFindRefs(Code);
2459TEST(FindReferences, RequiresExprParameters) {
2460 constexpr llvm::StringLiteral Code = R
"cpp(
2462 concept IsSmall = sizeof(T) <= 8;
2465 concept IsSmallPtr = requires(T $def[[^x]]) {
2466 { *$(IsSmallPtr)[[^x]] } -> IsSmall;
2469 checkFindRefs(Code);
2472TEST(FindReferences, IncludeOverrides) {
2473 llvm::StringRef Test =
2477 virtu^al void $decl(Base)[[f^unc]]() ^= ^0;
2479 class Derived : public Base {
2481 void $overridedecl(Derived::func)[[func]]() override;
2483 void Derived::$overridedef[[func]]() {}
2484 class Derived2 : public Base {
2485 void $overridedef(Derived2::func)[[func]]() override {}
2487 void test(Derived* D, Base* B) {
2488 D->func(); // No references to the overrides.
2489 B->$(test)[[func]]();
2491 checkFindRefs(Test, true);
2494TEST(FindReferences, IncludeOverridesObjC) {
2495 llvm::StringRef Test =
2498 - (void)$decl(Base)[[f^unc]];
2500 @interface Derived : Base
2501 - (void)$overridedecl(Derived::func)[[func]];
2503 @implementation Derived
2504 - (void)$overridedef[[func]] {}
2506 void test(Derived *derived, Base *base) {
2507 [derived func]; // No references to the overrides.
2508 [base $(test)[[func]]];
2510 checkFindRefs(Test, true);
2513TEST(FindReferences, RefsToBaseMethod) {
2514 llvm::StringRef Test =
2518 virtual void $(BaseBase)[[func]]();
2520 class Base : public BaseBase {
2522 void $(Base)[[func]]() override;
2524 class Derived : public Base {
2526 void $decl(Derived)[[fu^nc]]() over^ride;
2528 void test(BaseBase* BB, Base* B, Derived* D) {
2529 // refs to overridden methods in complete type hierarchy are reported.
2530 BB->$(test)[[func]]();
2531 B->$(test)[[func]]();
2532 D->$(test)[[fu^nc]]();
2534 checkFindRefs(Test, true);
2537TEST(FindReferences, RefsToBaseMethodObjC) {
2538 llvm::StringRef Test =
2541 - (void)$(BaseBase)[[func]];
2543 @interface Base : BaseBase
2544 - (void)$(Base)[[func]];
2546 @interface Derived : Base
2547 - (void)$decl(Derived)[[fu^nc]];
2549 void test(BaseBase *bb, Base *b, Derived *d) {
2550 // refs to overridden methods in complete type hierarchy are reported.
2551 [bb $(test)[[func]]];
2552 [b $(test)[[func]]];
2553 [d $(test)[[fu^nc]]];
2555 checkFindRefs(Test, true);
2558TEST(FindReferences, MainFileReferencesOnly) {
2559 llvm::StringRef Test =
2563 // refs not from main file should not be included.
2569 TU.AdditionalFiles[
"foo.inc"] = R
"cpp(
2572 auto AST = TU.build();
2574 std::vector<Matcher<ReferencesResult::Reference>> ExpectedLocations;
2575 for (
const auto &R : Code.ranges())
2576 ExpectedLocations.push_back(rangeIs(R));
2578 ElementsAreArray(ExpectedLocations))
2582TEST(FindReferences, ExplicitSymbols) {
2583 const char *Tests[] = {
2585 struct Foo { Foo* $decl(Foo)[[self]]() const; };
2588 if (Foo* T = foo.$(f)[[^self]]()) {} // Foo member call expr.
2593 struct Foo { Foo(int); };
2596 return $(f)[[^b]]; // Foo constructor expr.
2605 g($(call)[[^f]]()); // Foo constructor expr.
2610 void $decl[[foo]](int);
2611 void $decl[[foo]](double);
2614 using ::$decl(ns)[[fo^o]];
2625 $(test)[[a]].operator bool();
2626 if ($(test)[[a^]]) {} // ignore implicit conversion-operator AST node
2631 for (
const char *Test : Tests)
2632 checkFindRefs(Test);
2635TEST(FindReferences, UsedSymbolsFromInclude) {
2636 const char *Tests[] = {
2637 R
"cpp( [[#include ^"bar.h"]]
2639 int fstBar = [[bar1]]();
2640 int sndBar = [[bar2]]();
2642 int macroBar = [[BAR]];
2643 std::vector<int> vec;
2646 R"cpp([[#in^clude <vector>]]
2647 std::[[vector]]<int> vec;
2651 [[#include ^"udl_header.h"]]
2655 for (
const char *Test : Tests) {
2658 TU.ExtraArgs.push_back(
"-std=c++20");
2659 TU.AdditionalFiles[
"bar.h"] = guard(R
"cpp(
2665 TU.AdditionalFiles["system/vector"] = guard(R
"cpp(
2671 TU.AdditionalFiles["udl_header.h"] = guard(R
"cpp(
2672 bool operator"" _b(unsigned long long value);
2674 TU.ExtraArgs.push_back("-isystem" +
testPath(
"system"));
2676 auto AST = TU.build();
2677 std::vector<Matcher<ReferencesResult::Reference>> ExpectedLocations;
2678 for (
const auto &R :
T.ranges())
2679 ExpectedLocations.push_back(AllOf(rangeIs(R), attrsAre(0u)));
2680 for (
const auto &P :
T.points())
2682 UnorderedElementsAreArray(ExpectedLocations))
2683 <<
"Failed for Refs at " <<
P <<
"\n"
2688TEST(FindReferences, NeedsIndexForSymbols) {
2689 const char *Header =
"int foo();";
2692 TU.
Code = std::string(Main.code());
2693 TU.HeaderCode = Header;
2694 auto AST = TU.build();
2699 ElementsAre(rangeIs(Main.range())));
2701 int $decl[[foo]]() { return 42; }
2702 void bar() { $bar(bar)[[foo]](); }
2703 struct S { void bar() { $S(S::bar)[[foo]](); } };
2704 namespace N { void bar() { $N(N::bar)[[foo]](); } }
2709 IndexedTU.
Code = std::string(IndexedMain.code());
2710 IndexedTU.Filename =
"Indexed.cpp";
2711 IndexedTU.HeaderCode = Header;
2717 rangeIs(Main.range()),
2718 AllOf(rangeIs(IndexedMain.range(
"decl")),
2721 AllOf(rangeIs(IndexedMain.range(
"bar")), containerIs(
"bar")),
2722 AllOf(rangeIs(IndexedMain.range(
"S")), containerIs(
"S::bar")),
2723 AllOf(rangeIs(IndexedMain.range(
"N")), containerIs(
"N::bar"))));
2726 EXPECT_EQ(1u, LimitRefs.References.size());
2727 EXPECT_TRUE(LimitRefs.HasMore);
2730 TU.Code = (
"\n\n" + Main.code()).str();
2732 ElementsAre(rangeIs(Main.range())));
2735TEST(FindReferences, NeedsIndexForMacro) {
2736 const char *Header =
"#define MACRO(X) (X+1)";
2739 int a = [[MA^CRO]](1);
2743 TU.Code = std::string(Main.code());
2744 TU.HeaderCode = Header;
2745 auto AST = TU.build();
2750 ElementsAre(rangeIs(Main.range())));
2753 int indexed_main() {
2754 int a = [[MACRO]](1);
2761 IndexedTU.
Code = std::string(IndexedMain.code());
2762 IndexedTU.Filename =
"Indexed.cpp";
2763 IndexedTU.HeaderCode = Header;
2766 ElementsAre(rangeIs(Main.range()), rangeIs(IndexedMain.range())));
2769 EXPECT_EQ(1u, LimitRefs.References.size());
2770 EXPECT_TRUE(LimitRefs.HasMore);
2773TEST(FindReferences, NoQueryForLocalSymbols) {
2774 struct RecordingIndex :
public MemIndex {
2775 mutable std::optional<llvm::DenseSet<SymbolID>> RefIDs;
2776 bool refs(
const RefsRequest &Req,
2777 llvm::function_ref<
void(
const Ref &)>)
const override {
2784 StringRef AnnotatedCode;
2789 {
"namespace { int ^x; }",
true},
2790 {
"static int ^x;",
true},
2792 {
"void foo() { int ^x; }",
false},
2793 {
"void foo() { struct ^x{}; }",
false},
2794 {
"auto lambda = []{ int ^x; };",
false},
2796 for (Test T : Tests) {
2802 EXPECT_NE(Rec.RefIDs, std::nullopt) <<
T.AnnotatedCode;
2804 EXPECT_EQ(Rec.RefIDs, std::nullopt) <<
T.AnnotatedCode;
2808TEST(FindReferences, ConstructorForwardingInAST) {
2811 template <class T> T &&forward(T &t);
2812 template <class T, class... Args> T *make_unique(Args &&...args) {
2813 return new T(std::forward<Args>(args)...);
2818 $Constructor[[T^est]](){}
2822 auto a = std::$Caller[[make_unique]]<Test>();
2826 TU.Code = std::string(Main.code());
2827 auto AST = TU.build();
2830 ElementsAre(rangeIs(Main.range(
"Constructor")),
2831 rangeIs(Main.range(
"Caller"))));
2834TEST(FindReferences, ConstructorForwardingInASTChained) {
2837 template <class T> T &&forward(T &t);
2838 template <class T, class... Args> T *make_unique(Args &&...args) {
2839 return new T(forward<Args>(args)...);
2841 template <class T, class... Args> T *make_unique2(Args &&...args) {
2842 return make_unique<T>(forward<Args>(args)...);
2844 template <class T, class... Args> T *make_unique3(Args &&...args) {
2845 return make_unique2<T>(forward<Args>(args)...);
2850 $Constructor[[T^est]](){}
2854 auto a = std::$Caller[[make_unique3]]<Test>();
2858 TU.Code = std::string(Main.code());
2859 auto AST = TU.build();
2862 ElementsAre(rangeIs(Main.range(
"Constructor")),
2863 rangeIs(Main.range(
"Caller"))));
2866TEST(FindReferences, ConstructorForwardingInIndex) {
2869 template <class T> T &&forward(T &t);
2870 template <class T, class... Args> T *make_unique(Args &&...args) {
2871 return new T(std::forward<Args>(args)...);
2879 #include "header.hpp"
2881 auto a = std::[[make_unique]]<Test>();
2885 TW.addSource("header.hpp", Header.code());
2886 TW.addMainFile(
"main.cpp", Main.code());
2887 auto AST = TW.openFile(
"header.hpp").value();
2888 auto Index = TW.index();
2895 AllOf(rangeIs(Header.range()), fileIs(
testPath(
"header.hpp"))),
2896 AllOf(rangeIs(Main.range()), fileIs(
testPath(
"main.cpp")))));
2899TEST(FindReferences, TemplatedConstructorForwarding) {
2902 template <class T> T &&forward(T &t);
2903 template <class T, class... Args> T *make_unique(Args &&...args) {
2904 return new T(std::forward<Args>(args)...);
2909 template <typename T>
2910 $Constructor[[W$Waldo^aldo]](T);
2912 template <typename T>
2914 $Constructor2[[W$Waldo2^aldo2]](int);
2920 Waldo $Caller[[w]](s);
2921 std::$ForwardedCaller[[make_unique]]<Waldo>(s);
2923 Waldo2<int> $Caller2[[w2]](42);
2924 std::$ForwardedCaller2[[make_unique]]<Waldo2<int>>(42);
2928 TU.Code = std::string(Main.code());
2929 auto AST = TU.build();
2932 ElementsAre(rangeIs(Main.range(
"Constructor")),
2933 rangeIs(Main.range(
"Caller")),
2934 rangeIs(Main.range(
"ForwardedCaller"))));
2937 ElementsAre(rangeIs(Main.range(
"Constructor2")),
2938 rangeIs(Main.range(
"Caller2")),
2939 rangeIs(Main.range(
"ForwardedCaller2"))));
2942TEST(GetNonLocalDeclRefs,
All) {
2944 llvm::StringRef AnnotatedCode;
2945 std::vector<std::string> ExpectedDecls;
2951 void ^foo(int baz) {
2960 class Foo { public: void foo(); };
2970 {"Bar",
"Bar::bar",
"Foo",
"Foo::foo"},
2976 class Foo { public: void foo() {} };
2977 class Bar { public: void bar() {} };
2988 template <typename T, template<typename> class Q>
2996 for (
const Case &C : Cases) {
2999 SourceLocation SL = llvm::cantFail(
3002 const FunctionDecl *FD =
3003 llvm::dyn_cast<FunctionDecl>(&
findDecl(
AST, [SL](
const NamedDecl &ND) {
3004 return ND.getLocation() == SL && llvm::isa<FunctionDecl>(ND);
3006 ASSERT_NE(FD,
nullptr);
3009 std::vector<std::string> Names;
3010 for (
const Decl *D : NonLocalDeclRefs) {
3011 if (
const auto *ND = llvm::dyn_cast<NamedDecl>(D))
3012 Names.push_back(ND->getQualifiedNameAsString());
3014 EXPECT_THAT(Names, UnorderedElementsAreArray(
C.ExpectedDecls))
3021 #define HEADER_AA "faa.h"
3022 #define HEADER_BB "fbb.h"
3023 #define GET_HEADER(X) HEADER_ ## X
3025 #/*comments*/include /*comments*/ $foo[["foo.h"]] //more comments
3026 int end_of_preamble = 0;
3027 #include $bar[[<bar.h>]]
3028 #include $AA[[GET_HEADER]](AA) // Some comment !
3029 # /* What about */ \
3030 include /* multiple line */ \
3031 $BB[[GET_HEADER]]( /* statements ? */ \
3036 TU.Code = std::string(MainCpp.code());
3037 TU.AdditionalFiles = {
3038 {"faa.h",
""}, {
"fbb.h",
""}, {
"foo.h",
""}, {
"bar.h",
""}};
3039 TU.ExtraArgs = {
"-isystem."};
3040 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.
MATCHER_P2(hasFlag, Flag, Path, "")
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.