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

source code of clang-tools-extra/clangd/unittests/HoverTests.cpp