clang-tools 24.0.0git
HoverTests.cpp
Go to the documentation of this file.
1//===-- HoverTests.cpp ----------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "AST.h"
10#include "Annotations.h"
11#include "Config.h"
12#include "Hover.h"
13#include "Protocol.h"
14#include "TestFS.h"
15#include "TestIndex.h"
16#include "TestTU.h"
17#include "index/MemIndex.h"
18#include "clang/AST/Attr.h"
19#include "clang/Format/Format.h"
20#include "clang/Index/IndexSymbol.h"
21#include "llvm/ADT/StringRef.h"
22#include "llvm/ADT/Twine.h"
23
24#include "gtest/gtest.h"
25#include <functional>
26#include <optional>
27#include <string>
28#include <vector>
29
30namespace clang {
31namespace clangd {
32namespace {
33
34using PassMode = HoverInfo::PassType::PassMode;
35
36std::string guard(llvm::StringRef Code) {
37 return "#pragma once\n" + Code.str();
38}
39
40TEST(Hover, Structured) {
41 struct {
42 const char *const Code;
43 const std::function<void(HoverInfo &)> ExpectedBuilder;
44 } Cases[] = {
45 // Global scope.
46 {R"cpp(
47 // Best foo ever.
48 void [[fo^o]]() {}
49 )cpp",
50 [](HoverInfo &HI) {
51 HI.NamespaceScope = "";
52 HI.Name = "foo";
53 HI.Kind = index::SymbolKind::Function;
54 HI.Documentation = "Best foo ever.";
55 HI.Definition = "void foo()";
56 HI.ReturnType = "void";
57 HI.Type = "void ()";
58 HI.Parameters.emplace();
59 }},
60 {R"cpp(
61 // Best foo ever.
62 void [[fo^o]](auto x) {}
63 )cpp",
64 [](HoverInfo &HI) {
65 HI.NamespaceScope = "";
66 HI.Name = "foo";
67 HI.Kind = index::SymbolKind::Function;
68 HI.Documentation = "Best foo ever.";
69 HI.Definition = "void foo(auto x)";
70 HI.ReturnType = "void";
71 HI.Type = "void (auto)";
72 HI.TemplateParameters = {
73 {{"class"}, std::string("x:auto"), std::nullopt},
74 };
75 HI.Parameters = {
76 {{"auto"}, std::string("x"), std::nullopt},
77 };
78 }},
79 {R"cpp(
80 // Best foo ever.
81 template <class T>
82 void [[fo^o]](T x) {}
83 )cpp",
84 [](HoverInfo &HI) {
85 HI.NamespaceScope = "";
86 HI.Name = "foo";
87 HI.Kind = index::SymbolKind::Function;
88 HI.Documentation = "Best foo ever.";
89 HI.Definition = "template <class T> void foo(T x)";
90 HI.ReturnType = "void";
91 HI.Type = "void (T)";
92 HI.TemplateParameters = {
93 {{"class"}, std::string("T"), std::nullopt},
94 };
95 HI.Parameters = {
96 {{"T"}, std::string("x"), std::nullopt},
97 };
98 }},
99 {R"cpp(
100 // Best foo ever.
101 template <class T>
102 void [[fo^o]](T x, auto y) {}
103 )cpp",
104 [](HoverInfo &HI) {
105 HI.NamespaceScope = "";
106 HI.Name = "foo";
107 HI.Kind = index::SymbolKind::Function;
108 HI.Documentation = "Best foo ever.";
109 HI.Definition = "template <class T> void foo(T x, auto y)";
110 HI.ReturnType = "void";
111 HI.Type = "void (T, auto)";
112 HI.TemplateParameters = {
113 {{"class"}, std::string("T"), std::nullopt},
114 {{"class"}, std::string("y:auto"), std::nullopt},
115 };
116 HI.Parameters = {
117 {{"T"}, std::string("x"), std::nullopt},
118 {{"auto"}, std::string("y"), std::nullopt},
119 };
120 }},
121 {R"cpp(
122 template<typename T1, typename T2>
123 concept C = requires () { true; };
124
125 // Best foo ever.
126 template<C<int> T>
127 void [[fo^o]](T x) {}
128 )cpp",
129 [](HoverInfo &HI) {
130 HI.NamespaceScope = "";
131 HI.Name = "foo";
132 HI.Kind = index::SymbolKind::Function;
133 HI.Documentation = "Best foo ever.";
134 HI.Definition = "template <C<int> T> void foo(T x)";
135 HI.ReturnType = "void";
136 HI.Type = "void (T)";
137 HI.TemplateParameters = {
138 {{"class"}, std::string("T"), std::nullopt},
139 };
140 HI.Parameters = {
141 {{"T"}, std::string("x"), std::nullopt},
142 };
143 }},
144 {R"cpp(
145 template<typename T1, typename T2>
146 concept C = requires () { true; };
147
148 // Best foo ever.
149 void [[fo^o]](C<int> auto x) {}
150 )cpp",
151 [](HoverInfo &HI) {
152 HI.NamespaceScope = "";
153 HI.Name = "foo";
154 HI.Kind = index::SymbolKind::Function;
155 HI.Documentation = "Best foo ever.";
156 HI.Definition = "void foo(C<int> auto x)";
157 HI.ReturnType = "void";
158 HI.Type = "void (C<int> auto)";
159 HI.TemplateParameters = {
160 {{"class"}, std::string("x:auto"), std::nullopt},
161 };
162 HI.Parameters = {
163 {{"C<int> auto"}, std::string("x"), std::nullopt},
164 };
165 }},
166 {R"cpp(
167 template<typename T1, typename T2>
168 concept C = requires () { true; };
169
170 // Best foo ever.
171 template<C<int> T>
172 void [[fo^o]](T x, C<int> auto y) {}
173 )cpp",
174 [](HoverInfo &HI) {
175 HI.NamespaceScope = "";
176 HI.Name = "foo";
177 HI.Kind = index::SymbolKind::Function;
178 HI.Documentation = "Best foo ever.";
179 HI.Definition = "template <C<int> T> void foo(T x, C<int> auto y)";
180 HI.ReturnType = "void";
181 HI.Type = "void (T, C<int> auto)";
182 HI.TemplateParameters = {
183 {{"class"}, std::string("T"), std::nullopt},
184 {{"class"}, std::string("y:auto"), std::nullopt},
185 };
186 HI.Parameters = {
187 {{"T"}, std::string("x"), std::nullopt},
188 {{"C<int> auto"}, std::string("y"), std::nullopt},
189 };
190 }},
191 // Inside namespace
192 {R"cpp(
193 namespace ns1 { namespace ns2 {
194 /// Best foo ever.
195 void [[fo^o]]() {}
196 }}
197 )cpp",
198 [](HoverInfo &HI) {
199 HI.NamespaceScope = "ns1::ns2::";
200 HI.Name = "foo";
201 HI.Kind = index::SymbolKind::Function;
202 HI.Documentation = "Best foo ever.";
203 HI.Definition = "void foo()";
204 HI.ReturnType = "void";
205 HI.Type = "void ()";
206 HI.Parameters.emplace();
207 }},
208 // Field
209 {R"cpp(
210 namespace ns1 { namespace ns2 {
211 class Foo {
212 char [[b^ar]];
213 double y[2];
214 };
215 }}
216 )cpp",
217 [](HoverInfo &HI) {
218 HI.NamespaceScope = "ns1::ns2::";
219 HI.LocalScope = "Foo::";
220 HI.Name = "bar";
221 HI.Kind = index::SymbolKind::Field;
222 HI.Definition = "char bar";
223 HI.Type = "char";
224 HI.Offset = 0;
225 HI.Size = 8;
226 HI.Padding = 56;
227 HI.Align = 8;
228 HI.AccessSpecifier = "private";
229 }},
230 // Union field
231 {R"cpp(
232 union Foo {
233 char [[b^ar]];
234 double y[2];
235 };
236 )cpp",
237 [](HoverInfo &HI) {
238 HI.NamespaceScope = "";
239 HI.LocalScope = "Foo::";
240 HI.Name = "bar";
241 HI.Kind = index::SymbolKind::Field;
242 HI.Definition = "char bar";
243 HI.Type = "char";
244 HI.Size = 8;
245 HI.Padding = 120;
246 HI.Align = 8;
247 HI.AccessSpecifier = "public";
248 }},
249 // Bitfield
250 {R"cpp(
251 struct Foo {
252 int [[^x]] : 1;
253 int y : 1;
254 };
255 )cpp",
256 [](HoverInfo &HI) {
257 HI.NamespaceScope = "";
258 HI.LocalScope = "Foo::";
259 HI.Name = "x";
260 HI.Kind = index::SymbolKind::Field;
261 HI.Definition = "int x : 1";
262 HI.Type = "int";
263 HI.Offset = 0;
264 HI.Size = 1;
265 HI.Align = 32;
266 HI.AccessSpecifier = "public";
267 }},
268 // Local to class method.
269 {R"cpp(
270 namespace ns1 { namespace ns2 {
271 struct Foo {
272 void foo() {
273 int [[b^ar]];
274 }
275 };
276 }}
277 )cpp",
278 [](HoverInfo &HI) {
279 HI.NamespaceScope = "ns1::ns2::";
280 HI.LocalScope = "Foo::foo::";
281 HI.Name = "bar";
282 HI.Kind = index::SymbolKind::Variable;
283 HI.Definition = "int bar";
284 HI.Type = "int";
285 }},
286 // Predefined variable
287 {R"cpp(
288 void foo() {
289 [[__f^unc__]];
290 }
291 )cpp",
292 [](HoverInfo &HI) {
293 HI.Name = "__func__";
294 HI.Kind = index::SymbolKind::Variable;
295 HI.Documentation =
296 "Name of the current function (predefined variable)";
297 HI.Value = "\"foo\"";
298 HI.Type = "const char[4]";
299 }},
300 // Predefined variable (dependent)
301 {R"cpp(
302 template<int> void foo() {
303 [[__f^unc__]];
304 }
305 )cpp",
306 [](HoverInfo &HI) {
307 HI.Name = "__func__";
308 HI.Kind = index::SymbolKind::Variable;
309 HI.Documentation =
310 "Name of the current function (predefined variable)";
311 HI.Type = "const char[]";
312 }},
313 // Anon namespace and local scope.
314 {R"cpp(
315 namespace ns1 { namespace {
316 struct {
317 char [[b^ar]];
318 } T;
319 }}
320 )cpp",
321 [](HoverInfo &HI) {
322 HI.NamespaceScope = "ns1::";
323 HI.LocalScope = "(anonymous struct)::";
324 HI.Name = "bar";
325 HI.Kind = index::SymbolKind::Field;
326 HI.Definition = "char bar";
327 HI.Type = "char";
328 HI.Offset = 0;
329 HI.Size = 8;
330 HI.Align = 8;
331 HI.AccessSpecifier = "public";
332 }},
333 // Struct definition shows size.
334 {R"cpp(
335 struct [[^X]]{};
336 )cpp",
337 [](HoverInfo &HI) {
338 HI.NamespaceScope = "";
339 HI.Name = "X";
340 HI.Kind = index::SymbolKind::Struct;
341 HI.Definition = "struct X {}";
342 HI.Size = 8;
343 HI.Align = 8;
344 }},
345 // Variable with template type
346 {R"cpp(
347 template <typename T, class... Ts> class Foo { public: Foo(int); };
348 Foo<int, char, bool> [[fo^o]] = Foo<int, char, bool>(5);
349 )cpp",
350 [](HoverInfo &HI) {
351 HI.NamespaceScope = "";
352 HI.Name = "foo";
353 HI.Kind = index::SymbolKind::Variable;
354 HI.Definition = "Foo<int, char, bool> foo = Foo<int, char, bool>(5)";
355 HI.Type = "Foo<int, char, bool>";
356 }},
357 // Implicit template instantiation
358 {R"cpp(
359 template <typename T> class vector{};
360 [[vec^tor]]<int> foo;
361 )cpp",
362 [](HoverInfo &HI) {
363 HI.NamespaceScope = "";
364 HI.Name = "vector<int>";
365 HI.Kind = index::SymbolKind::Class;
366 HI.Definition = "template <> class vector<int> {}";
367 }},
368 // Class template
369 {R"cpp(
370 template <template<typename, bool...> class C,
371 typename = char,
372 int = 0,
373 bool Q = false,
374 class... Ts> class Foo final {};
375 template <template<typename, bool...> class T>
376 [[F^oo]]<T> foo;
377 )cpp",
378 [](HoverInfo &HI) {
379 HI.NamespaceScope = "";
380 HI.Name = "Foo";
381 HI.Kind = index::SymbolKind::Class;
382 HI.Definition =
383 R"cpp(template <template <typename, bool...> class C, typename = char, int = 0,
384 bool Q = false, class... Ts>
385class Foo final {})cpp";
386 HI.TemplateParameters = {
387 {{"template <typename, bool...> class"},
388 std::string("C"),
389 std::nullopt},
390 {{"typename"}, std::nullopt, std::string("char")},
391 {{"int"}, std::nullopt, std::string("0")},
392 {{"bool"}, std::string("Q"), std::string("false")},
393 {{"class..."}, std::string("Ts"), std::nullopt},
394 };
395 }},
396 // Function template
397 {R"cpp(
398 template <template<typename, bool...> class C,
399 typename = char,
400 int = 0,
401 bool Q = false,
402 class... Ts> void foo();
403 template<typename, bool...> class Foo;
404
405 void bar() {
406 [[fo^o]]<Foo>();
407 }
408 )cpp",
409 [](HoverInfo &HI) {
410 HI.NamespaceScope = "";
411 HI.Name = "foo";
412 HI.Kind = index::SymbolKind::Function;
413 HI.Definition = "template <> void foo<Foo, char, 0, false, <>>()";
414 HI.ReturnType = "void";
415 HI.Type = "void ()";
416 HI.Parameters.emplace();
417 }},
418 // Function decl
419 {R"cpp(
420 template<typename, bool...> class Foo {};
421 Foo<bool, true, false> foo(int, bool T = false);
422
423 void bar() {
424 [[fo^o]](3);
425 }
426 )cpp",
427 [](HoverInfo &HI) {
428 HI.NamespaceScope = "";
429 HI.Name = "foo";
430 HI.Kind = index::SymbolKind::Function;
431 HI.Definition = "Foo<bool, true, false> foo(int, bool T = false)";
432 HI.ReturnType = "Foo<bool, true, false>";
433 HI.Type = "Foo<bool, true, false> (int, bool)";
434 HI.Parameters = {
435 {{"int"}, std::nullopt, std::nullopt},
436 {{"bool"}, std::string("T"), std::string("false")},
437 };
438 }},
439 // Pointers to lambdas
440 {R"cpp(
441 void foo() {
442 auto lamb = [](int T, bool B) -> bool { return T && B; };
443 auto *b = &lamb;
444 auto *[[^c]] = &b;
445 }
446 )cpp",
447 [](HoverInfo &HI) {
448 HI.NamespaceScope = "";
449 HI.LocalScope = "foo::";
450 HI.Name = "c";
451 HI.Kind = index::SymbolKind::Variable;
452 HI.Definition = "auto *c = &b";
453 HI.Type = "(lambda) **";
454 HI.ReturnType = "bool";
455 HI.Parameters = {
456 {{"int"}, std::string("T"), std::nullopt},
457 {{"bool"}, std::string("B"), std::nullopt},
458 };
459 return HI;
460 }},
461 // Lambda parameter with decltype reference
462 {R"cpp(
463 auto lamb = [](int T, bool B) -> bool { return T && B; };
464 void foo(decltype(lamb)& bar) {
465 [[ba^r]](0, false);
466 }
467 )cpp",
468 [](HoverInfo &HI) {
469 HI.NamespaceScope = "";
470 HI.LocalScope = "foo::";
471 HI.Name = "bar";
472 HI.Kind = index::SymbolKind::Parameter;
473 HI.Definition = "decltype(lamb) &bar";
474 HI.Type = "(lambda) &";
475 HI.ReturnType = "bool";
476 HI.Parameters = {
477 {{"int"}, std::string("T"), std::nullopt},
478 {{"bool"}, std::string("B"), std::nullopt},
479 };
480 return HI;
481 }},
482 // Lambda parameter with decltype
483 {R"cpp(
484 auto lamb = [](int T, bool B) -> bool { return T && B; };
485 void foo(decltype(lamb) bar) {
486 [[ba^r]](0, false);
487 }
488 )cpp",
489 [](HoverInfo &HI) {
490 HI.NamespaceScope = "";
491 HI.LocalScope = "foo::";
492 HI.Name = "bar";
493 HI.Kind = index::SymbolKind::Parameter;
494 HI.Definition = "decltype(lamb) bar";
495 HI.Type = "class (lambda)";
496 HI.ReturnType = "bool";
497 HI.Parameters = {
498 {{"int"}, std::string("T"), std::nullopt},
499 {{"bool"}, std::string("B"), std::nullopt},
500 };
501 HI.Value = "false";
502 return HI;
503 }},
504 // Lambda variable
505 {R"cpp(
506 void foo() {
507 int bar = 5;
508 auto lamb = [&bar](int T, bool B) -> bool { return T && B && bar; };
509 bool res = [[lam^b]](bar, false);
510 }
511 )cpp",
512 [](HoverInfo &HI) {
513 HI.NamespaceScope = "";
514 HI.LocalScope = "foo::";
515 HI.Name = "lamb";
516 HI.Kind = index::SymbolKind::Variable;
517 HI.Definition = "auto lamb = [&bar](int T, bool B) -> bool {}";
518 HI.Type = "class (lambda)";
519 HI.ReturnType = "bool";
520 HI.Parameters = {
521 {{"int"}, std::string("T"), std::nullopt},
522 {{"bool"}, std::string("B"), std::nullopt},
523 };
524 return HI;
525 }},
526 // Local variable in lambda
527 {R"cpp(
528 void foo() {
529 auto lamb = []{int [[te^st]];};
530 }
531 )cpp",
532 [](HoverInfo &HI) {
533 HI.NamespaceScope = "";
534 HI.LocalScope = "foo::(anonymous class)::operator()::";
535 HI.Name = "test";
536 HI.Kind = index::SymbolKind::Variable;
537 HI.Definition = "int test";
538 HI.Type = "int";
539 }},
540 // Partially-specialized class template. (formerly type-parameter-0-0)
541 {R"cpp(
542 template <typename T> class X;
543 template <typename T> class [[^X]]<T*> {};
544 )cpp",
545 [](HoverInfo &HI) {
546 HI.Name = "X<T *>";
547 HI.NamespaceScope = "";
548 HI.Kind = index::SymbolKind::Class;
549 HI.Definition = "template <typename T> class X<T *> {}";
550 }},
551 // Constructor of partially-specialized class template
552 {R"cpp(
553 template<typename, typename=void> struct X;
554 template<typename T> struct X<T*>{ [[^X]](); };
555 )cpp",
556 [](HoverInfo &HI) {
557 HI.NamespaceScope = "";
558 HI.Name = "X";
559 HI.LocalScope = "X<T *>::"; // FIXME: X<T *, void>::
560 HI.Kind = index::SymbolKind::Constructor;
561 HI.Definition = "X()";
562 HI.Parameters.emplace();
563 HI.AccessSpecifier = "public";
564 }},
565 {"class X { [[^~]]X(); };", // FIXME: Should be [[~X]]()
566 [](HoverInfo &HI) {
567 HI.NamespaceScope = "";
568 HI.Name = "~X";
569 HI.LocalScope = "X::";
570 HI.Kind = index::SymbolKind::Destructor;
571 HI.Definition = "~X()";
572 HI.Parameters.emplace();
573 HI.AccessSpecifier = "private";
574 }},
575 {"class X { [[op^erator]] int(); };",
576 [](HoverInfo &HI) {
577 HI.NamespaceScope = "";
578 HI.Name = "operator int";
579 HI.LocalScope = "X::";
580 HI.Kind = index::SymbolKind::ConversionFunction;
581 HI.Definition = "operator int()";
582 HI.Parameters.emplace();
583 HI.AccessSpecifier = "private";
584 }},
585 {"class X { operator [[^X]](); };",
586 [](HoverInfo &HI) {
587 HI.NamespaceScope = "";
588 HI.Name = "X";
589 HI.Kind = index::SymbolKind::Class;
590 HI.Definition = "class X {}";
591 }},
592
593 // auto on structured bindings
594 {R"cpp(
595 void foo() {
596 struct S { int x; float y; };
597 [[au^to]] [x, y] = S();
598 }
599 )cpp",
600 [](HoverInfo &HI) {
601 HI.Name = "auto";
602 HI.Kind = index::SymbolKind::TypeAlias;
603 HI.Definition = "S";
604 }},
605 // undeduced auto
606 {R"cpp(
607 template<typename T>
608 void foo() {
609 [[au^to]] x = T{};
610 }
611 )cpp",
612 [](HoverInfo &HI) {
613 HI.Name = "auto";
614 HI.Kind = index::SymbolKind::TypeAlias;
615 HI.Definition = "T";
616 }},
617 // constrained auto
618 {R"cpp(
619 template <class T> concept F = true;
620 F [[au^to]] x = 1;
621 )cpp",
622 [](HoverInfo &HI) {
623 HI.Name = "auto";
624 HI.Kind = index::SymbolKind::TypeAlias;
625 HI.Definition = "int";
626 }},
627 {R"cpp(
628 template <class T> concept F = true;
629 [[^F]] auto x = 1;
630 )cpp",
631 [](HoverInfo &HI) {
632 HI.NamespaceScope = "";
633 HI.Name = "F";
634 HI.Kind = index::SymbolKind::Concept;
635 HI.Definition = "template <class T>\nconcept F = true";
636 }},
637 // auto on lambda
638 {R"cpp(
639 void foo() {
640 [[au^to]] lamb = []{};
641 }
642 )cpp",
643 [](HoverInfo &HI) {
644 HI.Name = "auto";
645 HI.Kind = index::SymbolKind::TypeAlias;
646 HI.Definition = "class(lambda)";
647 }},
648 // auto on template instantiation
649 {R"cpp(
650 template<typename T> class Foo{};
651 void foo() {
652 [[au^to]] x = Foo<int>();
653 }
654 )cpp",
655 [](HoverInfo &HI) {
656 HI.Name = "auto";
657 HI.Kind = index::SymbolKind::TypeAlias;
658 HI.Definition = "Foo<int>";
659 }},
660 // auto on specialized template
661 {R"cpp(
662 template<typename T> class Foo{};
663 template<> class Foo<int>{};
664 void foo() {
665 [[au^to]] x = Foo<int>();
666 }
667 )cpp",
668 [](HoverInfo &HI) {
669 HI.Name = "auto";
670 HI.Kind = index::SymbolKind::TypeAlias;
671 HI.Definition = "Foo<int>";
672 }},
673 // constrained template parameter
674 {R"cpp(
675 template<class T> concept Fooable = true;
676 template<[[Foo^able]] T>
677 void bar(T t) {}
678 )cpp",
679 [](HoverInfo &HI) {
680 HI.NamespaceScope = "";
681 HI.Name = "Fooable";
682 HI.Kind = index::SymbolKind::Concept;
683 HI.Definition = "template <class T>\nconcept Fooable = true";
684 }},
685 {R"cpp(
686 template<class T> concept Fooable = true;
687 template<Fooable [[T^T]]>
688 void bar(TT t) {}
689 )cpp",
690 [](HoverInfo &HI) {
691 HI.Name = "TT";
692 HI.Type = "class";
693 HI.AccessSpecifier = "public";
694 HI.NamespaceScope = "";
695 HI.LocalScope = "bar::";
696 HI.Kind = index::SymbolKind::TemplateTypeParm;
697 HI.Definition = "Fooable TT";
698 }},
699 {R"cpp(
700 template<class T> concept Fooable = true;
701 void bar([[Foo^able]] auto t) {}
702 )cpp",
703 [](HoverInfo &HI) {
704 HI.NamespaceScope = "";
705 HI.Name = "Fooable";
706 HI.Kind = index::SymbolKind::Concept;
707 HI.Definition = "template <class T>\nconcept Fooable = true";
708 }},
709 // concept reference
710 {R"cpp(
711 template<class T> concept Fooable = true;
712 auto X = [[Fooa^ble]]<int>;
713 )cpp",
714 [](HoverInfo &HI) {
715 HI.NamespaceScope = "";
716 HI.Name = "Fooable";
717 HI.Kind = index::SymbolKind::Concept;
718 HI.Definition = "template <class T>\nconcept Fooable = true";
719 HI.Value = "true";
720 }},
721
722 // empty macro
723 {R"cpp(
724 #define MACRO
725 [[MAC^RO]]
726 )cpp",
727 [](HoverInfo &HI) {
728 HI.Name = "MACRO";
729 HI.Kind = index::SymbolKind::Macro;
730 HI.Definition = "#define MACRO";
731 }},
732
733 // object-like macro
734 {R"cpp(
735 #define MACRO 41
736 int x = [[MAC^RO]];
737 )cpp",
738 [](HoverInfo &HI) {
739 HI.Name = "MACRO";
740 HI.Kind = index::SymbolKind::Macro;
741 HI.Value = "41 (0x29)";
742 HI.Type = "int";
743 HI.Definition = "#define MACRO 41\n\n"
744 "// Expands to\n"
745 "41";
746 }},
747
748 // function-like macro
749 {R"cpp(
750 // Best MACRO ever.
751 #define MACRO(x,y,z) void foo(x, y, z)
752 [[MAC^RO]](int, double d, bool z = false);
753 )cpp",
754 [](HoverInfo &HI) {
755 HI.Name = "MACRO";
756 HI.Kind = index::SymbolKind::Macro;
757 HI.Definition = "#define MACRO(x, y, z) void foo(x, y, z)\n\n"
758 "// Expands to\n"
759 "void foo(int, double d, bool z = false)";
760 }},
761
762 // nested macro
763 {R"cpp(
764 #define STRINGIFY_AUX(s) #s
765 #define STRINGIFY(s) STRINGIFY_AUX(s)
766 #define DECL_STR(NAME, VALUE) const char *v_##NAME = STRINGIFY(VALUE)
767 #define FOO 41
768
769 [[DECL^_STR]](foo, FOO);
770 )cpp",
771 [](HoverInfo &HI) {
772 HI.Name = "DECL_STR";
773 HI.Kind = index::SymbolKind::Macro;
774 HI.Type = HoverInfo::PrintedType("const char *");
775 HI.Definition = "#define DECL_STR(NAME, VALUE) const char *v_##NAME = "
776 "STRINGIFY(VALUE)\n\n"
777 "// Expands to\n"
778 "const char *v_foo = \"41\"";
779 }},
780
781 // constexprs
782 {R"cpp(
783 constexpr int add(int a, int b) { return a + b; }
784 int [[b^ar]] = add(1, 2);
785 )cpp",
786 [](HoverInfo &HI) {
787 HI.Name = "bar";
788 HI.Definition = "int bar = add(1, 2)";
789 HI.Kind = index::SymbolKind::Variable;
790 HI.Type = "int";
791 HI.NamespaceScope = "";
792 HI.Value = "3";
793 }},
794 {R"cpp(
795 int [[b^ar]] = sizeof(char);
796 )cpp",
797 [](HoverInfo &HI) {
798 HI.Name = "bar";
799 HI.Definition = "int bar = sizeof(char)";
800 HI.Kind = index::SymbolKind::Variable;
801 HI.Type = "int";
802 HI.NamespaceScope = "";
803 HI.Value = "1";
804 }},
805 {R"cpp(
806 template<int a, int b> struct Add {
807 static constexpr int result = a + b;
808 };
809 int [[ba^r]] = Add<1, 2>::result;
810 )cpp",
811 [](HoverInfo &HI) {
812 HI.Name = "bar";
813 HI.Definition = "int bar = Add<1, 2>::result";
814 HI.Kind = index::SymbolKind::Variable;
815 HI.Type = "int";
816 HI.NamespaceScope = "";
817 HI.Value = "3";
818 }},
819 {R"cpp(
820 enum Color { RED = -123, GREEN = 5, };
821 Color x = [[GR^EEN]];
822 )cpp",
823 [](HoverInfo &HI) {
824 HI.Name = "GREEN";
825 HI.NamespaceScope = "";
826 HI.LocalScope = "Color::";
827 HI.Definition = "GREEN = 5";
828 HI.Kind = index::SymbolKind::EnumConstant;
829 HI.Type = "enum Color";
830 HI.Value = "5"; // Numeric on the enumerator name, no hex as small.
831 }},
832 {R"cpp(
833 enum Color { RED = -123, GREEN = 5, };
834 Color x = RED;
835 Color y = [[^x]];
836 )cpp",
837 [](HoverInfo &HI) {
838 HI.Name = "x";
839 HI.NamespaceScope = "";
840 HI.Definition = "Color x = RED";
841 HI.Kind = index::SymbolKind::Variable;
842 HI.Type = "Color";
843 HI.Value = "RED (0xffffff85)"; // Symbolic on an expression.
844 }},
845 {R"cpp(
846 template<int a, int b> struct Add {
847 static constexpr int result = a + b;
848 };
849 int bar = Add<1, 2>::[[resu^lt]];
850 )cpp",
851 [](HoverInfo &HI) {
852 HI.Name = "result";
853 HI.Definition = "static constexpr int result = a + b";
854 HI.Kind = index::SymbolKind::StaticProperty;
855 HI.Type = "const int";
856 HI.NamespaceScope = "";
857 HI.LocalScope = "Add<1, 2>::";
858 HI.Value = "3";
859 HI.AccessSpecifier = "public";
860 }},
861 {R"cpp(
862 using my_int = int;
863 constexpr my_int answer() { return 40 + 2; }
864 int x = [[ans^wer]]();
865 )cpp",
866 [](HoverInfo &HI) {
867 HI.Name = "answer";
868 HI.Definition = "constexpr my_int answer()";
869 HI.Kind = index::SymbolKind::Function;
870 HI.Type = {"my_int ()", "int ()"};
871 HI.ReturnType = {"my_int", "int"};
872 HI.Parameters.emplace();
873 HI.NamespaceScope = "";
874 HI.Value = "42 (0x2a)";
875 }},
876 {R"cpp(
877 const char *[[ba^r]] = "1234";
878 )cpp",
879 [](HoverInfo &HI) {
880 HI.Name = "bar";
881 HI.Definition = "const char *bar = \"1234\"";
882 HI.Kind = index::SymbolKind::Variable;
883 HI.Type = "const char *";
884 HI.NamespaceScope = "";
885 HI.Value = "&\"1234\"[0]";
886 }},
887 {R"cpp(// Should not crash
888 template <typename T>
889 struct Tmpl {
890 Tmpl(int name);
891 };
892
893 template <typename A>
894 void boom(int name) {
895 new Tmpl<A>([[na^me]]);
896 })cpp",
897 [](HoverInfo &HI) {
898 HI.Name = "name";
899 HI.Definition = "int name";
900 HI.Kind = index::SymbolKind::Parameter;
901 HI.Type = "int";
902 HI.NamespaceScope = "";
903 HI.LocalScope = "boom::";
904 }},
905 {
906 R"cpp(// Should not print inline or anon namespaces.
907 namespace ns {
908 inline namespace in_ns {
909 namespace a {
910 namespace {
911 namespace b {
912 inline namespace in_ns2 {
913 class Foo {};
914 } // in_ns2
915 } // b
916 } // anon
917 } // a
918 } // in_ns
919 } // ns
920 void foo() {
921 ns::a::b::[[F^oo]] x;
922 (void)x;
923 }
924 )cpp",
925 [](HoverInfo &HI) {
926 HI.Name = "Foo";
927 HI.Kind = index::SymbolKind::Class;
928 HI.NamespaceScope = "ns::a::b::";
929 HI.Definition = "class Foo {}";
930 }},
931 {
932 R"cpp(
933 template <typename T> class Foo {};
934 class X;
935 void foo() {
936 [[^auto]] x = Foo<X>();
937 }
938 )cpp",
939 [](HoverInfo &HI) {
940 HI.Name = "auto";
941 HI.Kind = index::SymbolKind::TypeAlias;
942 HI.Definition = "Foo<X>";
943 }},
944 {// Falls back to primary template, when the type is not instantiated.
945 R"cpp(
946 // comment from primary
947 template <typename T> class Foo {};
948 // comment from specialization
949 template <typename T> class Foo<T*> {};
950 void foo() {
951 [[Fo^o]]<int*> *x = nullptr;
952 }
953 )cpp",
954 [](HoverInfo &HI) {
955 HI.Name = "Foo<int *>";
956 HI.Kind = index::SymbolKind::Class;
957 HI.NamespaceScope = "";
958 HI.Definition = "template <> class Foo<int *>";
959 // FIXME: Maybe force instantiation to make use of real template
960 // pattern.
961 HI.Documentation = "comment from primary";
962 }},
963 {// Template Type Parameter
964 R"cpp(
965 template <typename [[^T]] = int> void foo();
966 )cpp",
967 [](HoverInfo &HI) {
968 HI.Name = "T";
969 HI.Kind = index::SymbolKind::TemplateTypeParm;
970 HI.NamespaceScope = "";
971 HI.Definition = "typename T = int";
972 HI.LocalScope = "foo::";
973 HI.Type = "typename";
974 HI.AccessSpecifier = "public";
975 }},
976 {// TemplateTemplate Type Parameter
977 R"cpp(
978 template <template<typename> class [[^T]]> void foo();
979 )cpp",
980 [](HoverInfo &HI) {
981 HI.Name = "T";
982 HI.Kind = index::SymbolKind::TemplateTemplateParm;
983 HI.NamespaceScope = "";
984 HI.Definition = "template <typename> class T";
985 HI.LocalScope = "foo::";
986 HI.Type = "template <typename> class";
987 HI.AccessSpecifier = "public";
988 }},
989 {// NonType Template Parameter
990 R"cpp(
991 template <int [[^T]] = 5> void foo();
992 )cpp",
993 [](HoverInfo &HI) {
994 HI.Name = "T";
995 HI.Kind = index::SymbolKind::NonTypeTemplateParm;
996 HI.NamespaceScope = "";
997 HI.Definition = "int T = 5";
998 HI.LocalScope = "foo::";
999 HI.Type = "int";
1000 HI.AccessSpecifier = "public";
1001 }},
1002
1003 {// Getter
1004 R"cpp(
1005 struct X { int Y; float [[^y]]() { return Y; } };
1006 )cpp",
1007 [](HoverInfo &HI) {
1008 HI.Name = "y";
1009 HI.Kind = index::SymbolKind::InstanceMethod;
1010 HI.NamespaceScope = "";
1011 HI.Definition = "float y()";
1012 HI.LocalScope = "X::";
1013 HI.Documentation = "Trivial accessor for `Y`.";
1014 HI.Type = "float ()";
1015 HI.ReturnType = "float";
1016 HI.Parameters.emplace();
1017 HI.AccessSpecifier = "public";
1018 }},
1019 {// Getter with comment
1020 R"cpp(
1021 struct X {
1022 // An int named Y
1023 int Y;
1024 float [[^y]]() { return Y; }
1025 };
1026 )cpp",
1027 [](HoverInfo &HI) {
1028 HI.Name = "y";
1029 HI.Kind = index::SymbolKind::InstanceMethod;
1030 HI.NamespaceScope = "";
1031 HI.Definition = "float y()";
1032 HI.LocalScope = "X::";
1033 HI.Documentation = "Trivial accessor for `Y`.\n\nAn int named Y";
1034 HI.Type = "float ()";
1035 HI.ReturnType = "float";
1036 HI.Parameters.emplace();
1037 HI.AccessSpecifier = "public";
1038 }},
1039 {// Setter
1040 R"cpp(
1041 struct X { int Y; void [[^setY]](float v) { Y = v; } };
1042 )cpp",
1043 [](HoverInfo &HI) {
1044 HI.Name = "setY";
1045 HI.Kind = index::SymbolKind::InstanceMethod;
1046 HI.NamespaceScope = "";
1047 HI.Definition = "void setY(float v)";
1048 HI.LocalScope = "X::";
1049 HI.Documentation = "Trivial setter for `Y`.";
1050 HI.Type = "void (float)";
1051 HI.ReturnType = "void";
1052 HI.Parameters.emplace();
1053 HI.Parameters->emplace_back();
1054 HI.Parameters->back().Type = "float";
1055 HI.Parameters->back().Name = "v";
1056 HI.AccessSpecifier = "public";
1057 }},
1058 {// Setter (builder)
1059 R"cpp(
1060 struct X { int Y; X& [[^setY]](float v) { Y = v; return *this; } };
1061 )cpp",
1062 [](HoverInfo &HI) {
1063 HI.Name = "setY";
1064 HI.Kind = index::SymbolKind::InstanceMethod;
1065 HI.NamespaceScope = "";
1066 HI.Definition = "X &setY(float v)";
1067 HI.LocalScope = "X::";
1068 HI.Documentation = "Trivial setter for `Y`.";
1069 HI.Type = "X &(float)";
1070 HI.ReturnType = "X &";
1071 HI.Parameters.emplace();
1072 HI.Parameters->emplace_back();
1073 HI.Parameters->back().Type = "float";
1074 HI.Parameters->back().Name = "v";
1075 HI.AccessSpecifier = "public";
1076 }},
1077 {// Setter (move)
1078 R"cpp(
1079 namespace std { template<typename T> T&& move(T&& t); }
1080 struct X { int Y; void [[^setY]](float v) { Y = std::move(v); } };
1081 )cpp",
1082 [](HoverInfo &HI) {
1083 HI.Name = "setY";
1084 HI.Kind = index::SymbolKind::InstanceMethod;
1085 HI.NamespaceScope = "";
1086 HI.Definition = "void setY(float v)";
1087 HI.LocalScope = "X::";
1088 HI.Documentation = "Trivial setter for `Y`.";
1089 HI.Type = "void (float)";
1090 HI.ReturnType = "void";
1091 HI.Parameters.emplace();
1092 HI.Parameters->emplace_back();
1093 HI.Parameters->back().Type = "float";
1094 HI.Parameters->back().Name = "v";
1095 HI.AccessSpecifier = "public";
1096 }},
1097 {// Setter with comment
1098 R"cpp(
1099 struct X {
1100 // An int named Y
1101 int Y;
1102 void [[^setY]](float v) { Y = v; }
1103 };
1104 )cpp",
1105 [](HoverInfo &HI) {
1106 HI.Name = "setY";
1107 HI.Kind = index::SymbolKind::InstanceMethod;
1108 HI.NamespaceScope = "";
1109 HI.Definition = "void setY(float v)";
1110 HI.LocalScope = "X::";
1111 HI.Documentation = "Trivial setter for `Y`.\n\nAn int named Y";
1112 HI.Type = "void (float)";
1113 HI.ReturnType = "void";
1114 HI.Parameters.emplace();
1115 HI.Parameters->emplace_back();
1116 HI.Parameters->back().Type = "float";
1117 HI.Parameters->back().Name = "v";
1118 HI.AccessSpecifier = "public";
1119 }},
1120 {// Field type initializer.
1121 R"cpp(
1122 struct X { int x = 2; };
1123 X ^[[x]];
1124 )cpp",
1125 [](HoverInfo &HI) {
1126 HI.Name = "x";
1127 HI.Kind = index::SymbolKind::Variable;
1128 HI.NamespaceScope = "";
1129 HI.Definition = "X x";
1130 HI.Type = "X";
1131 }},
1132 {// Don't crash on null types.
1133 R"cpp(auto [^[[x]]] = 1; /*error-ok*/)cpp",
1134 [](HoverInfo &HI) {
1135 HI.Name = "x";
1136 HI.Kind = index::SymbolKind::Variable;
1137 HI.NamespaceScope = "";
1138 HI.Definition = "";
1139 HI.Type = "NULL TYPE";
1140 // Bindings are in theory public members of an anonymous struct.
1141 HI.AccessSpecifier = "public";
1142 }},
1143 {// Don't crash on invalid decl with invalid init expr.
1144 R"cpp(
1145 Unknown [[^abc]] = invalid;
1146 // error-ok
1147 )cpp",
1148 [](HoverInfo &HI) {
1149 HI.Name = "abc";
1150 HI.Kind = index::SymbolKind::Variable;
1151 HI.NamespaceScope = "";
1152 HI.Definition = "int abc";
1153 HI.Type = "int";
1154 HI.AccessSpecifier = "public";
1155 }},
1156 {// Extra info for function call.
1157 R"cpp(
1158 void fun(int arg_a, int &arg_b) {};
1159 void code() {
1160 int a = 1, b = 2;
1161 fun(a, [[^b]]);
1162 }
1163 )cpp",
1164 [](HoverInfo &HI) {
1165 HI.Name = "b";
1166 HI.Kind = index::SymbolKind::Variable;
1167 HI.NamespaceScope = "";
1168 HI.Definition = "int b = 2";
1169 HI.LocalScope = "code::";
1170 HI.Value = "2";
1171 HI.Type = "int";
1172 HI.CalleeArgInfo.emplace();
1173 HI.CalleeArgInfo->Name = "arg_b";
1174 HI.CalleeArgInfo->Type = "int &";
1175 HI.CallPassType = HoverInfo::PassType{PassMode::Ref, false};
1176 }},
1177 {// make_unique-like function call
1178 R"cpp(
1179 struct Foo {
1180 explicit Foo(int arg_a) {}
1181 };
1182 template<class T, class... Args>
1183 T make(Args&&... args)
1184 {
1185 return T(args...);
1186 }
1187
1188 void code() {
1189 int a = 1;
1190 auto foo = make<Foo>([[^a]]);
1191 }
1192 )cpp",
1193 [](HoverInfo &HI) {
1194 HI.Name = "a";
1195 HI.Kind = index::SymbolKind::Variable;
1196 HI.NamespaceScope = "";
1197 HI.Definition = "int a = 1";
1198 HI.LocalScope = "code::";
1199 HI.Value = "1";
1200 HI.Type = "int";
1201 HI.CalleeArgInfo.emplace();
1202 HI.CalleeArgInfo->Name = "arg_a";
1203 HI.CalleeArgInfo->Type = "int";
1204 HI.CallPassType = HoverInfo::PassType{PassMode::Value, false};
1205 }},
1206 {
1207 R"cpp(
1208 void foobar(const float &arg);
1209 int main() {
1210 int a = 0;
1211 foobar([[^a]]);
1212 }
1213 )cpp",
1214 [](HoverInfo &HI) {
1215 HI.Name = "a";
1216 HI.Kind = index::SymbolKind::Variable;
1217 HI.NamespaceScope = "";
1218 HI.Definition = "int a = 0";
1219 HI.LocalScope = "main::";
1220 HI.Value = "0";
1221 HI.Type = "int";
1222 HI.CalleeArgInfo.emplace();
1223 HI.CalleeArgInfo->Name = "arg";
1224 HI.CalleeArgInfo->Type = "const float &";
1225 HI.CallPassType = HoverInfo::PassType{PassMode::Value, true};
1226 }},
1227 {
1228 R"cpp(
1229 struct Foo {
1230 explicit Foo(const float& arg) {}
1231 };
1232 int main() {
1233 int a = 0;
1234 Foo foo([[^a]]);
1235 }
1236 )cpp",
1237 [](HoverInfo &HI) {
1238 HI.Name = "a";
1239 HI.Kind = index::SymbolKind::Variable;
1240 HI.NamespaceScope = "";
1241 HI.Definition = "int a = 0";
1242 HI.LocalScope = "main::";
1243 HI.Value = "0";
1244 HI.Type = "int";
1245 HI.CalleeArgInfo.emplace();
1246 HI.CalleeArgInfo->Name = "arg";
1247 HI.CalleeArgInfo->Type = "const float &";
1248 HI.CallPassType = HoverInfo::PassType{PassMode::Value, true};
1249 }},
1250 {// Literal passed to function call
1251 R"cpp(
1252 void fun(int arg_a, const int &arg_b) {};
1253 void code() {
1254 int a = 1;
1255 fun(a, [[^2]]);
1256 }
1257 )cpp",
1258 [](HoverInfo &HI) {
1259 HI.Name = "literal";
1260 HI.Kind = index::SymbolKind::Unknown;
1261 HI.CalleeArgInfo.emplace();
1262 HI.CalleeArgInfo->Name = "arg_b";
1263 HI.CalleeArgInfo->Type = "const int &";
1264 HI.CallPassType = HoverInfo::PassType{PassMode::ConstRef, false};
1265 }},
1266 {// Expression passed to function call
1267 R"cpp(
1268 void fun(int arg_a, const int &arg_b) {};
1269 void code() {
1270 int a = 1;
1271 fun(a, 1 [[^+]] 2);
1272 }
1273 )cpp",
1274 [](HoverInfo &HI) {
1275 HI.Name = "expression";
1276 HI.Kind = index::SymbolKind::Unknown;
1277 HI.Type = "int";
1278 HI.Value = "3";
1279 HI.CalleeArgInfo.emplace();
1280 HI.CalleeArgInfo->Name = "arg_b";
1281 HI.CalleeArgInfo->Type = "const int &";
1282 HI.CallPassType = HoverInfo::PassType{PassMode::ConstRef, false};
1283 }},
1284 {
1285 R"cpp(
1286 int add(int lhs, int rhs);
1287 int main() {
1288 add(1 [[^+]] 2, 3);
1289 }
1290 )cpp",
1291 [](HoverInfo &HI) {
1292 HI.Name = "expression";
1293 HI.Kind = index::SymbolKind::Unknown;
1294 HI.Type = "int";
1295 HI.Value = "3";
1296 HI.CalleeArgInfo.emplace();
1297 HI.CalleeArgInfo->Name = "lhs";
1298 HI.CalleeArgInfo->Type = "int";
1299 HI.CallPassType = HoverInfo::PassType{PassMode::Value, false};
1300 }},
1301 {
1302 R"cpp(
1303 void foobar(const float &arg);
1304 int main() {
1305 foobar([[^0]]);
1306 }
1307 )cpp",
1308 [](HoverInfo &HI) {
1309 HI.Name = "literal";
1310 HI.Kind = index::SymbolKind::Unknown;
1311 HI.CalleeArgInfo.emplace();
1312 HI.CalleeArgInfo->Name = "arg";
1313 HI.CalleeArgInfo->Type = "const float &";
1314 HI.CallPassType = HoverInfo::PassType{PassMode::Value, true};
1315 }},
1316 {// Extra info for method call.
1317 R"cpp(
1318 class C {
1319 public:
1320 void fun(int arg_a = 3, int arg_b = 4) {}
1321 };
1322 void code() {
1323 int a = 1, b = 2;
1324 C c;
1325 c.fun([[^a]], b);
1326 }
1327 )cpp",
1328 [](HoverInfo &HI) {
1329 HI.Name = "a";
1330 HI.Kind = index::SymbolKind::Variable;
1331 HI.NamespaceScope = "";
1332 HI.Definition = "int a = 1";
1333 HI.LocalScope = "code::";
1334 HI.Value = "1";
1335 HI.Type = "int";
1336 HI.CalleeArgInfo.emplace();
1337 HI.CalleeArgInfo->Name = "arg_a";
1338 HI.CalleeArgInfo->Type = "int";
1339 HI.CalleeArgInfo->Default = "3";
1340 HI.CallPassType = HoverInfo::PassType{PassMode::Value, false};
1341 }},
1342 {
1343 R"cpp(
1344 struct Foo {
1345 Foo(const int &);
1346 };
1347 void foo(Foo);
1348 void bar() {
1349 const int x = 0;
1350 foo([[^x]]);
1351 }
1352 )cpp",
1353 [](HoverInfo &HI) {
1354 HI.Name = "x";
1355 HI.Kind = index::SymbolKind::Variable;
1356 HI.NamespaceScope = "";
1357 HI.Definition = "const int x = 0";
1358 HI.LocalScope = "bar::";
1359 HI.Value = "0";
1360 HI.Type = "const int";
1361 HI.CalleeArgInfo.emplace();
1362 HI.CalleeArgInfo->Type = "Foo";
1363 HI.CallPassType = HoverInfo::PassType{PassMode::ConstRef, true};
1364 }},
1365 {// Dont crash on invalid decl
1366 R"cpp(
1367 // error-ok
1368 struct Foo {
1369 Bar [[x^x]];
1370 };)cpp",
1371 [](HoverInfo &HI) {
1372 HI.Name = "xx";
1373 HI.Kind = index::SymbolKind::Field;
1374 HI.NamespaceScope = "";
1375 HI.Definition = "int xx";
1376 HI.LocalScope = "Foo::";
1377 HI.Type = "int";
1378 HI.AccessSpecifier = "public";
1379 }},
1380 {R"cpp(
1381 // error-ok
1382 struct Foo {
1383 Bar xx;
1384 int [[y^y]];
1385 };)cpp",
1386 [](HoverInfo &HI) {
1387 HI.Name = "yy";
1388 HI.Kind = index::SymbolKind::Field;
1389 HI.NamespaceScope = "";
1390 HI.Definition = "int yy";
1391 HI.LocalScope = "Foo::";
1392 HI.Type = "int";
1393 HI.AccessSpecifier = "public";
1394 }},
1395 {// No crash on InitListExpr.
1396 R"cpp(
1397 struct Foo {
1398 int a[10];
1399 };
1400 constexpr Foo k2 = {
1401 ^[[{]]1} // FIXME: why the hover range is 1 character?
1402 };
1403 )cpp",
1404 [](HoverInfo &HI) {
1405 HI.Name = "expression";
1406 HI.Kind = index::SymbolKind::Unknown;
1407 HI.Type = "int[10]";
1408 HI.Value = "{1}";
1409 }},
1410 {// Var template decl
1411 R"cpp(
1412 using m_int = int;
1413
1414 template <int Size> m_int ^[[arr]][Size];
1415 )cpp",
1416 [](HoverInfo &HI) {
1417 HI.Name = "arr";
1418 HI.Kind = index::SymbolKind::Variable;
1419 HI.Type = {"m_int[Size]", "int[Size]"};
1420 HI.NamespaceScope = "";
1421 HI.Definition = "template <int Size> m_int arr[Size]";
1422 HI.TemplateParameters = {{{"int"}, {"Size"}, std::nullopt}};
1423 }},
1424 {// Var template decl specialization
1425 R"cpp(
1426 using m_int = int;
1427
1428 template <int Size> m_int arr[Size];
1429
1430 template <> m_int ^[[arr]]<4>[4];
1431 )cpp",
1432 [](HoverInfo &HI) {
1433 HI.Name = "arr<4>";
1434 HI.Kind = index::SymbolKind::Variable;
1435 HI.Type = {"m_int[4]", "int[4]"};
1436 HI.NamespaceScope = "";
1437 HI.Definition = "m_int arr[4]";
1438 }},
1439 {// Canonical type
1440 R"cpp(
1441 template<typename T>
1442 struct TestHover {
1443 using Type = T;
1444 };
1445
1446 void code() {
1447 TestHover<int>::Type ^[[a]];
1448 }
1449 )cpp",
1450 [](HoverInfo &HI) {
1451 HI.Name = "a";
1452 HI.NamespaceScope = "";
1453 HI.LocalScope = "code::";
1454 HI.Definition = "TestHover<int>::Type a";
1455 HI.Kind = index::SymbolKind::Variable;
1456 HI.Type = {"TestHover<int>::Type", "int"};
1457 }},
1458 {// Canonical template type
1459 R"cpp(
1460 template<typename T>
1461 void ^[[foo]](T arg) {}
1462 )cpp",
1463 [](HoverInfo &HI) {
1464 HI.Name = "foo";
1465 HI.Kind = index::SymbolKind::Function;
1466 HI.NamespaceScope = "";
1467 HI.Definition = "template <typename T> void foo(T arg)";
1468 HI.Type = "void (T)";
1469 HI.ReturnType = "void";
1470 HI.Parameters = {{{"T"}, std::string("arg"), std::nullopt}};
1471 HI.TemplateParameters = {
1472 {{"typename"}, std::string("T"), std::nullopt}};
1473 }},
1474 {// TypeAlias Template
1475 R"cpp(
1476 template<typename T>
1477 using ^[[alias]] = T;
1478 )cpp",
1479 [](HoverInfo &HI) {
1480 HI.Name = "alias";
1481 HI.NamespaceScope = "";
1482 HI.LocalScope = "";
1483 HI.Kind = index::SymbolKind::TypeAlias;
1484 HI.Definition = "template <typename T> using alias = T";
1485 HI.Type = "T";
1486 HI.TemplateParameters = {
1487 {{"typename"}, std::string("T"), std::nullopt}};
1488 }},
1489 {// TypeAlias Template
1490 R"cpp(
1491 template<typename T>
1492 using A = T;
1493
1494 template<typename T>
1495 using ^[[AA]] = A<T>;
1496 )cpp",
1497 [](HoverInfo &HI) {
1498 HI.Name = "AA";
1499 HI.NamespaceScope = "";
1500 HI.LocalScope = "";
1501 HI.Kind = index::SymbolKind::TypeAlias;
1502 HI.Definition = "template <typename T> using AA = A<T>";
1503 HI.Type = {"A<T>", "T"};
1504 HI.TemplateParameters = {
1505 {{"typename"}, std::string("T"), std::nullopt}};
1506 }},
1507 {// Constant array
1508 R"cpp(
1509 using m_int = int;
1510
1511 m_int ^[[arr]][10];
1512 )cpp",
1513 [](HoverInfo &HI) {
1514 HI.Name = "arr";
1515 HI.NamespaceScope = "";
1516 HI.LocalScope = "";
1517 HI.Kind = index::SymbolKind::Variable;
1518 HI.Definition = "m_int arr[10]";
1519 HI.Type = {"m_int[10]", "int[10]"};
1520 }},
1521 {// Incomplete array
1522 R"cpp(
1523 using m_int = int;
1524
1525 extern m_int ^[[arr]][];
1526 )cpp",
1527 [](HoverInfo &HI) {
1528 HI.Name = "arr";
1529 HI.NamespaceScope = "";
1530 HI.LocalScope = "";
1531 HI.Kind = index::SymbolKind::Variable;
1532 HI.Definition = "extern m_int arr[]";
1533 HI.Type = {"m_int[]", "int[]"};
1534 }},
1535 {// Dependent size array
1536 R"cpp(
1537 using m_int = int;
1538
1539 template<int Size>
1540 struct Test {
1541 m_int ^[[arr]][Size];
1542 };
1543 )cpp",
1544 [](HoverInfo &HI) {
1545 HI.Name = "arr";
1546 HI.NamespaceScope = "";
1547 HI.LocalScope = "Test<Size>::";
1548 HI.AccessSpecifier = "public";
1549 HI.Kind = index::SymbolKind::Field;
1550 HI.Definition = "m_int arr[Size]";
1551 HI.Type = {"m_int[Size]", "int[Size]"};
1552 }},
1553 {// Bitfield offset, size and padding
1554 R"cpp(
1555 struct Foo {
1556 char x;
1557 char [[^y]] : 1;
1558 int z;
1559 };
1560 )cpp",
1561 [](HoverInfo &HI) {
1562 HI.NamespaceScope = "";
1563 HI.LocalScope = "Foo::";
1564 HI.Name = "y";
1565 HI.Kind = index::SymbolKind::Field;
1566 HI.Definition = "char y : 1";
1567 HI.Type = "char";
1568 HI.Offset = 8;
1569 HI.Size = 1;
1570 HI.Padding = 23;
1571 HI.Align = 8;
1572 HI.AccessSpecifier = "public";
1573 }}};
1574 for (const auto &Case : Cases) {
1575 SCOPED_TRACE(Case.Code);
1576
1577 Annotations T(Case.Code);
1578 TestTU TU = TestTU::withCode(T.code());
1579 TU.ExtraArgs.push_back("-std=c++20");
1580 // Types might be different depending on the target triplet, we chose a
1581 // fixed one to make sure tests passes on different platform.
1582 TU.ExtraArgs.push_back("--target=x86_64-pc-linux-gnu");
1583 auto AST = TU.build();
1584 Config Cfg;
1585 Cfg.Hover.ShowAKA = true;
1586 WithContextValue WithCfg(Config::Key, std::move(Cfg));
1587
1588 auto H = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
1589 ASSERT_TRUE(H);
1590 HoverInfo Expected;
1591 Expected.SymRange = T.range();
1592 Case.ExpectedBuilder(Expected);
1593
1594 EXPECT_EQ(H->NamespaceScope, Expected.NamespaceScope);
1595 EXPECT_EQ(H->LocalScope, Expected.LocalScope);
1596 EXPECT_EQ(H->Name, Expected.Name);
1597 EXPECT_EQ(H->Kind, Expected.Kind);
1598 EXPECT_EQ(H->Documentation, Expected.Documentation);
1599 EXPECT_EQ(H->Definition, Expected.Definition);
1600 EXPECT_EQ(H->Type, Expected.Type);
1601 EXPECT_EQ(H->ReturnType, Expected.ReturnType);
1602 EXPECT_EQ(H->Parameters, Expected.Parameters);
1603 EXPECT_EQ(H->TemplateParameters, Expected.TemplateParameters);
1604 EXPECT_EQ(H->SymRange, Expected.SymRange);
1605 EXPECT_EQ(H->Value, Expected.Value);
1606 EXPECT_EQ(H->Size, Expected.Size);
1607 EXPECT_EQ(H->Offset, Expected.Offset);
1608 EXPECT_EQ(H->Align, Expected.Align);
1609 EXPECT_EQ(H->AccessSpecifier, Expected.AccessSpecifier);
1610 EXPECT_EQ(H->CalleeArgInfo, Expected.CalleeArgInfo);
1611 EXPECT_EQ(H->CallPassType, Expected.CallPassType);
1612 }
1613}
1614
1615TEST(Hover, DefinitionLanuage) {
1616 struct {
1617 const char *const Code;
1618 const std::string ClangLanguageFlag;
1619 const char *const ExpectedDefinitionLanguage;
1620 } Cases[] = {{R"cpp(
1621 void [[some^Global]]() {}
1622 )cpp",
1623 "", "cpp"},
1624 {R"cpp(
1625 void [[some^Global]]() {}
1626 )cpp",
1627 "-xobjective-c++", "objective-cpp"},
1628 {R"cpp(
1629 void [[some^Global]]() {}
1630 )cpp",
1631 "-xobjective-c", "objective-c"}};
1632 for (const auto &Case : Cases) {
1633 SCOPED_TRACE(Case.Code);
1634
1635 Annotations T(Case.Code);
1636 TestTU TU = TestTU::withCode(T.code());
1637 if (!Case.ClangLanguageFlag.empty())
1638 TU.ExtraArgs.push_back(Case.ClangLanguageFlag);
1639 auto AST = TU.build();
1640
1641 auto H = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
1642 ASSERT_TRUE(H);
1643
1644 EXPECT_STREQ(H->DefinitionLanguage, Case.ExpectedDefinitionLanguage);
1645 }
1646}
1647
1648TEST(Hover, CallPassType) {
1649 const llvm::StringRef CodePrefix = R"cpp(
1650class Base {};
1651class Derived : public Base {};
1652class CustomClass {
1653 public:
1654 CustomClass() {}
1655 CustomClass(const Base &x) {}
1656 CustomClass(int &x) {}
1657 CustomClass(float x) {}
1658 CustomClass(int x, int y) {}
1659};
1660
1661void int_by_ref(int &x) {}
1662void int_by_const_ref(const int &x) {}
1663void int_by_value(int x) {}
1664void base_by_ref(Base &x) {}
1665void base_by_const_ref(const Base &x) {}
1666void base_by_value(Base x) {}
1667void float_by_value(float x) {}
1668void custom_by_value(CustomClass x) {}
1669
1670void fun() {
1671 int int_x;
1672 int &int_ref = int_x;
1673 const int &int_const_ref = int_x;
1674 Base base;
1675 const Base &base_const_ref = base;
1676 Derived derived;
1677 float float_x;
1678)cpp";
1679 const llvm::StringRef CodeSuffix = "}";
1680
1681 struct {
1682 const char *const Code;
1684 bool Converted;
1685 } Tests[] = {
1686 // Integer tests
1687 {"int_by_value([[^int_x]]);", PassMode::Value, false},
1688 {"int_by_value([[^123]]);", PassMode::Value, false},
1689 {"int_by_ref([[^int_x]]);", PassMode::Ref, false},
1690 {"int_by_const_ref([[^int_x]]);", PassMode::ConstRef, false},
1691 {"int_by_const_ref([[^123]]);", PassMode::ConstRef, false},
1692 {"int_by_value([[^int_ref]]);", PassMode::Value, false},
1693 {"int_by_const_ref([[^int_ref]]);", PassMode::ConstRef, false},
1694 {"int_by_const_ref([[^int_ref]]);", PassMode::ConstRef, false},
1695 {"int_by_const_ref([[^int_const_ref]]);", PassMode::ConstRef, false},
1696 // Custom class tests
1697 {"base_by_ref([[^base]]);", PassMode::Ref, false},
1698 {"base_by_const_ref([[^base]]);", PassMode::ConstRef, false},
1699 {"base_by_const_ref([[^base_const_ref]]);", PassMode::ConstRef, false},
1700 {"base_by_value([[^base]]);", PassMode::Value, false},
1701 {"base_by_value([[^base_const_ref]]);", PassMode::Value, false},
1702 {"base_by_ref([[^derived]]);", PassMode::Ref, false},
1703 {"base_by_const_ref([[^derived]]);", PassMode::ConstRef, false},
1704 {"base_by_value([[^derived]]);", PassMode::Value, false},
1705 // Custom class constructor tests
1706 {"CustomClass c1([[^base]]);", PassMode::ConstRef, false},
1707 {"auto c2 = new CustomClass([[^base]]);", PassMode::ConstRef, false},
1708 {"CustomClass c3([[^int_x]]);", PassMode::Ref, false},
1709 {"CustomClass c3(int_x, [[^int_x]]);", PassMode::Value, false},
1710 // Converted tests
1711 {"float_by_value([[^int_x]]);", PassMode::Value, true},
1712 {"float_by_value([[^int_ref]]);", PassMode::Value, true},
1713 {"float_by_value([[^int_const_ref]]);", PassMode::Value, true},
1714 {"float_by_value([[^123.0f]]);", PassMode::Value, false},
1715 {"float_by_value([[^123]]);", PassMode::Value, true},
1716 {"custom_by_value([[^int_x]]);", PassMode::Ref, true},
1717 {"custom_by_value([[^float_x]]);", PassMode::Value, true},
1718 {"custom_by_value([[^base]]);", PassMode::ConstRef, true},
1719 };
1720 for (const auto &Test : Tests) {
1721 SCOPED_TRACE(Test.Code);
1722
1723 const auto Code = (CodePrefix + Test.Code + CodeSuffix).str();
1724 Annotations T(Code);
1725 TestTU TU = TestTU::withCode(T.code());
1726 TU.ExtraArgs.push_back("-std=c++17");
1727 auto AST = TU.build();
1728 auto H = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
1729 ASSERT_TRUE(H);
1730 EXPECT_EQ(H->CallPassType->PassBy, Test.PassBy);
1731 EXPECT_EQ(H->CallPassType->Converted, Test.Converted);
1732 }
1733}
1734
1735TEST(Hover, NoHover) {
1736 llvm::StringRef Tests[] = {
1737 "^int main() {}",
1738 "void foo() {^}",
1739 // FIXME: "decltype(auto)" should be a single hover
1740 "decltype(au^to) x = 0;",
1741 // FIXME: not supported yet
1742 R"cpp(// Lambda auto parameter
1743 auto lamb = [](a^uto){};
1744 )cpp",
1745 R"cpp(// non-named decls don't get hover. Don't crash!
1746 ^static_assert(1, "");
1747 )cpp",
1748 R"cpp(// non-evaluatable expr
1749 template <typename T> void foo() {
1750 (void)[[size^of]](T);
1751 })cpp",
1752 R"cpp(// should not crash on invalid semantic form of init-list-expr.
1753 /*error-ok*/
1754 struct Foo {
1755 int xyz = 0;
1756 };
1757 class Bar {};
1758 constexpr Foo s = ^{
1759 .xyz = Bar(),
1760 };
1761 )cpp",
1762 // literals
1763 "auto x = t^rue;",
1764 "auto x = ^(int){42};",
1765 "auto x = ^42.;",
1766 "auto x = ^42.0i;",
1767 "auto x = ^42;",
1768 "auto x = ^nullptr;",
1769 };
1770
1771 for (const auto &Test : Tests) {
1772 SCOPED_TRACE(Test);
1773
1774 Annotations T(Test);
1775 TestTU TU = TestTU::withCode(T.code());
1776 TU.ExtraArgs.push_back("-std=c++17");
1777 auto AST = TU.build();
1778 auto H = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
1779 ASSERT_FALSE(H);
1780 }
1781}
1782
1783TEST(Hover, OffsetOfBuiltin) {
1784 Annotations T(R"cpp(
1785 struct Foo { int x; };
1786 int y = __builtin_o^ffsetof(Foo, x);
1787 )cpp");
1788 auto AST = TestTU::withCode(T.code()).build();
1789 auto H = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
1790 ASSERT_TRUE(H);
1791 EXPECT_EQ(H->Name, "expression");
1792 EXPECT_EQ(H->Kind, index::SymbolKind::Unknown);
1793}
1794
1795TEST(Hover, All) {
1796 struct {
1797 const char *const Code;
1798 const std::function<void(HoverInfo &)> ExpectedBuilder;
1799 } Cases[] = {
1800 {"auto x = [['^A']]; // character literal",
1801 [](HoverInfo &HI) {
1802 HI.Name = "expression";
1803 HI.Type = "char";
1804 HI.Value = "65 (0x41)";
1805 }},
1806 {"auto s = ^[[\"Hello, world!\"]]; // string literal",
1807 [](HoverInfo &HI) {
1808 HI.Name = "string-literal";
1809 HI.Size = 112;
1810 HI.Type = "const char[14]";
1811 }},
1812 {
1813 R"cpp(// Local variable
1814 int main() {
1815 int bonjour;
1816 ^[[bonjour]] = 2;
1817 int test1 = bonjour;
1818 }
1819 )cpp",
1820 [](HoverInfo &HI) {
1821 HI.Name = "bonjour";
1822 HI.Kind = index::SymbolKind::Variable;
1823 HI.NamespaceScope = "";
1824 HI.LocalScope = "main::";
1825 HI.Type = "int";
1826 HI.Definition = "int bonjour";
1827 }},
1828 {
1829 R"cpp(// Local variable in method
1830 struct s {
1831 void method() {
1832 int bonjour;
1833 ^[[bonjour]] = 2;
1834 }
1835 };
1836 )cpp",
1837 [](HoverInfo &HI) {
1838 HI.Name = "bonjour";
1839 HI.Kind = index::SymbolKind::Variable;
1840 HI.NamespaceScope = "";
1841 HI.LocalScope = "s::method::";
1842 HI.Type = "int";
1843 HI.Definition = "int bonjour";
1844 }},
1845 {
1846 R"cpp(// Struct
1847 namespace ns1 {
1848 struct MyClass {};
1849 } // namespace ns1
1850 int main() {
1851 ns1::[[My^Class]]* Params;
1852 }
1853 )cpp",
1854 [](HoverInfo &HI) {
1855 HI.Name = "MyClass";
1856 HI.Kind = index::SymbolKind::Struct;
1857 HI.NamespaceScope = "ns1::";
1858 HI.Definition = "struct MyClass {}";
1859 }},
1860 {
1861 R"cpp(// Class
1862 namespace ns1 {
1863 class MyClass {};
1864 } // namespace ns1
1865 int main() {
1866 ns1::[[My^Class]]* Params;
1867 }
1868 )cpp",
1869 [](HoverInfo &HI) {
1870 HI.Name = "MyClass";
1871 HI.Kind = index::SymbolKind::Class;
1872 HI.NamespaceScope = "ns1::";
1873 HI.Definition = "class MyClass {}";
1874 }},
1875 {
1876 R"cpp(// Union
1877 namespace ns1 {
1878 union MyUnion { int x; int y; };
1879 } // namespace ns1
1880 int main() {
1881 ns1::[[My^Union]] Params;
1882 }
1883 )cpp",
1884 [](HoverInfo &HI) {
1885 HI.Name = "MyUnion";
1886 HI.Kind = index::SymbolKind::Union;
1887 HI.NamespaceScope = "ns1::";
1888 HI.Definition = "union MyUnion {}";
1889 }},
1890 {
1891 R"cpp(// Function definition via pointer
1892 void foo(int) {}
1893 int main() {
1894 auto *X = &^[[foo]];
1895 }
1896 )cpp",
1897 [](HoverInfo &HI) {
1898 HI.Name = "foo";
1899 HI.Kind = index::SymbolKind::Function;
1900 HI.NamespaceScope = "";
1901 HI.Type = "void (int)";
1902 HI.Definition = "void foo(int)";
1903 HI.Documentation = "Function definition via pointer";
1904 HI.ReturnType = "void";
1905 HI.Parameters = {
1906 {{"int"}, std::nullopt, std::nullopt},
1907 };
1908 }},
1909 {
1910 R"cpp(// Function declaration via call
1911 int foo(int);
1912 int main() {
1913 return ^[[foo]](42);
1914 }
1915 )cpp",
1916 [](HoverInfo &HI) {
1917 HI.Name = "foo";
1918 HI.Kind = index::SymbolKind::Function;
1919 HI.NamespaceScope = "";
1920 HI.Type = "int (int)";
1921 HI.Definition = "int foo(int)";
1922 HI.Documentation = "Function declaration via call";
1923 HI.ReturnType = "int";
1924 HI.Parameters = {
1925 {{"int"}, std::nullopt, std::nullopt},
1926 };
1927 }},
1928 {
1929 R"cpp(// Field
1930 struct Foo { int x; };
1931 int main() {
1932 Foo bar;
1933 (void)bar.^[[x]];
1934 }
1935 )cpp",
1936 [](HoverInfo &HI) {
1937 HI.Name = "x";
1938 HI.Kind = index::SymbolKind::Field;
1939 HI.NamespaceScope = "";
1940 HI.LocalScope = "Foo::";
1941 HI.Type = "int";
1942 HI.Definition = "int x";
1943 }},
1944 {
1945 R"cpp(// Field with initialization
1946 struct Foo { int x = 5; };
1947 int main() {
1948 Foo bar;
1949 (void)bar.^[[x]];
1950 }
1951 )cpp",
1952 [](HoverInfo &HI) {
1953 HI.Name = "x";
1954 HI.Kind = index::SymbolKind::Field;
1955 HI.NamespaceScope = "";
1956 HI.LocalScope = "Foo::";
1957 HI.Type = "int";
1958 HI.Definition = "int x = 5";
1959 }},
1960 {
1961 R"cpp(// Static field
1962 struct Foo { static int x; };
1963 int main() {
1964 (void)Foo::^[[x]];
1965 }
1966 )cpp",
1967 [](HoverInfo &HI) {
1968 HI.Name = "x";
1969 HI.Kind = index::SymbolKind::StaticProperty;
1970 HI.NamespaceScope = "";
1971 HI.LocalScope = "Foo::";
1972 HI.Type = "int";
1973 HI.Definition = "static int x";
1974 }},
1975 {
1976 R"cpp(// Field, member initializer
1977 struct Foo {
1978 int x;
1979 Foo() : ^[[x]](0) {}
1980 };
1981 )cpp",
1982 [](HoverInfo &HI) {
1983 HI.Name = "x";
1984 HI.Kind = index::SymbolKind::Field;
1985 HI.NamespaceScope = "";
1986 HI.LocalScope = "Foo::";
1987 HI.Type = "int";
1988 HI.Definition = "int x";
1989 }},
1990 {
1991 R"cpp(// Field, GNU old-style field designator
1992 struct Foo { int x; };
1993 int main() {
1994 Foo bar = { ^[[x]] : 1 };
1995 }
1996 )cpp",
1997 [](HoverInfo &HI) {
1998 HI.Name = "x";
1999 HI.Kind = index::SymbolKind::Field;
2000 HI.NamespaceScope = "";
2001 HI.LocalScope = "Foo::";
2002 HI.Type = "int";
2003 HI.Definition = "int x";
2004 // FIXME: Initializer for x is a DesignatedInitListExpr, hence it is
2005 // of struct type and omitted.
2006 }},
2007 {
2008 R"cpp(// Field, field designator
2009 struct Foo { int x; int y; };
2010 int main() {
2011 Foo bar = { .^[[x]] = 2, .y = 2 };
2012 }
2013 )cpp",
2014 [](HoverInfo &HI) {
2015 HI.Name = "x";
2016 HI.Kind = index::SymbolKind::Field;
2017 HI.NamespaceScope = "";
2018 HI.LocalScope = "Foo::";
2019 HI.Type = "int";
2020 HI.Definition = "int x";
2021 }},
2022 {
2023 R"cpp(// Field, offsetof
2024 struct Foo { int x; int y; };
2025 int z = __builtin_offsetof(Foo, ^[[x]]);
2026 )cpp",
2027 [](HoverInfo &HI) {
2028 HI.Name = "x";
2029 HI.Kind = index::SymbolKind::Field;
2030 HI.NamespaceScope = "";
2031 HI.LocalScope = "Foo::";
2032 HI.Type = "int";
2033 HI.Definition = "int x";
2034 HI.Value = "0";
2035 }},
2036 {
2037 R"cpp(// Outer field, nested offsetof designator
2038 struct Inner { int c; };
2039 struct A { Inner B; };
2040 int z = __builtin_offsetof(A, ^[[B]].c);
2041 )cpp",
2042 [](HoverInfo &HI) {
2043 HI.Name = "B";
2044 HI.Kind = index::SymbolKind::Field;
2045 HI.NamespaceScope = "";
2046 HI.LocalScope = "A::";
2047 HI.Type = "Inner";
2048 HI.Definition = "Inner B";
2049 HI.Value = "0";
2050 }},
2051 {
2052 R"cpp(// Inner field, nested offsetof designator
2053 struct Inner { int c; };
2054 struct A { Inner B; };
2055 int z = __builtin_offsetof(A, B.^[[c]]);
2056 )cpp",
2057 [](HoverInfo &HI) {
2058 HI.Name = "c";
2059 HI.Kind = index::SymbolKind::Field;
2060 HI.NamespaceScope = "";
2061 HI.LocalScope = "Inner::";
2062 HI.Type = "int";
2063 HI.Definition = "int c";
2064 HI.Value = "0";
2065 }},
2066 {
2067 R"cpp(// Method call
2068 struct Foo { int x(); };
2069 int main() {
2070 Foo bar;
2071 bar.^[[x]]();
2072 }
2073 )cpp",
2074 [](HoverInfo &HI) {
2075 HI.Name = "x";
2076 HI.Kind = index::SymbolKind::InstanceMethod;
2077 HI.NamespaceScope = "";
2078 HI.LocalScope = "Foo::";
2079 HI.Type = "int ()";
2080 HI.Definition = "int x()";
2081 HI.ReturnType = "int";
2082 HI.Parameters = std::vector<HoverInfo::Param>{};
2083 }},
2084 {
2085 R"cpp(// Static method call
2086 struct Foo { static int x(); };
2087 int main() {
2088 Foo::^[[x]]();
2089 }
2090 )cpp",
2091 [](HoverInfo &HI) {
2092 HI.Name = "x";
2093 HI.Kind = index::SymbolKind::StaticMethod;
2094 HI.NamespaceScope = "";
2095 HI.LocalScope = "Foo::";
2096 HI.Type = "int ()";
2097 HI.Definition = "static int x()";
2098 HI.ReturnType = "int";
2099 HI.Parameters = std::vector<HoverInfo::Param>{};
2100 }},
2101 {
2102 R"cpp(// Typedef
2103 typedef int Foo;
2104 int main() {
2105 ^[[Foo]] bar;
2106 }
2107 )cpp",
2108 [](HoverInfo &HI) {
2109 HI.Name = "Foo";
2110 HI.Kind = index::SymbolKind::TypeAlias;
2111 HI.NamespaceScope = "";
2112 HI.Definition = "typedef int Foo";
2113 HI.Type = "int";
2114 HI.Documentation = "Typedef";
2115 }},
2116 {
2117 R"cpp(// Typedef with embedded definition
2118 typedef struct Bar {} Foo;
2119 int main() {
2120 ^[[Foo]] bar;
2121 }
2122 )cpp",
2123 [](HoverInfo &HI) {
2124 HI.Name = "Foo";
2125 HI.Kind = index::SymbolKind::TypeAlias;
2126 HI.NamespaceScope = "";
2127 HI.Definition = "typedef struct Bar Foo";
2128 HI.Type = "struct Bar";
2129 HI.Documentation = "Typedef with embedded definition";
2130 }},
2131 {
2132 R"cpp(// Namespace
2133 namespace ns {
2134 struct Foo { static void bar(); };
2135 } // namespace ns
2136 int main() { ^[[ns]]::Foo::bar(); }
2137 )cpp",
2138 [](HoverInfo &HI) {
2139 HI.Name = "ns";
2140 HI.Kind = index::SymbolKind::Namespace;
2141 HI.NamespaceScope = "";
2142 HI.Definition = "namespace ns {}";
2143 }},
2144 {
2145 R"cpp(// Anonymous namespace
2146 namespace ns {
2147 namespace {
2148 int foo;
2149 } // anonymous namespace
2150 } // namespace ns
2151 int main() { ns::[[f^oo]]++; }
2152 )cpp",
2153 [](HoverInfo &HI) {
2154 HI.Name = "foo";
2155 HI.Kind = index::SymbolKind::Variable;
2156 HI.NamespaceScope = "ns::";
2157 HI.Type = "int";
2158 HI.Definition = "int foo";
2159 }},
2160 {
2161 R"cpp(// Function definition via using declaration
2162 namespace ns {
2163 void foo();
2164 }
2165 int main() {
2166 using ns::foo;
2167 ^[[foo]]();
2168 }
2169 )cpp",
2170 [](HoverInfo &HI) {
2171 HI.Name = "foo";
2172 HI.Kind = index::SymbolKind::Function;
2173 HI.NamespaceScope = "ns::";
2174 HI.Type = "void ()";
2175 HI.Definition = "void foo()";
2176 HI.Documentation = "";
2177 HI.ReturnType = "void";
2178 HI.Parameters = std::vector<HoverInfo::Param>{};
2179 }},
2180 {
2181 R"cpp( // using declaration and two possible function declarations
2182 namespace ns { void foo(int); void foo(char); }
2183 using ns::foo;
2184 template <typename T> void bar() { [[f^oo]](T{}); }
2185 )cpp",
2186 [](HoverInfo &HI) {
2187 HI.Name = "foo";
2188 HI.Kind = index::SymbolKind::Using;
2189 HI.NamespaceScope = "";
2190 HI.Definition = "using ns::foo";
2191 }},
2192 {
2193 R"cpp(// Macro
2194 #define MACRO 0
2195 int main() { return ^[[MACRO]]; }
2196 )cpp",
2197 [](HoverInfo &HI) {
2198 HI.Name = "MACRO";
2199 HI.Value = "0";
2200 HI.Type = "int";
2201 HI.Kind = index::SymbolKind::Macro;
2202 HI.Definition = "#define MACRO 0\n\n"
2203 "// Expands to\n"
2204 "0";
2205 }},
2206 {
2207 R"cpp(// Macro
2208 #define MACRO 0
2209 #define MACRO2 ^[[MACRO]]
2210 )cpp",
2211 [](HoverInfo &HI) {
2212 HI.Name = "MACRO";
2213 HI.Kind = index::SymbolKind::Macro;
2214 HI.Definition = "#define MACRO 0";
2215 // NOTE MACRO doesn't have expansion since it technically isn't
2216 // expanded here
2217 }},
2218 {
2219 R"cpp(// Macro
2220 #define MACRO {\
2221 return 0;\
2222 }
2223 int main() ^[[MACRO]]
2224 )cpp",
2225 [](HoverInfo &HI) {
2226 HI.Name = "MACRO";
2227 HI.Kind = index::SymbolKind::Macro;
2228 HI.Definition =
2229 R"cpp(#define MACRO \
2230 { \
2231 return 0; \
2232 }
2233
2234// Expands to
2235{
2236 return 0;
2237})cpp";
2238 }},
2239 {
2240 R"cpp(// Forward class declaration
2241 class Foo;
2242 class Foo {};
2243 [[F^oo]]* foo();
2244 )cpp",
2245 [](HoverInfo &HI) {
2246 HI.Name = "Foo";
2247 HI.Kind = index::SymbolKind::Class;
2248 HI.NamespaceScope = "";
2249 HI.Definition = "class Foo {}";
2250 HI.Documentation = "Forward class declaration";
2251 }},
2252 {
2253 R"cpp(// Function declaration
2254 void foo();
2255 void g() { [[f^oo]](); }
2256 void foo() {}
2257 )cpp",
2258 [](HoverInfo &HI) {
2259 HI.Name = "foo";
2260 HI.Kind = index::SymbolKind::Function;
2261 HI.NamespaceScope = "";
2262 HI.Type = "void ()";
2263 HI.Definition = "void foo()";
2264 HI.Documentation = "Function declaration";
2265 HI.ReturnType = "void";
2266 HI.Parameters = std::vector<HoverInfo::Param>{};
2267 }},
2268 {
2269 R"cpp(// Enum declaration
2270 enum Hello {
2271 ONE, TWO, THREE,
2272 };
2273 void foo() {
2274 [[Hel^lo]] hello = ONE;
2275 }
2276 )cpp",
2277 [](HoverInfo &HI) {
2278 HI.Name = "Hello";
2279 HI.Kind = index::SymbolKind::Enum;
2280 HI.NamespaceScope = "";
2281 HI.Definition = "enum Hello {}";
2282 HI.Documentation = "Enum declaration";
2283 }},
2284 {
2285 R"cpp(// Enumerator
2286 enum Hello {
2287 ONE, TWO, THREE,
2288 };
2289 void foo() {
2290 Hello hello = [[O^NE]];
2291 }
2292 )cpp",
2293 [](HoverInfo &HI) {
2294 HI.Name = "ONE";
2295 HI.Kind = index::SymbolKind::EnumConstant;
2296 HI.NamespaceScope = "";
2297 HI.LocalScope = "Hello::";
2298 HI.Type = "enum Hello";
2299 HI.Definition = "ONE";
2300 HI.Value = "0";
2301 }},
2302 {
2303 R"cpp(// C++20's using enum
2304 enum class Hello {
2305 ONE, TWO, THREE,
2306 };
2307 void foo() {
2308 using enum Hello;
2309 Hello hello = [[O^NE]];
2310 }
2311 )cpp",
2312 [](HoverInfo &HI) {
2313 HI.Name = "ONE";
2314 HI.Kind = index::SymbolKind::EnumConstant;
2315 HI.NamespaceScope = "";
2316 HI.LocalScope = "Hello::";
2317 HI.Type = "enum Hello";
2318 HI.Definition = "ONE";
2319 HI.Value = "0";
2320 }},
2321 {
2322 R"cpp(// Enumerator in anonymous enum
2323 enum {
2324 ONE, TWO, THREE,
2325 };
2326 void foo() {
2327 int hello = [[O^NE]];
2328 }
2329 )cpp",
2330 [](HoverInfo &HI) {
2331 HI.Name = "ONE";
2332 HI.Kind = index::SymbolKind::EnumConstant;
2333 HI.NamespaceScope = "";
2334 // FIXME: This should be `(anon enum)::`
2335 HI.LocalScope = "";
2336 HI.Type = "enum (unnamed)";
2337 HI.Definition = "ONE";
2338 HI.Value = "0";
2339 }},
2340 {
2341 R"cpp(// Global variable
2342 static int hey = 10;
2343 void foo() {
2344 [[he^y]]++;
2345 }
2346 )cpp",
2347 [](HoverInfo &HI) {
2348 HI.Name = "hey";
2349 HI.Kind = index::SymbolKind::Variable;
2350 HI.NamespaceScope = "";
2351 HI.Type = "int";
2352 HI.Definition = "static int hey = 10";
2353 HI.Documentation = "Global variable";
2354 // FIXME: Value shouldn't be set in this case
2355 HI.Value = "10 (0xa)";
2356 }},
2357 {
2358 R"cpp(// Global variable in namespace
2359 namespace ns1 {
2360 static long long hey = -36637162602497;
2361 }
2362 void foo() {
2363 ns1::[[he^y]]++;
2364 }
2365 )cpp",
2366 [](HoverInfo &HI) {
2367 HI.Name = "hey";
2368 HI.Kind = index::SymbolKind::Variable;
2369 HI.NamespaceScope = "ns1::";
2370 HI.Type = "long long";
2371 HI.Definition = "static long long hey = -36637162602497";
2372 HI.Value = "-36637162602497 (0xffffdeadbeefffff)"; // needs 64 bits
2373 }},
2374 {
2375 R"cpp(// Field in anonymous struct
2376 static struct {
2377 int hello;
2378 } s;
2379 void foo() {
2380 s.[[he^llo]]++;
2381 }
2382 )cpp",
2383 [](HoverInfo &HI) {
2384 HI.Name = "hello";
2385 HI.Kind = index::SymbolKind::Field;
2386 HI.NamespaceScope = "";
2387 HI.LocalScope = "(anonymous struct)::";
2388 HI.Type = "int";
2389 HI.Definition = "int hello";
2390 }},
2391 {
2392 R"cpp(// Templated function
2393 template <typename T>
2394 T foo() {
2395 return 17;
2396 }
2397 void g() { auto x = [[f^oo]]<int>(); }
2398 )cpp",
2399 [](HoverInfo &HI) {
2400 HI.Name = "foo";
2401 HI.Kind = index::SymbolKind::Function;
2402 HI.NamespaceScope = "";
2403 HI.Type = "int ()";
2404 HI.Definition = "template <> int foo<int>()";
2405 HI.Documentation = "Templated function";
2406 HI.ReturnType = "int";
2407 HI.Parameters = std::vector<HoverInfo::Param>{};
2408 // FIXME: We should populate template parameters with arguments in
2409 // case of instantiations.
2410 }},
2411 {
2412 R"cpp(// Anonymous union
2413 struct outer {
2414 union {
2415 int abc, def;
2416 } v;
2417 };
2418 void g() { struct outer o; o.v.[[d^ef]]++; }
2419 )cpp",
2420 [](HoverInfo &HI) {
2421 HI.Name = "def";
2422 HI.Kind = index::SymbolKind::Field;
2423 HI.NamespaceScope = "";
2424 HI.LocalScope = "outer::(anonymous union)::";
2425 HI.Type = "int";
2426 HI.Definition = "int def";
2427 }},
2428 {
2429 R"cpp(// documentation from index
2430 int nextSymbolIsAForwardDeclFromIndexWithNoLocalDocs;
2431 void indexSymbol();
2432 void g() { [[ind^exSymbol]](); }
2433 )cpp",
2434 [](HoverInfo &HI) {
2435 HI.Name = "indexSymbol";
2436 HI.Kind = index::SymbolKind::Function;
2437 HI.NamespaceScope = "";
2438 HI.Type = "void ()";
2439 HI.Definition = "void indexSymbol()";
2440 HI.ReturnType = "void";
2441 HI.Parameters = std::vector<HoverInfo::Param>{};
2442 HI.Documentation = "comment from index";
2443 }},
2444 {
2445 R"cpp(// Simple initialization with auto
2446 void foo() {
2447 ^[[auto]] i = 1;
2448 }
2449 )cpp",
2450 [](HoverInfo &HI) {
2451 HI.Name = "auto";
2452 HI.Kind = index::SymbolKind::TypeAlias;
2453 HI.Definition = "int";
2454 }},
2455 {
2456 R"cpp(// Simple initialization with const auto
2457 void foo() {
2458 const ^[[auto]] i = 1;
2459 }
2460 )cpp",
2461 [](HoverInfo &HI) {
2462 HI.Name = "auto";
2463 HI.Kind = index::SymbolKind::TypeAlias;
2464 HI.Definition = "int";
2465 }},
2466 {
2467 R"cpp(// Simple initialization with const auto&
2468 void foo() {
2469 const ^[[auto]]& i = 1;
2470 }
2471 )cpp",
2472 [](HoverInfo &HI) {
2473 HI.Name = "auto";
2474 HI.Kind = index::SymbolKind::TypeAlias;
2475 HI.Definition = "int";
2476 }},
2477 {
2478 R"cpp(// Simple initialization with auto&
2479 void foo() {
2480 int x;
2481 ^[[auto]]& i = x;
2482 }
2483 )cpp",
2484 [](HoverInfo &HI) {
2485 HI.Name = "auto";
2486 HI.Kind = index::SymbolKind::TypeAlias;
2487 HI.Definition = "int";
2488 }},
2489 {
2490 R"cpp(// Simple initialization with auto*
2491 void foo() {
2492 int a = 1;
2493 ^[[auto]]* i = &a;
2494 }
2495 )cpp",
2496 [](HoverInfo &HI) {
2497 HI.Name = "auto";
2498 HI.Kind = index::SymbolKind::TypeAlias;
2499 HI.Definition = "int";
2500 }},
2501 {
2502 R"cpp(// Simple initialization with auto from pointer
2503 void foo() {
2504 int a = 1;
2505 ^[[auto]] i = &a;
2506 }
2507 )cpp",
2508 [](HoverInfo &HI) {
2509 HI.Name = "auto";
2510 HI.Kind = index::SymbolKind::TypeAlias;
2511 HI.Definition = "int *";
2512 }},
2513 {
2514 R"cpp(// Auto with initializer list.
2515 namespace std
2516 {
2517 template<class _E>
2518 class initializer_list { const _E *a, *b; };
2519 }
2520 void foo() {
2521 ^[[auto]] i = {1,2};
2522 }
2523 )cpp",
2524 [](HoverInfo &HI) {
2525 HI.Name = "auto";
2526 HI.Kind = index::SymbolKind::TypeAlias;
2527 HI.Definition = "std::initializer_list<int>";
2528 }},
2529 {
2530 R"cpp(// User defined conversion to auto
2531 struct Bar {
2532 operator ^[[auto]]() const { return 10; }
2533 };
2534 )cpp",
2535 [](HoverInfo &HI) {
2536 HI.Name = "auto";
2537 HI.Kind = index::SymbolKind::TypeAlias;
2538 HI.Definition = "int";
2539 }},
2540 {
2541 R"cpp(// Simple initialization with decltype(auto)
2542 void foo() {
2543 ^[[decltype]](auto) i = 1;
2544 }
2545 )cpp",
2546 [](HoverInfo &HI) {
2547 HI.Name = "decltype";
2548 HI.Kind = index::SymbolKind::TypeAlias;
2549 HI.Definition = "int";
2550 }},
2551 {
2552 R"cpp(// Simple initialization with const decltype(auto)
2553 void foo() {
2554 const int j = 0;
2555 ^[[decltype]](auto) i = j;
2556 }
2557 )cpp",
2558 [](HoverInfo &HI) {
2559 HI.Name = "decltype";
2560 HI.Kind = index::SymbolKind::TypeAlias;
2561 HI.Definition = "const int";
2562 }},
2563 {
2564 R"cpp(// Simple initialization with const& decltype(auto)
2565 void foo() {
2566 int k = 0;
2567 const int& j = k;
2568 ^[[decltype]](auto) i = j;
2569 }
2570 )cpp",
2571 [](HoverInfo &HI) {
2572 HI.Name = "decltype";
2573 HI.Kind = index::SymbolKind::TypeAlias;
2574 HI.Definition = "const int &";
2575 }},
2576 {
2577 R"cpp(// Simple initialization with & decltype(auto)
2578 void foo() {
2579 int k = 0;
2580 int& j = k;
2581 ^[[decltype]](auto) i = j;
2582 }
2583 )cpp",
2584 [](HoverInfo &HI) {
2585 HI.Name = "decltype";
2586 HI.Kind = index::SymbolKind::TypeAlias;
2587 HI.Definition = "int &";
2588 }},
2589 {
2590 R"cpp(// simple trailing return type
2591 ^[[auto]] main() -> int {
2592 return 0;
2593 }
2594 )cpp",
2595 [](HoverInfo &HI) {
2596 HI.Name = "auto";
2597 HI.Kind = index::SymbolKind::TypeAlias;
2598 HI.Definition = "int";
2599 }},
2600 {
2601 R"cpp(// auto function return with trailing type
2602 struct Bar {};
2603 ^[[auto]] test() -> decltype(Bar()) {
2604 return Bar();
2605 }
2606 )cpp",
2607 [](HoverInfo &HI) {
2608 HI.Name = "auto";
2609 HI.Kind = index::SymbolKind::TypeAlias;
2610 HI.Definition = "Bar";
2611 HI.Documentation = "auto function return with trailing type";
2612 }},
2613 {
2614 R"cpp(// trailing return type
2615 struct Bar {};
2616 auto test() -> ^[[decltype]](Bar()) {
2617 return Bar();
2618 }
2619 )cpp",
2620 [](HoverInfo &HI) {
2621 HI.Name = "decltype";
2622 HI.Kind = index::SymbolKind::TypeAlias;
2623 HI.Definition = "Bar";
2624 HI.Documentation = "trailing return type";
2625 }},
2626 {
2627 R"cpp(// auto in function return
2628 struct Bar {};
2629 ^[[auto]] test() {
2630 return Bar();
2631 }
2632 )cpp",
2633 [](HoverInfo &HI) {
2634 HI.Name = "auto";
2635 HI.Kind = index::SymbolKind::TypeAlias;
2636 HI.Definition = "Bar";
2637 HI.Documentation = "auto in function return";
2638 }},
2639 {
2640 R"cpp(// auto& in function return
2641 struct Bar {};
2642 ^[[auto]]& test() {
2643 static Bar x;
2644 return x;
2645 }
2646 )cpp",
2647 [](HoverInfo &HI) {
2648 HI.Name = "auto";
2649 HI.Kind = index::SymbolKind::TypeAlias;
2650 HI.Definition = "Bar";
2651 HI.Documentation = "auto& in function return";
2652 }},
2653 {
2654 R"cpp(// auto* in function return
2655 struct Bar {};
2656 ^[[auto]]* test() {
2657 Bar* bar;
2658 return bar;
2659 }
2660 )cpp",
2661 [](HoverInfo &HI) {
2662 HI.Name = "auto";
2663 HI.Kind = index::SymbolKind::TypeAlias;
2664 HI.Definition = "Bar";
2665 HI.Documentation = "auto* in function return";
2666 }},
2667 {
2668 R"cpp(// const auto& in function return
2669 struct Bar {};
2670 const ^[[auto]]& test() {
2671 static Bar x;
2672 return x;
2673 }
2674 )cpp",
2675 [](HoverInfo &HI) {
2676 HI.Name = "auto";
2677 HI.Kind = index::SymbolKind::TypeAlias;
2678 HI.Definition = "Bar";
2679 HI.Documentation = "const auto& in function return";
2680 }},
2681 {
2682 R"cpp(// decltype(auto) in function return
2683 struct Bar {};
2684 ^[[decltype]](auto) test() {
2685 return Bar();
2686 }
2687 )cpp",
2688 [](HoverInfo &HI) {
2689 HI.Name = "decltype";
2690 HI.Kind = index::SymbolKind::TypeAlias;
2691 HI.Definition = "Bar";
2692 HI.Documentation = "decltype(auto) in function return";
2693 }},
2694 {
2695 R"cpp(// decltype(auto) reference in function return
2696 ^[[decltype]](auto) test() {
2697 static int a;
2698 return (a);
2699 }
2700 )cpp",
2701 [](HoverInfo &HI) {
2702 HI.Name = "decltype";
2703 HI.Kind = index::SymbolKind::TypeAlias;
2704 HI.Definition = "int &";
2705 }},
2706 {
2707 R"cpp(// decltype lvalue reference
2708 void foo() {
2709 int I = 0;
2710 ^[[decltype]](I) J = I;
2711 }
2712 )cpp",
2713 [](HoverInfo &HI) {
2714 HI.Name = "decltype";
2715 HI.Kind = index::SymbolKind::TypeAlias;
2716 HI.Definition = "int";
2717 }},
2718 {
2719 R"cpp(// decltype lvalue reference
2720 void foo() {
2721 int I= 0;
2722 int &K = I;
2723 ^[[decltype]](K) J = I;
2724 }
2725 )cpp",
2726 [](HoverInfo &HI) {
2727 HI.Name = "decltype";
2728 HI.Kind = index::SymbolKind::TypeAlias;
2729 HI.Definition = "int &";
2730 }},
2731 {
2732 R"cpp(// decltype lvalue reference parenthesis
2733 void foo() {
2734 int I = 0;
2735 ^[[decltype]]((I)) J = I;
2736 }
2737 )cpp",
2738 [](HoverInfo &HI) {
2739 HI.Name = "decltype";
2740 HI.Kind = index::SymbolKind::TypeAlias;
2741 HI.Definition = "int &";
2742 }},
2743 {
2744 R"cpp(// decltype rvalue reference
2745 void foo() {
2746 int I = 0;
2747 ^[[decltype]](static_cast<int&&>(I)) J = static_cast<int&&>(I);
2748 }
2749 )cpp",
2750 [](HoverInfo &HI) {
2751 HI.Name = "decltype";
2752 HI.Kind = index::SymbolKind::TypeAlias;
2753 HI.Definition = "int &&";
2754 }},
2755 {
2756 R"cpp(// decltype rvalue reference function call
2757 int && bar();
2758 void foo() {
2759 int I = 0;
2760 ^[[decltype]](bar()) J = bar();
2761 }
2762 )cpp",
2763 [](HoverInfo &HI) {
2764 HI.Name = "decltype";
2765 HI.Kind = index::SymbolKind::TypeAlias;
2766 HI.Definition = "int &&";
2767 }},
2768 {
2769 R"cpp(// decltype of function with trailing return type.
2770 struct Bar {};
2771 auto test() -> decltype(Bar()) {
2772 return Bar();
2773 }
2774 void foo() {
2775 ^[[decltype]](test()) i = test();
2776 }
2777 )cpp",
2778 [](HoverInfo &HI) {
2779 HI.Name = "decltype";
2780 HI.Kind = index::SymbolKind::TypeAlias;
2781 HI.Definition = "Bar";
2782 HI.Documentation =
2783 "decltype of function with trailing return type.";
2784 }},
2785 {
2786 R"cpp(// decltype of var with decltype.
2787 void foo() {
2788 int I = 0;
2789 decltype(I) J = I;
2790 ^[[decltype]](J) K = J;
2791 }
2792 )cpp",
2793 [](HoverInfo &HI) {
2794 HI.Name = "decltype";
2795 HI.Kind = index::SymbolKind::TypeAlias;
2796 HI.Definition = "int";
2797 }},
2798 {
2799 R"cpp(// decltype of dependent type
2800 template <typename T>
2801 struct X {
2802 using Y = ^[[decltype]](T::Z);
2803 };
2804 )cpp",
2805 [](HoverInfo &HI) {
2806 HI.Name = "decltype";
2807 HI.Kind = index::SymbolKind::TypeAlias;
2808 HI.Definition = "<dependent type>";
2809 }},
2810 {
2811 R"cpp(// More complicated structured types.
2812 int bar();
2813 ^[[auto]] (*foo)() = bar;
2814 )cpp",
2815 [](HoverInfo &HI) {
2816 HI.Name = "auto";
2817 HI.Kind = index::SymbolKind::TypeAlias;
2818 HI.Definition = "int";
2819 }},
2820 {
2821 R"cpp(// Should not crash when evaluating the initializer.
2822 struct Test {};
2823 void test() { Test && [[te^st]] = {}; }
2824 )cpp",
2825 [](HoverInfo &HI) {
2826 HI.Name = "test";
2827 HI.Kind = index::SymbolKind::Variable;
2828 HI.NamespaceScope = "";
2829 HI.LocalScope = "test::";
2830 HI.Type = "Test &&";
2831 HI.Definition = "Test &&test = {}";
2832 }},
2833 {
2834 R"cpp(// Shouldn't crash when evaluating the initializer.
2835 struct Bar {}; // error-ok
2836 struct Foo { void foo(Bar x = y); }
2837 void Foo::foo(Bar [[^x]]) {})cpp",
2838 [](HoverInfo &HI) {
2839 HI.Name = "x";
2840 HI.Kind = index::SymbolKind::Parameter;
2841 HI.NamespaceScope = "";
2842 HI.LocalScope = "Foo::foo::";
2843 HI.Type = "Bar";
2844 HI.Definition = "Bar x = <recovery - expr>()";
2845 }},
2846 {
2847 R"cpp(// auto on alias
2848 typedef int int_type;
2849 ^[[auto]] x = int_type();
2850 )cpp",
2851 [](HoverInfo &HI) {
2852 HI.Name = "auto";
2853 HI.Kind = index::SymbolKind::TypeAlias;
2854 HI.Definition = "int_type // aka: int";
2855 }},
2856 {
2857 R"cpp(// auto on alias
2858 struct cls {};
2859 typedef cls cls_type;
2860 ^[[auto]] y = cls_type();
2861 )cpp",
2862 [](HoverInfo &HI) {
2863 HI.Name = "auto";
2864 HI.Kind = index::SymbolKind::TypeAlias;
2865 HI.Definition = "cls_type // aka: cls";
2866 HI.Documentation = "auto on alias";
2867 }},
2868 {
2869 R"cpp(// auto on alias
2870 template <class>
2871 struct templ {};
2872 ^[[auto]] z = templ<int>();
2873 )cpp",
2874 [](HoverInfo &HI) {
2875 HI.Name = "auto";
2876 HI.Kind = index::SymbolKind::TypeAlias;
2877 HI.Definition = "templ<int>";
2878 HI.Documentation = "auto on alias";
2879 }},
2880 {
2881 R"cpp(// Undeduced auto declaration
2882 template<typename T>
2883 void foo() {
2884 ^[[auto]] x = T();
2885 }
2886 )cpp",
2887 [](HoverInfo &HI) {
2888 HI.Name = "auto";
2889 HI.Kind = index::SymbolKind::TypeAlias;
2890 HI.Definition = "T";
2891 }},
2892 {
2893 R"cpp(// Undeduced auto return type
2894 template<typename T>
2895 ^[[auto]] foo() {
2896 return T();
2897 }
2898 )cpp",
2899 [](HoverInfo &HI) {
2900 HI.Name = "auto";
2901 HI.Kind = index::SymbolKind::TypeAlias;
2902 HI.Definition = "/* not deduced */";
2903 }},
2904 {
2905 R"cpp(// Template auto parameter
2906 template<[[a^uto]] T>
2907 void func() {
2908 }
2909 )cpp",
2910 [](HoverInfo &HI) {
2911 // FIXME: not sure this is what we want, but this
2912 // is what we currently get with getDeducedType
2913 HI.Name = "auto";
2914 HI.Kind = index::SymbolKind::TypeAlias;
2915 HI.Definition = "/* not deduced */";
2916 }},
2917 {
2918 R"cpp(// Undeduced decltype(auto) return type
2919 template<typename T>
2920 ^[[decltype]](auto) foo() {
2921 return T();
2922 }
2923 )cpp",
2924 [](HoverInfo &HI) {
2925 HI.Name = "decltype";
2926 HI.Kind = index::SymbolKind::TypeAlias;
2927 HI.Definition = "/* not deduced */";
2928 }},
2929 {
2930 R"cpp(// should not crash.
2931 template <class T> struct cls {
2932 int method();
2933 };
2934
2935 auto test = cls<int>().[[m^ethod]]();
2936 )cpp",
2937 [](HoverInfo &HI) {
2938 HI.Definition = "int method()";
2939 HI.Kind = index::SymbolKind::InstanceMethod;
2940 HI.NamespaceScope = "";
2941 HI.LocalScope = "cls<int>::";
2942 HI.Name = "method";
2943 HI.Parameters.emplace();
2944 HI.ReturnType = "int";
2945 HI.Type = "int ()";
2946 }},
2947 {
2948 R"cpp(// type of nested templates.
2949 template <class T> struct cls {};
2950 cls<cls<cls<int>>> [[fo^o]];
2951 )cpp",
2952 [](HoverInfo &HI) {
2953 HI.Definition = "cls<cls<cls<int>>> foo";
2954 HI.Kind = index::SymbolKind::Variable;
2955 HI.NamespaceScope = "";
2956 HI.Name = "foo";
2957 HI.Type = "cls<cls<cls<int>>>";
2958 }},
2959 {
2960 R"cpp(// type of nested templates.
2961 template <class T> struct cls {};
2962 [[cl^s]]<cls<cls<int>>> foo;
2963 )cpp",
2964 [](HoverInfo &HI) {
2965 HI.Definition = "template <> struct cls<cls<cls<int>>> {}";
2966 HI.Kind = index::SymbolKind::Struct;
2967 HI.NamespaceScope = "";
2968 HI.Name = "cls<cls<cls<int>>>";
2969 HI.Documentation = "type of nested templates.";
2970 }},
2971 {
2972 R"cpp(// type with decltype
2973 int a;
2974 decltype(a) [[b^]] = a;)cpp",
2975 [](HoverInfo &HI) {
2976 HI.Definition = "decltype(a) b = a";
2977 HI.Kind = index::SymbolKind::Variable;
2978 HI.NamespaceScope = "";
2979 HI.Name = "b";
2980 HI.Type = "int";
2981 }},
2982 {
2983 R"cpp(// type with decltype
2984 int a;
2985 decltype(a) c;
2986 decltype(c) [[b^]] = a;)cpp",
2987 [](HoverInfo &HI) {
2988 HI.Definition = "decltype(c) b = a";
2989 HI.Kind = index::SymbolKind::Variable;
2990 HI.NamespaceScope = "";
2991 HI.Name = "b";
2992 HI.Type = "int";
2993 }},
2994 {
2995 R"cpp(// type with decltype
2996 int a;
2997 const decltype(a) [[b^]] = a;)cpp",
2998 [](HoverInfo &HI) {
2999 HI.Definition = "const decltype(a) b = a";
3000 HI.Kind = index::SymbolKind::Variable;
3001 HI.NamespaceScope = "";
3002 HI.Name = "b";
3003 HI.Type = "const int";
3004 }},
3005 {
3006 R"cpp(// type with decltype
3007 int a;
3008 auto [[f^oo]](decltype(a) x) -> decltype(a) { return 0; })cpp",
3009 [](HoverInfo &HI) {
3010 HI.Definition = "auto foo(decltype(a) x) -> decltype(a)";
3011 HI.Kind = index::SymbolKind::Function;
3012 HI.NamespaceScope = "";
3013 HI.Name = "foo";
3014 HI.Type = "auto (int) -> int";
3015 HI.ReturnType = "int";
3016 HI.Parameters = {{{"int"}, std::string("x"), std::nullopt}};
3017 }},
3018 {
3019 R"cpp(// sizeof expr
3020 void foo() {
3021 (void)[[size^of]](char);
3022 })cpp",
3023 [](HoverInfo &HI) {
3024 HI.Name = "expression";
3025 HI.Type = {"__size_t", "unsigned long"};
3026 HI.Value = "1";
3027 }},
3028 {
3029 R"cpp(// alignof expr
3030 void foo() {
3031 (void)[[align^of]](char);
3032 })cpp",
3033 [](HoverInfo &HI) {
3034 HI.Name = "expression";
3035 HI.Type = {"__size_t", "unsigned long"};
3036 HI.Value = "1";
3037 }},
3038 {
3039 R"cpp(
3040 template <typename T = int>
3041 void foo(const T& = T()) {
3042 [[f^oo]]<>(3);
3043 })cpp",
3044 [](HoverInfo &HI) {
3045 HI.Name = "foo";
3046 HI.Kind = index::SymbolKind::Function;
3047 HI.Type = "void (const int &)";
3048 HI.ReturnType = "void";
3049 HI.Parameters = {
3050 {{"const int &"}, std::nullopt, std::string("T()")}};
3051 HI.Definition = "template <> void foo<int>(const int &)";
3052 HI.NamespaceScope = "";
3053 }},
3054 {
3055 R"cpp(// should not crash
3056 @interface ObjC {
3057 char [[da^ta]];
3058 }@end
3059 )cpp",
3060 [](HoverInfo &HI) {
3061 HI.Name = "data";
3062 HI.Type = "char";
3063 HI.Kind = index::SymbolKind::Field;
3064 HI.LocalScope = "ObjC::";
3065 HI.NamespaceScope = "";
3066 HI.Definition = "char data";
3067 }},
3068 {
3069 R"cpp(
3070 @interface MYObject
3071 @end
3072 @interface Interface
3073 @property(retain) [[MYOb^ject]] *x;
3074 @end
3075 )cpp",
3076 [](HoverInfo &HI) {
3077 HI.Name = "MYObject";
3078 HI.Kind = index::SymbolKind::Class;
3079 HI.NamespaceScope = "";
3080 HI.Definition = "@interface MYObject\n@end";
3081 }},
3082 {
3083 R"cpp(
3084 @interface MYObject
3085 @end
3086 @interface Interface
3087 - (void)doWith:([[MYOb^ject]] *)object;
3088 @end
3089 )cpp",
3090 [](HoverInfo &HI) {
3091 HI.Name = "MYObject";
3092 HI.Kind = index::SymbolKind::Class;
3093 HI.NamespaceScope = "";
3094 HI.Definition = "@interface MYObject\n@end";
3095 }},
3096 {
3097 R"cpp(// this expr
3098 // comment
3099 namespace ns {
3100 class Foo {
3101 Foo* bar() {
3102 return [[t^his]];
3103 }
3104 };
3105 }
3106 )cpp",
3107 [](HoverInfo &HI) {
3108 HI.Name = "this";
3109 HI.Definition = "ns::Foo *";
3110 }},
3111 {
3112 R"cpp(// this expr for template class
3113 namespace ns {
3114 template <typename T>
3115 class Foo {
3116 Foo* bar() const {
3117 return [[t^his]];
3118 }
3119 };
3120 }
3121 )cpp",
3122 [](HoverInfo &HI) {
3123 HI.Name = "this";
3124 HI.Definition = "const ns::Foo<T> *";
3125 }},
3126 {
3127 R"cpp(// this expr for specialization class
3128 namespace ns {
3129 template <typename T> class Foo {};
3130 template <>
3131 struct Foo<int> {
3132 Foo* bar() {
3133 return [[thi^s]];
3134 }
3135 };
3136 }
3137 )cpp",
3138 [](HoverInfo &HI) {
3139 HI.Name = "this";
3140 HI.Definition = "ns::Foo<int> *";
3141 }},
3142 {
3143 R"cpp(// this expr for partial specialization struct
3144 namespace ns {
3145 template <typename T, typename F> struct Foo {};
3146 template <typename F>
3147 struct Foo<int, F> {
3148 Foo* bar() const {
3149 return [[thi^s]];
3150 }
3151 };
3152 }
3153 )cpp",
3154 [](HoverInfo &HI) {
3155 HI.Name = "this";
3156 HI.Definition = "const ns::Foo<int, F> *";
3157 }},
3158 {
3159 R"cpp(
3160 @interface MYObject
3161 @end
3162 @interface MYObject (Private)
3163 @property(nonatomic, assign) int privateField;
3164 @end
3165
3166 int someFunction() {
3167 MYObject *obj = [MYObject sharedInstance];
3168 return obj.[[private^Field]];
3169 }
3170 )cpp",
3171 [](HoverInfo &HI) {
3172 HI.Name = "privateField";
3173 HI.Kind = index::SymbolKind::InstanceProperty;
3174 HI.LocalScope = "MYObject(Private)::";
3175 HI.NamespaceScope = "";
3176 HI.Definition = "@property(nonatomic, assign, unsafe_unretained, "
3177 "readwrite) int privateField;";
3178 }},
3179 {
3180 R"cpp(
3181 @protocol MYProtocol
3182 @property(nonatomic, assign) int prop1;
3183 @end
3184
3185 int someFunction() {
3186 id<MYProtocol> obj = 0;
3187 return obj.[[pro^p1]];
3188 }
3189 )cpp",
3190 [](HoverInfo &HI) {
3191 HI.Name = "prop1";
3192 HI.Kind = index::SymbolKind::InstanceProperty;
3193 HI.LocalScope = "MYProtocol::";
3194 HI.NamespaceScope = "";
3195 HI.Definition = "@property(nonatomic, assign, unsafe_unretained, "
3196 "readwrite) int prop1;";
3197 }},
3198 {
3199 R"cpp(
3200 @protocol MYProtocol
3201 @end
3202 @interface MYObject
3203 @end
3204
3205 @interface MYObject (Ext) <[[MYProt^ocol]]>
3206 @end
3207 )cpp",
3208 [](HoverInfo &HI) {
3209 HI.Name = "MYProtocol";
3210 HI.Kind = index::SymbolKind::Protocol;
3211 HI.NamespaceScope = "";
3212 HI.Definition = "@protocol MYProtocol\n@end";
3213 }},
3214 {R"objc(
3215 @interface Foo
3216 @end
3217
3218 @implementation Foo(Private)
3219 + (int)somePrivateMethod {
3220 int [[res^ult]] = 2;
3221 return result;
3222 }
3223 @end
3224 )objc",
3225 [](HoverInfo &HI) {
3226 HI.Name = "result";
3227 HI.Definition = "int result = 2";
3228 HI.Kind = index::SymbolKind::Variable;
3229 HI.Type = "int";
3230 HI.LocalScope = "+[Foo(Private) somePrivateMethod]::";
3231 HI.NamespaceScope = "";
3232 HI.Value = "2";
3233 }},
3234 {R"objc(
3235 @interface Foo
3236 @end
3237
3238 @implementation Foo
3239 - (int)variadicArgMethod:(id)first, ... {
3240 int [[res^ult]] = 0;
3241 return result;
3242 }
3243 @end
3244 )objc",
3245 [](HoverInfo &HI) {
3246 HI.Name = "result";
3247 HI.Definition = "int result = 0";
3248 HI.Kind = index::SymbolKind::Variable;
3249 HI.Type = "int";
3250 HI.LocalScope = "-[Foo variadicArgMethod:, ...]::";
3251 HI.NamespaceScope = "";
3252 HI.Value = "0";
3253 }},
3254 // Should not crash.
3255 {R"objc(
3256 typedef struct MyRect {} MyRect;
3257
3258 @interface IFace
3259 @property(nonatomic) MyRect frame;
3260 @end
3261
3262 MyRect foobar() {
3263 MyRect mr;
3264 return mr;
3265 }
3266 void test() {
3267 IFace *v;
3268 v.frame = [[foo^bar]]();
3269 }
3270 )objc",
3271 [](HoverInfo &HI) {
3272 HI.Name = "foobar";
3273 HI.Kind = index::SymbolKind::Function;
3274 HI.NamespaceScope = "";
3275 HI.Definition = "MyRect foobar()";
3276 HI.Type = {"MyRect ()", "struct MyRect ()"};
3277 HI.ReturnType = {"MyRect", "struct MyRect"};
3278 HI.Parameters.emplace();
3279 }},
3280 {R"cpp(
3281 void foo(int * __attribute__(([[non^null]], noescape)) );
3282 )cpp",
3283 [](HoverInfo &HI) {
3284 HI.Name = "nonnull";
3285 HI.Kind = index::SymbolKind::Unknown; // FIXME: no suitable value
3286 HI.Definition = "__attribute__((nonnull))";
3287 HI.Documentation = Attr::getDocumentation(attr::NonNull).str();
3288 }},
3289 {
3290 R"cpp(
3291 namespace std {
3292 struct strong_ordering {
3293 int n;
3294 constexpr operator int() const { return n; }
3295 static const strong_ordering equal, greater, less;
3296 };
3297 constexpr strong_ordering strong_ordering::equal = {0};
3298 constexpr strong_ordering strong_ordering::greater = {1};
3299 constexpr strong_ordering strong_ordering::less = {-1};
3300 }
3301
3302 struct Foo
3303 {
3304 int x;
3305 // Foo spaceship
3306 auto operator<=>(const Foo&) const = default;
3307 };
3308
3309 bool x = Foo(1) [[!^=]] Foo(2);
3310 )cpp",
3311 [](HoverInfo &HI) {
3312 HI.Type = "bool (const Foo &) const noexcept";
3313 HI.Value = "true";
3314 HI.Name = "operator==";
3315 HI.Parameters = {{{"const Foo &"}, std::nullopt, std::nullopt}};
3316 HI.ReturnType = "bool";
3317 HI.Kind = index::SymbolKind::InstanceMethod;
3318 HI.LocalScope = "Foo::";
3319 HI.NamespaceScope = "";
3320 HI.Definition =
3321 "bool operator==(const Foo &) const noexcept = default";
3322 HI.Documentation = "";
3323 }},
3324 };
3325
3326 // Create a tiny index, so tests above can verify documentation is fetched.
3327 Symbol IndexSym = func("indexSymbol");
3328 IndexSym.Documentation = "comment from index";
3330 Symbols.insert(IndexSym);
3331 auto Index =
3332 MemIndex::build(std::move(Symbols).build(), RefSlab(), RelationSlab());
3333
3334 for (const auto &Case : Cases) {
3335 SCOPED_TRACE(Case.Code);
3336
3337 Annotations T(Case.Code);
3338 TestTU TU = TestTU::withCode(T.code());
3339 TU.ExtraArgs.push_back("-std=c++20");
3340 TU.ExtraArgs.push_back("-xobjective-c++");
3341
3342 TU.ExtraArgs.push_back("-Wno-gnu-designator");
3343 // Types might be different depending on the target triplet, we chose a
3344 // fixed one to make sure tests passes on different platform.
3345 TU.ExtraArgs.push_back("--target=x86_64-pc-linux-gnu");
3346 auto AST = TU.build();
3347 Config Cfg;
3348 Cfg.Hover.ShowAKA = true;
3349 WithContextValue WithCfg(Config::Key, std::move(Cfg));
3350 auto H = getHover(AST, T.point(), format::getLLVMStyle(), Index.get());
3351 ASSERT_TRUE(H);
3352 HoverInfo Expected;
3353 Expected.SymRange = T.range();
3354 Case.ExpectedBuilder(Expected);
3355
3356 SCOPED_TRACE(H->present(MarkupKind::PlainText));
3357 EXPECT_EQ(H->NamespaceScope, Expected.NamespaceScope);
3358 EXPECT_EQ(H->LocalScope, Expected.LocalScope);
3359 EXPECT_EQ(H->Name, Expected.Name);
3360 EXPECT_EQ(H->Kind, Expected.Kind);
3361 EXPECT_EQ(H->Documentation, Expected.Documentation);
3362 EXPECT_EQ(H->Definition, Expected.Definition);
3363 EXPECT_EQ(H->Type, Expected.Type);
3364 EXPECT_EQ(H->ReturnType, Expected.ReturnType);
3365 EXPECT_EQ(H->Parameters, Expected.Parameters);
3366 EXPECT_EQ(H->TemplateParameters, Expected.TemplateParameters);
3367 EXPECT_EQ(H->SymRange, Expected.SymRange);
3368 EXPECT_EQ(H->Value, Expected.Value);
3369 }
3370}
3371
3372TEST(Hover, Providers) {
3373 struct {
3374 const char *Code;
3375 const std::function<void(HoverInfo &)> ExpectedBuilder;
3376 } Cases[] = {{R"cpp(
3377 struct Foo {};
3378 Foo F = Fo^o{};
3379 )cpp",
3380 [](HoverInfo &HI) { HI.Provider = ""; }},
3381 {R"cpp(
3382 #include "foo.h"
3383 Foo F = Fo^o{};
3384 )cpp",
3385 [](HoverInfo &HI) { HI.Provider = "\"foo.h\""; }},
3386 {R"cpp(
3387 #include "all.h"
3388 Foo F = Fo^o{};
3389 )cpp",
3390 [](HoverInfo &HI) { HI.Provider = "\"foo.h\""; }},
3391 {R"cpp(
3392 #define FOO 5
3393 int F = ^FOO;
3394 )cpp",
3395 [](HoverInfo &HI) { HI.Provider = ""; }},
3396 {R"cpp(
3397 #include "foo.h"
3398 int F = ^FOO;
3399 )cpp",
3400 [](HoverInfo &HI) { HI.Provider = "\"foo.h\""; }},
3401 {R"cpp(
3402 #include "all.h"
3403 int F = ^FOO;
3404 )cpp",
3405 [](HoverInfo &HI) { HI.Provider = "\"foo.h\""; }},
3406 {R"cpp(
3407 #include "foo.h"
3408 Foo A;
3409 Foo B;
3410 Foo C = A ^+ B;
3411 )cpp",
3412 [](HoverInfo &HI) { HI.Provider = "\"foo.h\""; }},
3413 // Hover selects the underlying decl of the using decl
3414 {R"cpp(
3415 #include "foo.h"
3416 namespace ns {
3417 using ::Foo;
3418 }
3419 ns::F^oo d;
3420 )cpp",
3421 [](HoverInfo &HI) { HI.Provider = "\"foo.h\""; }},
3422 {R"cpp(
3423 namespace foo {};
3424 using namespace fo^o;
3425 )cpp",
3426 [](HoverInfo &HI) { HI.Provider = ""; }},
3427 };
3428
3429 for (const auto &Case : Cases) {
3430 Annotations Code{Case.Code};
3431 SCOPED_TRACE(Code.code());
3432
3433 TestTU TU;
3434 TU.Filename = "foo.cpp";
3435 TU.Code = Code.code();
3436 TU.AdditionalFiles["foo.h"] = guard(R"cpp(
3437 #define FOO 1
3438 class Foo {};
3439 Foo& operator+(const Foo, const Foo);
3440 )cpp");
3441 TU.AdditionalFiles["all.h"] = guard("#include \"foo.h\"");
3442
3443 auto AST = TU.build();
3444 auto H = getHover(AST, Code.point(), format::getLLVMStyle(), nullptr);
3445 ASSERT_TRUE(H);
3446 HoverInfo Expected;
3447 Case.ExpectedBuilder(Expected);
3448 SCOPED_TRACE(H->present(MarkupKind::Markdown));
3449 EXPECT_EQ(H->Provider, Expected.Provider);
3450 }
3451}
3452
3453TEST(Hover, ParseProviderInfo) {
3454 HoverInfo HIFoo;
3455 HIFoo.Name = "foo";
3456 HIFoo.Provider = "\"foo.h\"";
3457
3458 HoverInfo HIFooBar;
3459 HIFooBar.Name = "foo";
3460 HIFooBar.Provider = "<bar.h>";
3461 struct Case {
3462 HoverInfo HI;
3463 llvm::StringRef ExpectedMarkdown;
3464 } Cases[] = {{HIFoo, "### `foo`\n\nprovided by `\"foo.h\"`"},
3465 {HIFooBar, "### `foo`\n\nprovided by `<bar.h>`"}};
3466
3467 for (const auto &Case : Cases)
3468 EXPECT_EQ(Case.HI.present(MarkupKind::Markdown), Case.ExpectedMarkdown);
3469}
3470
3471TEST(Hover, UsedSymbols) {
3472 struct {
3473 const char *Code;
3474 const std::function<void(HoverInfo &)> ExpectedBuilder;
3475 } Cases[] = {{R"cpp(
3476 #include ^"bar.h"
3477 int fstBar = bar1();
3478 int another= bar1(0);
3479 int sndBar = bar2();
3480 Bar bar;
3481 int macroBar = BAR;
3482 )cpp",
3483 [](HoverInfo &HI) {
3484 HI.UsedSymbolNames = {"BAR", "Bar", "bar1", "bar2"};
3485 }},
3486 {R"cpp(
3487 #in^clude <vector>
3488 std::vector<int> vec;
3489 )cpp",
3490 [](HoverInfo &HI) { HI.UsedSymbolNames = {"vector"}; }}};
3491 for (const auto &Case : Cases) {
3492 Annotations Code{Case.Code};
3493 SCOPED_TRACE(Code.code());
3494
3495 TestTU TU;
3496 TU.Filename = "foo.cpp";
3497 TU.Code = Code.code();
3498 TU.AdditionalFiles["bar.h"] = guard(R"cpp(
3499 #define BAR 5
3500 int bar1();
3501 int bar2();
3502 int bar1(double);
3503 class Bar {};
3504 )cpp");
3505 TU.AdditionalFiles["system/vector"] = guard(R"cpp(
3506 namespace std {
3507 template<typename>
3508 class vector{};
3509 }
3510 )cpp");
3511 TU.ExtraArgs.push_back("-isystem" + testPath("system"));
3512
3513 auto AST = TU.build();
3514 auto H = getHover(AST, Code.point(), format::getLLVMStyle(), nullptr);
3515 ASSERT_TRUE(H);
3516 HoverInfo Expected;
3517 Case.ExpectedBuilder(Expected);
3518 SCOPED_TRACE(H->present(MarkupKind::Markdown));
3519 EXPECT_EQ(H->UsedSymbolNames, Expected.UsedSymbolNames);
3520 }
3521}
3522
3523TEST(Hover, DocsFromIndex) {
3524 Annotations T(R"cpp(
3525 template <typename T> class X {};
3526 void foo() {
3527 auto t = X<int>();
3528 X^<int> w;
3529 (void)w;
3530 })cpp");
3531
3532 TestTU TU = TestTU::withCode(T.code());
3533 auto AST = TU.build();
3534 Symbol IndexSym;
3535 IndexSym.ID = getSymbolID(&findDecl(AST, "X"));
3536 IndexSym.Documentation = "comment from index";
3538 Symbols.insert(IndexSym);
3539 auto Index =
3540 MemIndex::build(std::move(Symbols).build(), RefSlab(), RelationSlab());
3541
3542 for (const auto &P : T.points()) {
3543 auto H = getHover(AST, P, format::getLLVMStyle(), Index.get());
3544 ASSERT_TRUE(H);
3545 EXPECT_EQ(H->Documentation, IndexSym.Documentation);
3546 }
3547}
3548
3549TEST(Hover, DocsFromAST) {
3550 Annotations T(R"cpp(
3551 // doc
3552 template <typename T> class X {};
3553 // doc
3554 template <typename T> void bar() {}
3555 // doc
3556 template <typename T> T baz;
3557 void foo() {
3558 au^to t = X<int>();
3559 X^<int>();
3560 b^ar<int>();
3561 au^to T = ba^z<X<int>>;
3562 ba^z<int> = 0;
3563 })cpp");
3564
3565 TestTU TU = TestTU::withCode(T.code());
3566 auto AST = TU.build();
3567 for (const auto &P : T.points()) {
3568 auto H = getHover(AST, P, format::getLLVMStyle(), nullptr);
3569 ASSERT_TRUE(H);
3570 EXPECT_EQ(H->Documentation, "doc");
3571 }
3572}
3573
3574TEST(Hover, NoCrash) {
3575 Annotations T(R"cpp(
3576 /* error-ok */
3577 template<typename T> T foo(T);
3578
3579 // Setter variable heuristic might fail if the callexpr is broken.
3580 struct X { int Y; void [[^setY]](float) { Y = foo(undefined); } };)cpp");
3581
3582 TestTU TU = TestTU::withCode(T.code());
3583 auto AST = TU.build();
3584 for (const auto &P : T.points())
3585 getHover(AST, P, format::getLLVMStyle(), nullptr);
3586}
3587
3588TEST(Hover, NoCrashAPInt64) {
3589 Annotations T(R"cpp(
3590 constexpr unsigned long value = -1; // wrap around
3591 void foo() { va^lue; }
3592 )cpp");
3593 auto AST = TestTU::withCode(T.code()).build();
3594 getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
3595}
3596
3597TEST(Hover, NoCrashInt128) {
3598 Annotations T(R"cpp(
3599 constexpr __int128_t value = -4;
3600 void foo() { va^lue; }
3601 )cpp");
3602 auto TU = TestTU::withCode(T.code());
3603 // Need a triple that support __int128_t.
3604 TU.ExtraArgs.push_back("--target=x86_64-pc-linux-gnu");
3605 auto AST = TU.build();
3606 auto H = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
3607 ASSERT_TRUE(H);
3608 EXPECT_EQ(H->Value, "-4 (0xfffffffc)");
3609}
3610
3611TEST(Hover, DocsFromMostSpecial) {
3612 Annotations T(R"cpp(
3613 // doc1
3614 template <typename T> class $doc1^X {};
3615 // doc2
3616 template <> class $doc2^X<int> {};
3617 // doc3
3618 template <typename T> class $doc3^X<T*> {};
3619 void foo() {
3620 X$doc1^<char>();
3621 X$doc2^<int>();
3622 X$doc3^<int*>();
3623 })cpp");
3624
3625 TestTU TU = TestTU::withCode(T.code());
3626 auto AST = TU.build();
3627 for (const auto *Comment : {"doc1", "doc2", "doc3"}) {
3628 for (const auto &P : T.points(Comment)) {
3629 auto H = getHover(AST, P, format::getLLVMStyle(), nullptr);
3630 ASSERT_TRUE(H);
3631 EXPECT_EQ(H->Documentation, Comment);
3632 }
3633 }
3634}
3635
3636TEST(Hover, Present) {
3637 struct {
3638 const std::function<void(HoverInfo &)> Builder;
3639 llvm::StringRef ExpectedMarkdownRender;
3640 llvm::StringRef ExpectedDoxygenRender;
3641 } Cases[] = {
3642 {
3643 [](HoverInfo &HI) {
3644 HI.Kind = index::SymbolKind::Unknown;
3645 HI.Name = "X";
3646 },
3647 R"(X)",
3648 R"(### `X`)",
3649 },
3650 {
3651 [](HoverInfo &HI) {
3652 HI.Kind = index::SymbolKind::NamespaceAlias;
3653 HI.Name = "foo";
3654 },
3655 R"(namespace-alias foo)",
3656 R"(### namespace-alias `foo`)",
3657 },
3658 {
3659 [](HoverInfo &HI) {
3660 HI.Kind = index::SymbolKind::Class;
3661 HI.Size = 80;
3662 HI.TemplateParameters = {
3663 {{"typename"}, std::string("T"), std::nullopt},
3664 {{"typename"}, std::string("C"), std::string("bool")},
3665 };
3666 HI.Documentation = "documentation";
3667 HI.Definition =
3668 "template <typename T, typename C = bool> class Foo {}";
3669 HI.Name = "foo";
3670 HI.NamespaceScope.emplace();
3671 },
3672 R"(class foo
3673
3674Size: 10 bytes
3675
3676documentation
3677
3678template <typename T, typename C = bool> class Foo {})",
3679 R"(### class
3680
3681---
3682```cpp
3683template <typename T, typename C = bool> class Foo {}
3684```
3685
3686---
3687### Brief
3688
3689documentation
3690
3691---
3692### Template Parameters
3693
3694- `typename T`
3695- `typename C = bool`
3696
3697---
3698Size: 10 bytes)",
3699 },
3700 {
3701 [](HoverInfo &HI) {
3702 HI.Kind = index::SymbolKind::Function;
3703 HI.Name = "foo";
3704 HI.Type = {"type", "c_type"};
3705 HI.ReturnType = {"ret_type", "can_ret_type"};
3706 HI.Parameters.emplace();
3708 HI.Parameters->push_back(P);
3709 P.Type = {"type", "can_type"};
3710 HI.Parameters->push_back(P);
3711 P.Name = "foo";
3712 HI.Parameters->push_back(P);
3713 P.Default = "default";
3714 HI.Parameters->push_back(P);
3715 HI.NamespaceScope = "ns::";
3716 HI.Definition = "ret_type foo(params) {}";
3717 },
3718 "function foo\n"
3719 "\n"
3720 "→ ret_type (aka can_ret_type)\n\n"
3721 "Parameters:\n\n"
3722 "- \n"
3723 "- type (aka can_type)\n"
3724 "- type foo (aka can_type)\n"
3725 "- type foo = default (aka can_type)\n"
3726 "\n"
3727 "// In namespace ns\n"
3728 "ret_type foo(params) {}",
3729 R"(### function
3730
3731---
3732```cpp
3733// In namespace ns
3734ret_type foo(params) {}
3735```
3736
3737---
3738### Parameters
3739
3740-
3741- `type (aka can_type)`
3742- `type foo (aka can_type)`
3743- `type foo = default (aka can_type)`
3744
3745---
3746### Returns
3747
3748`ret_type (aka can_ret_type)`)",
3749 },
3750 {
3751 [](HoverInfo &HI) {
3752 HI.Kind = index::SymbolKind::Field;
3753 HI.LocalScope = "test::Bar::";
3754 HI.Value = "value";
3755 HI.Name = "foo";
3756 HI.Type = {"type", "can_type"};
3757 HI.Definition = "def";
3758 HI.Size = 32;
3759 HI.Offset = 96;
3760 HI.Padding = 32;
3761 HI.Align = 32;
3762 },
3763 R"(field foo
3764
3765Type: type (aka can_type)
3766
3767Value = value
3768
3769Offset: 12 bytes
3770
3771Size: 4 bytes (+4 bytes padding), alignment 4 bytes
3772
3773// In test::Bar
3774def)",
3775 R"(### field
3776
3777---
3778```cpp
3779// In test::Bar
3780def
3781```
3782
3783---
3784Type: `type (aka can_type)`
3785
3786Value = `value`
3787
3788Offset: 12 bytes
3789
3790Size: 4 bytes (+4 bytes padding), alignment 4 bytes)",
3791 },
3792 {
3793 [](HoverInfo &HI) {
3794 HI.Kind = index::SymbolKind::Field;
3795 HI.LocalScope = "test::Bar::";
3796 HI.Value = "value";
3797 HI.Name = "foo";
3798 HI.Type = {"type", "can_type"};
3799 HI.Definition = "def";
3800 HI.Size = 25;
3801 HI.Offset = 35;
3802 HI.Padding = 4;
3803 HI.Align = 64;
3804 },
3805 R"(field foo
3806
3807Type: type (aka can_type)
3808
3809Value = value
3810
3811Offset: 4 bytes and 3 bits
3812
3813Size: 25 bits (+4 bits padding), alignment 8 bytes
3814
3815// In test::Bar
3816def)",
3817 R"(### field
3818
3819---
3820```cpp
3821// In test::Bar
3822def
3823```
3824
3825---
3826Type: `type (aka can_type)`
3827
3828Value = `value`
3829
3830Offset: 4 bytes and 3 bits
3831
3832Size: 25 bits (+4 bits padding), alignment 8 bytes)",
3833 },
3834 {
3835 [](HoverInfo &HI) {
3836 HI.Kind = index::SymbolKind::Field;
3837 HI.AccessSpecifier = "public";
3838 HI.Name = "foo";
3839 HI.LocalScope = "test::Bar::";
3840 HI.Definition = "def";
3841 },
3842 R"(field foo
3843
3844// In test::Bar
3845public: def)",
3846 R"(### field
3847
3848---
3849```cpp
3850// In test::Bar
3851public: def
3852```)",
3853 },
3854 {
3855 [](HoverInfo &HI) {
3856 HI.Definition = "size_t method()";
3857 HI.AccessSpecifier = "protected";
3858 HI.Kind = index::SymbolKind::InstanceMethod;
3859 HI.NamespaceScope = "";
3860 HI.LocalScope = "cls<int>::";
3861 HI.Name = "method";
3862 HI.Parameters.emplace();
3863 HI.ReturnType = {"size_t", "unsigned long"};
3864 HI.Type = {"size_t ()", "unsigned long ()"};
3865 },
3866 R"(instance-method method
3867
3868→ size_t (aka unsigned long)
3869
3870// In cls<int>
3871protected: size_t method())",
3872 R"(### instance-method
3873
3874---
3875```cpp
3876// In cls<int>
3877protected: size_t method()
3878```
3879
3880---
3881### Returns
3882
3883`size_t (aka unsigned long)`)",
3884 },
3885 {
3886 [](HoverInfo &HI) {
3887 HI.Definition = "cls(int a, int b = 5)";
3888 HI.AccessSpecifier = "public";
3889 HI.Kind = index::SymbolKind::Constructor;
3890 HI.NamespaceScope = "";
3891 HI.LocalScope = "cls";
3892 HI.Name = "cls";
3893 HI.Parameters.emplace();
3894 HI.Parameters->emplace_back();
3895 HI.Parameters->back().Type = "int";
3896 HI.Parameters->back().Name = "a";
3897 HI.Parameters->emplace_back();
3898 HI.Parameters->back().Type = "int";
3899 HI.Parameters->back().Name = "b";
3900 HI.Parameters->back().Default = "5";
3901 },
3902 R"(constructor cls
3903
3904Parameters:
3905
3906- int a
3907- int b = 5
3908
3909// In cls
3910public: cls(int a, int b = 5))",
3911 R"(### constructor
3912
3913---
3914```cpp
3915// In cls
3916public: cls(int a, int b = 5)
3917```
3918
3919---
3920### Parameters
3921
3922- `int a`
3923- `int b = 5`)",
3924 },
3925 {
3926 [](HoverInfo &HI) {
3927 HI.Kind = index::SymbolKind::Union;
3928 HI.AccessSpecifier = "private";
3929 HI.Name = "foo";
3930 HI.NamespaceScope = "ns1::";
3931 HI.Definition = "union foo {}";
3932 },
3933 R"(union foo
3934
3935// In namespace ns1
3936private: union foo {})",
3937 R"(### union
3938
3939---
3940```cpp
3941// In namespace ns1
3942private: union foo {}
3943```)",
3944 },
3945 {
3946 [](HoverInfo &HI) {
3947 HI.Kind = index::SymbolKind::Variable;
3948 HI.Name = "foo";
3949 HI.Definition = "int foo = 3";
3950 HI.LocalScope = "test::Bar::";
3951 HI.Value = "3";
3952 HI.Type = "int";
3953 HI.CalleeArgInfo.emplace();
3954 HI.CalleeArgInfo->Name = "arg_a";
3955 HI.CalleeArgInfo->Type = "int";
3956 HI.CalleeArgInfo->Default = "7";
3957 HI.CallPassType = HoverInfo::PassType{PassMode::Value, false};
3958 },
3959 R"(variable foo
3960
3961Type: int
3962
3963Value = 3
3964
3965Passed as arg_a
3966
3967// In test::Bar
3968int foo = 3)",
3969 R"(### variable
3970
3971---
3972```cpp
3973// In test::Bar
3974int foo = 3
3975```
3976
3977---
3978Type: `int`
3979
3980Value = `3`
3981
3982Passed as arg_a)",
3983 },
3984 {
3985 [](HoverInfo &HI) {
3986 HI.Kind = index::SymbolKind::Variable;
3987 HI.Name = "foo";
3988 HI.CalleeArgInfo.emplace();
3989 HI.CalleeArgInfo->Type = "int";
3990 HI.CallPassType = HoverInfo::PassType{PassMode::Value, false};
3991 },
3992 R"(variable foo
3993
3994Passed by value)",
3995 R"(### variable `foo`
3996
3997---
3998Passed by value)",
3999 },
4000 {
4001 [](HoverInfo &HI) {
4002 HI.Kind = index::SymbolKind::Variable;
4003 HI.Name = "foo";
4004 HI.Definition = "int foo = 3";
4005 HI.LocalScope = "test::Bar::";
4006 HI.Value = "3";
4007 HI.Type = "int";
4008 HI.CalleeArgInfo.emplace();
4009 HI.CalleeArgInfo->Name = "arg_a";
4010 HI.CalleeArgInfo->Type = "int";
4011 HI.CalleeArgInfo->Default = "7";
4012 HI.CallPassType = HoverInfo::PassType{PassMode::Ref, false};
4013 },
4014 R"(variable foo
4015
4016Type: int
4017
4018Value = 3
4019
4020Passed by reference as arg_a
4021
4022// In test::Bar
4023int foo = 3)",
4024 R"(### variable
4025
4026---
4027```cpp
4028// In test::Bar
4029int foo = 3
4030```
4031
4032---
4033Type: `int`
4034
4035Value = `3`
4036
4037Passed by reference as arg_a)",
4038 },
4039 {
4040 [](HoverInfo &HI) {
4041 HI.Kind = index::SymbolKind::Variable;
4042 HI.Name = "foo";
4043 HI.Definition = "int foo = 3";
4044 HI.LocalScope = "test::Bar::";
4045 HI.Value = "3";
4046 HI.Type = "int";
4047 HI.CalleeArgInfo.emplace();
4048 HI.CalleeArgInfo->Name = "arg_a";
4049 HI.CalleeArgInfo->Type = {"alias_int", "int"};
4050 HI.CalleeArgInfo->Default = "7";
4051 HI.CallPassType = HoverInfo::PassType{PassMode::Value, true};
4052 },
4053 R"(variable foo
4054
4055Type: int
4056
4057Value = 3
4058
4059Passed as arg_a (converted to alias_int)
4060
4061// In test::Bar
4062int foo = 3)",
4063 R"(### variable
4064
4065---
4066```cpp
4067// In test::Bar
4068int foo = 3
4069```
4070
4071---
4072Type: `int`
4073
4074Value = `3`
4075
4076Passed as arg_a (converted to alias_int))",
4077 },
4078 {
4079 [](HoverInfo &HI) {
4080 HI.Kind = index::SymbolKind::Macro;
4081 HI.Name = "PLUS_ONE";
4082 HI.Definition = "#define PLUS_ONE(X) (X+1)\n\n"
4083 "// Expands to\n"
4084 "(1 + 1)";
4085 },
4086 R"(macro PLUS_ONE
4087
4088#define PLUS_ONE(X) (X+1)
4089
4090// Expands to
4091(1 + 1))",
4092 R"(### macro
4093
4094---
4095```cpp
4096#define PLUS_ONE(X) (X+1)
4097
4098// Expands to
4099(1 + 1)
4100```)",
4101 },
4102 {
4103 [](HoverInfo &HI) {
4104 HI.Kind = index::SymbolKind::Variable;
4105 HI.Name = "foo";
4106 HI.Definition = "int foo = 3";
4107 HI.LocalScope = "test::Bar::";
4108 HI.Value = "3";
4109 HI.Type = "int";
4110 HI.CalleeArgInfo.emplace();
4111 HI.CalleeArgInfo->Name = "arg_a";
4112 HI.CalleeArgInfo->Type = "int";
4113 HI.CalleeArgInfo->Default = "7";
4114 HI.CallPassType = HoverInfo::PassType{PassMode::ConstRef, true};
4115 },
4116 R"(variable foo
4117
4118Type: int
4119
4120Value = 3
4121
4122Passed by const reference as arg_a (converted to int)
4123
4124// In test::Bar
4125int foo = 3)",
4126 R"(### variable
4127
4128---
4129```cpp
4130// In test::Bar
4131int foo = 3
4132```
4133
4134---
4135Type: `int`
4136
4137Value = `3`
4138
4139Passed by const reference as arg_a (converted to int))",
4140 },
4141 {
4142 [](HoverInfo &HI) {
4143 HI.Name = "stdio.h";
4144 HI.Definition = "/usr/include/stdio.h";
4145 HI.Kind = index::SymbolKind::IncludeDirective;
4146 },
4147 R"(stdio.h
4148
4149/usr/include/stdio.h)",
4150 R"(### `stdio.h`
4151
4152`/usr/include/stdio.h`)",
4153 },
4154 {
4155 [](HoverInfo &HI) {
4156 HI.Name = "foo.h";
4157 HI.UsedSymbolNames = {"Foo", "Bar", "Bar"};
4158 HI.Kind = index::SymbolKind::IncludeDirective;
4159 },
4160 R"(foo.h
4161
4162provides Foo, Bar, Bar)",
4163 R"(### `foo.h`
4164
4165---
4166provides `Foo`, `Bar`, `Bar`)",
4167 },
4168 {[](HoverInfo &HI) {
4169 HI.Name = "foo.h";
4170 HI.UsedSymbolNames = {"Foo", "Bar", "Baz", "Foobar", "Qux", "Quux"};
4171 HI.Kind = index::SymbolKind::IncludeDirective;
4172 },
4173 R"(foo.h
4174
4175provides Foo, Bar, Baz, Foobar, Qux and 1 more)",
4176 R"(### `foo.h`
4177
4178---
4179provides `Foo`, `Bar`, `Baz`, `Foobar`, `Qux` and 1 more)"}};
4180
4181 for (const auto &C : Cases) {
4182 HoverInfo HI;
4183 C.Builder(HI);
4184 Config Cfg;
4185 Cfg.Hover.ShowAKA = true;
4186 Cfg.Documentation.CommentFormat = Config::CommentFormatPolicy::Markdown;
4187 WithContextValue WithCfg(Config::Key, std::move(Cfg));
4188 EXPECT_EQ(HI.present(MarkupKind::PlainText), C.ExpectedMarkdownRender);
4189 }
4190 for (const auto &C : Cases) {
4191 HoverInfo HI;
4192 C.Builder(HI);
4193 Config Cfg;
4194 Cfg.Hover.ShowAKA = true;
4195 Cfg.Documentation.CommentFormat = Config::CommentFormatPolicy::Doxygen;
4196 WithContextValue WithCfg(Config::Key, std::move(Cfg));
4197 EXPECT_EQ(HI.present(MarkupKind::Markdown), C.ExpectedDoxygenRender);
4198 }
4199}
4200
4201TEST(Hover, PresentDocumentation) {
4202 struct {
4203 const std::function<void(HoverInfo &)> Builder;
4204 llvm::StringRef ExpectedMarkdownRender;
4205 llvm::StringRef ExpectedDoxygenRender;
4206 } Cases[] = {
4207 {[](HoverInfo &HI) {
4208 HI.Kind = index::SymbolKind::Function;
4209 HI.Documentation = "@brief brief doc\n\n"
4210 "longer doc";
4211 HI.Definition = "void foo()";
4212 HI.Name = "foo";
4213 },
4214 R"(### function `foo`
4215
4216---
4217@brief brief doc
4218
4219longer doc
4220
4221---
4222```cpp
4223void foo()
4224```)",
4225 R"(### function
4226
4227---
4228```cpp
4229void foo()
4230```
4231
4232---
4233### Brief
4234
4235brief doc
4236
4237---
4238### Details
4239
4240longer doc)"},
4241 {[](HoverInfo &HI) {
4242 HI.Kind = index::SymbolKind::Function;
4243 HI.Documentation = "@brief brief doc\n\n"
4244 "longer doc";
4245 HI.Definition = "int foo()";
4246 HI.ReturnType = "int";
4247 HI.Name = "foo";
4248 },
4249 R"(### function `foo`
4250
4251---
4252→ `int`
4253
4254@brief brief doc
4255
4256longer doc
4257
4258---
4259```cpp
4260int foo()
4261```)",
4262 R"(### function
4263
4264---
4265```cpp
4266int foo()
4267```
4268
4269---
4270### Brief
4271
4272brief doc
4273
4274---
4275### Returns
4276
4277`int`
4278
4279---
4280### Details
4281
4282longer doc)"},
4283 {[](HoverInfo &HI) {
4284 HI.Kind = index::SymbolKind::Function;
4285 HI.Documentation = R"(@brief brief doc
4286
4287longer doc
4288@note this is a note
4289
4290As you see, notes are "inlined".
4291@warning this is a warning
4292
4293As well as warnings
4294@param a this is a param
4295@return it returns something
4296@retval 0 if successful
4297@retval 1 if failed)";
4298 HI.Definition = "int foo(int a)";
4299 HI.ReturnType = "int";
4300 HI.Name = "foo";
4301 HI.Parameters.emplace();
4302 HI.Parameters->emplace_back();
4303 HI.Parameters->back().Type = "int";
4304 HI.Parameters->back().Name = "a";
4305 },
4306 R"(### function `foo`
4307
4308---
4309→ `int`
4310
4311Parameters:
4312
4313- `int a`
4314
4315@brief brief doc
4316
4317longer doc
4318@note this is a note
4319
4320As you see, notes are "inlined".
4321@warning this is a warning
4322
4323As well as warnings
4324@param a this is a param
4325@return it returns something
4326@retval 0 if successful
4327@retval 1 if failed
4328
4329---
4330```cpp
4331int foo(int a)
4332```)",
4333 R"(### function
4334
4335---
4336```cpp
4337int foo(int a)
4338```
4339
4340---
4341### Brief
4342
4343brief doc
4344
4345---
4346### Parameters
4347
4348- `int a` - this is a param
4349
4350---
4351### Returns
4352
4353`int` - it returns something
4354
4355- `0` - if successful
4356- `1` - if failed
4357
4358---
4359### Details
4360
4361longer doc
4362
4363**Note:**
4364this is a note
4365
4366As you see, notes are "inlined".
4367
4368**Warning:**
4369this is a warning
4370
4371As well as warnings)"},
4372 {[](HoverInfo &HI) {
4373 HI.Kind = index::SymbolKind::Function;
4374 HI.Documentation = "@brief brief doc\n\n"
4375 "longer doc\n@param a this is a param\n@param b "
4376 "does not exist\n@return it returns something";
4377 HI.Definition = "int foo(int a)";
4378 HI.ReturnType = "int";
4379 HI.Name = "foo";
4380 HI.Parameters.emplace();
4381 HI.Parameters->emplace_back();
4382 HI.Parameters->back().Type = "int";
4383 HI.Parameters->back().Name = "a";
4384 },
4385 R"(### function `foo`
4386
4387---
4388→ `int`
4389
4390Parameters:
4391
4392- `int a`
4393
4394@brief brief doc
4395
4396longer doc
4397@param a this is a param
4398@param b does not exist
4399@return it returns something
4400
4401---
4402```cpp
4403int foo(int a)
4404```)",
4405 R"(### function
4406
4407---
4408```cpp
4409int foo(int a)
4410```
4411
4412---
4413### Brief
4414
4415brief doc
4416
4417---
4418### Parameters
4419
4420- `int a` - this is a param
4421
4422---
4423### Returns
4424
4425`int` - it returns something
4426
4427---
4428### Details
4429
4430longer doc)"},
4431 {[](HoverInfo &HI) {
4432 HI.Kind = index::SymbolKind::Function;
4433 HI.Documentation = "@brief brief doc\n"
4434 "@unknown command is treated as an inline command";
4435 HI.Definition = "int foo(int a)";
4436 HI.ReturnType = "int";
4437 HI.Name = "foo";
4438 HI.Parameters.emplace();
4439 HI.Parameters->emplace_back();
4440 HI.Parameters->back().Type = "int";
4441 HI.Parameters->back().Name = "a";
4442 },
4443 R"(### function `foo`
4444
4445---
4446→ `int`
4447
4448Parameters:
4449
4450- `int a`
4451
4452@brief brief doc
4453@unknown command is treated as an inline command
4454
4455---
4456```cpp
4457int foo(int a)
4458```)",
4459 R"(### function
4460
4461---
4462```cpp
4463int foo(int a)
4464```
4465
4466---
4467### Brief
4468
4469brief doc
4470**@unknown** command is treated as an inline command
4471
4472---
4473### Parameters
4474
4475- `int a`
4476
4477---
4478### Returns
4479
4480`int`)"},
4481 };
4482
4483 for (const auto &C : Cases) {
4484 HoverInfo HI;
4485 C.Builder(HI);
4486 Config Cfg;
4487 Cfg.Hover.ShowAKA = true;
4488 Cfg.Documentation.CommentFormat = Config::CommentFormatPolicy::Markdown;
4489 WithContextValue WithCfg(Config::Key, std::move(Cfg));
4490 EXPECT_EQ(HI.present(MarkupKind::Markdown), C.ExpectedMarkdownRender);
4491 }
4492 for (const auto &C : Cases) {
4493 HoverInfo HI;
4494 C.Builder(HI);
4495 Config Cfg;
4496 Cfg.Hover.ShowAKA = true;
4497 Cfg.Documentation.CommentFormat = Config::CommentFormatPolicy::Doxygen;
4498 WithContextValue WithCfg(Config::Key, std::move(Cfg));
4499 EXPECT_EQ(HI.present(MarkupKind::Markdown), C.ExpectedDoxygenRender);
4500 }
4501}
4502
4503TEST(Hover, ParseDocumentation) {
4504 struct Case {
4505 llvm::StringRef Documentation;
4506 llvm::StringRef ExpectedRenderEscapedMarkdown;
4507 llvm::StringRef ExpectedRenderMarkdown;
4508 llvm::StringRef ExpectedRenderPlainText;
4509 } Cases[] = {{
4510 " \n foo\nbar",
4511 "foo bar",
4512 "foo\nbar",
4513 "foo bar",
4514 },
4515 {
4516 "foo\nbar \n ",
4517 "foo bar",
4518 "foo\nbar",
4519 "foo bar",
4520 },
4521 {
4522 "foo \nbar",
4523 "foo \nbar",
4524 "foo \nbar",
4525 "foo\nbar",
4526 },
4527 {
4528 "foo \nbar",
4529 "foo \nbar",
4530 "foo \nbar",
4531 "foo\nbar",
4532 },
4533 {
4534 "foo\n\n\nbar",
4535 "foo\n\nbar",
4536 "foo\n\nbar",
4537 "foo\n\nbar",
4538 },
4539 {
4540 "foo\n\n\n\tbar",
4541 "foo\n\nbar",
4542 "foo\n\n\tbar",
4543 "foo\n\nbar",
4544 },
4545 {
4546 "foo\n\n\n bar",
4547 "foo\n\nbar",
4548 "foo\n\n bar",
4549 "foo\n\nbar",
4550 },
4551 {
4552 "foo\n\n\n bar",
4553 "foo\n\nbar",
4554 "foo\n\n bar",
4555 "foo\n\nbar",
4556 },
4557 {
4558 "foo\n\n\n bar",
4559 "foo\n\nbar",
4560 "foo\n\n bar",
4561 "foo\n\nbar",
4562 },
4563 {
4564 "foo\n\n\n\nbar",
4565 "foo\n\nbar",
4566 "foo\n\nbar",
4567 "foo\n\nbar",
4568 },
4569 {
4570 "foo\n\n\n\n\tbar",
4571 "foo\n\nbar",
4572 "foo\n\n\tbar",
4573 "foo\n\nbar",
4574 },
4575 {
4576 "foo\n\n\n\n bar",
4577 "foo\n\nbar",
4578 "foo\n\n bar",
4579 "foo\n\nbar",
4580 },
4581 {
4582 "foo\n\n\n\n bar",
4583 "foo\n\nbar",
4584 "foo\n\n bar",
4585 "foo\n\nbar",
4586 },
4587 {
4588 "foo\n\n\n\n bar",
4589 "foo\n\nbar",
4590 "foo\n\n bar",
4591 "foo\n\nbar",
4592 },
4593 {
4594 "foo.\nbar",
4595 "foo. \nbar",
4596 "foo. \nbar",
4597 "foo.\nbar",
4598 },
4599 {
4600 "foo. \nbar",
4601 "foo. \nbar",
4602 "foo. \nbar",
4603 "foo.\nbar",
4604 },
4605 {
4606 "foo\n*bar",
4607 "foo \n\\*bar",
4608 "foo\n*bar",
4609 "foo\n*bar",
4610 },
4611 {
4612 "foo\nbar",
4613 "foo bar",
4614 "foo\nbar",
4615 "foo bar",
4616 },
4617 {
4618 "Tests primality of `p`.",
4619 "Tests primality of `p`.",
4620 "Tests primality of `p`.",
4621 "Tests primality of `p`.",
4622 },
4623 {
4624 "'`' should not occur in `Code`",
4625 "'\\`' should not occur in `Code`",
4626 "'`' should not occur in `Code`",
4627 "'`' should not occur in `Code`",
4628 },
4629 {
4630 "`not\nparsed`",
4631 "\\`not parsed\\`",
4632 "`not\nparsed`",
4633 "`not parsed`",
4634 },
4635 {
4636 R"(@brief this is a typical use case
4637@param x this is x
4638\param y this is y
4639@return something)",
4640 R"(@brief this is a typical use case
4641@param x this is x
4642\\param y this is y
4643@return something)",
4644 R"(@brief this is a typical use case
4645@param x this is x
4646\param y this is y
4647@return something)",
4648 R"(@brief this is a typical use case
4649@param x this is x
4650\param y this is y
4651@return something)",
4652 }};
4653
4654 for (const auto &C : Cases) {
4655 markup::Document Output;
4656 parseDocumentation(C.Documentation, Output);
4657
4658 EXPECT_EQ(Output.asEscapedMarkdown(), C.ExpectedRenderEscapedMarkdown);
4659 EXPECT_EQ(Output.asMarkdown(), C.ExpectedRenderMarkdown);
4660 EXPECT_EQ(Output.asPlainText(), C.ExpectedRenderPlainText);
4661 }
4662}
4663
4664// This is a separate test as headings don't create any differences in
4665// plaintext mode.
4666TEST(Hover, PresentHeadings) {
4667 HoverInfo HI;
4668 HI.Kind = index::SymbolKind::Variable;
4669 HI.Name = "foo";
4670
4671 EXPECT_EQ(HI.present(MarkupKind::Markdown), "### variable `foo`");
4672}
4673
4674// This is a separate test as rulers behave differently in markdown vs
4675// plaintext.
4676TEST(Hover, PresentRulers) {
4677 HoverInfo HI;
4678 HI.Kind = index::SymbolKind::Variable;
4679 HI.Name = "foo";
4680 HI.Value = "val";
4681 HI.Definition = "def";
4682
4683 llvm::StringRef ExpectedMarkdown = //
4684 "### variable `foo`\n"
4685 "\n"
4686 "---\n"
4687 "Value = `val`\n"
4688 "\n"
4689 "---\n"
4690 "```cpp\n"
4691 "def\n"
4692 "```";
4693 EXPECT_EQ(HI.present(MarkupKind::Markdown), ExpectedMarkdown);
4694
4695 llvm::StringRef ExpectedDoxygenMarkdown = //
4696 "### variable\n"
4697 "\n"
4698 "---\n"
4699 "```cpp\n"
4700 "def\n"
4701 "```\n\n"
4702 "---\n"
4703 "Value = `val`";
4704 Config Cfg;
4705 Cfg.Hover.ShowAKA = true;
4706 Cfg.Documentation.CommentFormat = Config::CommentFormatPolicy::Doxygen;
4707 WithContextValue WithCfg(Config::Key, std::move(Cfg));
4708 EXPECT_EQ(HI.present(MarkupKind::Markdown), ExpectedDoxygenMarkdown);
4709
4710 llvm::StringRef ExpectedPlaintext = R"pt(variable foo
4711
4712Value = val
4713
4714def)pt";
4715 EXPECT_EQ(HI.present(MarkupKind::PlainText), ExpectedPlaintext);
4716}
4717
4718TEST(Hover, SpaceshipTemplateNoCrash) {
4719 Annotations T(R"cpp(
4720 namespace std {
4721 struct strong_ordering {
4722 int n;
4723 constexpr operator int() const { return n; }
4724 static const strong_ordering equal, greater, less;
4725 };
4726 constexpr strong_ordering strong_ordering::equal = {0};
4727 constexpr strong_ordering strong_ordering::greater = {1};
4728 constexpr strong_ordering strong_ordering::less = {-1};
4729 }
4730
4731 template <typename T>
4732 struct S {
4733 // Foo bar baz
4734 friend auto operator<=>(S, S) = default;
4735 };
4736 static_assert(S<void>() =^= S<void>());
4737 )cpp");
4738
4739 TestTU TU = TestTU::withCode(T.code());
4740 TU.ExtraArgs.push_back("-std=c++20");
4741 auto AST = TU.build();
4742 auto HI = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
4743 EXPECT_EQ(HI->Documentation, "");
4744}
4745
4746TEST(Hover, ForwardStructNoCrash) {
4747 Annotations T(R"cpp(
4748 struct Foo;
4749 int bar;
4750 auto baz = (Fo^o*)&bar;
4751 )cpp");
4752
4753 TestTU TU = TestTU::withCode(T.code());
4754 auto AST = TU.build();
4755 auto HI = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
4756 ASSERT_TRUE(HI);
4757 EXPECT_EQ(*HI->Value, "&bar");
4758}
4759
4760TEST(Hover, FunctionParameterDefaulValueNotEvaluatedOnInvalidDecls) {
4761 struct {
4762 const char *const Code;
4763 const std::optional<std::string> HoverValue;
4764 } Cases[] = {
4765 {R"cpp(
4766 // error-ok testing behavior on invalid decl
4767 class Foo {};
4768 void foo(Foo p^aram = nullptr);
4769 )cpp",
4770 std::nullopt},
4771 {R"cpp(
4772 class Foo {};
4773 void foo(Foo *p^aram = nullptr);
4774 )cpp",
4775 "nullptr"},
4776 };
4777
4778 for (const auto &C : Cases) {
4779 Annotations T(C.Code);
4780 TestTU TU = TestTU::withCode(T.code());
4781 auto AST = TU.build();
4782 auto HI = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
4783 ASSERT_TRUE(HI);
4784 ASSERT_EQ(HI->Value, C.HoverValue);
4785 }
4786}
4787
4788TEST(Hover, DisableShowAKA) {
4789 Annotations T(R"cpp(
4790 using m_int = int;
4791 m_int ^[[a]];
4792 )cpp");
4793
4794 Config Cfg;
4795 Cfg.Hover.ShowAKA = false;
4796 WithContextValue WithCfg(Config::Key, std::move(Cfg));
4797
4798 TestTU TU = TestTU::withCode(T.code());
4799 TU.ExtraArgs.push_back("-std=c++17");
4800 auto AST = TU.build();
4801 auto H = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
4802
4803 ASSERT_TRUE(H);
4804 EXPECT_EQ(H->Type, HoverInfo::PrintedType("m_int"));
4805}
4806
4807TEST(Hover, HideBigInitializers) {
4808 Annotations T(R"cpp(
4809 #define A(x) x, x, x, x
4810 #define B(x) A(A(A(A(x))))
4811 int a^rr[] = {B(0)};
4812 )cpp");
4813
4814 TestTU TU = TestTU::withCode(T.code());
4815 auto AST = TU.build();
4816 auto H = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
4817
4818 ASSERT_TRUE(H);
4819 EXPECT_EQ(H->Definition, "int arr[]");
4820}
4821
4822#if defined(__aarch64__)
4823// FIXME: AARCH64 sanitizer buildbots are broken after 72142fbac4.
4824#define PREDEFINEMACROS_TEST(x) DISABLED_##x
4825#else
4826#define PREDEFINEMACROS_TEST(x) x
4827#endif
4828
4829TEST(Hover, PREDEFINEMACROS_TEST(GlobalVarEnumeralCastNoCrash)) {
4830 Annotations T(R"cpp(
4831 using uintptr_t = __UINTPTR_TYPE__;
4832 enum Test : uintptr_t {};
4833 unsigned global_var;
4834 void foo() {
4835 Test v^al = static_cast<Test>(reinterpret_cast<uintptr_t>(&global_var));
4836 }
4837 )cpp");
4838
4839 TestTU TU = TestTU::withCode(T.code());
4840 TU.PredefineMacros = true;
4841 auto AST = TU.build();
4842 auto HI = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
4843 ASSERT_TRUE(HI);
4844 EXPECT_EQ(*HI->Value, "&global_var");
4845}
4846
4847TEST(Hover, PREDEFINEMACROS_TEST(GlobalVarIntCastNoCrash)) {
4848 Annotations T(R"cpp(
4849 using uintptr_t = __UINTPTR_TYPE__;
4850 unsigned global_var;
4851 void foo() {
4852 uintptr_t a^ddress = reinterpret_cast<uintptr_t>(&global_var);
4853 }
4854 )cpp");
4855
4856 TestTU TU = TestTU::withCode(T.code());
4857 TU.PredefineMacros = true;
4858 auto AST = TU.build();
4859 auto HI = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
4860 ASSERT_TRUE(HI);
4861 EXPECT_EQ(*HI->Value, "&global_var");
4862}
4863
4864TEST(Hover, Typedefs) {
4865 Annotations T(R"cpp(
4866 template <bool X, typename T, typename F>
4867 struct cond { using type = T; };
4868 template <typename T, typename F>
4869 struct cond<false, T, F> { using type = F; };
4870
4871 template <bool X, typename T, typename F>
4872 using type = typename cond<X, T, F>::type;
4873
4874 void foo() {
4875 using f^oo = type<true, int, double>;
4876 }
4877 )cpp");
4878
4879 TestTU TU = TestTU::withCode(T.code());
4880 auto AST = TU.build();
4881 auto H = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
4882
4883 ASSERT_TRUE(H && H->Type);
4884 EXPECT_EQ(H->Type->Type, "int");
4885 EXPECT_EQ(H->Definition, "using foo = type<true, int, double>");
4886}
4887
4888TEST(Hover, EvaluateMacros) {
4889 llvm::StringRef PredefinedCXX = R"cpp(
4890#define X 42
4891#define SizeOf sizeof
4892#define AlignOf alignof
4893#define PLUS_TWO +2
4894#define TWO 2
4895
4896using u64 = unsigned long long;
4897// calculate (a ** b) % p
4898constexpr u64 pow_with_mod(u64 a, u64 b, u64 p) {
4899 u64 ret = 1;
4900 while (b) {
4901 if (b & 1)
4902 ret = (ret * a) % p;
4903 a = (a * a) % p;
4904 b >>= 1;
4905 }
4906 return ret;
4907}
4908#define last_n_digit(x, y, n) \
4909 pow_with_mod(x, y, pow_with_mod(10, n, 2147483647))
4910#define declare_struct(X, name, value) \
4911 struct X { \
4912 constexpr auto name() { return value; } \
4913 }
4914#define gnu_statement_expression(value) \
4915 ({ \
4916 declare_struct(Widget, getter, value); \
4917 Widget().getter(); \
4918 })
4919#define define_lambda_begin(lambda, ...) \
4920 [&](__VA_ARGS__) {
4921#define define_lambda_end() }
4922
4923#define left_bracket [
4924#define right_bracket ]
4925#define dg_left_bracket <:
4926#define dg_right_bracket :>
4927#define array_decl(type, name, size) type name left_bracket size right_bracket
4928 )cpp";
4929
4930 struct {
4931 llvm::StringRef Code;
4932 const std::function<void(std::optional<HoverInfo>, size_t /*Id*/)>
4933 Validator;
4934 } Cases[] = {
4935 {
4936 /*Code=*/R"cpp(
4937 X^;
4938 )cpp",
4939 /*Validator=*/
4940 [](std::optional<HoverInfo> HI, size_t) {
4941 EXPECT_EQ(HI->Value, "42 (0x2a)");
4942 EXPECT_EQ(HI->Type, HoverInfo::PrintedType("int"));
4943 },
4944 },
4945 {
4946 /*Code=*/R"cpp(
4947 Size^Of(int);
4948 )cpp",
4949 /*Validator=*/
4950 [](std::optional<HoverInfo> HI, size_t) {
4951 EXPECT_TRUE(HI->Value);
4952 EXPECT_TRUE(HI->Type);
4953 // Don't validate type or value of `sizeof` and `alignof` as we're
4954 // getting different values or desugared types on different
4955 // platforms. Same as below.
4956 },
4957 },
4958 {
4959 /*Code=*/R"cpp(
4960 struct Y {
4961 int y;
4962 double z;
4963 };
4964 Alig^nOf(Y);
4965 )cpp",
4966 /*Validator=*/
4967 [](std::optional<HoverInfo> HI, size_t) {
4968 EXPECT_TRUE(HI->Value);
4969 EXPECT_TRUE(HI->Type);
4970 },
4971 },
4972 {
4973 /*Code=*/R"cpp(
4974 // 2**32 == 4294967296
4975 last_n_di^git(2, 32, 6);
4976 )cpp",
4977 /*Validator=*/
4978 [](std::optional<HoverInfo> HI, size_t) {
4979 EXPECT_EQ(HI->Value, "967296 (0xec280)");
4980 EXPECT_EQ(HI->Type, "u64");
4981 },
4982 },
4983 {
4984 /*Code=*/R"cpp(
4985 gnu_statement_exp^ression(42);
4986 )cpp",
4987 /*Validator=*/
4988 [](std::optional<HoverInfo> HI, size_t) {
4989 EXPECT_EQ(HI->Value, "42 (0x2a)");
4990 EXPECT_EQ(HI->Type, "int");
4991 },
4992 },
4993 {
4994 /*Code=*/R"cpp(
4995 40 + PLU^S_TWO;
4996 )cpp",
4997 /*Validator=*/
4998 [](std::optional<HoverInfo> HI, size_t) {
4999 EXPECT_EQ(HI->Value, "2");
5000 EXPECT_EQ(HI->Type, "int");
5001 },
5002 },
5003 {
5004 /*Code=*/R"cpp(
5005 40 PLU^S_TWO;
5006 )cpp",
5007 /*Validator=*/
5008 [](std::optional<HoverInfo> HI, size_t) {
5009 EXPECT_FALSE(HI->Value) << HI->Value;
5010 EXPECT_FALSE(HI->Type) << HI->Type;
5011 },
5012 },
5013 {
5014 /*Code=*/R"cpp(
5015 40 + TW^O;
5016 )cpp",
5017 /*Validator=*/
5018 [](std::optional<HoverInfo> HI, size_t) {
5019 EXPECT_EQ(HI->Value, "2");
5020 EXPECT_EQ(HI->Type, "int");
5021 },
5022 },
5023 {
5024 /*Code=*/R"cpp(
5025 arra^y_decl(int, vector, 10);
5026 vector left_b^racket 3 right_b^racket;
5027 vector dg_le^ft_bracket 3 dg_righ^t_bracket;
5028 )cpp",
5029 /*Validator=*/
5030 [](std::optional<HoverInfo> HI, size_t Id) {
5031 switch (Id) {
5032 case 0:
5033 EXPECT_EQ(HI->Type, HoverInfo::PrintedType("int[10]"));
5034 break;
5035 case 1:
5036 case 2:
5037 case 3:
5038 case 4:
5039 EXPECT_FALSE(HI->Type) << HI->Type;
5040 EXPECT_FALSE(HI->Value) << HI->Value;
5041 break;
5042 default:
5043 ASSERT_TRUE(false) << "Unhandled id: " << Id;
5044 }
5045 },
5046 },
5047 {
5048 /*Code=*/R"cpp(
5049 constexpr auto value = define_lamb^da_begin(lambda, int, char)
5050 // Check if the expansion range is right.
5051 return ^last_n_digit(10, 3, 3)^;
5052 define_lam^bda_end();
5053 )cpp",
5054 /*Validator=*/
5055 [](std::optional<HoverInfo> HI, size_t Id) {
5056 switch (Id) {
5057 case 0:
5058 EXPECT_FALSE(HI->Value);
5059 EXPECT_EQ(HI->Type, HoverInfo::PrintedType("const (lambda)"));
5060 break;
5061 case 1:
5062 EXPECT_EQ(HI->Value, "0");
5063 EXPECT_EQ(HI->Type, HoverInfo::PrintedType("u64"));
5064 break;
5065 case 2:
5066 EXPECT_FALSE(HI);
5067 break;
5068 case 3:
5069 EXPECT_FALSE(HI->Type) << HI->Type;
5070 EXPECT_FALSE(HI->Value) << HI->Value;
5071 break;
5072 default:
5073 ASSERT_TRUE(false) << "Unhandled id: " << Id;
5074 }
5075 },
5076 },
5077 };
5078
5079 Config Cfg;
5080 Cfg.Hover.ShowAKA = false;
5081 WithContextValue WithCfg(Config::Key, std::move(Cfg));
5082 for (const auto &C : Cases) {
5083 Annotations Code(
5084 (PredefinedCXX + "void function() {\n" + C.Code + "}\n").str());
5085 auto TU = TestTU::withCode(Code.code());
5086 TU.ExtraArgs.push_back("-std=c++17");
5087 auto AST = TU.build();
5088 for (auto [Index, Position] : llvm::enumerate(Code.points())) {
5089 C.Validator(getHover(AST, Position, format::getLLVMStyle(), nullptr),
5090 Index);
5091 }
5092 }
5093
5094 Annotations C(R"c(
5095 #define alignof _Alignof
5096 void foo() {
5097 al^ignof(struct { int x; char y[10]; });
5098 }
5099 )c");
5100
5101 auto TU = TestTU::withCode(C.code());
5102 TU.Filename = "TestTU.c";
5103 TU.ExtraArgs = {
5104 "-std=c17",
5105 };
5106 auto AST = TU.build();
5107 auto H = getHover(AST, C.point(), format::getLLVMStyle(), nullptr);
5108
5109 ASSERT_TRUE(H);
5110 EXPECT_TRUE(H->Value);
5111 EXPECT_TRUE(H->Type);
5112}
5113
5114TEST(Hover, HoverMacroContentsLimit) {
5115 const char *const Code =
5116 R"cpp(
5117 #define C(A) A##A // Concatenate
5118 #define E(A) C(A) // Expand
5119 #define Z0032 00000000000000000000000000000000
5120 #define Z0064 E(Z0032)
5121 #define Z0128 E(Z0064)
5122 #define Z0256 E(Z0128)
5123 #define Z0512 E(Z0256)
5124 #define Z1024 E(Z0512)
5125 #define Z2048 E(Z1024)
5126 #define Z4096 E(Z2048) // 4096 zeroes
5127 int main() { return [[^Z4096]]; }
5128 )cpp";
5129
5130 struct {
5131 uint32_t MacroContentsLimit;
5132 const std::string ExpectedDefinition;
5133 } Cases[] = {
5134 // With a limit of 2048, the macro expansion should get dropped.
5135 {2048, "#define Z4096 E(Z2048)"},
5136 // With a limit of 8192, the macro expansion should be fully expanded.
5137 {8192, std::string("#define Z4096 E(Z2048)\n\n") +
5138 std::string("// Expands to\n") + std::string(4096, '0')},
5139 };
5140 for (const auto &Case : Cases) {
5141 SCOPED_TRACE(Code);
5142
5143 Annotations T(Code);
5144 TestTU TU = TestTU::withCode(T.code());
5145 auto AST = TU.build();
5146 Config Cfg;
5147 Cfg.Hover.MacroContentsLimit = Case.MacroContentsLimit;
5148 WithContextValue WithCfg(Config::Key, std::move(Cfg));
5149 auto H = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
5150 ASSERT_TRUE(H);
5151
5152 EXPECT_EQ(H->Definition, Case.ExpectedDefinition);
5153 }
5154}
5155
5156TEST(Hover, FunctionParameters) {
5157 struct {
5158 const char *const Code;
5159 const std::function<void(HoverInfo &)> ExpectedBuilder;
5160 std::string ExpectedRender;
5161 } Cases[] = {
5162 {R"cpp(/// Function doc
5163 void foo(int [[^a]]);
5164 )cpp",
5165 [](HoverInfo &HI) {
5166 HI.Name = "a";
5167 HI.Kind = index::SymbolKind::Parameter;
5168 HI.NamespaceScope = "";
5169 HI.LocalScope = "foo::";
5170 HI.Type = "int";
5171 HI.Definition = "int a";
5172 HI.Documentation = "";
5173 },
5174 "### param\n\n---\n```cpp\n// In foo\nint a\n```\n\n---\nType: `int`"},
5175 {R"cpp(/// Function doc
5176 /// @param a this is doc for a
5177 void foo(int [[^a]]);
5178 )cpp",
5179 [](HoverInfo &HI) {
5180 HI.Name = "a";
5181 HI.Kind = index::SymbolKind::Parameter;
5182 HI.NamespaceScope = "";
5183 HI.LocalScope = "foo::";
5184 HI.Type = "int";
5185 HI.Definition = "int a";
5186 HI.Documentation = "this is doc for a";
5187 },
5188 "### param\n\n---\n```cpp\n// In foo\nint a\n```\n\n---\nthis is doc "
5189 "for a\n\n---\nType: `int`"},
5190 {R"cpp(/// Function doc
5191 /// @param b this is doc for b
5192 void foo(int [[^a]], int b);
5193 )cpp",
5194 [](HoverInfo &HI) {
5195 HI.Name = "a";
5196 HI.Kind = index::SymbolKind::Parameter;
5197 HI.NamespaceScope = "";
5198 HI.LocalScope = "foo::";
5199 HI.Type = "int";
5200 HI.Definition = "int a";
5201 HI.Documentation = "";
5202 },
5203 "### param\n\n---\n```cpp\n// In foo\nint a\n```\n\n---\nType: `int`"},
5204 {R"cpp(/// Function doc
5205 /// @param b this is doc for \p b
5206 void foo(int a, int [[^b]]);
5207 )cpp",
5208 [](HoverInfo &HI) {
5209 HI.Name = "b";
5210 HI.Kind = index::SymbolKind::Parameter;
5211 HI.NamespaceScope = "";
5212 HI.LocalScope = "foo::";
5213 HI.Type = "int";
5214 HI.Definition = "int b";
5215 HI.Documentation = "this is doc for \\p b";
5216 },
5217 "### param\n\n---\n```cpp\n// In foo\nint b\n```\n\n---\nthis is doc "
5218 "for `b`\n\n---\nType: `int`"},
5219 {R"cpp(/// Function doc
5220 /// @param b this is doc for \p b
5221 template <typename T>
5222 void foo(T a, T [[^b]]);
5223 )cpp",
5224 [](HoverInfo &HI) {
5225 HI.Name = "b";
5226 HI.Kind = index::SymbolKind::Parameter;
5227 HI.NamespaceScope = "";
5228 HI.LocalScope = "foo::";
5229 HI.Type = "T";
5230 HI.Definition = "T b";
5231 HI.Documentation = "this is doc for \\p b";
5232 },
5233 "### param\n\n---\n```cpp\n// In foo\nT b\n```\n\n---\nthis is doc for "
5234 "`b`\n\n---\nType: `T`"},
5235 {R"cpp(/// Function doc
5236 /// @param b this is <b>doc</b> <html-tag attribute/> <another-html-tag attribute="value">for</another-html-tag> \p b
5237 void foo(int a, int [[^b]]);
5238 )cpp",
5239 [](HoverInfo &HI) {
5240 HI.Name = "b";
5241 HI.Kind = index::SymbolKind::Parameter;
5242 HI.NamespaceScope = "";
5243 HI.LocalScope = "foo::";
5244 HI.Type = "int";
5245 HI.Definition = "int b";
5246 HI.Documentation =
5247 "this is <b>doc</b> <html-tag attribute/> <another-html-tag "
5248 "attribute=\"value\">for</another-html-tag> \\p b";
5249 },
5250 "### param\n\n---\n```cpp\n// In foo\nint b\n```\n\n---\nthis is "
5251 "\\<b>doc\\</b> \\<html-tag attribute/> \\<another-html-tag "
5252 "attribute=\"value\">for\\</another-html-tag> `b`\n\n---\nType: `int`"},
5253 {R"cpp(/// Function doc
5254 /// @param a the next command is an
5255 /// @unknown command.
5256 void foo(int [[^a]]);
5257 )cpp",
5258 [](HoverInfo &HI) {
5259 HI.Name = "a";
5260 HI.Kind = index::SymbolKind::Parameter;
5261 HI.NamespaceScope = "";
5262 HI.LocalScope = "foo::";
5263 HI.Type = "int";
5264 HI.Definition = "int a";
5265 HI.Documentation = "the next command is an\n @unknown command.";
5266 },
5267 "### param\n\n---\n```cpp\n// In foo\nint a\n```\n\n---\nthe next "
5268 "command is an\n**@unknown** command.\n\n---\nType: `int`"},
5269 };
5270
5271 // Create a tiny index, so tests above can verify documentation is fetched.
5272 Symbol IndexSym = func("indexSymbol");
5273 IndexSym.Documentation = "comment from index";
5275 Symbols.insert(IndexSym);
5276 auto Index =
5277 MemIndex::build(std::move(Symbols).build(), RefSlab(), RelationSlab());
5278
5279 for (const auto &Case : Cases) {
5280 SCOPED_TRACE(Case.Code);
5281
5282 Annotations T(Case.Code);
5283 TestTU TU = TestTU::withCode(T.code());
5284 auto AST = TU.build();
5285 Config Cfg;
5286 Cfg.Hover.ShowAKA = true;
5287 Cfg.Documentation.CommentFormat = Config::CommentFormatPolicy::Doxygen;
5288 WithContextValue WithCfg(Config::Key, std::move(Cfg));
5289 auto H = getHover(AST, T.point(), format::getLLVMStyle(), Index.get());
5290 ASSERT_TRUE(H);
5291 HoverInfo Expected;
5292 Expected.SymRange = T.range();
5293 Case.ExpectedBuilder(Expected);
5294
5295 EXPECT_EQ(H->present(MarkupKind::Markdown), Case.ExpectedRender);
5296 EXPECT_EQ(H->NamespaceScope, Expected.NamespaceScope);
5297 EXPECT_EQ(H->LocalScope, Expected.LocalScope);
5298 EXPECT_EQ(H->Name, Expected.Name);
5299 EXPECT_EQ(H->Kind, Expected.Kind);
5300 EXPECT_EQ(H->Documentation, Expected.Documentation);
5301 EXPECT_EQ(H->Definition, Expected.Definition);
5302 EXPECT_EQ(H->Type, Expected.Type);
5303 EXPECT_EQ(H->ReturnType, Expected.ReturnType);
5304 EXPECT_EQ(H->Parameters, Expected.Parameters);
5305 EXPECT_EQ(H->TemplateParameters, Expected.TemplateParameters);
5306 EXPECT_EQ(H->SymRange, Expected.SymRange);
5307 EXPECT_EQ(H->Value, Expected.Value);
5308 }
5309}
5310
5311static void configureHLSL(TestTU &TU, bool EnableMatrix = false) {
5312 TU.Filename = "TestTU.hlsl";
5313 TU.ExtraArgs.push_back("-x");
5314 TU.ExtraArgs.push_back("hlsl");
5315 if (EnableMatrix)
5316 TU.ExtraArgs.push_back("-fenable-matrix");
5317 TU.ExtraArgs.push_back("--target=dxil-pc-shadermodel6.3-library");
5318}
5319
5320TEST(Hover, HLSLVectorAndMatrixSwizzle) {
5321 struct {
5322 const char *const Code;
5323 const std::function<void(HoverInfo &)> ExpectedBuilder;
5324 } Cases[] = {
5325 {
5326 R"hlsl(
5327 typedef float float3 __attribute__((ext_vector_type(3)));
5328 void main() {
5329 float3 v;
5330 float3 s = v.^[[xyz]];
5331 }
5332 )hlsl",
5333 [](HoverInfo &HI) {
5334 HI.Name = "xyz";
5335 HI.Type = "float3";
5336 }},
5337 {
5338 R"hlsl(
5339 typedef float float3 __attribute__((ext_vector_type(3)));
5340 typedef float float2 __attribute__((ext_vector_type(2)));
5341 void main() {
5342 float3 v;
5343 float2 s = v.^[[xy]];
5344 }
5345 )hlsl",
5346 [](HoverInfo &HI) {
5347 HI.Name = "xy";
5348 HI.Type = "float2";
5349 }},
5350 {
5351 R"hlsl(
5352 typedef float float4x4 __attribute__((matrix_type(4, 4)));
5353 void main() {
5354 float4x4 m;
5355 float e = m.^[[_m00]];
5356 }
5357 )hlsl",
5358 [](HoverInfo &HI) {
5359 HI.Name = "_m00";
5360 HI.Type = "float";
5361 }},
5362 };
5363
5364 for (const auto &Case : Cases) {
5365 SCOPED_TRACE(Case.Code);
5366 Annotations T(Case.Code);
5367 TestTU TU = TestTU::withCode(T.code());
5368 configureHLSL(TU, /*EnableMatrix=*/true);
5369 auto AST = TU.build();
5370 auto H = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
5371 ASSERT_TRUE(H);
5372 HoverInfo Expected;
5373 Expected.SymRange = T.range();
5374 Case.ExpectedBuilder(Expected);
5375 SCOPED_TRACE(H->present(MarkupKind::PlainText));
5376 EXPECT_EQ(H->Name, Expected.Name);
5377 EXPECT_EQ(H->Type, Expected.Type);
5378 EXPECT_EQ(H->SymRange, Expected.SymRange);
5379 }
5380}
5381
5382TEST(Hover, HLSLInvalidMatrixSwizzleNoCrash) {
5383 Annotations T(R"hlsl(
5384 typedef float float2x2 __attribute__((matrix_type(2, 2)));
5385 void main() {
5386 float2x2 m;
5387 float bad = m.^[[_m22]]; // out of bounds for a 2x2 matrix /*error-ok*/
5388 }
5389 )hlsl");
5390 TestTU TU = TestTU::withCode(T.code());
5391 configureHLSL(TU, /*EnableMatrix=*/true);
5392 auto AST = TU.build();
5393 auto H = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
5394 EXPECT_FALSE(H);
5395}
5396
5397TEST(Hover, HLSLInvalidVectorSwizzleNoCrash) {
5398 Annotations T(R"hlsl(
5399 typedef float float3 __attribute__((ext_vector_type(3)));
5400 void main() {
5401 float3 v;
5402 float bad = v.^[[w]]; // 'w' is not a valid component for a 3-component vector /*error-ok*/
5403 }
5404 )hlsl");
5405 TestTU TU = TestTU::withCode(T.code());
5406 configureHLSL(TU);
5407 auto AST = TU.build();
5408 auto H = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
5409 EXPECT_FALSE(H);
5410}
5411
5412TEST(Hover, AttributedStmt) {
5413 struct {
5414 const char *const Code;
5415 const char *const ExpectedName;
5416 bool IsHLSL;
5417 bool ExpectDocumentation;
5418 } Cases[] = {
5419 {R"hlsl(
5420 [numthreads(1, 1, 1)]
5421 void main() {
5422 [^unroll]
5423 for (int i = 0; i < 4; i++) {}
5424 }
5425 )hlsl",
5426 "unroll", /*IsHLSL=*/true, /*ExpectDocumentation=*/true},
5427 {R"hlsl(
5428 [numthreads(1, 1, 1)]
5429 void main() {
5430 [l^oop]
5431 for (int i = 0; i < 4; i++) {}
5432 }
5433 )hlsl",
5434 "loop", /*IsHLSL=*/true, /*ExpectDocumentation=*/true},
5435 {R"hlsl(
5436 [numthreads(1, 1, 1)]
5437 void main() {
5438 [b^ranch]
5439 if (true) {}
5440 }
5441 )hlsl",
5442 "branch", /*IsHLSL=*/true, /*ExpectDocumentation=*/false},
5443 {R"hlsl(
5444 [numthreads(1, 1, 1)]
5445 void main() {
5446 [f^latten]
5447 if (true) {}
5448 }
5449 )hlsl",
5450 "flatten", /*IsHLSL=*/true, /*ExpectDocumentation=*/false},
5451 {R"cpp(
5452 void foo() {
5453 [[^likely]] if (true) {}
5454 }
5455 )cpp",
5456 "likely", /*IsHLSL=*/false, /*ExpectDocumentation=*/false},
5457 {R"cpp(
5458 void foo() {
5459 [[^unlikely]] if (true) {}
5460 }
5461 )cpp",
5462 "unlikely", /*IsHLSL=*/false, /*ExpectDocumentation=*/false},
5463 {R"cpp(
5464 void foo() {
5465 switch (1) {
5466 case 1:
5467 [[^fallthrough]];
5468 case 2:
5469 break;
5470 }
5471 }
5472 )cpp",
5473 "fallthrough", /*IsHLSL=*/false, /*ExpectDocumentation=*/false},
5474 };
5475 for (const auto &Case : Cases) {
5476 SCOPED_TRACE(Case.Code);
5477 Annotations T(Case.Code,
5478 Annotations::Markers().setRangeBegin("{{").setRangeEnd("}}"));
5479 TestTU TU = TestTU::withCode(T.code());
5480 if (Case.IsHLSL)
5481 configureHLSL(TU);
5482 else
5483 TU.ExtraArgs.push_back("-std=c++20");
5484 auto AST = TU.build();
5485 auto H = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
5486 ASSERT_TRUE(H);
5487 EXPECT_EQ(H->Name, Case.ExpectedName);
5488 if (Case.ExpectDocumentation) {
5489 EXPECT_FALSE(H->Documentation.empty());
5490 }
5491 }
5492}
5493TEST(Hover, HLSLRegisterAttributeRange) {
5494 Annotations T(R"hlsl(
5495 Texture2D tex : [[^register]]([[^t1]]);
5496 )hlsl");
5497
5498 TestTU TU = TestTU::withCode(T.code());
5499 configureHLSL(TU);
5500
5501 auto AST = TU.build();
5502
5503 for (const auto &P : T.points()) {
5504 auto H = getHover(AST, P, format::getLLVMStyle(), nullptr);
5505
5506 ASSERT_TRUE(H);
5507 EXPECT_EQ(H->Name, "register");
5508 EXPECT_FALSE(H->Documentation.empty());
5509 }
5510}
5511
5512} // namespace
5513} // namespace clangd
5514} // namespace clang
#define PREDEFINEMACROS_TEST(x)
Same as llvm::Annotations, but adjusts functions to LSP-specific types for positions and ranges.
Definition Annotations.h:23
static std::unique_ptr< SymbolIndex > build(SymbolSlab Symbols, RefSlab Refs, RelationSlab Relations)
Builds an index from slabs. The index takes ownership of the data.
Definition MemIndex.cpp:18
An efficient structure of storing large set of symbol references in memory.
Definition Ref.h:111
SymbolSlab::Builder is a mutable container that can 'freeze' to SymbolSlab.
Definition Symbol.h:238
WithContextValue extends Context::current() with a single value.
Definition Context.h:200
FIXME: Skip testing on windows temporarily due to the different escaping code mode.
Definition AST.cpp:44
SymbolID getSymbolID(const Decl *D)
Gets the symbol ID for a declaration. Returned SymbolID might be null.
Definition AST.cpp:354
Symbol func(llvm::StringRef Name)
Definition TestIndex.cpp:62
const NamedDecl & findDecl(ParsedAST &AST, llvm::StringRef QName)
Definition TestTU.cpp:220
std::string testPath(PathRef File, llvm::sys::path::Style Style)
Definition TestFS.cpp:94
std::optional< HoverInfo > getHover(ParsedAST &AST, Position Pos, const format::FormatStyle &Style, const SymbolIndex *Index)
Get the hover information when hovering at Pos.
Definition Hover.cpp:1313
TEST(BackgroundQueueTest, Priority)
void parseDocumentation(llvm::StringRef Input, markup::Document &Output)
Definition Hover.cpp:1852
cppcoreguidelines::ProBoundsAvoidUncheckedContainerAccessCheck P
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Settings that express user/project preferences and control clangd behavior.
Definition Config.h:45
static clangd::Key< Config > Key
Context key which can be used to set the current Config.
Definition Config.h:49
@ Markdown
Treat comments as Markdown.
Definition Config.h:217
@ Doxygen
Treat comments as doxygen.
Definition Config.h:219
struct clang::clangd::Config::@124253042262101241326257264241307221112313102042 Hover
Configures hover feature.
bool ShowAKA
Whether hover show a.k.a type.
Definition Config.h:186
uint32_t MacroContentsLimit
Limit the number of characters returned when hovering a macro; 0 is no limit.
Definition Config.h:189
Represents parameters of a function, a template or a macro.
Definition Hover.h:46
Contains pretty-printed type and desugared type.
Definition Hover.h:29
Contains detailed information about a Symbol.
Definition Hover.h:27
std::optional< Range > SymRange
Definition Hover.h:74
std::string Name
Name of the symbol, does not contain any "::".
Definition Hover.h:71
index::SymbolKind Kind
Definition Hover.h:75
Ensure we have enough bits to represent all SymbolTag values.
Definition Symbol.h:49
ParsedAST build() const
Definition TestTU.cpp:115
std::string Filename
Definition TestTU.h:50
static TestTU withCode(llvm::StringRef Code)
Definition TestTU.h:36