clang-tools 20.0.0git
HoverTests.cpp
Go to the documentation of this file.
1//===-- HoverTests.cpp ----------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "AST.h"
10#include "Annotations.h"
11#include "Config.h"
12#include "Hover.h"
13#include "TestFS.h"
14#include "TestIndex.h"
15#include "TestTU.h"
16#include "index/MemIndex.h"
17#include "clang/AST/Attr.h"
18#include "clang/Format/Format.h"
19#include "clang/Index/IndexSymbol.h"
20#include "llvm/ADT/StringRef.h"
21#include "llvm/ADT/Twine.h"
22
23#include "gtest/gtest.h"
24#include <functional>
25#include <optional>
26#include <string>
27#include <vector>
28
29namespace clang {
30namespace clangd {
31namespace {
32
33using PassMode = HoverInfo::PassType::PassMode;
34
35std::string guard(llvm::StringRef Code) {
36 return "#pragma once\n" + Code.str();
37}
38
39TEST(Hover, Structured) {
40 struct {
41 const char *const Code;
42 const std::function<void(HoverInfo &)> ExpectedBuilder;
43 } Cases[] = {
44 // Global scope.
45 {R"cpp(
46 // Best foo ever.
47 void [[fo^o]]() {}
48 )cpp",
49 [](HoverInfo &HI) {
50 HI.NamespaceScope = "";
51 HI.Name = "foo";
52 HI.Kind = index::SymbolKind::Function;
53 HI.Documentation = "Best foo ever.";
54 HI.Definition = "void foo()";
55 HI.ReturnType = "void";
56 HI.Type = "void ()";
57 HI.Parameters.emplace();
58 }},
59 // Inside namespace
60 {R"cpp(
61 namespace ns1 { namespace ns2 {
62 /// Best foo ever.
63 void [[fo^o]]() {}
64 }}
65 )cpp",
66 [](HoverInfo &HI) {
67 HI.NamespaceScope = "ns1::ns2::";
68 HI.Name = "foo";
69 HI.Kind = index::SymbolKind::Function;
70 HI.Documentation = "Best foo ever.";
71 HI.Definition = "void foo()";
72 HI.ReturnType = "void";
73 HI.Type = "void ()";
74 HI.Parameters.emplace();
75 }},
76 // Field
77 {R"cpp(
78 namespace ns1 { namespace ns2 {
79 class Foo {
80 char [[b^ar]];
81 double y[2];
82 };
83 }}
84 )cpp",
85 [](HoverInfo &HI) {
86 HI.NamespaceScope = "ns1::ns2::";
87 HI.LocalScope = "Foo::";
88 HI.Name = "bar";
89 HI.Kind = index::SymbolKind::Field;
90 HI.Definition = "char bar";
91 HI.Type = "char";
92 HI.Offset = 0;
93 HI.Size = 8;
94 HI.Padding = 56;
95 HI.Align = 8;
96 HI.AccessSpecifier = "private";
97 }},
98 // Union field
99 {R"cpp(
100 union Foo {
101 char [[b^ar]];
102 double y[2];
103 };
104 )cpp",
105 [](HoverInfo &HI) {
106 HI.NamespaceScope = "";
107 HI.LocalScope = "Foo::";
108 HI.Name = "bar";
109 HI.Kind = index::SymbolKind::Field;
110 HI.Definition = "char bar";
111 HI.Type = "char";
112 HI.Size = 8;
113 HI.Padding = 120;
114 HI.Align = 8;
115 HI.AccessSpecifier = "public";
116 }},
117 // Bitfield
118 {R"cpp(
119 struct Foo {
120 int [[^x]] : 1;
121 int y : 1;
122 };
123 )cpp",
124 [](HoverInfo &HI) {
125 HI.NamespaceScope = "";
126 HI.LocalScope = "Foo::";
127 HI.Name = "x";
128 HI.Kind = index::SymbolKind::Field;
129 HI.Definition = "int x : 1";
130 HI.Type = "int";
131 HI.Offset = 0;
132 HI.Size = 1;
133 HI.Align = 32;
134 HI.AccessSpecifier = "public";
135 }},
136 // Local to class method.
137 {R"cpp(
138 namespace ns1 { namespace ns2 {
139 struct Foo {
140 void foo() {
141 int [[b^ar]];
142 }
143 };
144 }}
145 )cpp",
146 [](HoverInfo &HI) {
147 HI.NamespaceScope = "ns1::ns2::";
148 HI.LocalScope = "Foo::foo::";
149 HI.Name = "bar";
150 HI.Kind = index::SymbolKind::Variable;
151 HI.Definition = "int bar";
152 HI.Type = "int";
153 }},
154 // Predefined variable
155 {R"cpp(
156 void foo() {
157 [[__f^unc__]];
158 }
159 )cpp",
160 [](HoverInfo &HI) {
161 HI.Name = "__func__";
162 HI.Kind = index::SymbolKind::Variable;
163 HI.Documentation =
164 "Name of the current function (predefined variable)";
165 HI.Value = "\"foo\"";
166 HI.Type = "const char[4]";
167 }},
168 // Predefined variable (dependent)
169 {R"cpp(
170 template<int> void foo() {
171 [[__f^unc__]];
172 }
173 )cpp",
174 [](HoverInfo &HI) {
175 HI.Name = "__func__";
176 HI.Kind = index::SymbolKind::Variable;
177 HI.Documentation =
178 "Name of the current function (predefined variable)";
179 HI.Type = "const char[]";
180 }},
181 // Anon namespace and local scope.
182 {R"cpp(
183 namespace ns1 { namespace {
184 struct {
185 char [[b^ar]];
186 } T;
187 }}
188 )cpp",
189 [](HoverInfo &HI) {
190 HI.NamespaceScope = "ns1::";
191 HI.LocalScope = "(anonymous struct)::";
192 HI.Name = "bar";
193 HI.Kind = index::SymbolKind::Field;
194 HI.Definition = "char bar";
195 HI.Type = "char";
196 HI.Offset = 0;
197 HI.Size = 8;
198 HI.Align = 8;
199 HI.AccessSpecifier = "public";
200 }},
201 // Struct definition shows size.
202 {R"cpp(
203 struct [[^X]]{};
204 )cpp",
205 [](HoverInfo &HI) {
206 HI.NamespaceScope = "";
207 HI.Name = "X";
208 HI.Kind = index::SymbolKind::Struct;
209 HI.Definition = "struct X {}";
210 HI.Size = 8;
211 HI.Align = 8;
212 }},
213 // Variable with template type
214 {R"cpp(
215 template <typename T, class... Ts> class Foo { public: Foo(int); };
216 Foo<int, char, bool> [[fo^o]] = Foo<int, char, bool>(5);
217 )cpp",
218 [](HoverInfo &HI) {
219 HI.NamespaceScope = "";
220 HI.Name = "foo";
221 HI.Kind = index::SymbolKind::Variable;
222 HI.Definition = "Foo<int, char, bool> foo = Foo<int, char, bool>(5)";
223 HI.Type = "Foo<int, char, bool>";
224 }},
225 // Implicit template instantiation
226 {R"cpp(
227 template <typename T> class vector{};
228 [[vec^tor]]<int> foo;
229 )cpp",
230 [](HoverInfo &HI) {
231 HI.NamespaceScope = "";
232 HI.Name = "vector<int>";
233 HI.Kind = index::SymbolKind::Class;
234 HI.Definition = "template <> class vector<int> {}";
235 }},
236 // Class template
237 {R"cpp(
238 template <template<typename, bool...> class C,
239 typename = char,
240 int = 0,
241 bool Q = false,
242 class... Ts> class Foo final {};
243 template <template<typename, bool...> class T>
244 [[F^oo]]<T> foo;
245 )cpp",
246 [](HoverInfo &HI) {
247 HI.NamespaceScope = "";
248 HI.Name = "Foo";
249 HI.Kind = index::SymbolKind::Class;
250 HI.Definition =
251 R"cpp(template <template <typename, bool...> class C, typename = char, int = 0,
252 bool Q = false, class... Ts>
253class Foo final {})cpp";
254 HI.TemplateParameters = {
255 {{"template <typename, bool...> class"},
256 std::string("C"),
257 std::nullopt},
258 {{"typename"}, std::nullopt, std::string("char")},
259 {{"int"}, std::nullopt, std::string("0")},
260 {{"bool"}, std::string("Q"), std::string("false")},
261 {{"class..."}, std::string("Ts"), std::nullopt},
262 };
263 }},
264 // Function template
265 {R"cpp(
266 template <template<typename, bool...> class C,
267 typename = char,
268 int = 0,
269 bool Q = false,
270 class... Ts> void foo();
271 template<typename, bool...> class Foo;
272
273 void bar() {
274 [[fo^o]]<Foo>();
275 }
276 )cpp",
277 [](HoverInfo &HI) {
278 HI.NamespaceScope = "";
279 HI.Name = "foo";
280 HI.Kind = index::SymbolKind::Function;
281 HI.Definition = "template <> void foo<Foo, char, 0, false, <>>()";
282 HI.ReturnType = "void";
283 HI.Type = "void ()";
284 HI.Parameters.emplace();
285 }},
286 // Function decl
287 {R"cpp(
288 template<typename, bool...> class Foo {};
289 Foo<bool, true, false> foo(int, bool T = false);
290
291 void bar() {
292 [[fo^o]](3);
293 }
294 )cpp",
295 [](HoverInfo &HI) {
296 HI.NamespaceScope = "";
297 HI.Name = "foo";
298 HI.Kind = index::SymbolKind::Function;
299 HI.Definition = "Foo<bool, true, false> foo(int, bool T = false)";
300 HI.ReturnType = "Foo<bool, true, false>";
301 HI.Type = "Foo<bool, true, false> (int, bool)";
302 HI.Parameters = {
303 {{"int"}, std::nullopt, std::nullopt},
304 {{"bool"}, std::string("T"), std::string("false")},
305 };
306 }},
307 // Pointers to lambdas
308 {R"cpp(
309 void foo() {
310 auto lamb = [](int T, bool B) -> bool { return T && B; };
311 auto *b = &lamb;
312 auto *[[^c]] = &b;
313 }
314 )cpp",
315 [](HoverInfo &HI) {
316 HI.NamespaceScope = "";
317 HI.LocalScope = "foo::";
318 HI.Name = "c";
319 HI.Kind = index::SymbolKind::Variable;
320 HI.Definition = "auto *c = &b";
321 HI.Type = "(lambda) **";
322 HI.ReturnType = "bool";
323 HI.Parameters = {
324 {{"int"}, std::string("T"), std::nullopt},
325 {{"bool"}, std::string("B"), std::nullopt},
326 };
327 return HI;
328 }},
329 // Lambda parameter with decltype reference
330 {R"cpp(
331 auto lamb = [](int T, bool B) -> bool { return T && B; };
332 void foo(decltype(lamb)& bar) {
333 [[ba^r]](0, false);
334 }
335 )cpp",
336 [](HoverInfo &HI) {
337 HI.NamespaceScope = "";
338 HI.LocalScope = "foo::";
339 HI.Name = "bar";
340 HI.Kind = index::SymbolKind::Parameter;
341 HI.Definition = "decltype(lamb) &bar";
342 HI.Type = {"decltype(lamb) &", "(lambda) &"};
343 HI.ReturnType = "bool";
344 HI.Parameters = {
345 {{"int"}, std::string("T"), std::nullopt},
346 {{"bool"}, std::string("B"), std::nullopt},
347 };
348 return HI;
349 }},
350 // Lambda parameter with decltype
351 {R"cpp(
352 auto lamb = [](int T, bool B) -> bool { return T && B; };
353 void foo(decltype(lamb) bar) {
354 [[ba^r]](0, false);
355 }
356 )cpp",
357 [](HoverInfo &HI) {
358 HI.NamespaceScope = "";
359 HI.LocalScope = "foo::";
360 HI.Name = "bar";
361 HI.Kind = index::SymbolKind::Parameter;
362 HI.Definition = "decltype(lamb) bar";
363 HI.Type = "class (lambda)";
364 HI.ReturnType = "bool";
365 HI.Parameters = {
366 {{"int"}, std::string("T"), std::nullopt},
367 {{"bool"}, std::string("B"), std::nullopt},
368 };
369 HI.Value = "false";
370 return HI;
371 }},
372 // Lambda variable
373 {R"cpp(
374 void foo() {
375 int bar = 5;
376 auto lamb = [&bar](int T, bool B) -> bool { return T && B && bar; };
377 bool res = [[lam^b]](bar, false);
378 }
379 )cpp",
380 [](HoverInfo &HI) {
381 HI.NamespaceScope = "";
382 HI.LocalScope = "foo::";
383 HI.Name = "lamb";
384 HI.Kind = index::SymbolKind::Variable;
385 HI.Definition = "auto lamb = [&bar](int T, bool B) -> bool {}";
386 HI.Type = "class (lambda)";
387 HI.ReturnType = "bool";
388 HI.Parameters = {
389 {{"int"}, std::string("T"), std::nullopt},
390 {{"bool"}, std::string("B"), std::nullopt},
391 };
392 return HI;
393 }},
394 // Local variable in lambda
395 {R"cpp(
396 void foo() {
397 auto lamb = []{int [[te^st]];};
398 }
399 )cpp",
400 [](HoverInfo &HI) {
401 HI.NamespaceScope = "";
402 HI.LocalScope = "foo::(anonymous class)::operator()::";
403 HI.Name = "test";
404 HI.Kind = index::SymbolKind::Variable;
405 HI.Definition = "int test";
406 HI.Type = "int";
407 }},
408 // Partially-specialized class template. (formerly type-parameter-0-0)
409 {R"cpp(
410 template <typename T> class X;
411 template <typename T> class [[^X]]<T*> {};
412 )cpp",
413 [](HoverInfo &HI) {
414 HI.Name = "X<T *>";
415 HI.NamespaceScope = "";
416 HI.Kind = index::SymbolKind::Class;
417 HI.Definition = "template <typename T> class X<T *> {}";
418 }},
419 // Constructor of partially-specialized class template
420 {R"cpp(
421 template<typename, typename=void> struct X;
422 template<typename T> struct X<T*>{ [[^X]](); };
423 )cpp",
424 [](HoverInfo &HI) {
425 HI.NamespaceScope = "";
426 HI.Name = "X";
427 HI.LocalScope = "X<T *>::"; // FIXME: X<T *, void>::
428 HI.Kind = index::SymbolKind::Constructor;
429 HI.Definition = "X()";
430 HI.Parameters.emplace();
431 HI.AccessSpecifier = "public";
432 }},
433 {"class X { [[^~]]X(); };", // FIXME: Should be [[~X]]()
434 [](HoverInfo &HI) {
435 HI.NamespaceScope = "";
436 HI.Name = "~X";
437 HI.LocalScope = "X::";
438 HI.Kind = index::SymbolKind::Destructor;
439 HI.Definition = "~X()";
440 HI.Parameters.emplace();
441 HI.AccessSpecifier = "private";
442 }},
443 {"class X { [[op^erator]] int(); };",
444 [](HoverInfo &HI) {
445 HI.NamespaceScope = "";
446 HI.Name = "operator int";
447 HI.LocalScope = "X::";
448 HI.Kind = index::SymbolKind::ConversionFunction;
449 HI.Definition = "operator int()";
450 HI.Parameters.emplace();
451 HI.AccessSpecifier = "private";
452 }},
453 {"class X { operator [[^X]](); };",
454 [](HoverInfo &HI) {
455 HI.NamespaceScope = "";
456 HI.Name = "X";
457 HI.Kind = index::SymbolKind::Class;
458 HI.Definition = "class X {}";
459 }},
460
461 // auto on structured bindings
462 {R"cpp(
463 void foo() {
464 struct S { int x; float y; };
465 [[au^to]] [x, y] = S();
466 }
467 )cpp",
468 [](HoverInfo &HI) {
469 HI.Name = "auto";
470 HI.Kind = index::SymbolKind::TypeAlias;
471 HI.Definition = "S";
472 }},
473 // undeduced auto
474 {R"cpp(
475 template<typename T>
476 void foo() {
477 [[au^to]] x = T{};
478 }
479 )cpp",
480 [](HoverInfo &HI) {
481 HI.Name = "auto";
482 HI.Kind = index::SymbolKind::TypeAlias;
483 HI.Definition = "/* not deduced */";
484 }},
485 // constrained auto
486 {R"cpp(
487 template <class T> concept F = true;
488 F [[au^to]] x = 1;
489 )cpp",
490 [](HoverInfo &HI) {
491 HI.Name = "auto";
492 HI.Kind = index::SymbolKind::TypeAlias;
493 HI.Definition = "int";
494 }},
495 {R"cpp(
496 template <class T> concept F = true;
497 [[^F]] auto x = 1;
498 )cpp",
499 [](HoverInfo &HI) {
500 HI.NamespaceScope = "";
501 HI.Name = "F";
502 HI.Kind = index::SymbolKind::Concept;
503 HI.Definition = "template <class T>\nconcept F = true";
504 }},
505 // auto on lambda
506 {R"cpp(
507 void foo() {
508 [[au^to]] lamb = []{};
509 }
510 )cpp",
511 [](HoverInfo &HI) {
512 HI.Name = "auto";
513 HI.Kind = index::SymbolKind::TypeAlias;
514 HI.Definition = "class(lambda)";
515 }},
516 // auto on template instantiation
517 {R"cpp(
518 template<typename T> class Foo{};
519 void foo() {
520 [[au^to]] x = Foo<int>();
521 }
522 )cpp",
523 [](HoverInfo &HI) {
524 HI.Name = "auto";
525 HI.Kind = index::SymbolKind::TypeAlias;
526 HI.Definition = "Foo<int>";
527 }},
528 // auto on specialized template
529 {R"cpp(
530 template<typename T> class Foo{};
531 template<> class Foo<int>{};
532 void foo() {
533 [[au^to]] x = Foo<int>();
534 }
535 )cpp",
536 [](HoverInfo &HI) {
537 HI.Name = "auto";
538 HI.Kind = index::SymbolKind::TypeAlias;
539 HI.Definition = "Foo<int>";
540 }},
541 // constrained template parameter
542 {R"cpp(
543 template<class T> concept Fooable = true;
544 template<[[Foo^able]] T>
545 void bar(T t) {}
546 )cpp",
547 [](HoverInfo &HI) {
548 HI.NamespaceScope = "";
549 HI.Name = "Fooable";
550 HI.Kind = index::SymbolKind::Concept;
551 HI.Definition = "template <class T>\nconcept Fooable = true";
552 }},
553 {R"cpp(
554 template<class T> concept Fooable = true;
555 template<Fooable [[T^T]]>
556 void bar(TT t) {}
557 )cpp",
558 [](HoverInfo &HI) {
559 HI.Name = "TT";
560 HI.Type = "class";
561 HI.AccessSpecifier = "public";
562 HI.NamespaceScope = "";
563 HI.LocalScope = "bar::";
564 HI.Kind = index::SymbolKind::TemplateTypeParm;
565 HI.Definition = "Fooable TT";
566 }},
567 {R"cpp(
568 template<class T> concept Fooable = true;
569 void bar([[Foo^able]] auto t) {}
570 )cpp",
571 [](HoverInfo &HI) {
572 HI.NamespaceScope = "";
573 HI.Name = "Fooable";
574 HI.Kind = index::SymbolKind::Concept;
575 HI.Definition = "template <class T>\nconcept Fooable = true";
576 }},
577 // concept reference
578 {R"cpp(
579 template<class T> concept Fooable = true;
580 auto X = [[Fooa^ble]]<int>;
581 )cpp",
582 [](HoverInfo &HI) {
583 HI.NamespaceScope = "";
584 HI.Name = "Fooable";
585 HI.Kind = index::SymbolKind::Concept;
586 HI.Definition = "template <class T>\nconcept Fooable = true";
587 HI.Value = "true";
588 }},
589
590 // empty macro
591 {R"cpp(
592 #define MACRO
593 [[MAC^RO]]
594 )cpp",
595 [](HoverInfo &HI) {
596 HI.Name = "MACRO";
597 HI.Kind = index::SymbolKind::Macro;
598 HI.Definition = "#define MACRO";
599 }},
600
601 // object-like macro
602 {R"cpp(
603 #define MACRO 41
604 int x = [[MAC^RO]];
605 )cpp",
606 [](HoverInfo &HI) {
607 HI.Name = "MACRO";
608 HI.Kind = index::SymbolKind::Macro;
609 HI.Value = "41 (0x29)";
610 HI.Type = "int";
611 HI.Definition = "#define MACRO 41\n\n"
612 "// Expands to\n"
613 "41";
614 }},
615
616 // function-like macro
617 {R"cpp(
618 // Best MACRO ever.
619 #define MACRO(x,y,z) void foo(x, y, z)
620 [[MAC^RO]](int, double d, bool z = false);
621 )cpp",
622 [](HoverInfo &HI) {
623 HI.Name = "MACRO";
624 HI.Kind = index::SymbolKind::Macro;
625 HI.Definition = "#define MACRO(x, y, z) void foo(x, y, z)\n\n"
626 "// Expands to\n"
627 "void foo(int, double d, bool z = false)";
628 }},
629
630 // nested macro
631 {R"cpp(
632 #define STRINGIFY_AUX(s) #s
633 #define STRINGIFY(s) STRINGIFY_AUX(s)
634 #define DECL_STR(NAME, VALUE) const char *v_##NAME = STRINGIFY(VALUE)
635 #define FOO 41
636
637 [[DECL^_STR]](foo, FOO);
638 )cpp",
639 [](HoverInfo &HI) {
640 HI.Name = "DECL_STR";
641 HI.Kind = index::SymbolKind::Macro;
642 HI.Type = HoverInfo::PrintedType("const char *");
643 HI.Definition = "#define DECL_STR(NAME, VALUE) const char *v_##NAME = "
644 "STRINGIFY(VALUE)\n\n"
645 "// Expands to\n"
646 "const char *v_foo = \"41\"";
647 }},
648
649 // constexprs
650 {R"cpp(
651 constexpr int add(int a, int b) { return a + b; }
652 int [[b^ar]] = add(1, 2);
653 )cpp",
654 [](HoverInfo &HI) {
655 HI.Name = "bar";
656 HI.Definition = "int bar = add(1, 2)";
657 HI.Kind = index::SymbolKind::Variable;
658 HI.Type = "int";
659 HI.NamespaceScope = "";
660 HI.Value = "3";
661 }},
662 {R"cpp(
663 int [[b^ar]] = sizeof(char);
664 )cpp",
665 [](HoverInfo &HI) {
666 HI.Name = "bar";
667 HI.Definition = "int bar = sizeof(char)";
668 HI.Kind = index::SymbolKind::Variable;
669 HI.Type = "int";
670 HI.NamespaceScope = "";
671 HI.Value = "1";
672 }},
673 {R"cpp(
674 template<int a, int b> struct Add {
675 static constexpr int result = a + b;
676 };
677 int [[ba^r]] = Add<1, 2>::result;
678 )cpp",
679 [](HoverInfo &HI) {
680 HI.Name = "bar";
681 HI.Definition = "int bar = Add<1, 2>::result";
682 HI.Kind = index::SymbolKind::Variable;
683 HI.Type = "int";
684 HI.NamespaceScope = "";
685 HI.Value = "3";
686 }},
687 {R"cpp(
688 enum Color { RED = -123, GREEN = 5, };
689 Color x = [[GR^EEN]];
690 )cpp",
691 [](HoverInfo &HI) {
692 HI.Name = "GREEN";
693 HI.NamespaceScope = "";
694 HI.LocalScope = "Color::";
695 HI.Definition = "GREEN = 5";
696 HI.Kind = index::SymbolKind::EnumConstant;
697 HI.Type = "enum Color";
698 HI.Value = "5"; // Numeric on the enumerator name, no hex as small.
699 }},
700 {R"cpp(
701 enum Color { RED = -123, GREEN = 5, };
702 Color x = RED;
703 Color y = [[^x]];
704 )cpp",
705 [](HoverInfo &HI) {
706 HI.Name = "x";
707 HI.NamespaceScope = "";
708 HI.Definition = "Color x = RED";
709 HI.Kind = index::SymbolKind::Variable;
710 HI.Type = "Color";
711 HI.Value = "RED (0xffffff85)"; // Symbolic on an expression.
712 }},
713 {R"cpp(
714 template<int a, int b> struct Add {
715 static constexpr int result = a + b;
716 };
717 int bar = Add<1, 2>::[[resu^lt]];
718 )cpp",
719 [](HoverInfo &HI) {
720 HI.Name = "result";
721 HI.Definition = "static constexpr int result = a + b";
722 HI.Kind = index::SymbolKind::StaticProperty;
723 HI.Type = "const int";
724 HI.NamespaceScope = "";
725 HI.LocalScope = "Add<1, 2>::";
726 HI.Value = "3";
727 HI.AccessSpecifier = "public";
728 }},
729 {R"cpp(
730 using my_int = int;
731 constexpr my_int answer() { return 40 + 2; }
732 int x = [[ans^wer]]();
733 )cpp",
734 [](HoverInfo &HI) {
735 HI.Name = "answer";
736 HI.Definition = "constexpr my_int answer()";
737 HI.Kind = index::SymbolKind::Function;
738 HI.Type = {"my_int ()", "int ()"};
739 HI.ReturnType = {"my_int", "int"};
740 HI.Parameters.emplace();
741 HI.NamespaceScope = "";
742 HI.Value = "42 (0x2a)";
743 }},
744 {R"cpp(
745 const char *[[ba^r]] = "1234";
746 )cpp",
747 [](HoverInfo &HI) {
748 HI.Name = "bar";
749 HI.Definition = "const char *bar = \"1234\"";
750 HI.Kind = index::SymbolKind::Variable;
751 HI.Type = "const char *";
752 HI.NamespaceScope = "";
753 HI.Value = "&\"1234\"[0]";
754 }},
755 {R"cpp(// Should not crash
756 template <typename T>
757 struct Tmpl {
758 Tmpl(int name);
759 };
760
761 template <typename A>
762 void boom(int name) {
763 new Tmpl<A>([[na^me]]);
764 })cpp",
765 [](HoverInfo &HI) {
766 HI.Name = "name";
767 HI.Definition = "int name";
768 HI.Kind = index::SymbolKind::Parameter;
769 HI.Type = "int";
770 HI.NamespaceScope = "";
771 HI.LocalScope = "boom::";
772 }},
773 {
774 R"cpp(// Should not print inline or anon namespaces.
775 namespace ns {
776 inline namespace in_ns {
777 namespace a {
778 namespace {
779 namespace b {
780 inline namespace in_ns2 {
781 class Foo {};
782 } // in_ns2
783 } // b
784 } // anon
785 } // a
786 } // in_ns
787 } // ns
788 void foo() {
789 ns::a::b::[[F^oo]] x;
790 (void)x;
791 }
792 )cpp",
793 [](HoverInfo &HI) {
794 HI.Name = "Foo";
795 HI.Kind = index::SymbolKind::Class;
796 HI.NamespaceScope = "ns::a::b::";
797 HI.Definition = "class Foo {}";
798 }},
799 {
800 R"cpp(
801 template <typename T> class Foo {};
802 class X;
803 void foo() {
804 [[^auto]] x = Foo<X>();
805 }
806 )cpp",
807 [](HoverInfo &HI) {
808 HI.Name = "auto";
809 HI.Kind = index::SymbolKind::TypeAlias;
810 HI.Definition = "Foo<X>";
811 }},
812 {// Falls back to primary template, when the type is not instantiated.
813 R"cpp(
814 // comment from primary
815 template <typename T> class Foo {};
816 // comment from specialization
817 template <typename T> class Foo<T*> {};
818 void foo() {
819 [[Fo^o]]<int*> *x = nullptr;
820 }
821 )cpp",
822 [](HoverInfo &HI) {
823 HI.Name = "Foo<int *>";
824 HI.Kind = index::SymbolKind::Class;
825 HI.NamespaceScope = "";
826 HI.Definition = "template <> class Foo<int *>";
827 // FIXME: Maybe force instantiation to make use of real template
828 // pattern.
829 HI.Documentation = "comment from primary";
830 }},
831 {// Template Type Parameter
832 R"cpp(
833 template <typename [[^T]] = int> void foo();
834 )cpp",
835 [](HoverInfo &HI) {
836 HI.Name = "T";
837 HI.Kind = index::SymbolKind::TemplateTypeParm;
838 HI.NamespaceScope = "";
839 HI.Definition = "typename T = int";
840 HI.LocalScope = "foo::";
841 HI.Type = "typename";
842 HI.AccessSpecifier = "public";
843 }},
844 {// TemplateTemplate Type Parameter
845 R"cpp(
846 template <template<typename> class [[^T]]> void foo();
847 )cpp",
848 [](HoverInfo &HI) {
849 HI.Name = "T";
850 HI.Kind = index::SymbolKind::TemplateTemplateParm;
851 HI.NamespaceScope = "";
852 HI.Definition = "template <typename> class T";
853 HI.LocalScope = "foo::";
854 HI.Type = "template <typename> class";
855 HI.AccessSpecifier = "public";
856 }},
857 {// NonType Template Parameter
858 R"cpp(
859 template <int [[^T]] = 5> void foo();
860 )cpp",
861 [](HoverInfo &HI) {
862 HI.Name = "T";
863 HI.Kind = index::SymbolKind::NonTypeTemplateParm;
864 HI.NamespaceScope = "";
865 HI.Definition = "int T = 5";
866 HI.LocalScope = "foo::";
867 HI.Type = "int";
868 HI.AccessSpecifier = "public";
869 }},
870
871 {// Getter
872 R"cpp(
873 struct X { int Y; float [[^y]]() { return Y; } };
874 )cpp",
875 [](HoverInfo &HI) {
876 HI.Name = "y";
877 HI.Kind = index::SymbolKind::InstanceMethod;
878 HI.NamespaceScope = "";
879 HI.Definition = "float y()";
880 HI.LocalScope = "X::";
881 HI.Documentation = "Trivial accessor for `Y`.";
882 HI.Type = "float ()";
883 HI.ReturnType = "float";
884 HI.Parameters.emplace();
885 HI.AccessSpecifier = "public";
886 }},
887 {// Setter
888 R"cpp(
889 struct X { int Y; void [[^setY]](float v) { Y = v; } };
890 )cpp",
891 [](HoverInfo &HI) {
892 HI.Name = "setY";
893 HI.Kind = index::SymbolKind::InstanceMethod;
894 HI.NamespaceScope = "";
895 HI.Definition = "void setY(float v)";
896 HI.LocalScope = "X::";
897 HI.Documentation = "Trivial setter for `Y`.";
898 HI.Type = "void (float)";
899 HI.ReturnType = "void";
900 HI.Parameters.emplace();
901 HI.Parameters->emplace_back();
902 HI.Parameters->back().Type = "float";
903 HI.Parameters->back().Name = "v";
904 HI.AccessSpecifier = "public";
905 }},
906 {// Setter (builder)
907 R"cpp(
908 struct X { int Y; X& [[^setY]](float v) { Y = v; return *this; } };
909 )cpp",
910 [](HoverInfo &HI) {
911 HI.Name = "setY";
912 HI.Kind = index::SymbolKind::InstanceMethod;
913 HI.NamespaceScope = "";
914 HI.Definition = "X &setY(float v)";
915 HI.LocalScope = "X::";
916 HI.Documentation = "Trivial setter for `Y`.";
917 HI.Type = "X &(float)";
918 HI.ReturnType = "X &";
919 HI.Parameters.emplace();
920 HI.Parameters->emplace_back();
921 HI.Parameters->back().Type = "float";
922 HI.Parameters->back().Name = "v";
923 HI.AccessSpecifier = "public";
924 }},
925 {// Setter (move)
926 R"cpp(
927 namespace std { template<typename T> T&& move(T&& t); }
928 struct X { int Y; void [[^setY]](float v) { Y = std::move(v); } };
929 )cpp",
930 [](HoverInfo &HI) {
931 HI.Name = "setY";
932 HI.Kind = index::SymbolKind::InstanceMethod;
933 HI.NamespaceScope = "";
934 HI.Definition = "void setY(float v)";
935 HI.LocalScope = "X::";
936 HI.Documentation = "Trivial setter for `Y`.";
937 HI.Type = "void (float)";
938 HI.ReturnType = "void";
939 HI.Parameters.emplace();
940 HI.Parameters->emplace_back();
941 HI.Parameters->back().Type = "float";
942 HI.Parameters->back().Name = "v";
943 HI.AccessSpecifier = "public";
944 }},
945 {// Field type initializer.
946 R"cpp(
947 struct X { int x = 2; };
948 X ^[[x]];
949 )cpp",
950 [](HoverInfo &HI) {
951 HI.Name = "x";
952 HI.Kind = index::SymbolKind::Variable;
953 HI.NamespaceScope = "";
954 HI.Definition = "X x";
955 HI.Type = "X";
956 }},
957 {// Don't crash on null types.
958 R"cpp(auto [^[[x]]] = 1; /*error-ok*/)cpp",
959 [](HoverInfo &HI) {
960 HI.Name = "x";
961 HI.Kind = index::SymbolKind::Variable;
962 HI.NamespaceScope = "";
963 HI.Definition = "";
964 HI.Type = "NULL TYPE";
965 // Bindings are in theory public members of an anonymous struct.
966 HI.AccessSpecifier = "public";
967 }},
968 {// Don't crash on invalid decl with invalid init expr.
969 R"cpp(
970 Unknown [[^abc]] = invalid;
971 // error-ok
972 )cpp",
973 [](HoverInfo &HI) {
974 HI.Name = "abc";
975 HI.Kind = index::SymbolKind::Variable;
976 HI.NamespaceScope = "";
977 HI.Definition = "int abc = <recovery - expr>()";
978 HI.Type = "int";
979 HI.AccessSpecifier = "public";
980 }},
981 {// Extra info for function call.
982 R"cpp(
983 void fun(int arg_a, int &arg_b) {};
984 void code() {
985 int a = 1, b = 2;
986 fun(a, [[^b]]);
987 }
988 )cpp",
989 [](HoverInfo &HI) {
990 HI.Name = "b";
991 HI.Kind = index::SymbolKind::Variable;
992 HI.NamespaceScope = "";
993 HI.Definition = "int b = 2";
994 HI.LocalScope = "code::";
995 HI.Value = "2";
996 HI.Type = "int";
997 HI.CalleeArgInfo.emplace();
998 HI.CalleeArgInfo->Name = "arg_b";
999 HI.CalleeArgInfo->Type = "int &";
1000 HI.CallPassType = HoverInfo::PassType{PassMode::Ref, false};
1001 }},
1002 {// make_unique-like function call
1003 R"cpp(
1004 struct Foo {
1005 explicit Foo(int arg_a) {}
1006 };
1007 template<class T, class... Args>
1008 T make(Args&&... args)
1009 {
1010 return T(args...);
1011 }
1012
1013 void code() {
1014 int a = 1;
1015 auto foo = make<Foo>([[^a]]);
1016 }
1017 )cpp",
1018 [](HoverInfo &HI) {
1019 HI.Name = "a";
1020 HI.Kind = index::SymbolKind::Variable;
1021 HI.NamespaceScope = "";
1022 HI.Definition = "int a = 1";
1023 HI.LocalScope = "code::";
1024 HI.Value = "1";
1025 HI.Type = "int";
1026 HI.CalleeArgInfo.emplace();
1027 HI.CalleeArgInfo->Name = "arg_a";
1028 HI.CalleeArgInfo->Type = "int";
1029 HI.CallPassType = HoverInfo::PassType{PassMode::Value, false};
1030 }},
1031 {
1032 R"cpp(
1033 void foobar(const float &arg);
1034 int main() {
1035 int a = 0;
1036 foobar([[^a]]);
1037 }
1038 )cpp",
1039 [](HoverInfo &HI) {
1040 HI.Name = "a";
1041 HI.Kind = index::SymbolKind::Variable;
1042 HI.NamespaceScope = "";
1043 HI.Definition = "int a = 0";
1044 HI.LocalScope = "main::";
1045 HI.Value = "0";
1046 HI.Type = "int";
1047 HI.CalleeArgInfo.emplace();
1048 HI.CalleeArgInfo->Name = "arg";
1049 HI.CalleeArgInfo->Type = "const float &";
1050 HI.CallPassType = HoverInfo::PassType{PassMode::Value, true};
1051 }},
1052 {
1053 R"cpp(
1054 struct Foo {
1055 explicit Foo(const float& arg) {}
1056 };
1057 int main() {
1058 int a = 0;
1059 Foo foo([[^a]]);
1060 }
1061 )cpp",
1062 [](HoverInfo &HI) {
1063 HI.Name = "a";
1064 HI.Kind = index::SymbolKind::Variable;
1065 HI.NamespaceScope = "";
1066 HI.Definition = "int a = 0";
1067 HI.LocalScope = "main::";
1068 HI.Value = "0";
1069 HI.Type = "int";
1070 HI.CalleeArgInfo.emplace();
1071 HI.CalleeArgInfo->Name = "arg";
1072 HI.CalleeArgInfo->Type = "const float &";
1073 HI.CallPassType = HoverInfo::PassType{PassMode::Value, true};
1074 }},
1075 {// Literal passed to function call
1076 R"cpp(
1077 void fun(int arg_a, const int &arg_b) {};
1078 void code() {
1079 int a = 1;
1080 fun(a, [[^2]]);
1081 }
1082 )cpp",
1083 [](HoverInfo &HI) {
1084 HI.Name = "literal";
1085 HI.Kind = index::SymbolKind::Unknown;
1086 HI.CalleeArgInfo.emplace();
1087 HI.CalleeArgInfo->Name = "arg_b";
1088 HI.CalleeArgInfo->Type = "const int &";
1089 HI.CallPassType = HoverInfo::PassType{PassMode::ConstRef, false};
1090 }},
1091 {// Expression passed to function call
1092 R"cpp(
1093 void fun(int arg_a, const int &arg_b) {};
1094 void code() {
1095 int a = 1;
1096 fun(a, 1 [[^+]] 2);
1097 }
1098 )cpp",
1099 [](HoverInfo &HI) {
1100 HI.Name = "expression";
1101 HI.Kind = index::SymbolKind::Unknown;
1102 HI.Type = "int";
1103 HI.Value = "3";
1104 HI.CalleeArgInfo.emplace();
1105 HI.CalleeArgInfo->Name = "arg_b";
1106 HI.CalleeArgInfo->Type = "const int &";
1107 HI.CallPassType = HoverInfo::PassType{PassMode::ConstRef, false};
1108 }},
1109 {
1110 R"cpp(
1111 int add(int lhs, int rhs);
1112 int main() {
1113 add(1 [[^+]] 2, 3);
1114 }
1115 )cpp",
1116 [](HoverInfo &HI) {
1117 HI.Name = "expression";
1118 HI.Kind = index::SymbolKind::Unknown;
1119 HI.Type = "int";
1120 HI.Value = "3";
1121 HI.CalleeArgInfo.emplace();
1122 HI.CalleeArgInfo->Name = "lhs";
1123 HI.CalleeArgInfo->Type = "int";
1124 HI.CallPassType = HoverInfo::PassType{PassMode::Value, false};
1125 }},
1126 {
1127 R"cpp(
1128 void foobar(const float &arg);
1129 int main() {
1130 foobar([[^0]]);
1131 }
1132 )cpp",
1133 [](HoverInfo &HI) {
1134 HI.Name = "literal";
1135 HI.Kind = index::SymbolKind::Unknown;
1136 HI.CalleeArgInfo.emplace();
1137 HI.CalleeArgInfo->Name = "arg";
1138 HI.CalleeArgInfo->Type = "const float &";
1139 HI.CallPassType = HoverInfo::PassType{PassMode::Value, true};
1140 }},
1141 {// Extra info for method call.
1142 R"cpp(
1143 class C {
1144 public:
1145 void fun(int arg_a = 3, int arg_b = 4) {}
1146 };
1147 void code() {
1148 int a = 1, b = 2;
1149 C c;
1150 c.fun([[^a]], b);
1151 }
1152 )cpp",
1153 [](HoverInfo &HI) {
1154 HI.Name = "a";
1155 HI.Kind = index::SymbolKind::Variable;
1156 HI.NamespaceScope = "";
1157 HI.Definition = "int a = 1";
1158 HI.LocalScope = "code::";
1159 HI.Value = "1";
1160 HI.Type = "int";
1161 HI.CalleeArgInfo.emplace();
1162 HI.CalleeArgInfo->Name = "arg_a";
1163 HI.CalleeArgInfo->Type = "int";
1164 HI.CalleeArgInfo->Default = "3";
1165 HI.CallPassType = HoverInfo::PassType{PassMode::Value, false};
1166 }},
1167 {
1168 R"cpp(
1169 struct Foo {
1170 Foo(const int &);
1171 };
1172 void foo(Foo);
1173 void bar() {
1174 const int x = 0;
1175 foo([[^x]]);
1176 }
1177 )cpp",
1178 [](HoverInfo &HI) {
1179 HI.Name = "x";
1180 HI.Kind = index::SymbolKind::Variable;
1181 HI.NamespaceScope = "";
1182 HI.Definition = "const int x = 0";
1183 HI.LocalScope = "bar::";
1184 HI.Value = "0";
1185 HI.Type = "const int";
1186 HI.CalleeArgInfo.emplace();
1187 HI.CalleeArgInfo->Type = "Foo";
1188 HI.CallPassType = HoverInfo::PassType{PassMode::ConstRef, true};
1189 }},
1190 {// Dont crash on invalid decl
1191 R"cpp(
1192 // error-ok
1193 struct Foo {
1194 Bar [[x^x]];
1195 };)cpp",
1196 [](HoverInfo &HI) {
1197 HI.Name = "xx";
1198 HI.Kind = index::SymbolKind::Field;
1199 HI.NamespaceScope = "";
1200 HI.Definition = "int xx";
1201 HI.LocalScope = "Foo::";
1202 HI.Type = "int";
1203 HI.AccessSpecifier = "public";
1204 }},
1205 {R"cpp(
1206 // error-ok
1207 struct Foo {
1208 Bar xx;
1209 int [[y^y]];
1210 };)cpp",
1211 [](HoverInfo &HI) {
1212 HI.Name = "yy";
1213 HI.Kind = index::SymbolKind::Field;
1214 HI.NamespaceScope = "";
1215 HI.Definition = "int yy";
1216 HI.LocalScope = "Foo::";
1217 HI.Type = "int";
1218 HI.AccessSpecifier = "public";
1219 }},
1220 {// No crash on InitListExpr.
1221 R"cpp(
1222 struct Foo {
1223 int a[10];
1224 };
1225 constexpr Foo k2 = {
1226 ^[[{]]1} // FIXME: why the hover range is 1 character?
1227 };
1228 )cpp",
1229 [](HoverInfo &HI) {
1230 HI.Name = "expression";
1231 HI.Kind = index::SymbolKind::Unknown;
1232 HI.Type = "int[10]";
1233 HI.Value = "{1}";
1234 }},
1235 {// Var template decl
1236 R"cpp(
1237 using m_int = int;
1238
1239 template <int Size> m_int ^[[arr]][Size];
1240 )cpp",
1241 [](HoverInfo &HI) {
1242 HI.Name = "arr";
1243 HI.Kind = index::SymbolKind::Variable;
1244 HI.Type = {"m_int[Size]", "int[Size]"};
1245 HI.NamespaceScope = "";
1246 HI.Definition = "template <int Size> m_int arr[Size]";
1247 HI.TemplateParameters = {{{"int"}, {"Size"}, std::nullopt}};
1248 }},
1249 {// Var template decl specialization
1250 R"cpp(
1251 using m_int = int;
1252
1253 template <int Size> m_int arr[Size];
1254
1255 template <> m_int ^[[arr]]<4>[4];
1256 )cpp",
1257 [](HoverInfo &HI) {
1258 HI.Name = "arr<4>";
1259 HI.Kind = index::SymbolKind::Variable;
1260 HI.Type = {"m_int[4]", "int[4]"};
1261 HI.NamespaceScope = "";
1262 HI.Definition = "m_int arr[4]";
1263 }},
1264 {// Canonical type
1265 R"cpp(
1266 template<typename T>
1267 struct TestHover {
1268 using Type = T;
1269 };
1270
1271 void code() {
1272 TestHover<int>::Type ^[[a]];
1273 }
1274 )cpp",
1275 [](HoverInfo &HI) {
1276 HI.Name = "a";
1277 HI.NamespaceScope = "";
1278 HI.LocalScope = "code::";
1279 HI.Definition = "TestHover<int>::Type a";
1280 HI.Kind = index::SymbolKind::Variable;
1281 HI.Type = {"TestHover<int>::Type", "int"};
1282 }},
1283 {// Canonical template type
1284 R"cpp(
1285 template<typename T>
1286 void ^[[foo]](T arg) {}
1287 )cpp",
1288 [](HoverInfo &HI) {
1289 HI.Name = "foo";
1290 HI.Kind = index::SymbolKind::Function;
1291 HI.NamespaceScope = "";
1292 HI.Definition = "template <typename T> void foo(T arg)";
1293 HI.Type = "void (T)";
1294 HI.ReturnType = "void";
1295 HI.Parameters = {{{"T"}, std::string("arg"), std::nullopt}};
1296 HI.TemplateParameters = {
1297 {{"typename"}, std::string("T"), std::nullopt}};
1298 }},
1299 {// TypeAlias Template
1300 R"cpp(
1301 template<typename T>
1302 using ^[[alias]] = T;
1303 )cpp",
1304 [](HoverInfo &HI) {
1305 HI.Name = "alias";
1306 HI.NamespaceScope = "";
1307 HI.LocalScope = "";
1308 HI.Kind = index::SymbolKind::TypeAlias;
1309 HI.Definition = "template <typename T> using alias = T";
1310 HI.Type = "T";
1311 HI.TemplateParameters = {
1312 {{"typename"}, std::string("T"), std::nullopt}};
1313 }},
1314 {// TypeAlias Template
1315 R"cpp(
1316 template<typename T>
1317 using A = T;
1318
1319 template<typename T>
1320 using ^[[AA]] = A<T>;
1321 )cpp",
1322 [](HoverInfo &HI) {
1323 HI.Name = "AA";
1324 HI.NamespaceScope = "";
1325 HI.LocalScope = "";
1326 HI.Kind = index::SymbolKind::TypeAlias;
1327 HI.Definition = "template <typename T> using AA = A<T>";
1328 HI.Type = {"A<T>", "T"};
1329 HI.TemplateParameters = {
1330 {{"typename"}, std::string("T"), std::nullopt}};
1331 }},
1332 {// Constant array
1333 R"cpp(
1334 using m_int = int;
1335
1336 m_int ^[[arr]][10];
1337 )cpp",
1338 [](HoverInfo &HI) {
1339 HI.Name = "arr";
1340 HI.NamespaceScope = "";
1341 HI.LocalScope = "";
1342 HI.Kind = index::SymbolKind::Variable;
1343 HI.Definition = "m_int arr[10]";
1344 HI.Type = {"m_int[10]", "int[10]"};
1345 }},
1346 {// Incomplete array
1347 R"cpp(
1348 using m_int = int;
1349
1350 extern m_int ^[[arr]][];
1351 )cpp",
1352 [](HoverInfo &HI) {
1353 HI.Name = "arr";
1354 HI.NamespaceScope = "";
1355 HI.LocalScope = "";
1356 HI.Kind = index::SymbolKind::Variable;
1357 HI.Definition = "extern m_int arr[]";
1358 HI.Type = {"m_int[]", "int[]"};
1359 }},
1360 {// Dependent size array
1361 R"cpp(
1362 using m_int = int;
1363
1364 template<int Size>
1365 struct Test {
1366 m_int ^[[arr]][Size];
1367 };
1368 )cpp",
1369 [](HoverInfo &HI) {
1370 HI.Name = "arr";
1371 HI.NamespaceScope = "";
1372 HI.LocalScope = "Test<Size>::";
1373 HI.AccessSpecifier = "public";
1374 HI.Kind = index::SymbolKind::Field;
1375 HI.Definition = "m_int arr[Size]";
1376 HI.Type = {"m_int[Size]", "int[Size]"};
1377 }},
1378 {// Bitfield offset, size and padding
1379 R"cpp(
1380 struct Foo {
1381 char x;
1382 char [[^y]] : 1;
1383 int z;
1384 };
1385 )cpp",
1386 [](HoverInfo &HI) {
1387 HI.NamespaceScope = "";
1388 HI.LocalScope = "Foo::";
1389 HI.Name = "y";
1390 HI.Kind = index::SymbolKind::Field;
1391 HI.Definition = "char y : 1";
1392 HI.Type = "char";
1393 HI.Offset = 8;
1394 HI.Size = 1;
1395 HI.Padding = 23;
1396 HI.Align = 8;
1397 HI.AccessSpecifier = "public";
1398 }}};
1399 for (const auto &Case : Cases) {
1400 SCOPED_TRACE(Case.Code);
1401
1402 Annotations T(Case.Code);
1403 TestTU TU = TestTU::withCode(T.code());
1404 TU.ExtraArgs.push_back("-std=c++20");
1405 // Types might be different depending on the target triplet, we chose a
1406 // fixed one to make sure tests passes on different platform.
1407 TU.ExtraArgs.push_back("--target=x86_64-pc-linux-gnu");
1408 auto AST = TU.build();
1409 Config Cfg;
1410 Cfg.Hover.ShowAKA = true;
1411 WithContextValue WithCfg(Config::Key, std::move(Cfg));
1412
1413 auto H = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
1414 ASSERT_TRUE(H);
1415 HoverInfo Expected;
1416 Expected.SymRange = T.range();
1417 Case.ExpectedBuilder(Expected);
1418
1419 EXPECT_EQ(H->NamespaceScope, Expected.NamespaceScope);
1420 EXPECT_EQ(H->LocalScope, Expected.LocalScope);
1421 EXPECT_EQ(H->Name, Expected.Name);
1422 EXPECT_EQ(H->Kind, Expected.Kind);
1423 EXPECT_EQ(H->Documentation, Expected.Documentation);
1424 EXPECT_EQ(H->Definition, Expected.Definition);
1425 EXPECT_EQ(H->Type, Expected.Type);
1426 EXPECT_EQ(H->ReturnType, Expected.ReturnType);
1427 EXPECT_EQ(H->Parameters, Expected.Parameters);
1428 EXPECT_EQ(H->TemplateParameters, Expected.TemplateParameters);
1429 EXPECT_EQ(H->SymRange, Expected.SymRange);
1430 EXPECT_EQ(H->Value, Expected.Value);
1431 EXPECT_EQ(H->Size, Expected.Size);
1432 EXPECT_EQ(H->Offset, Expected.Offset);
1433 EXPECT_EQ(H->Align, Expected.Align);
1434 EXPECT_EQ(H->AccessSpecifier, Expected.AccessSpecifier);
1435 EXPECT_EQ(H->CalleeArgInfo, Expected.CalleeArgInfo);
1436 EXPECT_EQ(H->CallPassType, Expected.CallPassType);
1437 }
1438}
1439
1440TEST(Hover, DefinitionLanuage) {
1441 struct {
1442 const char *const Code;
1443 const std::string ClangLanguageFlag;
1444 const char *const ExpectedDefinitionLanguage;
1445 } Cases[] = {{R"cpp(
1446 void [[some^Global]]() {}
1447 )cpp",
1448 "", "cpp"},
1449 {R"cpp(
1450 void [[some^Global]]() {}
1451 )cpp",
1452 "-xobjective-c++", "objective-cpp"},
1453 {R"cpp(
1454 void [[some^Global]]() {}
1455 )cpp",
1456 "-xobjective-c", "objective-c"}};
1457 for (const auto &Case : Cases) {
1458 SCOPED_TRACE(Case.Code);
1459
1460 Annotations T(Case.Code);
1461 TestTU TU = TestTU::withCode(T.code());
1462 if (!Case.ClangLanguageFlag.empty())
1463 TU.ExtraArgs.push_back(Case.ClangLanguageFlag);
1464 auto AST = TU.build();
1465
1466 auto H = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
1467 ASSERT_TRUE(H);
1468
1469 EXPECT_STREQ(H->DefinitionLanguage, Case.ExpectedDefinitionLanguage);
1470 }
1471}
1472
1473TEST(Hover, CallPassType) {
1474 const llvm::StringRef CodePrefix = R"cpp(
1475class Base {};
1476class Derived : public Base {};
1477class CustomClass {
1478 public:
1479 CustomClass() {}
1480 CustomClass(const Base &x) {}
1481 CustomClass(int &x) {}
1482 CustomClass(float x) {}
1483 CustomClass(int x, int y) {}
1484};
1485
1486void int_by_ref(int &x) {}
1487void int_by_const_ref(const int &x) {}
1488void int_by_value(int x) {}
1489void base_by_ref(Base &x) {}
1490void base_by_const_ref(const Base &x) {}
1491void base_by_value(Base x) {}
1492void float_by_value(float x) {}
1493void custom_by_value(CustomClass x) {}
1494
1495void fun() {
1496 int int_x;
1497 int &int_ref = int_x;
1498 const int &int_const_ref = int_x;
1499 Base base;
1500 const Base &base_const_ref = base;
1501 Derived derived;
1502 float float_x;
1503)cpp";
1504 const llvm::StringRef CodeSuffix = "}";
1505
1506 struct {
1507 const char *const Code;
1509 bool Converted;
1510 } Tests[] = {
1511 // Integer tests
1512 {"int_by_value([[^int_x]]);", PassMode::Value, false},
1513 {"int_by_value([[^123]]);", PassMode::Value, false},
1514 {"int_by_ref([[^int_x]]);", PassMode::Ref, false},
1515 {"int_by_const_ref([[^int_x]]);", PassMode::ConstRef, false},
1516 {"int_by_const_ref([[^123]]);", PassMode::ConstRef, false},
1517 {"int_by_value([[^int_ref]]);", PassMode::Value, false},
1518 {"int_by_const_ref([[^int_ref]]);", PassMode::ConstRef, false},
1519 {"int_by_const_ref([[^int_ref]]);", PassMode::ConstRef, false},
1520 {"int_by_const_ref([[^int_const_ref]]);", PassMode::ConstRef, false},
1521 // Custom class tests
1522 {"base_by_ref([[^base]]);", PassMode::Ref, false},
1523 {"base_by_const_ref([[^base]]);", PassMode::ConstRef, false},
1524 {"base_by_const_ref([[^base_const_ref]]);", PassMode::ConstRef, false},
1525 {"base_by_value([[^base]]);", PassMode::Value, false},
1526 {"base_by_value([[^base_const_ref]]);", PassMode::Value, false},
1527 {"base_by_ref([[^derived]]);", PassMode::Ref, false},
1528 {"base_by_const_ref([[^derived]]);", PassMode::ConstRef, false},
1529 {"base_by_value([[^derived]]);", PassMode::Value, false},
1530 // Custom class constructor tests
1531 {"CustomClass c1([[^base]]);", PassMode::ConstRef, false},
1532 {"auto c2 = new CustomClass([[^base]]);", PassMode::ConstRef, false},
1533 {"CustomClass c3([[^int_x]]);", PassMode::Ref, false},
1534 {"CustomClass c3(int_x, [[^int_x]]);", PassMode::Value, false},
1535 // Converted tests
1536 {"float_by_value([[^int_x]]);", PassMode::Value, true},
1537 {"float_by_value([[^int_ref]]);", PassMode::Value, true},
1538 {"float_by_value([[^int_const_ref]]);", PassMode::Value, true},
1539 {"float_by_value([[^123.0f]]);", PassMode::Value, false},
1540 {"float_by_value([[^123]]);", PassMode::Value, true},
1541 {"custom_by_value([[^int_x]]);", PassMode::Ref, true},
1542 {"custom_by_value([[^float_x]]);", PassMode::Value, true},
1543 {"custom_by_value([[^base]]);", PassMode::ConstRef, true},
1544 };
1545 for (const auto &Test : Tests) {
1546 SCOPED_TRACE(Test.Code);
1547
1548 const auto Code = (CodePrefix + Test.Code + CodeSuffix).str();
1549 Annotations T(Code);
1550 TestTU TU = TestTU::withCode(T.code());
1551 TU.ExtraArgs.push_back("-std=c++17");
1552 auto AST = TU.build();
1553 auto H = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
1554 ASSERT_TRUE(H);
1555 EXPECT_EQ(H->CallPassType->PassBy, Test.PassBy);
1556 EXPECT_EQ(H->CallPassType->Converted, Test.Converted);
1557 }
1558}
1559
1560TEST(Hover, NoHover) {
1561 llvm::StringRef Tests[] = {
1562 "^int main() {}",
1563 "void foo() {^}",
1564 // FIXME: "decltype(auto)" should be a single hover
1565 "decltype(au^to) x = 0;",
1566 // FIXME: not supported yet
1567 R"cpp(// Lambda auto parameter
1568 auto lamb = [](a^uto){};
1569 )cpp",
1570 R"cpp(// non-named decls don't get hover. Don't crash!
1571 ^static_assert(1, "");
1572 )cpp",
1573 R"cpp(// non-evaluatable expr
1574 template <typename T> void foo() {
1575 (void)[[size^of]](T);
1576 })cpp",
1577 R"cpp(// should not crash on invalid semantic form of init-list-expr.
1578 /*error-ok*/
1579 struct Foo {
1580 int xyz = 0;
1581 };
1582 class Bar {};
1583 constexpr Foo s = ^{
1584 .xyz = Bar(),
1585 };
1586 )cpp",
1587 // literals
1588 "auto x = t^rue;",
1589 "auto x = ^(int){42};",
1590 "auto x = ^42.;",
1591 "auto x = ^42.0i;",
1592 "auto x = ^42;",
1593 "auto x = ^nullptr;",
1594 };
1595
1596 for (const auto &Test : Tests) {
1597 SCOPED_TRACE(Test);
1598
1599 Annotations T(Test);
1600 TestTU TU = TestTU::withCode(T.code());
1601 TU.ExtraArgs.push_back("-std=c++17");
1602 auto AST = TU.build();
1603 auto H = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
1604 ASSERT_FALSE(H);
1605 }
1606}
1607
1608TEST(Hover, All) {
1609 struct {
1610 const char *const Code;
1611 const std::function<void(HoverInfo &)> ExpectedBuilder;
1612 } Cases[] = {
1613 {"auto x = [['^A']]; // character literal",
1614 [](HoverInfo &HI) {
1615 HI.Name = "expression";
1616 HI.Type = "char";
1617 HI.Value = "65 (0x41)";
1618 }},
1619 {"auto s = ^[[\"Hello, world!\"]]; // string literal",
1620 [](HoverInfo &HI) {
1621 HI.Name = "string-literal";
1622 HI.Size = 112;
1623 HI.Type = "const char[14]";
1624 }},
1625 {
1626 R"cpp(// Local variable
1627 int main() {
1628 int bonjour;
1629 ^[[bonjour]] = 2;
1630 int test1 = bonjour;
1631 }
1632 )cpp",
1633 [](HoverInfo &HI) {
1634 HI.Name = "bonjour";
1635 HI.Kind = index::SymbolKind::Variable;
1636 HI.NamespaceScope = "";
1637 HI.LocalScope = "main::";
1638 HI.Type = "int";
1639 HI.Definition = "int bonjour";
1640 }},
1641 {
1642 R"cpp(// Local variable in method
1643 struct s {
1644 void method() {
1645 int bonjour;
1646 ^[[bonjour]] = 2;
1647 }
1648 };
1649 )cpp",
1650 [](HoverInfo &HI) {
1651 HI.Name = "bonjour";
1652 HI.Kind = index::SymbolKind::Variable;
1653 HI.NamespaceScope = "";
1654 HI.LocalScope = "s::method::";
1655 HI.Type = "int";
1656 HI.Definition = "int bonjour";
1657 }},
1658 {
1659 R"cpp(// Struct
1660 namespace ns1 {
1661 struct MyClass {};
1662 } // namespace ns1
1663 int main() {
1664 ns1::[[My^Class]]* Params;
1665 }
1666 )cpp",
1667 [](HoverInfo &HI) {
1668 HI.Name = "MyClass";
1669 HI.Kind = index::SymbolKind::Struct;
1670 HI.NamespaceScope = "ns1::";
1671 HI.Definition = "struct MyClass {}";
1672 }},
1673 {
1674 R"cpp(// Class
1675 namespace ns1 {
1676 class MyClass {};
1677 } // namespace ns1
1678 int main() {
1679 ns1::[[My^Class]]* Params;
1680 }
1681 )cpp",
1682 [](HoverInfo &HI) {
1683 HI.Name = "MyClass";
1684 HI.Kind = index::SymbolKind::Class;
1685 HI.NamespaceScope = "ns1::";
1686 HI.Definition = "class MyClass {}";
1687 }},
1688 {
1689 R"cpp(// Union
1690 namespace ns1 {
1691 union MyUnion { int x; int y; };
1692 } // namespace ns1
1693 int main() {
1694 ns1::[[My^Union]] Params;
1695 }
1696 )cpp",
1697 [](HoverInfo &HI) {
1698 HI.Name = "MyUnion";
1699 HI.Kind = index::SymbolKind::Union;
1700 HI.NamespaceScope = "ns1::";
1701 HI.Definition = "union MyUnion {}";
1702 }},
1703 {
1704 R"cpp(// Function definition via pointer
1705 void foo(int) {}
1706 int main() {
1707 auto *X = &^[[foo]];
1708 }
1709 )cpp",
1710 [](HoverInfo &HI) {
1711 HI.Name = "foo";
1712 HI.Kind = index::SymbolKind::Function;
1713 HI.NamespaceScope = "";
1714 HI.Type = "void (int)";
1715 HI.Definition = "void foo(int)";
1716 HI.Documentation = "Function definition via pointer";
1717 HI.ReturnType = "void";
1718 HI.Parameters = {
1719 {{"int"}, std::nullopt, std::nullopt},
1720 };
1721 }},
1722 {
1723 R"cpp(// Function declaration via call
1724 int foo(int);
1725 int main() {
1726 return ^[[foo]](42);
1727 }
1728 )cpp",
1729 [](HoverInfo &HI) {
1730 HI.Name = "foo";
1731 HI.Kind = index::SymbolKind::Function;
1732 HI.NamespaceScope = "";
1733 HI.Type = "int (int)";
1734 HI.Definition = "int foo(int)";
1735 HI.Documentation = "Function declaration via call";
1736 HI.ReturnType = "int";
1737 HI.Parameters = {
1738 {{"int"}, std::nullopt, std::nullopt},
1739 };
1740 }},
1741 {
1742 R"cpp(// Field
1743 struct Foo { int x; };
1744 int main() {
1745 Foo bar;
1746 (void)bar.^[[x]];
1747 }
1748 )cpp",
1749 [](HoverInfo &HI) {
1750 HI.Name = "x";
1751 HI.Kind = index::SymbolKind::Field;
1752 HI.NamespaceScope = "";
1753 HI.LocalScope = "Foo::";
1754 HI.Type = "int";
1755 HI.Definition = "int x";
1756 }},
1757 {
1758 R"cpp(// Field with initialization
1759 struct Foo { int x = 5; };
1760 int main() {
1761 Foo bar;
1762 (void)bar.^[[x]];
1763 }
1764 )cpp",
1765 [](HoverInfo &HI) {
1766 HI.Name = "x";
1767 HI.Kind = index::SymbolKind::Field;
1768 HI.NamespaceScope = "";
1769 HI.LocalScope = "Foo::";
1770 HI.Type = "int";
1771 HI.Definition = "int x = 5";
1772 }},
1773 {
1774 R"cpp(// Static field
1775 struct Foo { static int x; };
1776 int main() {
1777 (void)Foo::^[[x]];
1778 }
1779 )cpp",
1780 [](HoverInfo &HI) {
1781 HI.Name = "x";
1782 HI.Kind = index::SymbolKind::StaticProperty;
1783 HI.NamespaceScope = "";
1784 HI.LocalScope = "Foo::";
1785 HI.Type = "int";
1786 HI.Definition = "static int x";
1787 }},
1788 {
1789 R"cpp(// Field, member initializer
1790 struct Foo {
1791 int x;
1792 Foo() : ^[[x]](0) {}
1793 };
1794 )cpp",
1795 [](HoverInfo &HI) {
1796 HI.Name = "x";
1797 HI.Kind = index::SymbolKind::Field;
1798 HI.NamespaceScope = "";
1799 HI.LocalScope = "Foo::";
1800 HI.Type = "int";
1801 HI.Definition = "int x";
1802 }},
1803 {
1804 R"cpp(// Field, GNU old-style field designator
1805 struct Foo { int x; };
1806 int main() {
1807 Foo bar = { ^[[x]] : 1 };
1808 }
1809 )cpp",
1810 [](HoverInfo &HI) {
1811 HI.Name = "x";
1812 HI.Kind = index::SymbolKind::Field;
1813 HI.NamespaceScope = "";
1814 HI.LocalScope = "Foo::";
1815 HI.Type = "int";
1816 HI.Definition = "int x";
1817 // FIXME: Initializer for x is a DesignatedInitListExpr, hence it is
1818 // of struct type and omitted.
1819 }},
1820 {
1821 R"cpp(// Field, field designator
1822 struct Foo { int x; int y; };
1823 int main() {
1824 Foo bar = { .^[[x]] = 2, .y = 2 };
1825 }
1826 )cpp",
1827 [](HoverInfo &HI) {
1828 HI.Name = "x";
1829 HI.Kind = index::SymbolKind::Field;
1830 HI.NamespaceScope = "";
1831 HI.LocalScope = "Foo::";
1832 HI.Type = "int";
1833 HI.Definition = "int x";
1834 }},
1835 {
1836 R"cpp(// Method call
1837 struct Foo { int x(); };
1838 int main() {
1839 Foo bar;
1840 bar.^[[x]]();
1841 }
1842 )cpp",
1843 [](HoverInfo &HI) {
1844 HI.Name = "x";
1845 HI.Kind = index::SymbolKind::InstanceMethod;
1846 HI.NamespaceScope = "";
1847 HI.LocalScope = "Foo::";
1848 HI.Type = "int ()";
1849 HI.Definition = "int x()";
1850 HI.ReturnType = "int";
1851 HI.Parameters = std::vector<HoverInfo::Param>{};
1852 }},
1853 {
1854 R"cpp(// Static method call
1855 struct Foo { static int x(); };
1856 int main() {
1857 Foo::^[[x]]();
1858 }
1859 )cpp",
1860 [](HoverInfo &HI) {
1861 HI.Name = "x";
1862 HI.Kind = index::SymbolKind::StaticMethod;
1863 HI.NamespaceScope = "";
1864 HI.LocalScope = "Foo::";
1865 HI.Type = "int ()";
1866 HI.Definition = "static int x()";
1867 HI.ReturnType = "int";
1868 HI.Parameters = std::vector<HoverInfo::Param>{};
1869 }},
1870 {
1871 R"cpp(// Typedef
1872 typedef int Foo;
1873 int main() {
1874 ^[[Foo]] bar;
1875 }
1876 )cpp",
1877 [](HoverInfo &HI) {
1878 HI.Name = "Foo";
1879 HI.Kind = index::SymbolKind::TypeAlias;
1880 HI.NamespaceScope = "";
1881 HI.Definition = "typedef int Foo";
1882 HI.Type = "int";
1883 HI.Documentation = "Typedef";
1884 }},
1885 {
1886 R"cpp(// Typedef with embedded definition
1887 typedef struct Bar {} Foo;
1888 int main() {
1889 ^[[Foo]] bar;
1890 }
1891 )cpp",
1892 [](HoverInfo &HI) {
1893 HI.Name = "Foo";
1894 HI.Kind = index::SymbolKind::TypeAlias;
1895 HI.NamespaceScope = "";
1896 HI.Definition = "typedef struct Bar Foo";
1897 HI.Type = "struct Bar";
1898 HI.Documentation = "Typedef with embedded definition";
1899 }},
1900 {
1901 R"cpp(// Namespace
1902 namespace ns {
1903 struct Foo { static void bar(); };
1904 } // namespace ns
1905 int main() { ^[[ns]]::Foo::bar(); }
1906 )cpp",
1907 [](HoverInfo &HI) {
1908 HI.Name = "ns";
1909 HI.Kind = index::SymbolKind::Namespace;
1910 HI.NamespaceScope = "";
1911 HI.Definition = "namespace ns {}";
1912 }},
1913 {
1914 R"cpp(// Anonymous namespace
1915 namespace ns {
1916 namespace {
1917 int foo;
1918 } // anonymous namespace
1919 } // namespace ns
1920 int main() { ns::[[f^oo]]++; }
1921 )cpp",
1922 [](HoverInfo &HI) {
1923 HI.Name = "foo";
1924 HI.Kind = index::SymbolKind::Variable;
1925 HI.NamespaceScope = "ns::";
1926 HI.Type = "int";
1927 HI.Definition = "int foo";
1928 }},
1929 {
1930 R"cpp(// Function definition via using declaration
1931 namespace ns {
1932 void foo();
1933 }
1934 int main() {
1935 using ns::foo;
1936 ^[[foo]]();
1937 }
1938 )cpp",
1939 [](HoverInfo &HI) {
1940 HI.Name = "foo";
1941 HI.Kind = index::SymbolKind::Function;
1942 HI.NamespaceScope = "ns::";
1943 HI.Type = "void ()";
1944 HI.Definition = "void foo()";
1945 HI.Documentation = "";
1946 HI.ReturnType = "void";
1947 HI.Parameters = std::vector<HoverInfo::Param>{};
1948 }},
1949 {
1950 R"cpp( // using declaration and two possible function declarations
1951 namespace ns { void foo(int); void foo(char); }
1952 using ns::foo;
1953 template <typename T> void bar() { [[f^oo]](T{}); }
1954 )cpp",
1955 [](HoverInfo &HI) {
1956 HI.Name = "foo";
1957 HI.Kind = index::SymbolKind::Using;
1958 HI.NamespaceScope = "";
1959 HI.Definition = "using ns::foo";
1960 }},
1961 {
1962 R"cpp(// Macro
1963 #define MACRO 0
1964 int main() { return ^[[MACRO]]; }
1965 )cpp",
1966 [](HoverInfo &HI) {
1967 HI.Name = "MACRO";
1968 HI.Value = "0";
1969 HI.Type = "int";
1970 HI.Kind = index::SymbolKind::Macro;
1971 HI.Definition = "#define MACRO 0\n\n"
1972 "// Expands to\n"
1973 "0";
1974 }},
1975 {
1976 R"cpp(// Macro
1977 #define MACRO 0
1978 #define MACRO2 ^[[MACRO]]
1979 )cpp",
1980 [](HoverInfo &HI) {
1981 HI.Name = "MACRO";
1982 HI.Kind = index::SymbolKind::Macro;
1983 HI.Definition = "#define MACRO 0";
1984 // NOTE MACRO doesn't have expansion since it technically isn't
1985 // expanded here
1986 }},
1987 {
1988 R"cpp(// Macro
1989 #define MACRO {\
1990 return 0;\
1991 }
1992 int main() ^[[MACRO]]
1993 )cpp",
1994 [](HoverInfo &HI) {
1995 HI.Name = "MACRO";
1996 HI.Kind = index::SymbolKind::Macro;
1997 HI.Definition =
1998 R"cpp(#define MACRO \
1999 { \
2000 return 0; \
2001 }
2002
2003// Expands to
2004{
2005 return 0;
2006})cpp";
2007 }},
2008 {
2009 R"cpp(// Forward class declaration
2010 class Foo;
2011 class Foo {};
2012 [[F^oo]]* foo();
2013 )cpp",
2014 [](HoverInfo &HI) {
2015 HI.Name = "Foo";
2016 HI.Kind = index::SymbolKind::Class;
2017 HI.NamespaceScope = "";
2018 HI.Definition = "class Foo {}";
2019 HI.Documentation = "Forward class declaration";
2020 }},
2021 {
2022 R"cpp(// Function declaration
2023 void foo();
2024 void g() { [[f^oo]](); }
2025 void foo() {}
2026 )cpp",
2027 [](HoverInfo &HI) {
2028 HI.Name = "foo";
2029 HI.Kind = index::SymbolKind::Function;
2030 HI.NamespaceScope = "";
2031 HI.Type = "void ()";
2032 HI.Definition = "void foo()";
2033 HI.Documentation = "Function declaration";
2034 HI.ReturnType = "void";
2035 HI.Parameters = std::vector<HoverInfo::Param>{};
2036 }},
2037 {
2038 R"cpp(// Enum declaration
2039 enum Hello {
2040 ONE, TWO, THREE,
2041 };
2042 void foo() {
2043 [[Hel^lo]] hello = ONE;
2044 }
2045 )cpp",
2046 [](HoverInfo &HI) {
2047 HI.Name = "Hello";
2048 HI.Kind = index::SymbolKind::Enum;
2049 HI.NamespaceScope = "";
2050 HI.Definition = "enum Hello {}";
2051 HI.Documentation = "Enum declaration";
2052 }},
2053 {
2054 R"cpp(// Enumerator
2055 enum Hello {
2056 ONE, TWO, THREE,
2057 };
2058 void foo() {
2059 Hello hello = [[O^NE]];
2060 }
2061 )cpp",
2062 [](HoverInfo &HI) {
2063 HI.Name = "ONE";
2064 HI.Kind = index::SymbolKind::EnumConstant;
2065 HI.NamespaceScope = "";
2066 HI.LocalScope = "Hello::";
2067 HI.Type = "enum Hello";
2068 HI.Definition = "ONE";
2069 HI.Value = "0";
2070 }},
2071 {
2072 R"cpp(// C++20's using enum
2073 enum class Hello {
2074 ONE, TWO, THREE,
2075 };
2076 void foo() {
2077 using enum Hello;
2078 Hello hello = [[O^NE]];
2079 }
2080 )cpp",
2081 [](HoverInfo &HI) {
2082 HI.Name = "ONE";
2083 HI.Kind = index::SymbolKind::EnumConstant;
2084 HI.NamespaceScope = "";
2085 HI.LocalScope = "Hello::";
2086 HI.Type = "enum Hello";
2087 HI.Definition = "ONE";
2088 HI.Value = "0";
2089 }},
2090 {
2091 R"cpp(// Enumerator in anonymous enum
2092 enum {
2093 ONE, TWO, THREE,
2094 };
2095 void foo() {
2096 int hello = [[O^NE]];
2097 }
2098 )cpp",
2099 [](HoverInfo &HI) {
2100 HI.Name = "ONE";
2101 HI.Kind = index::SymbolKind::EnumConstant;
2102 HI.NamespaceScope = "";
2103 // FIXME: This should be `(anon enum)::`
2104 HI.LocalScope = "";
2105 HI.Type = "enum (unnamed)";
2106 HI.Definition = "ONE";
2107 HI.Value = "0";
2108 }},
2109 {
2110 R"cpp(// Global variable
2111 static int hey = 10;
2112 void foo() {
2113 [[he^y]]++;
2114 }
2115 )cpp",
2116 [](HoverInfo &HI) {
2117 HI.Name = "hey";
2118 HI.Kind = index::SymbolKind::Variable;
2119 HI.NamespaceScope = "";
2120 HI.Type = "int";
2121 HI.Definition = "static int hey = 10";
2122 HI.Documentation = "Global variable";
2123 // FIXME: Value shouldn't be set in this case
2124 HI.Value = "10 (0xa)";
2125 }},
2126 {
2127 R"cpp(// Global variable in namespace
2128 namespace ns1 {
2129 static long long hey = -36637162602497;
2130 }
2131 void foo() {
2132 ns1::[[he^y]]++;
2133 }
2134 )cpp",
2135 [](HoverInfo &HI) {
2136 HI.Name = "hey";
2137 HI.Kind = index::SymbolKind::Variable;
2138 HI.NamespaceScope = "ns1::";
2139 HI.Type = "long long";
2140 HI.Definition = "static long long hey = -36637162602497";
2141 HI.Value = "-36637162602497 (0xffffdeadbeefffff)"; // needs 64 bits
2142 }},
2143 {
2144 R"cpp(// Field in anonymous struct
2145 static struct {
2146 int hello;
2147 } s;
2148 void foo() {
2149 s.[[he^llo]]++;
2150 }
2151 )cpp",
2152 [](HoverInfo &HI) {
2153 HI.Name = "hello";
2154 HI.Kind = index::SymbolKind::Field;
2155 HI.NamespaceScope = "";
2156 HI.LocalScope = "(anonymous struct)::";
2157 HI.Type = "int";
2158 HI.Definition = "int hello";
2159 }},
2160 {
2161 R"cpp(// Templated function
2162 template <typename T>
2163 T foo() {
2164 return 17;
2165 }
2166 void g() { auto x = [[f^oo]]<int>(); }
2167 )cpp",
2168 [](HoverInfo &HI) {
2169 HI.Name = "foo";
2170 HI.Kind = index::SymbolKind::Function;
2171 HI.NamespaceScope = "";
2172 HI.Type = "int ()";
2173 HI.Definition = "template <> int foo<int>()";
2174 HI.Documentation = "Templated function";
2175 HI.ReturnType = "int";
2176 HI.Parameters = std::vector<HoverInfo::Param>{};
2177 // FIXME: We should populate template parameters with arguments in
2178 // case of instantiations.
2179 }},
2180 {
2181 R"cpp(// Anonymous union
2182 struct outer {
2183 union {
2184 int abc, def;
2185 } v;
2186 };
2187 void g() { struct outer o; o.v.[[d^ef]]++; }
2188 )cpp",
2189 [](HoverInfo &HI) {
2190 HI.Name = "def";
2191 HI.Kind = index::SymbolKind::Field;
2192 HI.NamespaceScope = "";
2193 HI.LocalScope = "outer::(anonymous union)::";
2194 HI.Type = "int";
2195 HI.Definition = "int def";
2196 }},
2197 {
2198 R"cpp(// documentation from index
2199 int nextSymbolIsAForwardDeclFromIndexWithNoLocalDocs;
2200 void indexSymbol();
2201 void g() { [[ind^exSymbol]](); }
2202 )cpp",
2203 [](HoverInfo &HI) {
2204 HI.Name = "indexSymbol";
2205 HI.Kind = index::SymbolKind::Function;
2206 HI.NamespaceScope = "";
2207 HI.Type = "void ()";
2208 HI.Definition = "void indexSymbol()";
2209 HI.ReturnType = "void";
2210 HI.Parameters = std::vector<HoverInfo::Param>{};
2211 HI.Documentation = "comment from index";
2212 }},
2213 {
2214 R"cpp(// Simple initialization with auto
2215 void foo() {
2216 ^[[auto]] i = 1;
2217 }
2218 )cpp",
2219 [](HoverInfo &HI) {
2220 HI.Name = "auto";
2221 HI.Kind = index::SymbolKind::TypeAlias;
2222 HI.Definition = "int";
2223 }},
2224 {
2225 R"cpp(// Simple initialization with const auto
2226 void foo() {
2227 const ^[[auto]] i = 1;
2228 }
2229 )cpp",
2230 [](HoverInfo &HI) {
2231 HI.Name = "auto";
2232 HI.Kind = index::SymbolKind::TypeAlias;
2233 HI.Definition = "int";
2234 }},
2235 {
2236 R"cpp(// Simple initialization with const auto&
2237 void foo() {
2238 const ^[[auto]]& i = 1;
2239 }
2240 )cpp",
2241 [](HoverInfo &HI) {
2242 HI.Name = "auto";
2243 HI.Kind = index::SymbolKind::TypeAlias;
2244 HI.Definition = "int";
2245 }},
2246 {
2247 R"cpp(// Simple initialization with auto&
2248 void foo() {
2249 int x;
2250 ^[[auto]]& i = x;
2251 }
2252 )cpp",
2253 [](HoverInfo &HI) {
2254 HI.Name = "auto";
2255 HI.Kind = index::SymbolKind::TypeAlias;
2256 HI.Definition = "int";
2257 }},
2258 {
2259 R"cpp(// Simple initialization with auto*
2260 void foo() {
2261 int a = 1;
2262 ^[[auto]]* i = &a;
2263 }
2264 )cpp",
2265 [](HoverInfo &HI) {
2266 HI.Name = "auto";
2267 HI.Kind = index::SymbolKind::TypeAlias;
2268 HI.Definition = "int";
2269 }},
2270 {
2271 R"cpp(// Simple initialization with auto from pointer
2272 void foo() {
2273 int a = 1;
2274 ^[[auto]] i = &a;
2275 }
2276 )cpp",
2277 [](HoverInfo &HI) {
2278 HI.Name = "auto";
2279 HI.Kind = index::SymbolKind::TypeAlias;
2280 HI.Definition = "int *";
2281 }},
2282 {
2283 R"cpp(// Auto with initializer list.
2284 namespace std
2285 {
2286 template<class _E>
2287 class initializer_list { const _E *a, *b; };
2288 }
2289 void foo() {
2290 ^[[auto]] i = {1,2};
2291 }
2292 )cpp",
2293 [](HoverInfo &HI) {
2294 HI.Name = "auto";
2295 HI.Kind = index::SymbolKind::TypeAlias;
2296 HI.Definition = "std::initializer_list<int>";
2297 }},
2298 {
2299 R"cpp(// User defined conversion to auto
2300 struct Bar {
2301 operator ^[[auto]]() const { return 10; }
2302 };
2303 )cpp",
2304 [](HoverInfo &HI) {
2305 HI.Name = "auto";
2306 HI.Kind = index::SymbolKind::TypeAlias;
2307 HI.Definition = "int";
2308 }},
2309 {
2310 R"cpp(// Simple initialization with decltype(auto)
2311 void foo() {
2312 ^[[decltype]](auto) i = 1;
2313 }
2314 )cpp",
2315 [](HoverInfo &HI) {
2316 HI.Name = "decltype";
2317 HI.Kind = index::SymbolKind::TypeAlias;
2318 HI.Definition = "int";
2319 }},
2320 {
2321 R"cpp(// Simple initialization with const decltype(auto)
2322 void foo() {
2323 const int j = 0;
2324 ^[[decltype]](auto) i = j;
2325 }
2326 )cpp",
2327 [](HoverInfo &HI) {
2328 HI.Name = "decltype";
2329 HI.Kind = index::SymbolKind::TypeAlias;
2330 HI.Definition = "const int";
2331 }},
2332 {
2333 R"cpp(// Simple initialization with const& decltype(auto)
2334 void foo() {
2335 int k = 0;
2336 const int& j = k;
2337 ^[[decltype]](auto) i = j;
2338 }
2339 )cpp",
2340 [](HoverInfo &HI) {
2341 HI.Name = "decltype";
2342 HI.Kind = index::SymbolKind::TypeAlias;
2343 HI.Definition = "const int &";
2344 }},
2345 {
2346 R"cpp(// Simple initialization with & decltype(auto)
2347 void foo() {
2348 int k = 0;
2349 int& j = k;
2350 ^[[decltype]](auto) i = j;
2351 }
2352 )cpp",
2353 [](HoverInfo &HI) {
2354 HI.Name = "decltype";
2355 HI.Kind = index::SymbolKind::TypeAlias;
2356 HI.Definition = "int &";
2357 }},
2358 {
2359 R"cpp(// simple trailing return type
2360 ^[[auto]] main() -> int {
2361 return 0;
2362 }
2363 )cpp",
2364 [](HoverInfo &HI) {
2365 HI.Name = "auto";
2366 HI.Kind = index::SymbolKind::TypeAlias;
2367 HI.Definition = "int";
2368 }},
2369 {
2370 R"cpp(// auto function return with trailing type
2371 struct Bar {};
2372 ^[[auto]] test() -> decltype(Bar()) {
2373 return Bar();
2374 }
2375 )cpp",
2376 [](HoverInfo &HI) {
2377 HI.Name = "auto";
2378 HI.Kind = index::SymbolKind::TypeAlias;
2379 HI.Definition = "Bar";
2380 HI.Documentation = "auto function return with trailing type";
2381 }},
2382 {
2383 R"cpp(// trailing return type
2384 struct Bar {};
2385 auto test() -> ^[[decltype]](Bar()) {
2386 return Bar();
2387 }
2388 )cpp",
2389 [](HoverInfo &HI) {
2390 HI.Name = "decltype";
2391 HI.Kind = index::SymbolKind::TypeAlias;
2392 HI.Definition = "Bar";
2393 HI.Documentation = "trailing return type";
2394 }},
2395 {
2396 R"cpp(// auto in function return
2397 struct Bar {};
2398 ^[[auto]] test() {
2399 return Bar();
2400 }
2401 )cpp",
2402 [](HoverInfo &HI) {
2403 HI.Name = "auto";
2404 HI.Kind = index::SymbolKind::TypeAlias;
2405 HI.Definition = "Bar";
2406 HI.Documentation = "auto in function return";
2407 }},
2408 {
2409 R"cpp(// auto& in function return
2410 struct Bar {};
2411 ^[[auto]]& test() {
2412 static Bar x;
2413 return x;
2414 }
2415 )cpp",
2416 [](HoverInfo &HI) {
2417 HI.Name = "auto";
2418 HI.Kind = index::SymbolKind::TypeAlias;
2419 HI.Definition = "Bar";
2420 HI.Documentation = "auto& in function return";
2421 }},
2422 {
2423 R"cpp(// auto* in function return
2424 struct Bar {};
2425 ^[[auto]]* test() {
2426 Bar* bar;
2427 return bar;
2428 }
2429 )cpp",
2430 [](HoverInfo &HI) {
2431 HI.Name = "auto";
2432 HI.Kind = index::SymbolKind::TypeAlias;
2433 HI.Definition = "Bar";
2434 HI.Documentation = "auto* in function return";
2435 }},
2436 {
2437 R"cpp(// const auto& in function return
2438 struct Bar {};
2439 const ^[[auto]]& test() {
2440 static Bar x;
2441 return x;
2442 }
2443 )cpp",
2444 [](HoverInfo &HI) {
2445 HI.Name = "auto";
2446 HI.Kind = index::SymbolKind::TypeAlias;
2447 HI.Definition = "Bar";
2448 HI.Documentation = "const auto& in function return";
2449 }},
2450 {
2451 R"cpp(// decltype(auto) in function return
2452 struct Bar {};
2453 ^[[decltype]](auto) test() {
2454 return Bar();
2455 }
2456 )cpp",
2457 [](HoverInfo &HI) {
2458 HI.Name = "decltype";
2459 HI.Kind = index::SymbolKind::TypeAlias;
2460 HI.Definition = "Bar";
2461 HI.Documentation = "decltype(auto) in function return";
2462 }},
2463 {
2464 R"cpp(// decltype(auto) reference in function return
2465 ^[[decltype]](auto) test() {
2466 static int a;
2467 return (a);
2468 }
2469 )cpp",
2470 [](HoverInfo &HI) {
2471 HI.Name = "decltype";
2472 HI.Kind = index::SymbolKind::TypeAlias;
2473 HI.Definition = "int &";
2474 }},
2475 {
2476 R"cpp(// decltype lvalue reference
2477 void foo() {
2478 int I = 0;
2479 ^[[decltype]](I) J = I;
2480 }
2481 )cpp",
2482 [](HoverInfo &HI) {
2483 HI.Name = "decltype";
2484 HI.Kind = index::SymbolKind::TypeAlias;
2485 HI.Definition = "int";
2486 }},
2487 {
2488 R"cpp(// decltype lvalue reference
2489 void foo() {
2490 int I= 0;
2491 int &K = I;
2492 ^[[decltype]](K) J = I;
2493 }
2494 )cpp",
2495 [](HoverInfo &HI) {
2496 HI.Name = "decltype";
2497 HI.Kind = index::SymbolKind::TypeAlias;
2498 HI.Definition = "int &";
2499 }},
2500 {
2501 R"cpp(// decltype lvalue reference parenthesis
2502 void foo() {
2503 int I = 0;
2504 ^[[decltype]]((I)) J = I;
2505 }
2506 )cpp",
2507 [](HoverInfo &HI) {
2508 HI.Name = "decltype";
2509 HI.Kind = index::SymbolKind::TypeAlias;
2510 HI.Definition = "int &";
2511 }},
2512 {
2513 R"cpp(// decltype rvalue reference
2514 void foo() {
2515 int I = 0;
2516 ^[[decltype]](static_cast<int&&>(I)) J = static_cast<int&&>(I);
2517 }
2518 )cpp",
2519 [](HoverInfo &HI) {
2520 HI.Name = "decltype";
2521 HI.Kind = index::SymbolKind::TypeAlias;
2522 HI.Definition = "int &&";
2523 }},
2524 {
2525 R"cpp(// decltype rvalue reference function call
2526 int && bar();
2527 void foo() {
2528 int I = 0;
2529 ^[[decltype]](bar()) J = bar();
2530 }
2531 )cpp",
2532 [](HoverInfo &HI) {
2533 HI.Name = "decltype";
2534 HI.Kind = index::SymbolKind::TypeAlias;
2535 HI.Definition = "int &&";
2536 }},
2537 {
2538 R"cpp(// decltype of function with trailing return type.
2539 struct Bar {};
2540 auto test() -> decltype(Bar()) {
2541 return Bar();
2542 }
2543 void foo() {
2544 ^[[decltype]](test()) i = test();
2545 }
2546 )cpp",
2547 [](HoverInfo &HI) {
2548 HI.Name = "decltype";
2549 HI.Kind = index::SymbolKind::TypeAlias;
2550 HI.Definition = "Bar";
2551 HI.Documentation =
2552 "decltype of function with trailing return type.";
2553 }},
2554 {
2555 R"cpp(// decltype of var with decltype.
2556 void foo() {
2557 int I = 0;
2558 decltype(I) J = I;
2559 ^[[decltype]](J) K = J;
2560 }
2561 )cpp",
2562 [](HoverInfo &HI) {
2563 HI.Name = "decltype";
2564 HI.Kind = index::SymbolKind::TypeAlias;
2565 HI.Definition = "int";
2566 }},
2567 {
2568 R"cpp(// decltype of dependent type
2569 template <typename T>
2570 struct X {
2571 using Y = ^[[decltype]](T::Z);
2572 };
2573 )cpp",
2574 [](HoverInfo &HI) {
2575 HI.Name = "decltype";
2576 HI.Kind = index::SymbolKind::TypeAlias;
2577 HI.Definition = "<dependent type>";
2578 }},
2579 {
2580 R"cpp(// More complicated structured types.
2581 int bar();
2582 ^[[auto]] (*foo)() = bar;
2583 )cpp",
2584 [](HoverInfo &HI) {
2585 HI.Name = "auto";
2586 HI.Kind = index::SymbolKind::TypeAlias;
2587 HI.Definition = "int";
2588 }},
2589 {
2590 R"cpp(// Should not crash when evaluating the initializer.
2591 struct Test {};
2592 void test() { Test && [[te^st]] = {}; }
2593 )cpp",
2594 [](HoverInfo &HI) {
2595 HI.Name = "test";
2596 HI.Kind = index::SymbolKind::Variable;
2597 HI.NamespaceScope = "";
2598 HI.LocalScope = "test::";
2599 HI.Type = "Test &&";
2600 HI.Definition = "Test &&test = {}";
2601 }},
2602 {
2603 R"cpp(// Shouldn't crash when evaluating the initializer.
2604 struct Bar {}; // error-ok
2605 struct Foo { void foo(Bar x = y); }
2606 void Foo::foo(Bar [[^x]]) {})cpp",
2607 [](HoverInfo &HI) {
2608 HI.Name = "x";
2609 HI.Kind = index::SymbolKind::Parameter;
2610 HI.NamespaceScope = "";
2611 HI.LocalScope = "Foo::foo::";
2612 HI.Type = "Bar";
2613 HI.Definition = "Bar x = <recovery - expr>()";
2614 }},
2615 {
2616 R"cpp(// auto on alias
2617 typedef int int_type;
2618 ^[[auto]] x = int_type();
2619 )cpp",
2620 [](HoverInfo &HI) {
2621 HI.Name = "auto";
2622 HI.Kind = index::SymbolKind::TypeAlias;
2623 HI.Definition = "int_type // aka: int";
2624 }},
2625 {
2626 R"cpp(// auto on alias
2627 struct cls {};
2628 typedef cls cls_type;
2629 ^[[auto]] y = cls_type();
2630 )cpp",
2631 [](HoverInfo &HI) {
2632 HI.Name = "auto";
2633 HI.Kind = index::SymbolKind::TypeAlias;
2634 HI.Definition = "cls_type // aka: cls";
2635 HI.Documentation = "auto on alias";
2636 }},
2637 {
2638 R"cpp(// auto on alias
2639 template <class>
2640 struct templ {};
2641 ^[[auto]] z = templ<int>();
2642 )cpp",
2643 [](HoverInfo &HI) {
2644 HI.Name = "auto";
2645 HI.Kind = index::SymbolKind::TypeAlias;
2646 HI.Definition = "templ<int>";
2647 HI.Documentation = "auto on alias";
2648 }},
2649 {
2650 R"cpp(// Undeduced auto declaration
2651 template<typename T>
2652 void foo() {
2653 ^[[auto]] x = T();
2654 }
2655 )cpp",
2656 [](HoverInfo &HI) {
2657 HI.Name = "auto";
2658 HI.Kind = index::SymbolKind::TypeAlias;
2659 HI.Definition = "/* not deduced */";
2660 }},
2661 {
2662 R"cpp(// Undeduced auto return type
2663 template<typename T>
2664 ^[[auto]] foo() {
2665 return T();
2666 }
2667 )cpp",
2668 [](HoverInfo &HI) {
2669 HI.Name = "auto";
2670 HI.Kind = index::SymbolKind::TypeAlias;
2671 HI.Definition = "/* not deduced */";
2672 }},
2673 {
2674 R"cpp(// Template auto parameter
2675 template<[[a^uto]] T>
2676 void func() {
2677 }
2678 )cpp",
2679 [](HoverInfo &HI) {
2680 // FIXME: not sure this is what we want, but this
2681 // is what we currently get with getDeducedType
2682 HI.Name = "auto";
2683 HI.Kind = index::SymbolKind::TypeAlias;
2684 HI.Definition = "/* not deduced */";
2685 }},
2686 {
2687 R"cpp(// Undeduced decltype(auto) return type
2688 template<typename T>
2689 ^[[decltype]](auto) foo() {
2690 return T();
2691 }
2692 )cpp",
2693 [](HoverInfo &HI) {
2694 HI.Name = "decltype";
2695 HI.Kind = index::SymbolKind::TypeAlias;
2696 HI.Definition = "/* not deduced */";
2697 }},
2698 {
2699 R"cpp(// should not crash.
2700 template <class T> struct cls {
2701 int method();
2702 };
2703
2704 auto test = cls<int>().[[m^ethod]]();
2705 )cpp",
2706 [](HoverInfo &HI) {
2707 HI.Definition = "int method()";
2708 HI.Kind = index::SymbolKind::InstanceMethod;
2709 HI.NamespaceScope = "";
2710 HI.LocalScope = "cls<int>::";
2711 HI.Name = "method";
2712 HI.Parameters.emplace();
2713 HI.ReturnType = "int";
2714 HI.Type = "int ()";
2715 }},
2716 {
2717 R"cpp(// type of nested templates.
2718 template <class T> struct cls {};
2719 cls<cls<cls<int>>> [[fo^o]];
2720 )cpp",
2721 [](HoverInfo &HI) {
2722 HI.Definition = "cls<cls<cls<int>>> foo";
2723 HI.Kind = index::SymbolKind::Variable;
2724 HI.NamespaceScope = "";
2725 HI.Name = "foo";
2726 HI.Type = "cls<cls<cls<int>>>";
2727 }},
2728 {
2729 R"cpp(// type of nested templates.
2730 template <class T> struct cls {};
2731 [[cl^s]]<cls<cls<int>>> foo;
2732 )cpp",
2733 [](HoverInfo &HI) {
2734 HI.Definition = "template <> struct cls<cls<cls<int>>> {}";
2735 HI.Kind = index::SymbolKind::Struct;
2736 HI.NamespaceScope = "";
2737 HI.Name = "cls<cls<cls<int>>>";
2738 HI.Documentation = "type of nested templates.";
2739 }},
2740 {
2741 R"cpp(// type with decltype
2742 int a;
2743 decltype(a) [[b^]] = a;)cpp",
2744 [](HoverInfo &HI) {
2745 HI.Definition = "decltype(a) b = a";
2746 HI.Kind = index::SymbolKind::Variable;
2747 HI.NamespaceScope = "";
2748 HI.Name = "b";
2749 HI.Type = "int";
2750 }},
2751 {
2752 R"cpp(// type with decltype
2753 int a;
2754 decltype(a) c;
2755 decltype(c) [[b^]] = a;)cpp",
2756 [](HoverInfo &HI) {
2757 HI.Definition = "decltype(c) b = a";
2758 HI.Kind = index::SymbolKind::Variable;
2759 HI.NamespaceScope = "";
2760 HI.Name = "b";
2761 HI.Type = "int";
2762 }},
2763 {
2764 R"cpp(// type with decltype
2765 int a;
2766 const decltype(a) [[b^]] = a;)cpp",
2767 [](HoverInfo &HI) {
2768 HI.Definition = "const decltype(a) b = a";
2769 HI.Kind = index::SymbolKind::Variable;
2770 HI.NamespaceScope = "";
2771 HI.Name = "b";
2772 HI.Type = "int";
2773 }},
2774 {
2775 R"cpp(// type with decltype
2776 int a;
2777 auto [[f^oo]](decltype(a) x) -> decltype(a) { return 0; })cpp",
2778 [](HoverInfo &HI) {
2779 HI.Definition = "auto foo(decltype(a) x) -> decltype(a)";
2780 HI.Kind = index::SymbolKind::Function;
2781 HI.NamespaceScope = "";
2782 HI.Name = "foo";
2783 // FIXME: Handle composite types with decltype with a printing
2784 // policy.
2785 HI.Type = {"auto (decltype(a)) -> decltype(a)",
2786 "auto (int) -> int"};
2787 HI.ReturnType = "int";
2788 HI.Parameters = {{{"int"}, std::string("x"), std::nullopt}};
2789 }},
2790 {
2791 R"cpp(// sizeof expr
2792 void foo() {
2793 (void)[[size^of]](char);
2794 })cpp",
2795 [](HoverInfo &HI) {
2796 HI.Name = "expression";
2797 HI.Type = "unsigned long";
2798 HI.Value = "1";
2799 }},
2800 {
2801 R"cpp(// alignof expr
2802 void foo() {
2803 (void)[[align^of]](char);
2804 })cpp",
2805 [](HoverInfo &HI) {
2806 HI.Name = "expression";
2807 HI.Type = "unsigned long";
2808 HI.Value = "1";
2809 }},
2810 {
2811 R"cpp(
2812 template <typename T = int>
2813 void foo(const T& = T()) {
2814 [[f^oo]]<>(3);
2815 })cpp",
2816 [](HoverInfo &HI) {
2817 HI.Name = "foo";
2818 HI.Kind = index::SymbolKind::Function;
2819 HI.Type = "void (const int &)";
2820 HI.ReturnType = "void";
2821 HI.Parameters = {
2822 {{"const int &"}, std::nullopt, std::string("T()")}};
2823 HI.Definition = "template <> void foo<int>(const int &)";
2824 HI.NamespaceScope = "";
2825 }},
2826 {
2827 R"cpp(// should not crash
2828 @interface ObjC {
2829 char [[da^ta]];
2830 }@end
2831 )cpp",
2832 [](HoverInfo &HI) {
2833 HI.Name = "data";
2834 HI.Type = "char";
2835 HI.Kind = index::SymbolKind::Field;
2836 HI.LocalScope = "ObjC::";
2837 HI.NamespaceScope = "";
2838 HI.Definition = "char data";
2839 }},
2840 {
2841 R"cpp(
2842 @interface MYObject
2843 @end
2844 @interface Interface
2845 @property(retain) [[MYOb^ject]] *x;
2846 @end
2847 )cpp",
2848 [](HoverInfo &HI) {
2849 HI.Name = "MYObject";
2850 HI.Kind = index::SymbolKind::Class;
2851 HI.NamespaceScope = "";
2852 HI.Definition = "@interface MYObject\n@end";
2853 }},
2854 {
2855 R"cpp(
2856 @interface MYObject
2857 @end
2858 @interface Interface
2859 - (void)doWith:([[MYOb^ject]] *)object;
2860 @end
2861 )cpp",
2862 [](HoverInfo &HI) {
2863 HI.Name = "MYObject";
2864 HI.Kind = index::SymbolKind::Class;
2865 HI.NamespaceScope = "";
2866 HI.Definition = "@interface MYObject\n@end";
2867 }},
2868 {
2869 R"cpp(// this expr
2870 // comment
2871 namespace ns {
2872 class Foo {
2873 Foo* bar() {
2874 return [[t^his]];
2875 }
2876 };
2877 }
2878 )cpp",
2879 [](HoverInfo &HI) {
2880 HI.Name = "this";
2881 HI.Definition = "ns::Foo *";
2882 }},
2883 {
2884 R"cpp(// this expr for template class
2885 namespace ns {
2886 template <typename T>
2887 class Foo {
2888 Foo* bar() const {
2889 return [[t^his]];
2890 }
2891 };
2892 }
2893 )cpp",
2894 [](HoverInfo &HI) {
2895 HI.Name = "this";
2896 HI.Definition = "const Foo<T> *";
2897 }},
2898 {
2899 R"cpp(// this expr for specialization class
2900 namespace ns {
2901 template <typename T> class Foo {};
2902 template <>
2903 struct Foo<int> {
2904 Foo* bar() {
2905 return [[thi^s]];
2906 }
2907 };
2908 }
2909 )cpp",
2910 [](HoverInfo &HI) {
2911 HI.Name = "this";
2912 HI.Definition = "Foo<int> *";
2913 }},
2914 {
2915 R"cpp(// this expr for partial specialization struct
2916 namespace ns {
2917 template <typename T, typename F> struct Foo {};
2918 template <typename F>
2919 struct Foo<int, F> {
2920 Foo* bar() const {
2921 return [[thi^s]];
2922 }
2923 };
2924 }
2925 )cpp",
2926 [](HoverInfo &HI) {
2927 HI.Name = "this";
2928 HI.Definition = "const Foo<int, F> *";
2929 }},
2930 {
2931 R"cpp(
2932 @interface MYObject
2933 @end
2934 @interface MYObject (Private)
2935 @property(nonatomic, assign) int privateField;
2936 @end
2937
2938 int someFunction() {
2939 MYObject *obj = [MYObject sharedInstance];
2940 return obj.[[private^Field]];
2941 }
2942 )cpp",
2943 [](HoverInfo &HI) {
2944 HI.Name = "privateField";
2945 HI.Kind = index::SymbolKind::InstanceProperty;
2946 HI.LocalScope = "MYObject(Private)::";
2947 HI.NamespaceScope = "";
2948 HI.Definition = "@property(nonatomic, assign, unsafe_unretained, "
2949 "readwrite) int privateField;";
2950 }},
2951 {
2952 R"cpp(
2953 @protocol MYProtocol
2954 @property(nonatomic, assign) int prop1;
2955 @end
2956
2957 int someFunction() {
2958 id<MYProtocol> obj = 0;
2959 return obj.[[pro^p1]];
2960 }
2961 )cpp",
2962 [](HoverInfo &HI) {
2963 HI.Name = "prop1";
2964 HI.Kind = index::SymbolKind::InstanceProperty;
2965 HI.LocalScope = "MYProtocol::";
2966 HI.NamespaceScope = "";
2967 HI.Definition = "@property(nonatomic, assign, unsafe_unretained, "
2968 "readwrite) int prop1;";
2969 }},
2970 {
2971 R"cpp(
2972 @protocol MYProtocol
2973 @end
2974 @interface MYObject
2975 @end
2976
2977 @interface MYObject (Ext) <[[MYProt^ocol]]>
2978 @end
2979 )cpp",
2980 [](HoverInfo &HI) {
2981 HI.Name = "MYProtocol";
2982 HI.Kind = index::SymbolKind::Protocol;
2983 HI.NamespaceScope = "";
2984 HI.Definition = "@protocol MYProtocol\n@end";
2985 }},
2986 {R"objc(
2987 @interface Foo
2988 @end
2989
2990 @implementation Foo(Private)
2991 + (int)somePrivateMethod {
2992 int [[res^ult]] = 2;
2993 return result;
2994 }
2995 @end
2996 )objc",
2997 [](HoverInfo &HI) {
2998 HI.Name = "result";
2999 HI.Definition = "int result = 2";
3000 HI.Kind = index::SymbolKind::Variable;
3001 HI.Type = "int";
3002 HI.LocalScope = "+[Foo(Private) somePrivateMethod]::";
3003 HI.NamespaceScope = "";
3004 HI.Value = "2";
3005 }},
3006 {R"objc(
3007 @interface Foo
3008 @end
3009
3010 @implementation Foo
3011 - (int)variadicArgMethod:(id)first, ... {
3012 int [[res^ult]] = 0;
3013 return result;
3014 }
3015 @end
3016 )objc",
3017 [](HoverInfo &HI) {
3018 HI.Name = "result";
3019 HI.Definition = "int result = 0";
3020 HI.Kind = index::SymbolKind::Variable;
3021 HI.Type = "int";
3022 HI.LocalScope = "-[Foo variadicArgMethod:, ...]::";
3023 HI.NamespaceScope = "";
3024 HI.Value = "0";
3025 }},
3026 // Should not crash.
3027 {R"objc(
3028 typedef struct MyRect {} MyRect;
3029
3030 @interface IFace
3031 @property(nonatomic) MyRect frame;
3032 @end
3033
3034 MyRect foobar() {
3035 MyRect mr;
3036 return mr;
3037 }
3038 void test() {
3039 IFace *v;
3040 v.frame = [[foo^bar]]();
3041 }
3042 )objc",
3043 [](HoverInfo &HI) {
3044 HI.Name = "foobar";
3045 HI.Kind = index::SymbolKind::Function;
3046 HI.NamespaceScope = "";
3047 HI.Definition = "MyRect foobar()";
3048 HI.Type = {"MyRect ()", "MyRect ()"};
3049 HI.ReturnType = {"MyRect", "MyRect"};
3050 HI.Parameters.emplace();
3051 }},
3052 {R"cpp(
3053 void foo(int * __attribute__(([[non^null]], noescape)) );
3054 )cpp",
3055 [](HoverInfo &HI) {
3056 HI.Name = "nonnull";
3057 HI.Kind = index::SymbolKind::Unknown; // FIXME: no suitable value
3058 HI.Definition = "__attribute__((nonnull))";
3059 HI.Documentation = Attr::getDocumentation(attr::NonNull).str();
3060 }},
3061 {
3062 R"cpp(
3063 namespace std {
3064 struct strong_ordering {
3065 int n;
3066 constexpr operator int() const { return n; }
3067 static const strong_ordering equal, greater, less;
3068 };
3069 constexpr strong_ordering strong_ordering::equal = {0};
3070 constexpr strong_ordering strong_ordering::greater = {1};
3071 constexpr strong_ordering strong_ordering::less = {-1};
3072 }
3073
3074 struct Foo
3075 {
3076 int x;
3077 // Foo spaceship
3078 auto operator<=>(const Foo&) const = default;
3079 };
3080
3081 bool x = Foo(1) [[!^=]] Foo(2);
3082 )cpp",
3083 [](HoverInfo &HI) {
3084 HI.Type = "bool (const Foo &) const noexcept";
3085 HI.Value = "true";
3086 HI.Name = "operator==";
3087 HI.Parameters = {{{"const Foo &"}, std::nullopt, std::nullopt}};
3088 HI.ReturnType = "bool";
3089 HI.Kind = index::SymbolKind::InstanceMethod;
3090 HI.LocalScope = "Foo::";
3091 HI.NamespaceScope = "";
3092 HI.Definition =
3093 "bool operator==(const Foo &) const noexcept = default";
3094 HI.Documentation = "";
3095 }},
3096 };
3097
3098 // Create a tiny index, so tests above can verify documentation is fetched.
3099 Symbol IndexSym = func("indexSymbol");
3100 IndexSym.Documentation = "comment from index";
3101 SymbolSlab::Builder Symbols;
3102 Symbols.insert(IndexSym);
3103 auto Index =
3104 MemIndex::build(std::move(Symbols).build(), RefSlab(), RelationSlab());
3105
3106 for (const auto &Case : Cases) {
3107 SCOPED_TRACE(Case.Code);
3108
3109 Annotations T(Case.Code);
3110 TestTU TU = TestTU::withCode(T.code());
3111 TU.ExtraArgs.push_back("-std=c++20");
3112 TU.ExtraArgs.push_back("-xobjective-c++");
3113
3114 TU.ExtraArgs.push_back("-Wno-gnu-designator");
3115 // Types might be different depending on the target triplet, we chose a
3116 // fixed one to make sure tests passes on different platform.
3117 TU.ExtraArgs.push_back("--target=x86_64-pc-linux-gnu");
3118 auto AST = TU.build();
3119 Config Cfg;
3120 Cfg.Hover.ShowAKA = true;
3121 WithContextValue WithCfg(Config::Key, std::move(Cfg));
3122 auto H = getHover(AST, T.point(), format::getLLVMStyle(), Index.get());
3123 ASSERT_TRUE(H);
3124 HoverInfo Expected;
3125 Expected.SymRange = T.range();
3126 Case.ExpectedBuilder(Expected);
3127
3128 SCOPED_TRACE(H->present().asPlainText());
3129 EXPECT_EQ(H->NamespaceScope, Expected.NamespaceScope);
3130 EXPECT_EQ(H->LocalScope, Expected.LocalScope);
3131 EXPECT_EQ(H->Name, Expected.Name);
3132 EXPECT_EQ(H->Kind, Expected.Kind);
3133 EXPECT_EQ(H->Documentation, Expected.Documentation);
3134 EXPECT_EQ(H->Definition, Expected.Definition);
3135 EXPECT_EQ(H->Type, Expected.Type);
3136 EXPECT_EQ(H->ReturnType, Expected.ReturnType);
3137 EXPECT_EQ(H->Parameters, Expected.Parameters);
3138 EXPECT_EQ(H->TemplateParameters, Expected.TemplateParameters);
3139 EXPECT_EQ(H->SymRange, Expected.SymRange);
3140 EXPECT_EQ(H->Value, Expected.Value);
3141 }
3142}
3143
3144TEST(Hover, Providers) {
3145 struct {
3146 const char *Code;
3147 const std::function<void(HoverInfo &)> ExpectedBuilder;
3148 } Cases[] = {{R"cpp(
3149 struct Foo {};
3150 Foo F = Fo^o{};
3151 )cpp",
3152 [](HoverInfo &HI) { HI.Provider = ""; }},
3153 {R"cpp(
3154 #include "foo.h"
3155 Foo F = Fo^o{};
3156 )cpp",
3157 [](HoverInfo &HI) { HI.Provider = "\"foo.h\""; }},
3158 {R"cpp(
3159 #include "all.h"
3160 Foo F = Fo^o{};
3161 )cpp",
3162 [](HoverInfo &HI) { HI.Provider = "\"foo.h\""; }},
3163 {R"cpp(
3164 #define FOO 5
3165 int F = ^FOO;
3166 )cpp",
3167 [](HoverInfo &HI) { HI.Provider = ""; }},
3168 {R"cpp(
3169 #include "foo.h"
3170 int F = ^FOO;
3171 )cpp",
3172 [](HoverInfo &HI) { HI.Provider = "\"foo.h\""; }},
3173 {R"cpp(
3174 #include "all.h"
3175 int F = ^FOO;
3176 )cpp",
3177 [](HoverInfo &HI) { HI.Provider = "\"foo.h\""; }},
3178 {R"cpp(
3179 #include "foo.h"
3180 Foo A;
3181 Foo B;
3182 Foo C = A ^+ B;
3183 )cpp",
3184 [](HoverInfo &HI) { HI.Provider = "\"foo.h\""; }},
3185 // Hover selects the underlying decl of the using decl
3186 {R"cpp(
3187 #include "foo.h"
3188 namespace ns {
3189 using ::Foo;
3190 }
3191 ns::F^oo d;
3192 )cpp",
3193 [](HoverInfo &HI) { HI.Provider = "\"foo.h\""; }},
3194 {R"cpp(
3195 namespace foo {};
3196 using namespace fo^o;
3197 )cpp",
3198 [](HoverInfo &HI) { HI.Provider = ""; }},
3199 };
3200
3201 for (const auto &Case : Cases) {
3202 Annotations Code{Case.Code};
3203 SCOPED_TRACE(Code.code());
3204
3205 TestTU TU;
3206 TU.Filename = "foo.cpp";
3207 TU.Code = Code.code();
3208 TU.AdditionalFiles["foo.h"] = guard(R"cpp(
3209 #define FOO 1
3210 class Foo {};
3211 Foo& operator+(const Foo, const Foo);
3212 )cpp");
3213 TU.AdditionalFiles["all.h"] = guard("#include \"foo.h\"");
3214
3215 auto AST = TU.build();
3216 auto H = getHover(AST, Code.point(), format::getLLVMStyle(), nullptr);
3217 ASSERT_TRUE(H);
3218 HoverInfo Expected;
3219 Case.ExpectedBuilder(Expected);
3220 SCOPED_TRACE(H->present().asMarkdown());
3221 EXPECT_EQ(H->Provider, Expected.Provider);
3222 }
3223}
3224
3225TEST(Hover, ParseProviderInfo) {
3226 HoverInfo HIFoo;
3227 HIFoo.Name = "foo";
3228 HIFoo.Provider = "\"foo.h\"";
3229
3230 HoverInfo HIFooBar;
3231 HIFooBar.Name = "foo";
3232 HIFooBar.Provider = "<bar.h>";
3233 struct Case {
3234 HoverInfo HI;
3235 llvm::StringRef ExpectedMarkdown;
3236 } Cases[] = {{HIFoo, "### `foo` \nprovided by `\"foo.h\"`"},
3237 {HIFooBar, "### `foo` \nprovided by `<bar.h>`"}};
3238
3239 for (const auto &Case : Cases)
3240 EXPECT_EQ(Case.HI.present().asMarkdown(), Case.ExpectedMarkdown);
3241}
3242
3243TEST(Hover, UsedSymbols) {
3244 struct {
3245 const char *Code;
3246 const std::function<void(HoverInfo &)> ExpectedBuilder;
3247 } Cases[] = {{R"cpp(
3248 #include ^"bar.h"
3249 int fstBar = bar1();
3250 int another= bar1(0);
3251 int sndBar = bar2();
3252 Bar bar;
3253 int macroBar = BAR;
3254 )cpp",
3255 [](HoverInfo &HI) {
3256 HI.UsedSymbolNames = {"BAR", "Bar", "bar1", "bar2"};
3257 }},
3258 {R"cpp(
3259 #in^clude <vector>
3260 std::vector<int> vec;
3261 )cpp",
3262 [](HoverInfo &HI) { HI.UsedSymbolNames = {"vector"}; }}};
3263 for (const auto &Case : Cases) {
3264 Annotations Code{Case.Code};
3265 SCOPED_TRACE(Code.code());
3266
3267 TestTU TU;
3268 TU.Filename = "foo.cpp";
3269 TU.Code = Code.code();
3270 TU.AdditionalFiles["bar.h"] = guard(R"cpp(
3271 #define BAR 5
3272 int bar1();
3273 int bar2();
3274 int bar1(double);
3275 class Bar {};
3276 )cpp");
3277 TU.AdditionalFiles["system/vector"] = guard(R"cpp(
3278 namespace std {
3279 template<typename>
3280 class vector{};
3281 }
3282 )cpp");
3283 TU.ExtraArgs.push_back("-isystem" + testPath("system"));
3284
3285 auto AST = TU.build();
3286 auto H = getHover(AST, Code.point(), format::getLLVMStyle(), nullptr);
3287 ASSERT_TRUE(H);
3288 HoverInfo Expected;
3289 Case.ExpectedBuilder(Expected);
3290 SCOPED_TRACE(H->present().asMarkdown());
3291 EXPECT_EQ(H->UsedSymbolNames, Expected.UsedSymbolNames);
3292 }
3293}
3294
3295TEST(Hover, DocsFromIndex) {
3296 Annotations T(R"cpp(
3297 template <typename T> class X {};
3298 void foo() {
3299 auto t = X<int>();
3300 X^<int> w;
3301 (void)w;
3302 })cpp");
3303
3304 TestTU TU = TestTU::withCode(T.code());
3305 auto AST = TU.build();
3306 Symbol IndexSym;
3307 IndexSym.ID = getSymbolID(&findDecl(AST, "X"));
3308 IndexSym.Documentation = "comment from index";
3309 SymbolSlab::Builder Symbols;
3310 Symbols.insert(IndexSym);
3311 auto Index =
3312 MemIndex::build(std::move(Symbols).build(), RefSlab(), RelationSlab());
3313
3314 for (const auto &P : T.points()) {
3315 auto H = getHover(AST, P, format::getLLVMStyle(), Index.get());
3316 ASSERT_TRUE(H);
3317 EXPECT_EQ(H->Documentation, IndexSym.Documentation);
3318 }
3319}
3320
3321TEST(Hover, DocsFromAST) {
3322 Annotations T(R"cpp(
3323 // doc
3324 template <typename T> class X {};
3325 // doc
3326 template <typename T> void bar() {}
3327 // doc
3328 template <typename T> T baz;
3329 void foo() {
3330 au^to t = X<int>();
3331 X^<int>();
3332 b^ar<int>();
3333 au^to T = ba^z<X<int>>;
3334 ba^z<int> = 0;
3335 })cpp");
3336
3337 TestTU TU = TestTU::withCode(T.code());
3338 auto AST = TU.build();
3339 for (const auto &P : T.points()) {
3340 auto H = getHover(AST, P, format::getLLVMStyle(), nullptr);
3341 ASSERT_TRUE(H);
3342 EXPECT_EQ(H->Documentation, "doc");
3343 }
3344}
3345
3346TEST(Hover, NoCrash) {
3347 Annotations T(R"cpp(
3348 /* error-ok */
3349 template<typename T> T foo(T);
3350
3351 // Setter variable heuristic might fail if the callexpr is broken.
3352 struct X { int Y; void [[^setY]](float) { Y = foo(undefined); } };)cpp");
3353
3354 TestTU TU = TestTU::withCode(T.code());
3355 auto AST = TU.build();
3356 for (const auto &P : T.points())
3357 getHover(AST, P, format::getLLVMStyle(), nullptr);
3358}
3359
3360TEST(Hover, NoCrashAPInt64) {
3361 Annotations T(R"cpp(
3362 constexpr unsigned long value = -1; // wrap around
3363 void foo() { va^lue; }
3364 )cpp");
3365 auto AST = TestTU::withCode(T.code()).build();
3366 getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
3367}
3368
3369TEST(Hover, NoCrashInt128) {
3370 Annotations T(R"cpp(
3371 constexpr __int128_t value = -4;
3372 void foo() { va^lue; }
3373 )cpp");
3374 auto TU = TestTU::withCode(T.code());
3375 // Need a triple that support __int128_t.
3376 TU.ExtraArgs.push_back("--target=x86_64-pc-linux-gnu");
3377 auto AST = TU.build();
3378 auto H = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
3379 ASSERT_TRUE(H);
3380 EXPECT_EQ(H->Value, "-4 (0xfffffffc)");
3381}
3382
3383TEST(Hover, DocsFromMostSpecial) {
3384 Annotations T(R"cpp(
3385 // doc1
3386 template <typename T> class $doc1^X {};
3387 // doc2
3388 template <> class $doc2^X<int> {};
3389 // doc3
3390 template <typename T> class $doc3^X<T*> {};
3391 void foo() {
3392 X$doc1^<char>();
3393 X$doc2^<int>();
3394 X$doc3^<int*>();
3395 })cpp");
3396
3397 TestTU TU = TestTU::withCode(T.code());
3398 auto AST = TU.build();
3399 for (const auto *Comment : {"doc1", "doc2", "doc3"}) {
3400 for (const auto &P : T.points(Comment)) {
3401 auto H = getHover(AST, P, format::getLLVMStyle(), nullptr);
3402 ASSERT_TRUE(H);
3403 EXPECT_EQ(H->Documentation, Comment);
3404 }
3405 }
3406}
3407
3408TEST(Hover, Present) {
3409 struct {
3410 const std::function<void(HoverInfo &)> Builder;
3411 llvm::StringRef ExpectedRender;
3412 } Cases[] = {
3413 {
3414 [](HoverInfo &HI) {
3415 HI.Kind = index::SymbolKind::Unknown;
3416 HI.Name = "X";
3417 },
3418 R"(X)",
3419 },
3420 {
3421 [](HoverInfo &HI) {
3422 HI.Kind = index::SymbolKind::NamespaceAlias;
3423 HI.Name = "foo";
3424 },
3425 R"(namespace-alias foo)",
3426 },
3427 {
3428 [](HoverInfo &HI) {
3429 HI.Kind = index::SymbolKind::Class;
3430 HI.Size = 80;
3431 HI.TemplateParameters = {
3432 {{"typename"}, std::string("T"), std::nullopt},
3433 {{"typename"}, std::string("C"), std::string("bool")},
3434 };
3435 HI.Documentation = "documentation";
3436 HI.Definition =
3437 "template <typename T, typename C = bool> class Foo {}";
3438 HI.Name = "foo";
3439 HI.NamespaceScope.emplace();
3440 },
3441 R"(class foo
3442
3443Size: 10 bytes
3444documentation
3445
3446template <typename T, typename C = bool> class Foo {})",
3447 },
3448 {
3449 [](HoverInfo &HI) {
3450 HI.Kind = index::SymbolKind::Function;
3451 HI.Name = "foo";
3452 HI.Type = {"type", "c_type"};
3453 HI.ReturnType = {"ret_type", "can_ret_type"};
3454 HI.Parameters.emplace();
3455 HoverInfo::Param P;
3456 HI.Parameters->push_back(P);
3457 P.Type = {"type", "can_type"};
3458 HI.Parameters->push_back(P);
3459 P.Name = "foo";
3460 HI.Parameters->push_back(P);
3461 P.Default = "default";
3462 HI.Parameters->push_back(P);
3463 HI.NamespaceScope = "ns::";
3464 HI.Definition = "ret_type foo(params) {}";
3465 },
3466 "function foo\n"
3467 "\n"
3468 "→ ret_type (aka can_ret_type)\n"
3469 "Parameters:\n"
3470 "- \n"
3471 "- type (aka can_type)\n"
3472 "- type foo (aka can_type)\n"
3473 "- type foo = default (aka can_type)\n"
3474 "\n"
3475 "// In namespace ns\n"
3476 "ret_type foo(params) {}",
3477 },
3478 {
3479 [](HoverInfo &HI) {
3480 HI.Kind = index::SymbolKind::Field;
3481 HI.LocalScope = "test::Bar::";
3482 HI.Value = "value";
3483 HI.Name = "foo";
3484 HI.Type = {"type", "can_type"};
3485 HI.Definition = "def";
3486 HI.Size = 32;
3487 HI.Offset = 96;
3488 HI.Padding = 32;
3489 HI.Align = 32;
3490 },
3491 R"(field foo
3492
3493Type: type (aka can_type)
3494Value = value
3495Offset: 12 bytes
3496Size: 4 bytes (+4 bytes padding), alignment 4 bytes
3497
3498// In test::Bar
3499def)",
3500 },
3501 {
3502 [](HoverInfo &HI) {
3503 HI.Kind = index::SymbolKind::Field;
3504 HI.LocalScope = "test::Bar::";
3505 HI.Value = "value";
3506 HI.Name = "foo";
3507 HI.Type = {"type", "can_type"};
3508 HI.Definition = "def";
3509 HI.Size = 25;
3510 HI.Offset = 35;
3511 HI.Padding = 4;
3512 HI.Align = 64;
3513 },
3514 R"(field foo
3515
3516Type: type (aka can_type)
3517Value = value
3518Offset: 4 bytes and 3 bits
3519Size: 25 bits (+4 bits padding), alignment 8 bytes
3520
3521// In test::Bar
3522def)",
3523 },
3524 {
3525 [](HoverInfo &HI) {
3526 HI.Kind = index::SymbolKind::Field;
3527 HI.AccessSpecifier = "public";
3528 HI.Name = "foo";
3529 HI.LocalScope = "test::Bar::";
3530 HI.Definition = "def";
3531 },
3532 R"(field foo
3533
3534// In test::Bar
3535public: def)",
3536 },
3537 {
3538 [](HoverInfo &HI) {
3539 HI.Definition = "size_t method()";
3540 HI.AccessSpecifier = "protected";
3541 HI.Kind = index::SymbolKind::InstanceMethod;
3542 HI.NamespaceScope = "";
3543 HI.LocalScope = "cls<int>::";
3544 HI.Name = "method";
3545 HI.Parameters.emplace();
3546 HI.ReturnType = {"size_t", "unsigned long"};
3547 HI.Type = {"size_t ()", "unsigned long ()"};
3548 },
3549 R"(instance-method method
3550
3551→ size_t (aka unsigned long)
3552
3553// In cls<int>
3554protected: size_t method())",
3555 },
3556 {
3557 [](HoverInfo &HI) {
3558 HI.Definition = "cls(int a, int b = 5)";
3559 HI.AccessSpecifier = "public";
3560 HI.Kind = index::SymbolKind::Constructor;
3561 HI.NamespaceScope = "";
3562 HI.LocalScope = "cls";
3563 HI.Name = "cls";
3564 HI.Parameters.emplace();
3565 HI.Parameters->emplace_back();
3566 HI.Parameters->back().Type = "int";
3567 HI.Parameters->back().Name = "a";
3568 HI.Parameters->emplace_back();
3569 HI.Parameters->back().Type = "int";
3570 HI.Parameters->back().Name = "b";
3571 HI.Parameters->back().Default = "5";
3572 },
3573 R"(constructor cls
3574
3575Parameters:
3576- int a
3577- int b = 5
3578
3579// In cls
3580public: cls(int a, int b = 5))",
3581 },
3582 {
3583 [](HoverInfo &HI) {
3584 HI.Kind = index::SymbolKind::Union;
3585 HI.AccessSpecifier = "private";
3586 HI.Name = "foo";
3587 HI.NamespaceScope = "ns1::";
3588 HI.Definition = "union foo {}";
3589 },
3590 R"(union foo
3591
3592// In namespace ns1
3593private: union foo {})",
3594 },
3595 {
3596 [](HoverInfo &HI) {
3597 HI.Kind = index::SymbolKind::Variable;
3598 HI.Name = "foo";
3599 HI.Definition = "int foo = 3";
3600 HI.LocalScope = "test::Bar::";
3601 HI.Value = "3";
3602 HI.Type = "int";
3603 HI.CalleeArgInfo.emplace();
3604 HI.CalleeArgInfo->Name = "arg_a";
3605 HI.CalleeArgInfo->Type = "int";
3606 HI.CalleeArgInfo->Default = "7";
3607 HI.CallPassType = HoverInfo::PassType{PassMode::Value, false};
3608 },
3609 R"(variable foo
3610
3611Type: int
3612Value = 3
3613Passed as arg_a
3614
3615// In test::Bar
3616int foo = 3)",
3617 },
3618 {
3619 [](HoverInfo &HI) {
3620 HI.Kind = index::SymbolKind::Variable;
3621 HI.Name = "foo";
3622 HI.CalleeArgInfo.emplace();
3623 HI.CalleeArgInfo->Type = "int";
3624 HI.CallPassType = HoverInfo::PassType{PassMode::Value, false};
3625 },
3626 R"(variable foo
3627
3628Passed by value)",
3629 },
3630 {
3631 [](HoverInfo &HI) {
3632 HI.Kind = index::SymbolKind::Variable;
3633 HI.Name = "foo";
3634 HI.Definition = "int foo = 3";
3635 HI.LocalScope = "test::Bar::";
3636 HI.Value = "3";
3637 HI.Type = "int";
3638 HI.CalleeArgInfo.emplace();
3639 HI.CalleeArgInfo->Name = "arg_a";
3640 HI.CalleeArgInfo->Type = "int";
3641 HI.CalleeArgInfo->Default = "7";
3642 HI.CallPassType = HoverInfo::PassType{PassMode::Ref, false};
3643 },
3644 R"(variable foo
3645
3646Type: int
3647Value = 3
3648Passed by reference as arg_a
3649
3650// In test::Bar
3651int foo = 3)",
3652 },
3653 {
3654 [](HoverInfo &HI) {
3655 HI.Kind = index::SymbolKind::Variable;
3656 HI.Name = "foo";
3657 HI.Definition = "int foo = 3";
3658 HI.LocalScope = "test::Bar::";
3659 HI.Value = "3";
3660 HI.Type = "int";
3661 HI.CalleeArgInfo.emplace();
3662 HI.CalleeArgInfo->Name = "arg_a";
3663 HI.CalleeArgInfo->Type = {"alias_int", "int"};
3664 HI.CalleeArgInfo->Default = "7";
3665 HI.CallPassType = HoverInfo::PassType{PassMode::Value, true};
3666 },
3667 R"(variable foo
3668
3669Type: int
3670Value = 3
3671Passed as arg_a (converted to alias_int)
3672
3673// In test::Bar
3674int foo = 3)",
3675 },
3676 {
3677 [](HoverInfo &HI) {
3678 HI.Kind = index::SymbolKind::Macro;
3679 HI.Name = "PLUS_ONE";
3680 HI.Definition = "#define PLUS_ONE(X) (X+1)\n\n"
3681 "// Expands to\n"
3682 "(1 + 1)";
3683 },
3684 R"(macro PLUS_ONE
3685
3686#define PLUS_ONE(X) (X+1)
3687
3688// Expands to
3689(1 + 1))",
3690 },
3691 {
3692 [](HoverInfo &HI) {
3693 HI.Kind = index::SymbolKind::Variable;
3694 HI.Name = "foo";
3695 HI.Definition = "int foo = 3";
3696 HI.LocalScope = "test::Bar::";
3697 HI.Value = "3";
3698 HI.Type = "int";
3699 HI.CalleeArgInfo.emplace();
3700 HI.CalleeArgInfo->Name = "arg_a";
3701 HI.CalleeArgInfo->Type = "int";
3702 HI.CalleeArgInfo->Default = "7";
3703 HI.CallPassType = HoverInfo::PassType{PassMode::ConstRef, true};
3704 },
3705 R"(variable foo
3706
3707Type: int
3708Value = 3
3709Passed by const reference as arg_a (converted to int)
3710
3711// In test::Bar
3712int foo = 3)",
3713 },
3714 {
3715 [](HoverInfo &HI) {
3716 HI.Name = "stdio.h";
3717 HI.Definition = "/usr/include/stdio.h";
3718 },
3719 R"(stdio.h
3720
3721/usr/include/stdio.h)",
3722 },
3723 {[](HoverInfo &HI) {
3724 HI.Name = "foo.h";
3725 HI.UsedSymbolNames = {"Foo", "Bar", "Bar"};
3726 },
3727 R"(foo.h
3728
3729provides Foo, Bar, Bar)"},
3730 {[](HoverInfo &HI) {
3731 HI.Name = "foo.h";
3732 HI.UsedSymbolNames = {"Foo", "Bar", "Baz", "Foobar", "Qux", "Quux"};
3733 },
3734 R"(foo.h
3735
3736provides Foo, Bar, Baz, Foobar, Qux and 1 more)"}};
3737
3738 for (const auto &C : Cases) {
3739 HoverInfo HI;
3740 C.Builder(HI);
3741 Config Cfg;
3742 Cfg.Hover.ShowAKA = true;
3743 WithContextValue WithCfg(Config::Key, std::move(Cfg));
3744 EXPECT_EQ(HI.present().asPlainText(), C.ExpectedRender);
3745 }
3746}
3747
3748TEST(Hover, ParseDocumentation) {
3749 struct Case {
3750 llvm::StringRef Documentation;
3751 llvm::StringRef ExpectedRenderMarkdown;
3752 llvm::StringRef ExpectedRenderPlainText;
3753 } Cases[] = {{
3754 " \n foo\nbar",
3755 "foo bar",
3756 "foo bar",
3757 },
3758 {
3759 "foo\nbar \n ",
3760 "foo bar",
3761 "foo bar",
3762 },
3763 {
3764 "foo \nbar",
3765 "foo bar",
3766 "foo bar",
3767 },
3768 {
3769 "foo \nbar",
3770 "foo bar",
3771 "foo bar",
3772 },
3773 {
3774 "foo\n\n\nbar",
3775 "foo \nbar",
3776 "foo\nbar",
3777 },
3778 {
3779 "foo\n\n\n\tbar",
3780 "foo \nbar",
3781 "foo\nbar",
3782 },
3783 {
3784 "foo\n\n\n bar",
3785 "foo \nbar",
3786 "foo\nbar",
3787 },
3788 {
3789 "foo.\nbar",
3790 "foo. \nbar",
3791 "foo.\nbar",
3792 },
3793 {
3794 "foo. \nbar",
3795 "foo. \nbar",
3796 "foo.\nbar",
3797 },
3798 {
3799 "foo\n*bar",
3800 "foo \n\\*bar",
3801 "foo\n*bar",
3802 },
3803 {
3804 "foo\nbar",
3805 "foo bar",
3806 "foo bar",
3807 },
3808 {
3809 "Tests primality of `p`.",
3810 "Tests primality of `p`.",
3811 "Tests primality of `p`.",
3812 },
3813 {
3814 "'`' should not occur in `Code`",
3815 "'\\`' should not occur in `Code`",
3816 "'`' should not occur in `Code`",
3817 },
3818 {
3819 "`not\nparsed`",
3820 "\\`not parsed\\`",
3821 "`not parsed`",
3822 }};
3823
3824 for (const auto &C : Cases) {
3825 markup::Document Output;
3826 parseDocumentation(C.Documentation, Output);
3827
3828 EXPECT_EQ(Output.asMarkdown(), C.ExpectedRenderMarkdown);
3829 EXPECT_EQ(Output.asPlainText(), C.ExpectedRenderPlainText);
3830 }
3831}
3832
3833// This is a separate test as headings don't create any differences in
3834// plaintext mode.
3835TEST(Hover, PresentHeadings) {
3836 HoverInfo HI;
3837 HI.Kind = index::SymbolKind::Variable;
3838 HI.Name = "foo";
3839
3840 EXPECT_EQ(HI.present().asMarkdown(), "### variable `foo`");
3841}
3842
3843// This is a separate test as rulers behave differently in markdown vs
3844// plaintext.
3845TEST(Hover, PresentRulers) {
3846 HoverInfo HI;
3847 HI.Kind = index::SymbolKind::Variable;
3848 HI.Name = "foo";
3849 HI.Value = "val";
3850 HI.Definition = "def";
3851
3852 llvm::StringRef ExpectedMarkdown = //
3853 "### variable `foo` \n"
3854 "\n"
3855 "---\n"
3856 "Value = `val` \n"
3857 "\n"
3858 "---\n"
3859 "```cpp\n"
3860 "def\n"
3861 "```";
3862 EXPECT_EQ(HI.present().asMarkdown(), ExpectedMarkdown);
3863
3864 llvm::StringRef ExpectedPlaintext = R"pt(variable foo
3865
3866Value = val
3867
3868def)pt";
3869 EXPECT_EQ(HI.present().asPlainText(), ExpectedPlaintext);
3870}
3871
3872TEST(Hover, SpaceshipTemplateNoCrash) {
3873 Annotations T(R"cpp(
3874 namespace std {
3875 struct strong_ordering {
3876 int n;
3877 constexpr operator int() const { return n; }
3878 static const strong_ordering equal, greater, less;
3879 };
3880 constexpr strong_ordering strong_ordering::equal = {0};
3881 constexpr strong_ordering strong_ordering::greater = {1};
3882 constexpr strong_ordering strong_ordering::less = {-1};
3883 }
3884
3885 template <typename T>
3886 struct S {
3887 // Foo bar baz
3888 friend auto operator<=>(S, S) = default;
3889 };
3890 static_assert(S<void>() =^= S<void>());
3891 )cpp");
3892
3893 TestTU TU = TestTU::withCode(T.code());
3894 TU.ExtraArgs.push_back("-std=c++20");
3895 auto AST = TU.build();
3896 auto HI = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
3897 EXPECT_EQ(HI->Documentation, "");
3898}
3899
3900TEST(Hover, ForwardStructNoCrash) {
3901 Annotations T(R"cpp(
3902 struct Foo;
3903 int bar;
3904 auto baz = (Fo^o*)&bar;
3905 )cpp");
3906
3907 TestTU TU = TestTU::withCode(T.code());
3908 auto AST = TU.build();
3909 auto HI = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
3910 ASSERT_TRUE(HI);
3911 EXPECT_EQ(*HI->Value, "&bar");
3912}
3913
3914TEST(Hover, FunctionParameterDefaulValueNotEvaluatedOnInvalidDecls) {
3915 struct {
3916 const char *const Code;
3917 const std::optional<std::string> HoverValue;
3918 } Cases[] = {
3919 {R"cpp(
3920 // error-ok testing behavior on invalid decl
3921 class Foo {};
3922 void foo(Foo p^aram = nullptr);
3923 )cpp",
3924 std::nullopt},
3925 {R"cpp(
3926 class Foo {};
3927 void foo(Foo *p^aram = nullptr);
3928 )cpp",
3929 "nullptr"},
3930 };
3931
3932 for (const auto &C : Cases) {
3933 Annotations T(C.Code);
3934 TestTU TU = TestTU::withCode(T.code());
3935 auto AST = TU.build();
3936 auto HI = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
3937 ASSERT_TRUE(HI);
3938 ASSERT_EQ(HI->Value, C.HoverValue);
3939 }
3940}
3941
3942TEST(Hover, DisableShowAKA) {
3943 Annotations T(R"cpp(
3944 using m_int = int;
3945 m_int ^[[a]];
3946 )cpp");
3947
3948 Config Cfg;
3949 Cfg.Hover.ShowAKA = false;
3950 WithContextValue WithCfg(Config::Key, std::move(Cfg));
3951
3952 TestTU TU = TestTU::withCode(T.code());
3953 TU.ExtraArgs.push_back("-std=c++17");
3954 auto AST = TU.build();
3955 auto H = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
3956
3957 ASSERT_TRUE(H);
3958 EXPECT_EQ(H->Type, HoverInfo::PrintedType("m_int"));
3959}
3960
3961TEST(Hover, HideBigInitializers) {
3962 Annotations T(R"cpp(
3963 #define A(x) x, x, x, x
3964 #define B(x) A(A(A(A(x))))
3965 int a^rr[] = {B(0)};
3966 )cpp");
3967
3968 TestTU TU = TestTU::withCode(T.code());
3969 auto AST = TU.build();
3970 auto H = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
3971
3972 ASSERT_TRUE(H);
3973 EXPECT_EQ(H->Definition, "int arr[]");
3974}
3975
3976#if defined(__aarch64__)
3977// FIXME: AARCH64 sanitizer buildbots are broken after 72142fbac4.
3978#define PREDEFINEMACROS_TEST(x) DISABLED_##x
3979#else
3980#define PREDEFINEMACROS_TEST(x) x
3981#endif
3982
3983TEST(Hover, PREDEFINEMACROS_TEST(GlobalVarEnumeralCastNoCrash)) {
3984 Annotations T(R"cpp(
3985 using uintptr_t = __UINTPTR_TYPE__;
3986 enum Test : uintptr_t {};
3987 unsigned global_var;
3988 void foo() {
3989 Test v^al = static_cast<Test>(reinterpret_cast<uintptr_t>(&global_var));
3990 }
3991 )cpp");
3992
3993 TestTU TU = TestTU::withCode(T.code());
3994 TU.PredefineMacros = true;
3995 auto AST = TU.build();
3996 auto HI = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
3997 ASSERT_TRUE(HI);
3998 EXPECT_EQ(*HI->Value, "&global_var");
3999}
4000
4001TEST(Hover, PREDEFINEMACROS_TEST(GlobalVarIntCastNoCrash)) {
4002 Annotations T(R"cpp(
4003 using uintptr_t = __UINTPTR_TYPE__;
4004 unsigned global_var;
4005 void foo() {
4006 uintptr_t a^ddress = reinterpret_cast<uintptr_t>(&global_var);
4007 }
4008 )cpp");
4009
4010 TestTU TU = TestTU::withCode(T.code());
4011 TU.PredefineMacros = true;
4012 auto AST = TU.build();
4013 auto HI = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
4014 ASSERT_TRUE(HI);
4015 EXPECT_EQ(*HI->Value, "&global_var");
4016}
4017
4018TEST(Hover, Typedefs) {
4019 Annotations T(R"cpp(
4020 template <bool X, typename T, typename F>
4021 struct cond { using type = T; };
4022 template <typename T, typename F>
4023 struct cond<false, T, F> { using type = F; };
4024
4025 template <bool X, typename T, typename F>
4026 using type = typename cond<X, T, F>::type;
4027
4028 void foo() {
4029 using f^oo = type<true, int, double>;
4030 }
4031 )cpp");
4032
4033 TestTU TU = TestTU::withCode(T.code());
4034 auto AST = TU.build();
4035 auto H = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
4036
4037 ASSERT_TRUE(H && H->Type);
4038 EXPECT_EQ(H->Type->Type, "int");
4039 EXPECT_EQ(H->Definition, "using foo = type<true, int, double>");
4040}
4041
4042TEST(Hover, EvaluateMacros) {
4043 llvm::StringRef PredefinedCXX = R"cpp(
4044#define X 42
4045#define SizeOf sizeof
4046#define AlignOf alignof
4047#define PLUS_TWO +2
4048#define TWO 2
4049
4050using u64 = unsigned long long;
4051// calculate (a ** b) % p
4052constexpr u64 pow_with_mod(u64 a, u64 b, u64 p) {
4053 u64 ret = 1;
4054 while (b) {
4055 if (b & 1)
4056 ret = (ret * a) % p;
4057 a = (a * a) % p;
4058 b >>= 1;
4059 }
4060 return ret;
4061}
4062#define last_n_digit(x, y, n) \
4063 pow_with_mod(x, y, pow_with_mod(10, n, 2147483647))
4064#define declare_struct(X, name, value) \
4065 struct X { \
4066 constexpr auto name() { return value; } \
4067 }
4068#define gnu_statement_expression(value) \
4069 ({ \
4070 declare_struct(Widget, getter, value); \
4071 Widget().getter(); \
4072 })
4073#define define_lambda_begin(lambda, ...) \
4074 [&](__VA_ARGS__) {
4075#define define_lambda_end() }
4076
4077#define left_bracket [
4078#define right_bracket ]
4079#define dg_left_bracket <:
4080#define dg_right_bracket :>
4081#define array_decl(type, name, size) type name left_bracket size right_bracket
4082 )cpp";
4083
4084 struct {
4085 llvm::StringRef Code;
4086 const std::function<void(std::optional<HoverInfo>, size_t /*Id*/)>
4087 Validator;
4088 } Cases[] = {
4089 {
4090 /*Code=*/R"cpp(
4091 X^;
4092 )cpp",
4093 /*Validator=*/
4094 [](std::optional<HoverInfo> HI, size_t) {
4095 EXPECT_EQ(HI->Value, "42 (0x2a)");
4096 EXPECT_EQ(HI->Type, HoverInfo::PrintedType("int"));
4097 },
4098 },
4099 {
4100 /*Code=*/R"cpp(
4101 Size^Of(int);
4102 )cpp",
4103 /*Validator=*/
4104 [](std::optional<HoverInfo> HI, size_t) {
4105 EXPECT_TRUE(HI->Value);
4106 EXPECT_TRUE(HI->Type);
4107 // Don't validate type or value of `sizeof` and `alignof` as we're
4108 // getting different values or desugared types on different
4109 // platforms. Same as below.
4110 },
4111 },
4112 {
4113 /*Code=*/R"cpp(
4114 struct Y {
4115 int y;
4116 double z;
4117 };
4118 Alig^nOf(Y);
4119 )cpp",
4120 /*Validator=*/
4121 [](std::optional<HoverInfo> HI, size_t) {
4122 EXPECT_TRUE(HI->Value);
4123 EXPECT_TRUE(HI->Type);
4124 },
4125 },
4126 {
4127 /*Code=*/R"cpp(
4128 // 2**32 == 4294967296
4129 last_n_di^git(2, 32, 6);
4130 )cpp",
4131 /*Validator=*/
4132 [](std::optional<HoverInfo> HI, size_t) {
4133 EXPECT_EQ(HI->Value, "967296 (0xec280)");
4134 EXPECT_EQ(HI->Type, "u64");
4135 },
4136 },
4137 {
4138 /*Code=*/R"cpp(
4139 gnu_statement_exp^ression(42);
4140 )cpp",
4141 /*Validator=*/
4142 [](std::optional<HoverInfo> HI, size_t) {
4143 EXPECT_EQ(HI->Value, "42 (0x2a)");
4144 EXPECT_EQ(HI->Type, "int");
4145 },
4146 },
4147 {
4148 /*Code=*/R"cpp(
4149 40 + PLU^S_TWO;
4150 )cpp",
4151 /*Validator=*/
4152 [](std::optional<HoverInfo> HI, size_t) {
4153 EXPECT_EQ(HI->Value, "2");
4154 EXPECT_EQ(HI->Type, "int");
4155 },
4156 },
4157 {
4158 /*Code=*/R"cpp(
4159 40 PLU^S_TWO;
4160 )cpp",
4161 /*Validator=*/
4162 [](std::optional<HoverInfo> HI, size_t) {
4163 EXPECT_FALSE(HI->Value) << HI->Value;
4164 EXPECT_FALSE(HI->Type) << HI->Type;
4165 },
4166 },
4167 {
4168 /*Code=*/R"cpp(
4169 40 + TW^O;
4170 )cpp",
4171 /*Validator=*/
4172 [](std::optional<HoverInfo> HI, size_t) {
4173 EXPECT_EQ(HI->Value, "2");
4174 EXPECT_EQ(HI->Type, "int");
4175 },
4176 },
4177 {
4178 /*Code=*/R"cpp(
4179 arra^y_decl(int, vector, 10);
4180 vector left_b^racket 3 right_b^racket;
4181 vector dg_le^ft_bracket 3 dg_righ^t_bracket;
4182 )cpp",
4183 /*Validator=*/
4184 [](std::optional<HoverInfo> HI, size_t Id) {
4185 switch (Id) {
4186 case 0:
4187 EXPECT_EQ(HI->Type, HoverInfo::PrintedType("int[10]"));
4188 break;
4189 case 1:
4190 case 2:
4191 case 3:
4192 case 4:
4193 EXPECT_FALSE(HI->Type) << HI->Type;
4194 EXPECT_FALSE(HI->Value) << HI->Value;
4195 break;
4196 default:
4197 ASSERT_TRUE(false) << "Unhandled id: " << Id;
4198 }
4199 },
4200 },
4201 {
4202 /*Code=*/R"cpp(
4203 constexpr auto value = define_lamb^da_begin(lambda, int, char)
4204 // Check if the expansion range is right.
4205 return ^last_n_digit(10, 3, 3)^;
4206 define_lam^bda_end();
4207 )cpp",
4208 /*Validator=*/
4209 [](std::optional<HoverInfo> HI, size_t Id) {
4210 switch (Id) {
4211 case 0:
4212 EXPECT_FALSE(HI->Value);
4213 EXPECT_EQ(HI->Type, HoverInfo::PrintedType("const (lambda)"));
4214 break;
4215 case 1:
4216 EXPECT_EQ(HI->Value, "0");
4217 EXPECT_EQ(HI->Type, HoverInfo::PrintedType("u64"));
4218 break;
4219 case 2:
4220 EXPECT_FALSE(HI);
4221 break;
4222 case 3:
4223 EXPECT_FALSE(HI->Type) << HI->Type;
4224 EXPECT_FALSE(HI->Value) << HI->Value;
4225 break;
4226 default:
4227 ASSERT_TRUE(false) << "Unhandled id: " << Id;
4228 }
4229 },
4230 },
4231 };
4232
4233 Config Cfg;
4234 Cfg.Hover.ShowAKA = false;
4235 WithContextValue WithCfg(Config::Key, std::move(Cfg));
4236 for (const auto &C : Cases) {
4237 Annotations Code(
4238 (PredefinedCXX + "void function() {\n" + C.Code + "}\n").str());
4239 auto TU = TestTU::withCode(Code.code());
4240 TU.ExtraArgs.push_back("-std=c++17");
4241 auto AST = TU.build();
4242 for (auto [Index, Position] : llvm::enumerate(Code.points())) {
4243 C.Validator(getHover(AST, Position, format::getLLVMStyle(), nullptr),
4244 Index);
4245 }
4246 }
4247
4248 Annotations C(R"c(
4249 #define alignof _Alignof
4250 void foo() {
4251 al^ignof(struct { int x; char y[10]; });
4252 }
4253 )c");
4254
4255 auto TU = TestTU::withCode(C.code());
4256 TU.Filename = "TestTU.c";
4257 TU.ExtraArgs = {
4258 "-std=c17",
4259 };
4260 auto AST = TU.build();
4261 auto H = getHover(AST, C.point(), format::getLLVMStyle(), nullptr);
4262
4263 ASSERT_TRUE(H);
4264 EXPECT_TRUE(H->Value);
4265 EXPECT_TRUE(H->Type);
4266}
4267} // namespace
4268} // namespace clangd
4269} // namespace clang
CodeCompletionBuilder Builder
std::string Code
const Criteria C
#define PREDEFINEMACROS_TEST(x)
std::vector< const char * > Expected
std::string Output
Definition: TraceTests.cpp:159
static std::unique_ptr< SymbolIndex > build(SymbolSlab Symbols, RefSlab Refs, RelationSlab Relations)
Builds an index from slabs. The index takes ownership of the data.
Definition: MemIndex.cpp:17
SymbolID getSymbolID(const Decl *D)
Gets the symbol ID for a declaration. Returned SymbolID might be null.
Definition: AST.cpp:331
Symbol func(llvm::StringRef Name)
Definition: TestIndex.cpp:62
const NamedDecl & findDecl(ParsedAST &AST, llvm::StringRef QName)
Definition: TestTU.cpp:219
std::string testPath(PathRef File, llvm::sys::path::Style Style)
Definition: TestFS.cpp:93
std::optional< HoverInfo > getHover(ParsedAST &AST, Position Pos, const format::FormatStyle &Style, const SymbolIndex *Index)
Get the hover information when hovering at Pos.
Definition: Hover.cpp:1283
TEST(BackgroundQueueTest, Priority)
void parseDocumentation(llvm::StringRef Input, markup::Document &Output)
Definition: Hover.cpp:1623
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
static clangd::Key< Config > Key
Context key which can be used to set the current Config.
Definition: Config.h:48
bool ShowAKA
Whether hover show a.k.a type.
Definition: Config.h:139
struct clang::clangd::Config::@7 Hover
Configures hover feature.
ParsedAST build() const
Definition: TestTU.cpp:114
static TestTU withCode(llvm::StringRef Code)
Definition: TestTU.h:36