clang-tools 23.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 = {"decltype(lamb) &", "(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 {// Setter
1020 R"cpp(
1021 struct X { int Y; void [[^setY]](float v) { Y = v; } };
1022 )cpp",
1023 [](HoverInfo &HI) {
1024 HI.Name = "setY";
1025 HI.Kind = index::SymbolKind::InstanceMethod;
1026 HI.NamespaceScope = "";
1027 HI.Definition = "void setY(float v)";
1028 HI.LocalScope = "X::";
1029 HI.Documentation = "Trivial setter for `Y`.";
1030 HI.Type = "void (float)";
1031 HI.ReturnType = "void";
1032 HI.Parameters.emplace();
1033 HI.Parameters->emplace_back();
1034 HI.Parameters->back().Type = "float";
1035 HI.Parameters->back().Name = "v";
1036 HI.AccessSpecifier = "public";
1037 }},
1038 {// Setter (builder)
1039 R"cpp(
1040 struct X { int Y; X& [[^setY]](float v) { Y = v; return *this; } };
1041 )cpp",
1042 [](HoverInfo &HI) {
1043 HI.Name = "setY";
1044 HI.Kind = index::SymbolKind::InstanceMethod;
1045 HI.NamespaceScope = "";
1046 HI.Definition = "X &setY(float v)";
1047 HI.LocalScope = "X::";
1048 HI.Documentation = "Trivial setter for `Y`.";
1049 HI.Type = "X &(float)";
1050 HI.ReturnType = "X &";
1051 HI.Parameters.emplace();
1052 HI.Parameters->emplace_back();
1053 HI.Parameters->back().Type = "float";
1054 HI.Parameters->back().Name = "v";
1055 HI.AccessSpecifier = "public";
1056 }},
1057 {// Setter (move)
1058 R"cpp(
1059 namespace std { template<typename T> T&& move(T&& t); }
1060 struct X { int Y; void [[^setY]](float v) { Y = std::move(v); } };
1061 )cpp",
1062 [](HoverInfo &HI) {
1063 HI.Name = "setY";
1064 HI.Kind = index::SymbolKind::InstanceMethod;
1065 HI.NamespaceScope = "";
1066 HI.Definition = "void setY(float v)";
1067 HI.LocalScope = "X::";
1068 HI.Documentation = "Trivial setter for `Y`.";
1069 HI.Type = "void (float)";
1070 HI.ReturnType = "void";
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 {// Field type initializer.
1078 R"cpp(
1079 struct X { int x = 2; };
1080 X ^[[x]];
1081 )cpp",
1082 [](HoverInfo &HI) {
1083 HI.Name = "x";
1084 HI.Kind = index::SymbolKind::Variable;
1085 HI.NamespaceScope = "";
1086 HI.Definition = "X x";
1087 HI.Type = "X";
1088 }},
1089 {// Don't crash on null types.
1090 R"cpp(auto [^[[x]]] = 1; /*error-ok*/)cpp",
1091 [](HoverInfo &HI) {
1092 HI.Name = "x";
1093 HI.Kind = index::SymbolKind::Variable;
1094 HI.NamespaceScope = "";
1095 HI.Definition = "";
1096 HI.Type = "NULL TYPE";
1097 // Bindings are in theory public members of an anonymous struct.
1098 HI.AccessSpecifier = "public";
1099 }},
1100 {// Don't crash on invalid decl with invalid init expr.
1101 R"cpp(
1102 Unknown [[^abc]] = invalid;
1103 // error-ok
1104 )cpp",
1105 [](HoverInfo &HI) {
1106 HI.Name = "abc";
1107 HI.Kind = index::SymbolKind::Variable;
1108 HI.NamespaceScope = "";
1109 HI.Definition = "int abc";
1110 HI.Type = "int";
1111 HI.AccessSpecifier = "public";
1112 }},
1113 {// Extra info for function call.
1114 R"cpp(
1115 void fun(int arg_a, int &arg_b) {};
1116 void code() {
1117 int a = 1, b = 2;
1118 fun(a, [[^b]]);
1119 }
1120 )cpp",
1121 [](HoverInfo &HI) {
1122 HI.Name = "b";
1123 HI.Kind = index::SymbolKind::Variable;
1124 HI.NamespaceScope = "";
1125 HI.Definition = "int b = 2";
1126 HI.LocalScope = "code::";
1127 HI.Value = "2";
1128 HI.Type = "int";
1129 HI.CalleeArgInfo.emplace();
1130 HI.CalleeArgInfo->Name = "arg_b";
1131 HI.CalleeArgInfo->Type = "int &";
1132 HI.CallPassType = HoverInfo::PassType{PassMode::Ref, false};
1133 }},
1134 {// make_unique-like function call
1135 R"cpp(
1136 struct Foo {
1137 explicit Foo(int arg_a) {}
1138 };
1139 template<class T, class... Args>
1140 T make(Args&&... args)
1141 {
1142 return T(args...);
1143 }
1144
1145 void code() {
1146 int a = 1;
1147 auto foo = make<Foo>([[^a]]);
1148 }
1149 )cpp",
1150 [](HoverInfo &HI) {
1151 HI.Name = "a";
1152 HI.Kind = index::SymbolKind::Variable;
1153 HI.NamespaceScope = "";
1154 HI.Definition = "int a = 1";
1155 HI.LocalScope = "code::";
1156 HI.Value = "1";
1157 HI.Type = "int";
1158 HI.CalleeArgInfo.emplace();
1159 HI.CalleeArgInfo->Name = "arg_a";
1160 HI.CalleeArgInfo->Type = "int";
1161 HI.CallPassType = HoverInfo::PassType{PassMode::Value, false};
1162 }},
1163 {
1164 R"cpp(
1165 void foobar(const float &arg);
1166 int main() {
1167 int a = 0;
1168 foobar([[^a]]);
1169 }
1170 )cpp",
1171 [](HoverInfo &HI) {
1172 HI.Name = "a";
1173 HI.Kind = index::SymbolKind::Variable;
1174 HI.NamespaceScope = "";
1175 HI.Definition = "int a = 0";
1176 HI.LocalScope = "main::";
1177 HI.Value = "0";
1178 HI.Type = "int";
1179 HI.CalleeArgInfo.emplace();
1180 HI.CalleeArgInfo->Name = "arg";
1181 HI.CalleeArgInfo->Type = "const float &";
1182 HI.CallPassType = HoverInfo::PassType{PassMode::Value, true};
1183 }},
1184 {
1185 R"cpp(
1186 struct Foo {
1187 explicit Foo(const float& arg) {}
1188 };
1189 int main() {
1190 int a = 0;
1191 Foo foo([[^a]]);
1192 }
1193 )cpp",
1194 [](HoverInfo &HI) {
1195 HI.Name = "a";
1196 HI.Kind = index::SymbolKind::Variable;
1197 HI.NamespaceScope = "";
1198 HI.Definition = "int a = 0";
1199 HI.LocalScope = "main::";
1200 HI.Value = "0";
1201 HI.Type = "int";
1202 HI.CalleeArgInfo.emplace();
1203 HI.CalleeArgInfo->Name = "arg";
1204 HI.CalleeArgInfo->Type = "const float &";
1205 HI.CallPassType = HoverInfo::PassType{PassMode::Value, true};
1206 }},
1207 {// Literal passed to function call
1208 R"cpp(
1209 void fun(int arg_a, const int &arg_b) {};
1210 void code() {
1211 int a = 1;
1212 fun(a, [[^2]]);
1213 }
1214 )cpp",
1215 [](HoverInfo &HI) {
1216 HI.Name = "literal";
1217 HI.Kind = index::SymbolKind::Unknown;
1218 HI.CalleeArgInfo.emplace();
1219 HI.CalleeArgInfo->Name = "arg_b";
1220 HI.CalleeArgInfo->Type = "const int &";
1221 HI.CallPassType = HoverInfo::PassType{PassMode::ConstRef, false};
1222 }},
1223 {// Expression passed to function call
1224 R"cpp(
1225 void fun(int arg_a, const int &arg_b) {};
1226 void code() {
1227 int a = 1;
1228 fun(a, 1 [[^+]] 2);
1229 }
1230 )cpp",
1231 [](HoverInfo &HI) {
1232 HI.Name = "expression";
1233 HI.Kind = index::SymbolKind::Unknown;
1234 HI.Type = "int";
1235 HI.Value = "3";
1236 HI.CalleeArgInfo.emplace();
1237 HI.CalleeArgInfo->Name = "arg_b";
1238 HI.CalleeArgInfo->Type = "const int &";
1239 HI.CallPassType = HoverInfo::PassType{PassMode::ConstRef, false};
1240 }},
1241 {
1242 R"cpp(
1243 int add(int lhs, int rhs);
1244 int main() {
1245 add(1 [[^+]] 2, 3);
1246 }
1247 )cpp",
1248 [](HoverInfo &HI) {
1249 HI.Name = "expression";
1250 HI.Kind = index::SymbolKind::Unknown;
1251 HI.Type = "int";
1252 HI.Value = "3";
1253 HI.CalleeArgInfo.emplace();
1254 HI.CalleeArgInfo->Name = "lhs";
1255 HI.CalleeArgInfo->Type = "int";
1256 HI.CallPassType = HoverInfo::PassType{PassMode::Value, false};
1257 }},
1258 {
1259 R"cpp(
1260 void foobar(const float &arg);
1261 int main() {
1262 foobar([[^0]]);
1263 }
1264 )cpp",
1265 [](HoverInfo &HI) {
1266 HI.Name = "literal";
1267 HI.Kind = index::SymbolKind::Unknown;
1268 HI.CalleeArgInfo.emplace();
1269 HI.CalleeArgInfo->Name = "arg";
1270 HI.CalleeArgInfo->Type = "const float &";
1271 HI.CallPassType = HoverInfo::PassType{PassMode::Value, true};
1272 }},
1273 {// Extra info for method call.
1274 R"cpp(
1275 class C {
1276 public:
1277 void fun(int arg_a = 3, int arg_b = 4) {}
1278 };
1279 void code() {
1280 int a = 1, b = 2;
1281 C c;
1282 c.fun([[^a]], b);
1283 }
1284 )cpp",
1285 [](HoverInfo &HI) {
1286 HI.Name = "a";
1287 HI.Kind = index::SymbolKind::Variable;
1288 HI.NamespaceScope = "";
1289 HI.Definition = "int a = 1";
1290 HI.LocalScope = "code::";
1291 HI.Value = "1";
1292 HI.Type = "int";
1293 HI.CalleeArgInfo.emplace();
1294 HI.CalleeArgInfo->Name = "arg_a";
1295 HI.CalleeArgInfo->Type = "int";
1296 HI.CalleeArgInfo->Default = "3";
1297 HI.CallPassType = HoverInfo::PassType{PassMode::Value, false};
1298 }},
1299 {
1300 R"cpp(
1301 struct Foo {
1302 Foo(const int &);
1303 };
1304 void foo(Foo);
1305 void bar() {
1306 const int x = 0;
1307 foo([[^x]]);
1308 }
1309 )cpp",
1310 [](HoverInfo &HI) {
1311 HI.Name = "x";
1312 HI.Kind = index::SymbolKind::Variable;
1313 HI.NamespaceScope = "";
1314 HI.Definition = "const int x = 0";
1315 HI.LocalScope = "bar::";
1316 HI.Value = "0";
1317 HI.Type = "const int";
1318 HI.CalleeArgInfo.emplace();
1319 HI.CalleeArgInfo->Type = "Foo";
1320 HI.CallPassType = HoverInfo::PassType{PassMode::ConstRef, true};
1321 }},
1322 {// Dont crash on invalid decl
1323 R"cpp(
1324 // error-ok
1325 struct Foo {
1326 Bar [[x^x]];
1327 };)cpp",
1328 [](HoverInfo &HI) {
1329 HI.Name = "xx";
1330 HI.Kind = index::SymbolKind::Field;
1331 HI.NamespaceScope = "";
1332 HI.Definition = "int xx";
1333 HI.LocalScope = "Foo::";
1334 HI.Type = "int";
1335 HI.AccessSpecifier = "public";
1336 }},
1337 {R"cpp(
1338 // error-ok
1339 struct Foo {
1340 Bar xx;
1341 int [[y^y]];
1342 };)cpp",
1343 [](HoverInfo &HI) {
1344 HI.Name = "yy";
1345 HI.Kind = index::SymbolKind::Field;
1346 HI.NamespaceScope = "";
1347 HI.Definition = "int yy";
1348 HI.LocalScope = "Foo::";
1349 HI.Type = "int";
1350 HI.AccessSpecifier = "public";
1351 }},
1352 {// No crash on InitListExpr.
1353 R"cpp(
1354 struct Foo {
1355 int a[10];
1356 };
1357 constexpr Foo k2 = {
1358 ^[[{]]1} // FIXME: why the hover range is 1 character?
1359 };
1360 )cpp",
1361 [](HoverInfo &HI) {
1362 HI.Name = "expression";
1363 HI.Kind = index::SymbolKind::Unknown;
1364 HI.Type = "int[10]";
1365 HI.Value = "{1}";
1366 }},
1367 {// Var template decl
1368 R"cpp(
1369 using m_int = int;
1370
1371 template <int Size> m_int ^[[arr]][Size];
1372 )cpp",
1373 [](HoverInfo &HI) {
1374 HI.Name = "arr";
1375 HI.Kind = index::SymbolKind::Variable;
1376 HI.Type = {"m_int[Size]", "int[Size]"};
1377 HI.NamespaceScope = "";
1378 HI.Definition = "template <int Size> m_int arr[Size]";
1379 HI.TemplateParameters = {{{"int"}, {"Size"}, std::nullopt}};
1380 }},
1381 {// Var template decl specialization
1382 R"cpp(
1383 using m_int = int;
1384
1385 template <int Size> m_int arr[Size];
1386
1387 template <> m_int ^[[arr]]<4>[4];
1388 )cpp",
1389 [](HoverInfo &HI) {
1390 HI.Name = "arr<4>";
1391 HI.Kind = index::SymbolKind::Variable;
1392 HI.Type = {"m_int[4]", "int[4]"};
1393 HI.NamespaceScope = "";
1394 HI.Definition = "m_int arr[4]";
1395 }},
1396 {// Canonical type
1397 R"cpp(
1398 template<typename T>
1399 struct TestHover {
1400 using Type = T;
1401 };
1402
1403 void code() {
1404 TestHover<int>::Type ^[[a]];
1405 }
1406 )cpp",
1407 [](HoverInfo &HI) {
1408 HI.Name = "a";
1409 HI.NamespaceScope = "";
1410 HI.LocalScope = "code::";
1411 HI.Definition = "TestHover<int>::Type a";
1412 HI.Kind = index::SymbolKind::Variable;
1413 HI.Type = {"TestHover<int>::Type", "int"};
1414 }},
1415 {// Canonical template type
1416 R"cpp(
1417 template<typename T>
1418 void ^[[foo]](T arg) {}
1419 )cpp",
1420 [](HoverInfo &HI) {
1421 HI.Name = "foo";
1422 HI.Kind = index::SymbolKind::Function;
1423 HI.NamespaceScope = "";
1424 HI.Definition = "template <typename T> void foo(T arg)";
1425 HI.Type = "void (T)";
1426 HI.ReturnType = "void";
1427 HI.Parameters = {{{"T"}, std::string("arg"), std::nullopt}};
1428 HI.TemplateParameters = {
1429 {{"typename"}, std::string("T"), std::nullopt}};
1430 }},
1431 {// TypeAlias Template
1432 R"cpp(
1433 template<typename T>
1434 using ^[[alias]] = T;
1435 )cpp",
1436 [](HoverInfo &HI) {
1437 HI.Name = "alias";
1438 HI.NamespaceScope = "";
1439 HI.LocalScope = "";
1440 HI.Kind = index::SymbolKind::TypeAlias;
1441 HI.Definition = "template <typename T> using alias = T";
1442 HI.Type = "T";
1443 HI.TemplateParameters = {
1444 {{"typename"}, std::string("T"), std::nullopt}};
1445 }},
1446 {// TypeAlias Template
1447 R"cpp(
1448 template<typename T>
1449 using A = T;
1450
1451 template<typename T>
1452 using ^[[AA]] = A<T>;
1453 )cpp",
1454 [](HoverInfo &HI) {
1455 HI.Name = "AA";
1456 HI.NamespaceScope = "";
1457 HI.LocalScope = "";
1458 HI.Kind = index::SymbolKind::TypeAlias;
1459 HI.Definition = "template <typename T> using AA = A<T>";
1460 HI.Type = {"A<T>", "T"};
1461 HI.TemplateParameters = {
1462 {{"typename"}, std::string("T"), std::nullopt}};
1463 }},
1464 {// Constant array
1465 R"cpp(
1466 using m_int = int;
1467
1468 m_int ^[[arr]][10];
1469 )cpp",
1470 [](HoverInfo &HI) {
1471 HI.Name = "arr";
1472 HI.NamespaceScope = "";
1473 HI.LocalScope = "";
1474 HI.Kind = index::SymbolKind::Variable;
1475 HI.Definition = "m_int arr[10]";
1476 HI.Type = {"m_int[10]", "int[10]"};
1477 }},
1478 {// Incomplete array
1479 R"cpp(
1480 using m_int = int;
1481
1482 extern m_int ^[[arr]][];
1483 )cpp",
1484 [](HoverInfo &HI) {
1485 HI.Name = "arr";
1486 HI.NamespaceScope = "";
1487 HI.LocalScope = "";
1488 HI.Kind = index::SymbolKind::Variable;
1489 HI.Definition = "extern m_int arr[]";
1490 HI.Type = {"m_int[]", "int[]"};
1491 }},
1492 {// Dependent size array
1493 R"cpp(
1494 using m_int = int;
1495
1496 template<int Size>
1497 struct Test {
1498 m_int ^[[arr]][Size];
1499 };
1500 )cpp",
1501 [](HoverInfo &HI) {
1502 HI.Name = "arr";
1503 HI.NamespaceScope = "";
1504 HI.LocalScope = "Test<Size>::";
1505 HI.AccessSpecifier = "public";
1506 HI.Kind = index::SymbolKind::Field;
1507 HI.Definition = "m_int arr[Size]";
1508 HI.Type = {"m_int[Size]", "int[Size]"};
1509 }},
1510 {// Bitfield offset, size and padding
1511 R"cpp(
1512 struct Foo {
1513 char x;
1514 char [[^y]] : 1;
1515 int z;
1516 };
1517 )cpp",
1518 [](HoverInfo &HI) {
1519 HI.NamespaceScope = "";
1520 HI.LocalScope = "Foo::";
1521 HI.Name = "y";
1522 HI.Kind = index::SymbolKind::Field;
1523 HI.Definition = "char y : 1";
1524 HI.Type = "char";
1525 HI.Offset = 8;
1526 HI.Size = 1;
1527 HI.Padding = 23;
1528 HI.Align = 8;
1529 HI.AccessSpecifier = "public";
1530 }}};
1531 for (const auto &Case : Cases) {
1532 SCOPED_TRACE(Case.Code);
1533
1534 Annotations T(Case.Code);
1535 TestTU TU = TestTU::withCode(T.code());
1536 TU.ExtraArgs.push_back("-std=c++20");
1537 // Types might be different depending on the target triplet, we chose a
1538 // fixed one to make sure tests passes on different platform.
1539 TU.ExtraArgs.push_back("--target=x86_64-pc-linux-gnu");
1540 auto AST = TU.build();
1541 Config Cfg;
1542 Cfg.Hover.ShowAKA = true;
1543 WithContextValue WithCfg(Config::Key, std::move(Cfg));
1544
1545 auto H = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
1546 ASSERT_TRUE(H);
1547 HoverInfo Expected;
1548 Expected.SymRange = T.range();
1549 Case.ExpectedBuilder(Expected);
1550
1551 EXPECT_EQ(H->NamespaceScope, Expected.NamespaceScope);
1552 EXPECT_EQ(H->LocalScope, Expected.LocalScope);
1553 EXPECT_EQ(H->Name, Expected.Name);
1554 EXPECT_EQ(H->Kind, Expected.Kind);
1555 EXPECT_EQ(H->Documentation, Expected.Documentation);
1556 EXPECT_EQ(H->Definition, Expected.Definition);
1557 EXPECT_EQ(H->Type, Expected.Type);
1558 EXPECT_EQ(H->ReturnType, Expected.ReturnType);
1559 EXPECT_EQ(H->Parameters, Expected.Parameters);
1560 EXPECT_EQ(H->TemplateParameters, Expected.TemplateParameters);
1561 EXPECT_EQ(H->SymRange, Expected.SymRange);
1562 EXPECT_EQ(H->Value, Expected.Value);
1563 EXPECT_EQ(H->Size, Expected.Size);
1564 EXPECT_EQ(H->Offset, Expected.Offset);
1565 EXPECT_EQ(H->Align, Expected.Align);
1566 EXPECT_EQ(H->AccessSpecifier, Expected.AccessSpecifier);
1567 EXPECT_EQ(H->CalleeArgInfo, Expected.CalleeArgInfo);
1568 EXPECT_EQ(H->CallPassType, Expected.CallPassType);
1569 }
1570}
1571
1572TEST(Hover, DefinitionLanuage) {
1573 struct {
1574 const char *const Code;
1575 const std::string ClangLanguageFlag;
1576 const char *const ExpectedDefinitionLanguage;
1577 } Cases[] = {{R"cpp(
1578 void [[some^Global]]() {}
1579 )cpp",
1580 "", "cpp"},
1581 {R"cpp(
1582 void [[some^Global]]() {}
1583 )cpp",
1584 "-xobjective-c++", "objective-cpp"},
1585 {R"cpp(
1586 void [[some^Global]]() {}
1587 )cpp",
1588 "-xobjective-c", "objective-c"}};
1589 for (const auto &Case : Cases) {
1590 SCOPED_TRACE(Case.Code);
1591
1592 Annotations T(Case.Code);
1593 TestTU TU = TestTU::withCode(T.code());
1594 if (!Case.ClangLanguageFlag.empty())
1595 TU.ExtraArgs.push_back(Case.ClangLanguageFlag);
1596 auto AST = TU.build();
1597
1598 auto H = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
1599 ASSERT_TRUE(H);
1600
1601 EXPECT_STREQ(H->DefinitionLanguage, Case.ExpectedDefinitionLanguage);
1602 }
1603}
1604
1605TEST(Hover, CallPassType) {
1606 const llvm::StringRef CodePrefix = R"cpp(
1607class Base {};
1608class Derived : public Base {};
1609class CustomClass {
1610 public:
1611 CustomClass() {}
1612 CustomClass(const Base &x) {}
1613 CustomClass(int &x) {}
1614 CustomClass(float x) {}
1615 CustomClass(int x, int y) {}
1616};
1617
1618void int_by_ref(int &x) {}
1619void int_by_const_ref(const int &x) {}
1620void int_by_value(int x) {}
1621void base_by_ref(Base &x) {}
1622void base_by_const_ref(const Base &x) {}
1623void base_by_value(Base x) {}
1624void float_by_value(float x) {}
1625void custom_by_value(CustomClass x) {}
1626
1627void fun() {
1628 int int_x;
1629 int &int_ref = int_x;
1630 const int &int_const_ref = int_x;
1631 Base base;
1632 const Base &base_const_ref = base;
1633 Derived derived;
1634 float float_x;
1635)cpp";
1636 const llvm::StringRef CodeSuffix = "}";
1637
1638 struct {
1639 const char *const Code;
1641 bool Converted;
1642 } Tests[] = {
1643 // Integer tests
1644 {"int_by_value([[^int_x]]);", PassMode::Value, false},
1645 {"int_by_value([[^123]]);", PassMode::Value, false},
1646 {"int_by_ref([[^int_x]]);", PassMode::Ref, false},
1647 {"int_by_const_ref([[^int_x]]);", PassMode::ConstRef, false},
1648 {"int_by_const_ref([[^123]]);", PassMode::ConstRef, false},
1649 {"int_by_value([[^int_ref]]);", PassMode::Value, false},
1650 {"int_by_const_ref([[^int_ref]]);", PassMode::ConstRef, false},
1651 {"int_by_const_ref([[^int_ref]]);", PassMode::ConstRef, false},
1652 {"int_by_const_ref([[^int_const_ref]]);", PassMode::ConstRef, false},
1653 // Custom class tests
1654 {"base_by_ref([[^base]]);", PassMode::Ref, false},
1655 {"base_by_const_ref([[^base]]);", PassMode::ConstRef, false},
1656 {"base_by_const_ref([[^base_const_ref]]);", PassMode::ConstRef, false},
1657 {"base_by_value([[^base]]);", PassMode::Value, false},
1658 {"base_by_value([[^base_const_ref]]);", PassMode::Value, false},
1659 {"base_by_ref([[^derived]]);", PassMode::Ref, false},
1660 {"base_by_const_ref([[^derived]]);", PassMode::ConstRef, false},
1661 {"base_by_value([[^derived]]);", PassMode::Value, false},
1662 // Custom class constructor tests
1663 {"CustomClass c1([[^base]]);", PassMode::ConstRef, false},
1664 {"auto c2 = new CustomClass([[^base]]);", PassMode::ConstRef, false},
1665 {"CustomClass c3([[^int_x]]);", PassMode::Ref, false},
1666 {"CustomClass c3(int_x, [[^int_x]]);", PassMode::Value, false},
1667 // Converted tests
1668 {"float_by_value([[^int_x]]);", PassMode::Value, true},
1669 {"float_by_value([[^int_ref]]);", PassMode::Value, true},
1670 {"float_by_value([[^int_const_ref]]);", PassMode::Value, true},
1671 {"float_by_value([[^123.0f]]);", PassMode::Value, false},
1672 {"float_by_value([[^123]]);", PassMode::Value, true},
1673 {"custom_by_value([[^int_x]]);", PassMode::Ref, true},
1674 {"custom_by_value([[^float_x]]);", PassMode::Value, true},
1675 {"custom_by_value([[^base]]);", PassMode::ConstRef, true},
1676 };
1677 for (const auto &Test : Tests) {
1678 SCOPED_TRACE(Test.Code);
1679
1680 const auto Code = (CodePrefix + Test.Code + CodeSuffix).str();
1681 Annotations T(Code);
1682 TestTU TU = TestTU::withCode(T.code());
1683 TU.ExtraArgs.push_back("-std=c++17");
1684 auto AST = TU.build();
1685 auto H = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
1686 ASSERT_TRUE(H);
1687 EXPECT_EQ(H->CallPassType->PassBy, Test.PassBy);
1688 EXPECT_EQ(H->CallPassType->Converted, Test.Converted);
1689 }
1690}
1691
1692TEST(Hover, NoHover) {
1693 llvm::StringRef Tests[] = {
1694 "^int main() {}",
1695 "void foo() {^}",
1696 // FIXME: "decltype(auto)" should be a single hover
1697 "decltype(au^to) x = 0;",
1698 // FIXME: not supported yet
1699 R"cpp(// Lambda auto parameter
1700 auto lamb = [](a^uto){};
1701 )cpp",
1702 R"cpp(// non-named decls don't get hover. Don't crash!
1703 ^static_assert(1, "");
1704 )cpp",
1705 R"cpp(// non-evaluatable expr
1706 template <typename T> void foo() {
1707 (void)[[size^of]](T);
1708 })cpp",
1709 R"cpp(// should not crash on invalid semantic form of init-list-expr.
1710 /*error-ok*/
1711 struct Foo {
1712 int xyz = 0;
1713 };
1714 class Bar {};
1715 constexpr Foo s = ^{
1716 .xyz = Bar(),
1717 };
1718 )cpp",
1719 // literals
1720 "auto x = t^rue;",
1721 "auto x = ^(int){42};",
1722 "auto x = ^42.;",
1723 "auto x = ^42.0i;",
1724 "auto x = ^42;",
1725 "auto x = ^nullptr;",
1726 };
1727
1728 for (const auto &Test : Tests) {
1729 SCOPED_TRACE(Test);
1730
1731 Annotations T(Test);
1732 TestTU TU = TestTU::withCode(T.code());
1733 TU.ExtraArgs.push_back("-std=c++17");
1734 auto AST = TU.build();
1735 auto H = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
1736 ASSERT_FALSE(H);
1737 }
1738}
1739
1740TEST(Hover, All) {
1741 struct {
1742 const char *const Code;
1743 const std::function<void(HoverInfo &)> ExpectedBuilder;
1744 } Cases[] = {
1745 {"auto x = [['^A']]; // character literal",
1746 [](HoverInfo &HI) {
1747 HI.Name = "expression";
1748 HI.Type = "char";
1749 HI.Value = "65 (0x41)";
1750 }},
1751 {"auto s = ^[[\"Hello, world!\"]]; // string literal",
1752 [](HoverInfo &HI) {
1753 HI.Name = "string-literal";
1754 HI.Size = 112;
1755 HI.Type = "const char[14]";
1756 }},
1757 {
1758 R"cpp(// Local variable
1759 int main() {
1760 int bonjour;
1761 ^[[bonjour]] = 2;
1762 int test1 = bonjour;
1763 }
1764 )cpp",
1765 [](HoverInfo &HI) {
1766 HI.Name = "bonjour";
1767 HI.Kind = index::SymbolKind::Variable;
1768 HI.NamespaceScope = "";
1769 HI.LocalScope = "main::";
1770 HI.Type = "int";
1771 HI.Definition = "int bonjour";
1772 }},
1773 {
1774 R"cpp(// Local variable in method
1775 struct s {
1776 void method() {
1777 int bonjour;
1778 ^[[bonjour]] = 2;
1779 }
1780 };
1781 )cpp",
1782 [](HoverInfo &HI) {
1783 HI.Name = "bonjour";
1784 HI.Kind = index::SymbolKind::Variable;
1785 HI.NamespaceScope = "";
1786 HI.LocalScope = "s::method::";
1787 HI.Type = "int";
1788 HI.Definition = "int bonjour";
1789 }},
1790 {
1791 R"cpp(// Struct
1792 namespace ns1 {
1793 struct MyClass {};
1794 } // namespace ns1
1795 int main() {
1796 ns1::[[My^Class]]* Params;
1797 }
1798 )cpp",
1799 [](HoverInfo &HI) {
1800 HI.Name = "MyClass";
1801 HI.Kind = index::SymbolKind::Struct;
1802 HI.NamespaceScope = "ns1::";
1803 HI.Definition = "struct MyClass {}";
1804 }},
1805 {
1806 R"cpp(// Class
1807 namespace ns1 {
1808 class MyClass {};
1809 } // namespace ns1
1810 int main() {
1811 ns1::[[My^Class]]* Params;
1812 }
1813 )cpp",
1814 [](HoverInfo &HI) {
1815 HI.Name = "MyClass";
1816 HI.Kind = index::SymbolKind::Class;
1817 HI.NamespaceScope = "ns1::";
1818 HI.Definition = "class MyClass {}";
1819 }},
1820 {
1821 R"cpp(// Union
1822 namespace ns1 {
1823 union MyUnion { int x; int y; };
1824 } // namespace ns1
1825 int main() {
1826 ns1::[[My^Union]] Params;
1827 }
1828 )cpp",
1829 [](HoverInfo &HI) {
1830 HI.Name = "MyUnion";
1831 HI.Kind = index::SymbolKind::Union;
1832 HI.NamespaceScope = "ns1::";
1833 HI.Definition = "union MyUnion {}";
1834 }},
1835 {
1836 R"cpp(// Function definition via pointer
1837 void foo(int) {}
1838 int main() {
1839 auto *X = &^[[foo]];
1840 }
1841 )cpp",
1842 [](HoverInfo &HI) {
1843 HI.Name = "foo";
1844 HI.Kind = index::SymbolKind::Function;
1845 HI.NamespaceScope = "";
1846 HI.Type = "void (int)";
1847 HI.Definition = "void foo(int)";
1848 HI.Documentation = "Function definition via pointer";
1849 HI.ReturnType = "void";
1850 HI.Parameters = {
1851 {{"int"}, std::nullopt, std::nullopt},
1852 };
1853 }},
1854 {
1855 R"cpp(// Function declaration via call
1856 int foo(int);
1857 int main() {
1858 return ^[[foo]](42);
1859 }
1860 )cpp",
1861 [](HoverInfo &HI) {
1862 HI.Name = "foo";
1863 HI.Kind = index::SymbolKind::Function;
1864 HI.NamespaceScope = "";
1865 HI.Type = "int (int)";
1866 HI.Definition = "int foo(int)";
1867 HI.Documentation = "Function declaration via call";
1868 HI.ReturnType = "int";
1869 HI.Parameters = {
1870 {{"int"}, std::nullopt, std::nullopt},
1871 };
1872 }},
1873 {
1874 R"cpp(// Field
1875 struct Foo { int x; };
1876 int main() {
1877 Foo bar;
1878 (void)bar.^[[x]];
1879 }
1880 )cpp",
1881 [](HoverInfo &HI) {
1882 HI.Name = "x";
1883 HI.Kind = index::SymbolKind::Field;
1884 HI.NamespaceScope = "";
1885 HI.LocalScope = "Foo::";
1886 HI.Type = "int";
1887 HI.Definition = "int x";
1888 }},
1889 {
1890 R"cpp(// Field with initialization
1891 struct Foo { int x = 5; };
1892 int main() {
1893 Foo bar;
1894 (void)bar.^[[x]];
1895 }
1896 )cpp",
1897 [](HoverInfo &HI) {
1898 HI.Name = "x";
1899 HI.Kind = index::SymbolKind::Field;
1900 HI.NamespaceScope = "";
1901 HI.LocalScope = "Foo::";
1902 HI.Type = "int";
1903 HI.Definition = "int x = 5";
1904 }},
1905 {
1906 R"cpp(// Static field
1907 struct Foo { static int x; };
1908 int main() {
1909 (void)Foo::^[[x]];
1910 }
1911 )cpp",
1912 [](HoverInfo &HI) {
1913 HI.Name = "x";
1914 HI.Kind = index::SymbolKind::StaticProperty;
1915 HI.NamespaceScope = "";
1916 HI.LocalScope = "Foo::";
1917 HI.Type = "int";
1918 HI.Definition = "static int x";
1919 }},
1920 {
1921 R"cpp(// Field, member initializer
1922 struct Foo {
1923 int x;
1924 Foo() : ^[[x]](0) {}
1925 };
1926 )cpp",
1927 [](HoverInfo &HI) {
1928 HI.Name = "x";
1929 HI.Kind = index::SymbolKind::Field;
1930 HI.NamespaceScope = "";
1931 HI.LocalScope = "Foo::";
1932 HI.Type = "int";
1933 HI.Definition = "int x";
1934 }},
1935 {
1936 R"cpp(// Field, GNU old-style field designator
1937 struct Foo { int x; };
1938 int main() {
1939 Foo bar = { ^[[x]] : 1 };
1940 }
1941 )cpp",
1942 [](HoverInfo &HI) {
1943 HI.Name = "x";
1944 HI.Kind = index::SymbolKind::Field;
1945 HI.NamespaceScope = "";
1946 HI.LocalScope = "Foo::";
1947 HI.Type = "int";
1948 HI.Definition = "int x";
1949 // FIXME: Initializer for x is a DesignatedInitListExpr, hence it is
1950 // of struct type and omitted.
1951 }},
1952 {
1953 R"cpp(// Field, field designator
1954 struct Foo { int x; int y; };
1955 int main() {
1956 Foo bar = { .^[[x]] = 2, .y = 2 };
1957 }
1958 )cpp",
1959 [](HoverInfo &HI) {
1960 HI.Name = "x";
1961 HI.Kind = index::SymbolKind::Field;
1962 HI.NamespaceScope = "";
1963 HI.LocalScope = "Foo::";
1964 HI.Type = "int";
1965 HI.Definition = "int x";
1966 }},
1967 {
1968 R"cpp(// Method call
1969 struct Foo { int x(); };
1970 int main() {
1971 Foo bar;
1972 bar.^[[x]]();
1973 }
1974 )cpp",
1975 [](HoverInfo &HI) {
1976 HI.Name = "x";
1977 HI.Kind = index::SymbolKind::InstanceMethod;
1978 HI.NamespaceScope = "";
1979 HI.LocalScope = "Foo::";
1980 HI.Type = "int ()";
1981 HI.Definition = "int x()";
1982 HI.ReturnType = "int";
1983 HI.Parameters = std::vector<HoverInfo::Param>{};
1984 }},
1985 {
1986 R"cpp(// Static method call
1987 struct Foo { static int x(); };
1988 int main() {
1989 Foo::^[[x]]();
1990 }
1991 )cpp",
1992 [](HoverInfo &HI) {
1993 HI.Name = "x";
1994 HI.Kind = index::SymbolKind::StaticMethod;
1995 HI.NamespaceScope = "";
1996 HI.LocalScope = "Foo::";
1997 HI.Type = "int ()";
1998 HI.Definition = "static int x()";
1999 HI.ReturnType = "int";
2000 HI.Parameters = std::vector<HoverInfo::Param>{};
2001 }},
2002 {
2003 R"cpp(// Typedef
2004 typedef int Foo;
2005 int main() {
2006 ^[[Foo]] bar;
2007 }
2008 )cpp",
2009 [](HoverInfo &HI) {
2010 HI.Name = "Foo";
2011 HI.Kind = index::SymbolKind::TypeAlias;
2012 HI.NamespaceScope = "";
2013 HI.Definition = "typedef int Foo";
2014 HI.Type = "int";
2015 HI.Documentation = "Typedef";
2016 }},
2017 {
2018 R"cpp(// Typedef with embedded definition
2019 typedef struct Bar {} Foo;
2020 int main() {
2021 ^[[Foo]] bar;
2022 }
2023 )cpp",
2024 [](HoverInfo &HI) {
2025 HI.Name = "Foo";
2026 HI.Kind = index::SymbolKind::TypeAlias;
2027 HI.NamespaceScope = "";
2028 HI.Definition = "typedef struct Bar Foo";
2029 HI.Type = "struct Bar";
2030 HI.Documentation = "Typedef with embedded definition";
2031 }},
2032 {
2033 R"cpp(// Namespace
2034 namespace ns {
2035 struct Foo { static void bar(); };
2036 } // namespace ns
2037 int main() { ^[[ns]]::Foo::bar(); }
2038 )cpp",
2039 [](HoverInfo &HI) {
2040 HI.Name = "ns";
2041 HI.Kind = index::SymbolKind::Namespace;
2042 HI.NamespaceScope = "";
2043 HI.Definition = "namespace ns {}";
2044 }},
2045 {
2046 R"cpp(// Anonymous namespace
2047 namespace ns {
2048 namespace {
2049 int foo;
2050 } // anonymous namespace
2051 } // namespace ns
2052 int main() { ns::[[f^oo]]++; }
2053 )cpp",
2054 [](HoverInfo &HI) {
2055 HI.Name = "foo";
2056 HI.Kind = index::SymbolKind::Variable;
2057 HI.NamespaceScope = "ns::";
2058 HI.Type = "int";
2059 HI.Definition = "int foo";
2060 }},
2061 {
2062 R"cpp(// Function definition via using declaration
2063 namespace ns {
2064 void foo();
2065 }
2066 int main() {
2067 using ns::foo;
2068 ^[[foo]]();
2069 }
2070 )cpp",
2071 [](HoverInfo &HI) {
2072 HI.Name = "foo";
2073 HI.Kind = index::SymbolKind::Function;
2074 HI.NamespaceScope = "ns::";
2075 HI.Type = "void ()";
2076 HI.Definition = "void foo()";
2077 HI.Documentation = "";
2078 HI.ReturnType = "void";
2079 HI.Parameters = std::vector<HoverInfo::Param>{};
2080 }},
2081 {
2082 R"cpp( // using declaration and two possible function declarations
2083 namespace ns { void foo(int); void foo(char); }
2084 using ns::foo;
2085 template <typename T> void bar() { [[f^oo]](T{}); }
2086 )cpp",
2087 [](HoverInfo &HI) {
2088 HI.Name = "foo";
2089 HI.Kind = index::SymbolKind::Using;
2090 HI.NamespaceScope = "";
2091 HI.Definition = "using ns::foo";
2092 }},
2093 {
2094 R"cpp(// Macro
2095 #define MACRO 0
2096 int main() { return ^[[MACRO]]; }
2097 )cpp",
2098 [](HoverInfo &HI) {
2099 HI.Name = "MACRO";
2100 HI.Value = "0";
2101 HI.Type = "int";
2102 HI.Kind = index::SymbolKind::Macro;
2103 HI.Definition = "#define MACRO 0\n\n"
2104 "// Expands to\n"
2105 "0";
2106 }},
2107 {
2108 R"cpp(// Macro
2109 #define MACRO 0
2110 #define MACRO2 ^[[MACRO]]
2111 )cpp",
2112 [](HoverInfo &HI) {
2113 HI.Name = "MACRO";
2114 HI.Kind = index::SymbolKind::Macro;
2115 HI.Definition = "#define MACRO 0";
2116 // NOTE MACRO doesn't have expansion since it technically isn't
2117 // expanded here
2118 }},
2119 {
2120 R"cpp(// Macro
2121 #define MACRO {\
2122 return 0;\
2123 }
2124 int main() ^[[MACRO]]
2125 )cpp",
2126 [](HoverInfo &HI) {
2127 HI.Name = "MACRO";
2128 HI.Kind = index::SymbolKind::Macro;
2129 HI.Definition =
2130 R"cpp(#define MACRO \
2131 { \
2132 return 0; \
2133 }
2134
2135// Expands to
2136{
2137 return 0;
2138})cpp";
2139 }},
2140 {
2141 R"cpp(// Forward class declaration
2142 class Foo;
2143 class Foo {};
2144 [[F^oo]]* foo();
2145 )cpp",
2146 [](HoverInfo &HI) {
2147 HI.Name = "Foo";
2148 HI.Kind = index::SymbolKind::Class;
2149 HI.NamespaceScope = "";
2150 HI.Definition = "class Foo {}";
2151 HI.Documentation = "Forward class declaration";
2152 }},
2153 {
2154 R"cpp(// Function declaration
2155 void foo();
2156 void g() { [[f^oo]](); }
2157 void foo() {}
2158 )cpp",
2159 [](HoverInfo &HI) {
2160 HI.Name = "foo";
2161 HI.Kind = index::SymbolKind::Function;
2162 HI.NamespaceScope = "";
2163 HI.Type = "void ()";
2164 HI.Definition = "void foo()";
2165 HI.Documentation = "Function declaration";
2166 HI.ReturnType = "void";
2167 HI.Parameters = std::vector<HoverInfo::Param>{};
2168 }},
2169 {
2170 R"cpp(// Enum declaration
2171 enum Hello {
2172 ONE, TWO, THREE,
2173 };
2174 void foo() {
2175 [[Hel^lo]] hello = ONE;
2176 }
2177 )cpp",
2178 [](HoverInfo &HI) {
2179 HI.Name = "Hello";
2180 HI.Kind = index::SymbolKind::Enum;
2181 HI.NamespaceScope = "";
2182 HI.Definition = "enum Hello {}";
2183 HI.Documentation = "Enum declaration";
2184 }},
2185 {
2186 R"cpp(// Enumerator
2187 enum Hello {
2188 ONE, TWO, THREE,
2189 };
2190 void foo() {
2191 Hello hello = [[O^NE]];
2192 }
2193 )cpp",
2194 [](HoverInfo &HI) {
2195 HI.Name = "ONE";
2196 HI.Kind = index::SymbolKind::EnumConstant;
2197 HI.NamespaceScope = "";
2198 HI.LocalScope = "Hello::";
2199 HI.Type = "enum Hello";
2200 HI.Definition = "ONE";
2201 HI.Value = "0";
2202 }},
2203 {
2204 R"cpp(// C++20's using enum
2205 enum class Hello {
2206 ONE, TWO, THREE,
2207 };
2208 void foo() {
2209 using enum Hello;
2210 Hello hello = [[O^NE]];
2211 }
2212 )cpp",
2213 [](HoverInfo &HI) {
2214 HI.Name = "ONE";
2215 HI.Kind = index::SymbolKind::EnumConstant;
2216 HI.NamespaceScope = "";
2217 HI.LocalScope = "Hello::";
2218 HI.Type = "enum Hello";
2219 HI.Definition = "ONE";
2220 HI.Value = "0";
2221 }},
2222 {
2223 R"cpp(// Enumerator in anonymous enum
2224 enum {
2225 ONE, TWO, THREE,
2226 };
2227 void foo() {
2228 int hello = [[O^NE]];
2229 }
2230 )cpp",
2231 [](HoverInfo &HI) {
2232 HI.Name = "ONE";
2233 HI.Kind = index::SymbolKind::EnumConstant;
2234 HI.NamespaceScope = "";
2235 // FIXME: This should be `(anon enum)::`
2236 HI.LocalScope = "";
2237 HI.Type = "enum (unnamed)";
2238 HI.Definition = "ONE";
2239 HI.Value = "0";
2240 }},
2241 {
2242 R"cpp(// Global variable
2243 static int hey = 10;
2244 void foo() {
2245 [[he^y]]++;
2246 }
2247 )cpp",
2248 [](HoverInfo &HI) {
2249 HI.Name = "hey";
2250 HI.Kind = index::SymbolKind::Variable;
2251 HI.NamespaceScope = "";
2252 HI.Type = "int";
2253 HI.Definition = "static int hey = 10";
2254 HI.Documentation = "Global variable";
2255 // FIXME: Value shouldn't be set in this case
2256 HI.Value = "10 (0xa)";
2257 }},
2258 {
2259 R"cpp(// Global variable in namespace
2260 namespace ns1 {
2261 static long long hey = -36637162602497;
2262 }
2263 void foo() {
2264 ns1::[[he^y]]++;
2265 }
2266 )cpp",
2267 [](HoverInfo &HI) {
2268 HI.Name = "hey";
2269 HI.Kind = index::SymbolKind::Variable;
2270 HI.NamespaceScope = "ns1::";
2271 HI.Type = "long long";
2272 HI.Definition = "static long long hey = -36637162602497";
2273 HI.Value = "-36637162602497 (0xffffdeadbeefffff)"; // needs 64 bits
2274 }},
2275 {
2276 R"cpp(// Field in anonymous struct
2277 static struct {
2278 int hello;
2279 } s;
2280 void foo() {
2281 s.[[he^llo]]++;
2282 }
2283 )cpp",
2284 [](HoverInfo &HI) {
2285 HI.Name = "hello";
2286 HI.Kind = index::SymbolKind::Field;
2287 HI.NamespaceScope = "";
2288 HI.LocalScope = "(anonymous struct)::";
2289 HI.Type = "int";
2290 HI.Definition = "int hello";
2291 }},
2292 {
2293 R"cpp(// Templated function
2294 template <typename T>
2295 T foo() {
2296 return 17;
2297 }
2298 void g() { auto x = [[f^oo]]<int>(); }
2299 )cpp",
2300 [](HoverInfo &HI) {
2301 HI.Name = "foo";
2302 HI.Kind = index::SymbolKind::Function;
2303 HI.NamespaceScope = "";
2304 HI.Type = "int ()";
2305 HI.Definition = "template <> int foo<int>()";
2306 HI.Documentation = "Templated function";
2307 HI.ReturnType = "int";
2308 HI.Parameters = std::vector<HoverInfo::Param>{};
2309 // FIXME: We should populate template parameters with arguments in
2310 // case of instantiations.
2311 }},
2312 {
2313 R"cpp(// Anonymous union
2314 struct outer {
2315 union {
2316 int abc, def;
2317 } v;
2318 };
2319 void g() { struct outer o; o.v.[[d^ef]]++; }
2320 )cpp",
2321 [](HoverInfo &HI) {
2322 HI.Name = "def";
2323 HI.Kind = index::SymbolKind::Field;
2324 HI.NamespaceScope = "";
2325 HI.LocalScope = "outer::(anonymous union)::";
2326 HI.Type = "int";
2327 HI.Definition = "int def";
2328 }},
2329 {
2330 R"cpp(// documentation from index
2331 int nextSymbolIsAForwardDeclFromIndexWithNoLocalDocs;
2332 void indexSymbol();
2333 void g() { [[ind^exSymbol]](); }
2334 )cpp",
2335 [](HoverInfo &HI) {
2336 HI.Name = "indexSymbol";
2337 HI.Kind = index::SymbolKind::Function;
2338 HI.NamespaceScope = "";
2339 HI.Type = "void ()";
2340 HI.Definition = "void indexSymbol()";
2341 HI.ReturnType = "void";
2342 HI.Parameters = std::vector<HoverInfo::Param>{};
2343 HI.Documentation = "comment from index";
2344 }},
2345 {
2346 R"cpp(// Simple initialization with auto
2347 void foo() {
2348 ^[[auto]] i = 1;
2349 }
2350 )cpp",
2351 [](HoverInfo &HI) {
2352 HI.Name = "auto";
2353 HI.Kind = index::SymbolKind::TypeAlias;
2354 HI.Definition = "int";
2355 }},
2356 {
2357 R"cpp(// Simple initialization with const auto
2358 void foo() {
2359 const ^[[auto]] i = 1;
2360 }
2361 )cpp",
2362 [](HoverInfo &HI) {
2363 HI.Name = "auto";
2364 HI.Kind = index::SymbolKind::TypeAlias;
2365 HI.Definition = "int";
2366 }},
2367 {
2368 R"cpp(// Simple initialization with const auto&
2369 void foo() {
2370 const ^[[auto]]& i = 1;
2371 }
2372 )cpp",
2373 [](HoverInfo &HI) {
2374 HI.Name = "auto";
2375 HI.Kind = index::SymbolKind::TypeAlias;
2376 HI.Definition = "int";
2377 }},
2378 {
2379 R"cpp(// Simple initialization with auto&
2380 void foo() {
2381 int x;
2382 ^[[auto]]& i = x;
2383 }
2384 )cpp",
2385 [](HoverInfo &HI) {
2386 HI.Name = "auto";
2387 HI.Kind = index::SymbolKind::TypeAlias;
2388 HI.Definition = "int";
2389 }},
2390 {
2391 R"cpp(// Simple initialization with auto*
2392 void foo() {
2393 int a = 1;
2394 ^[[auto]]* i = &a;
2395 }
2396 )cpp",
2397 [](HoverInfo &HI) {
2398 HI.Name = "auto";
2399 HI.Kind = index::SymbolKind::TypeAlias;
2400 HI.Definition = "int";
2401 }},
2402 {
2403 R"cpp(// Simple initialization with auto from pointer
2404 void foo() {
2405 int a = 1;
2406 ^[[auto]] i = &a;
2407 }
2408 )cpp",
2409 [](HoverInfo &HI) {
2410 HI.Name = "auto";
2411 HI.Kind = index::SymbolKind::TypeAlias;
2412 HI.Definition = "int *";
2413 }},
2414 {
2415 R"cpp(// Auto with initializer list.
2416 namespace std
2417 {
2418 template<class _E>
2419 class initializer_list { const _E *a, *b; };
2420 }
2421 void foo() {
2422 ^[[auto]] i = {1,2};
2423 }
2424 )cpp",
2425 [](HoverInfo &HI) {
2426 HI.Name = "auto";
2427 HI.Kind = index::SymbolKind::TypeAlias;
2428 HI.Definition = "std::initializer_list<int>";
2429 }},
2430 {
2431 R"cpp(// User defined conversion to auto
2432 struct Bar {
2433 operator ^[[auto]]() const { return 10; }
2434 };
2435 )cpp",
2436 [](HoverInfo &HI) {
2437 HI.Name = "auto";
2438 HI.Kind = index::SymbolKind::TypeAlias;
2439 HI.Definition = "int";
2440 }},
2441 {
2442 R"cpp(// Simple initialization with decltype(auto)
2443 void foo() {
2444 ^[[decltype]](auto) i = 1;
2445 }
2446 )cpp",
2447 [](HoverInfo &HI) {
2448 HI.Name = "decltype";
2449 HI.Kind = index::SymbolKind::TypeAlias;
2450 HI.Definition = "int";
2451 }},
2452 {
2453 R"cpp(// Simple initialization with const decltype(auto)
2454 void foo() {
2455 const int j = 0;
2456 ^[[decltype]](auto) i = j;
2457 }
2458 )cpp",
2459 [](HoverInfo &HI) {
2460 HI.Name = "decltype";
2461 HI.Kind = index::SymbolKind::TypeAlias;
2462 HI.Definition = "const int";
2463 }},
2464 {
2465 R"cpp(// Simple initialization with const& decltype(auto)
2466 void foo() {
2467 int k = 0;
2468 const int& j = k;
2469 ^[[decltype]](auto) i = j;
2470 }
2471 )cpp",
2472 [](HoverInfo &HI) {
2473 HI.Name = "decltype";
2474 HI.Kind = index::SymbolKind::TypeAlias;
2475 HI.Definition = "const int &";
2476 }},
2477 {
2478 R"cpp(// Simple initialization with & decltype(auto)
2479 void foo() {
2480 int k = 0;
2481 int& j = k;
2482 ^[[decltype]](auto) i = j;
2483 }
2484 )cpp",
2485 [](HoverInfo &HI) {
2486 HI.Name = "decltype";
2487 HI.Kind = index::SymbolKind::TypeAlias;
2488 HI.Definition = "int &";
2489 }},
2490 {
2491 R"cpp(// simple trailing return type
2492 ^[[auto]] main() -> int {
2493 return 0;
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(// auto function return with trailing type
2503 struct Bar {};
2504 ^[[auto]] test() -> decltype(Bar()) {
2505 return Bar();
2506 }
2507 )cpp",
2508 [](HoverInfo &HI) {
2509 HI.Name = "auto";
2510 HI.Kind = index::SymbolKind::TypeAlias;
2511 HI.Definition = "Bar";
2512 HI.Documentation = "auto function return with trailing type";
2513 }},
2514 {
2515 R"cpp(// trailing return type
2516 struct Bar {};
2517 auto test() -> ^[[decltype]](Bar()) {
2518 return Bar();
2519 }
2520 )cpp",
2521 [](HoverInfo &HI) {
2522 HI.Name = "decltype";
2523 HI.Kind = index::SymbolKind::TypeAlias;
2524 HI.Definition = "Bar";
2525 HI.Documentation = "trailing return type";
2526 }},
2527 {
2528 R"cpp(// auto in function return
2529 struct Bar {};
2530 ^[[auto]] test() {
2531 return Bar();
2532 }
2533 )cpp",
2534 [](HoverInfo &HI) {
2535 HI.Name = "auto";
2536 HI.Kind = index::SymbolKind::TypeAlias;
2537 HI.Definition = "Bar";
2538 HI.Documentation = "auto in function return";
2539 }},
2540 {
2541 R"cpp(// auto& in function return
2542 struct Bar {};
2543 ^[[auto]]& test() {
2544 static Bar x;
2545 return x;
2546 }
2547 )cpp",
2548 [](HoverInfo &HI) {
2549 HI.Name = "auto";
2550 HI.Kind = index::SymbolKind::TypeAlias;
2551 HI.Definition = "Bar";
2552 HI.Documentation = "auto& in function return";
2553 }},
2554 {
2555 R"cpp(// auto* in function return
2556 struct Bar {};
2557 ^[[auto]]* test() {
2558 Bar* bar;
2559 return bar;
2560 }
2561 )cpp",
2562 [](HoverInfo &HI) {
2563 HI.Name = "auto";
2564 HI.Kind = index::SymbolKind::TypeAlias;
2565 HI.Definition = "Bar";
2566 HI.Documentation = "auto* in function return";
2567 }},
2568 {
2569 R"cpp(// const auto& in function return
2570 struct Bar {};
2571 const ^[[auto]]& test() {
2572 static Bar x;
2573 return x;
2574 }
2575 )cpp",
2576 [](HoverInfo &HI) {
2577 HI.Name = "auto";
2578 HI.Kind = index::SymbolKind::TypeAlias;
2579 HI.Definition = "Bar";
2580 HI.Documentation = "const auto& in function return";
2581 }},
2582 {
2583 R"cpp(// decltype(auto) in function return
2584 struct Bar {};
2585 ^[[decltype]](auto) test() {
2586 return Bar();
2587 }
2588 )cpp",
2589 [](HoverInfo &HI) {
2590 HI.Name = "decltype";
2591 HI.Kind = index::SymbolKind::TypeAlias;
2592 HI.Definition = "Bar";
2593 HI.Documentation = "decltype(auto) in function return";
2594 }},
2595 {
2596 R"cpp(// decltype(auto) reference in function return
2597 ^[[decltype]](auto) test() {
2598 static int a;
2599 return (a);
2600 }
2601 )cpp",
2602 [](HoverInfo &HI) {
2603 HI.Name = "decltype";
2604 HI.Kind = index::SymbolKind::TypeAlias;
2605 HI.Definition = "int &";
2606 }},
2607 {
2608 R"cpp(// decltype lvalue reference
2609 void foo() {
2610 int I = 0;
2611 ^[[decltype]](I) J = I;
2612 }
2613 )cpp",
2614 [](HoverInfo &HI) {
2615 HI.Name = "decltype";
2616 HI.Kind = index::SymbolKind::TypeAlias;
2617 HI.Definition = "int";
2618 }},
2619 {
2620 R"cpp(// decltype lvalue reference
2621 void foo() {
2622 int I= 0;
2623 int &K = I;
2624 ^[[decltype]](K) J = I;
2625 }
2626 )cpp",
2627 [](HoverInfo &HI) {
2628 HI.Name = "decltype";
2629 HI.Kind = index::SymbolKind::TypeAlias;
2630 HI.Definition = "int &";
2631 }},
2632 {
2633 R"cpp(// decltype lvalue reference parenthesis
2634 void foo() {
2635 int I = 0;
2636 ^[[decltype]]((I)) J = I;
2637 }
2638 )cpp",
2639 [](HoverInfo &HI) {
2640 HI.Name = "decltype";
2641 HI.Kind = index::SymbolKind::TypeAlias;
2642 HI.Definition = "int &";
2643 }},
2644 {
2645 R"cpp(// decltype rvalue reference
2646 void foo() {
2647 int I = 0;
2648 ^[[decltype]](static_cast<int&&>(I)) J = static_cast<int&&>(I);
2649 }
2650 )cpp",
2651 [](HoverInfo &HI) {
2652 HI.Name = "decltype";
2653 HI.Kind = index::SymbolKind::TypeAlias;
2654 HI.Definition = "int &&";
2655 }},
2656 {
2657 R"cpp(// decltype rvalue reference function call
2658 int && bar();
2659 void foo() {
2660 int I = 0;
2661 ^[[decltype]](bar()) J = bar();
2662 }
2663 )cpp",
2664 [](HoverInfo &HI) {
2665 HI.Name = "decltype";
2666 HI.Kind = index::SymbolKind::TypeAlias;
2667 HI.Definition = "int &&";
2668 }},
2669 {
2670 R"cpp(// decltype of function with trailing return type.
2671 struct Bar {};
2672 auto test() -> decltype(Bar()) {
2673 return Bar();
2674 }
2675 void foo() {
2676 ^[[decltype]](test()) i = test();
2677 }
2678 )cpp",
2679 [](HoverInfo &HI) {
2680 HI.Name = "decltype";
2681 HI.Kind = index::SymbolKind::TypeAlias;
2682 HI.Definition = "Bar";
2683 HI.Documentation =
2684 "decltype of function with trailing return type.";
2685 }},
2686 {
2687 R"cpp(// decltype of var with decltype.
2688 void foo() {
2689 int I = 0;
2690 decltype(I) J = I;
2691 ^[[decltype]](J) K = J;
2692 }
2693 )cpp",
2694 [](HoverInfo &HI) {
2695 HI.Name = "decltype";
2696 HI.Kind = index::SymbolKind::TypeAlias;
2697 HI.Definition = "int";
2698 }},
2699 {
2700 R"cpp(// decltype of dependent type
2701 template <typename T>
2702 struct X {
2703 using Y = ^[[decltype]](T::Z);
2704 };
2705 )cpp",
2706 [](HoverInfo &HI) {
2707 HI.Name = "decltype";
2708 HI.Kind = index::SymbolKind::TypeAlias;
2709 HI.Definition = "<dependent type>";
2710 }},
2711 {
2712 R"cpp(// More complicated structured types.
2713 int bar();
2714 ^[[auto]] (*foo)() = bar;
2715 )cpp",
2716 [](HoverInfo &HI) {
2717 HI.Name = "auto";
2718 HI.Kind = index::SymbolKind::TypeAlias;
2719 HI.Definition = "int";
2720 }},
2721 {
2722 R"cpp(// Should not crash when evaluating the initializer.
2723 struct Test {};
2724 void test() { Test && [[te^st]] = {}; }
2725 )cpp",
2726 [](HoverInfo &HI) {
2727 HI.Name = "test";
2728 HI.Kind = index::SymbolKind::Variable;
2729 HI.NamespaceScope = "";
2730 HI.LocalScope = "test::";
2731 HI.Type = "Test &&";
2732 HI.Definition = "Test &&test = {}";
2733 }},
2734 {
2735 R"cpp(// Shouldn't crash when evaluating the initializer.
2736 struct Bar {}; // error-ok
2737 struct Foo { void foo(Bar x = y); }
2738 void Foo::foo(Bar [[^x]]) {})cpp",
2739 [](HoverInfo &HI) {
2740 HI.Name = "x";
2741 HI.Kind = index::SymbolKind::Parameter;
2742 HI.NamespaceScope = "";
2743 HI.LocalScope = "Foo::foo::";
2744 HI.Type = "Bar";
2745 HI.Definition = "Bar x = <recovery - expr>()";
2746 }},
2747 {
2748 R"cpp(// auto on alias
2749 typedef int int_type;
2750 ^[[auto]] x = int_type();
2751 )cpp",
2752 [](HoverInfo &HI) {
2753 HI.Name = "auto";
2754 HI.Kind = index::SymbolKind::TypeAlias;
2755 HI.Definition = "int_type // aka: int";
2756 }},
2757 {
2758 R"cpp(// auto on alias
2759 struct cls {};
2760 typedef cls cls_type;
2761 ^[[auto]] y = cls_type();
2762 )cpp",
2763 [](HoverInfo &HI) {
2764 HI.Name = "auto";
2765 HI.Kind = index::SymbolKind::TypeAlias;
2766 HI.Definition = "cls_type // aka: cls";
2767 HI.Documentation = "auto on alias";
2768 }},
2769 {
2770 R"cpp(// auto on alias
2771 template <class>
2772 struct templ {};
2773 ^[[auto]] z = templ<int>();
2774 )cpp",
2775 [](HoverInfo &HI) {
2776 HI.Name = "auto";
2777 HI.Kind = index::SymbolKind::TypeAlias;
2778 HI.Definition = "templ<int>";
2779 HI.Documentation = "auto on alias";
2780 }},
2781 {
2782 R"cpp(// Undeduced auto declaration
2783 template<typename T>
2784 void foo() {
2785 ^[[auto]] x = T();
2786 }
2787 )cpp",
2788 [](HoverInfo &HI) {
2789 HI.Name = "auto";
2790 HI.Kind = index::SymbolKind::TypeAlias;
2791 HI.Definition = "T";
2792 }},
2793 {
2794 R"cpp(// Undeduced auto return type
2795 template<typename T>
2796 ^[[auto]] foo() {
2797 return T();
2798 }
2799 )cpp",
2800 [](HoverInfo &HI) {
2801 HI.Name = "auto";
2802 HI.Kind = index::SymbolKind::TypeAlias;
2803 HI.Definition = "/* not deduced */";
2804 }},
2805 {
2806 R"cpp(// Template auto parameter
2807 template<[[a^uto]] T>
2808 void func() {
2809 }
2810 )cpp",
2811 [](HoverInfo &HI) {
2812 // FIXME: not sure this is what we want, but this
2813 // is what we currently get with getDeducedType
2814 HI.Name = "auto";
2815 HI.Kind = index::SymbolKind::TypeAlias;
2816 HI.Definition = "/* not deduced */";
2817 }},
2818 {
2819 R"cpp(// Undeduced decltype(auto) return type
2820 template<typename T>
2821 ^[[decltype]](auto) foo() {
2822 return T();
2823 }
2824 )cpp",
2825 [](HoverInfo &HI) {
2826 HI.Name = "decltype";
2827 HI.Kind = index::SymbolKind::TypeAlias;
2828 HI.Definition = "/* not deduced */";
2829 }},
2830 {
2831 R"cpp(// should not crash.
2832 template <class T> struct cls {
2833 int method();
2834 };
2835
2836 auto test = cls<int>().[[m^ethod]]();
2837 )cpp",
2838 [](HoverInfo &HI) {
2839 HI.Definition = "int method()";
2840 HI.Kind = index::SymbolKind::InstanceMethod;
2841 HI.NamespaceScope = "";
2842 HI.LocalScope = "cls<int>::";
2843 HI.Name = "method";
2844 HI.Parameters.emplace();
2845 HI.ReturnType = "int";
2846 HI.Type = "int ()";
2847 }},
2848 {
2849 R"cpp(// type of nested templates.
2850 template <class T> struct cls {};
2851 cls<cls<cls<int>>> [[fo^o]];
2852 )cpp",
2853 [](HoverInfo &HI) {
2854 HI.Definition = "cls<cls<cls<int>>> foo";
2855 HI.Kind = index::SymbolKind::Variable;
2856 HI.NamespaceScope = "";
2857 HI.Name = "foo";
2858 HI.Type = "cls<cls<cls<int>>>";
2859 }},
2860 {
2861 R"cpp(// type of nested templates.
2862 template <class T> struct cls {};
2863 [[cl^s]]<cls<cls<int>>> foo;
2864 )cpp",
2865 [](HoverInfo &HI) {
2866 HI.Definition = "template <> struct cls<cls<cls<int>>> {}";
2867 HI.Kind = index::SymbolKind::Struct;
2868 HI.NamespaceScope = "";
2869 HI.Name = "cls<cls<cls<int>>>";
2870 HI.Documentation = "type of nested templates.";
2871 }},
2872 {
2873 R"cpp(// type with decltype
2874 int a;
2875 decltype(a) [[b^]] = a;)cpp",
2876 [](HoverInfo &HI) {
2877 HI.Definition = "decltype(a) b = a";
2878 HI.Kind = index::SymbolKind::Variable;
2879 HI.NamespaceScope = "";
2880 HI.Name = "b";
2881 HI.Type = "int";
2882 }},
2883 {
2884 R"cpp(// type with decltype
2885 int a;
2886 decltype(a) c;
2887 decltype(c) [[b^]] = a;)cpp",
2888 [](HoverInfo &HI) {
2889 HI.Definition = "decltype(c) b = a";
2890 HI.Kind = index::SymbolKind::Variable;
2891 HI.NamespaceScope = "";
2892 HI.Name = "b";
2893 HI.Type = "int";
2894 }},
2895 {
2896 R"cpp(// type with decltype
2897 int a;
2898 const decltype(a) [[b^]] = a;)cpp",
2899 [](HoverInfo &HI) {
2900 HI.Definition = "const decltype(a) b = a";
2901 HI.Kind = index::SymbolKind::Variable;
2902 HI.NamespaceScope = "";
2903 HI.Name = "b";
2904 HI.Type = "int";
2905 }},
2906 {
2907 R"cpp(// type with decltype
2908 int a;
2909 auto [[f^oo]](decltype(a) x) -> decltype(a) { return 0; })cpp",
2910 [](HoverInfo &HI) {
2911 HI.Definition = "auto foo(decltype(a) x) -> decltype(a)";
2912 HI.Kind = index::SymbolKind::Function;
2913 HI.NamespaceScope = "";
2914 HI.Name = "foo";
2915 // FIXME: Handle composite types with decltype with a printing
2916 // policy.
2917 HI.Type = {"auto (decltype(a)) -> decltype(a)",
2918 "auto (int) -> int"};
2919 HI.ReturnType = "int";
2920 HI.Parameters = {{{"int"}, std::string("x"), std::nullopt}};
2921 }},
2922 {
2923 R"cpp(// sizeof expr
2924 void foo() {
2925 (void)[[size^of]](char);
2926 })cpp",
2927 [](HoverInfo &HI) {
2928 HI.Name = "expression";
2929 HI.Type = {"__size_t", "unsigned long"};
2930 HI.Value = "1";
2931 }},
2932 {
2933 R"cpp(// alignof expr
2934 void foo() {
2935 (void)[[align^of]](char);
2936 })cpp",
2937 [](HoverInfo &HI) {
2938 HI.Name = "expression";
2939 HI.Type = {"__size_t", "unsigned long"};
2940 HI.Value = "1";
2941 }},
2942 {
2943 R"cpp(
2944 template <typename T = int>
2945 void foo(const T& = T()) {
2946 [[f^oo]]<>(3);
2947 })cpp",
2948 [](HoverInfo &HI) {
2949 HI.Name = "foo";
2950 HI.Kind = index::SymbolKind::Function;
2951 HI.Type = "void (const int &)";
2952 HI.ReturnType = "void";
2953 HI.Parameters = {
2954 {{"const int &"}, std::nullopt, std::string("T()")}};
2955 HI.Definition = "template <> void foo<int>(const int &)";
2956 HI.NamespaceScope = "";
2957 }},
2958 {
2959 R"cpp(// should not crash
2960 @interface ObjC {
2961 char [[da^ta]];
2962 }@end
2963 )cpp",
2964 [](HoverInfo &HI) {
2965 HI.Name = "data";
2966 HI.Type = "char";
2967 HI.Kind = index::SymbolKind::Field;
2968 HI.LocalScope = "ObjC::";
2969 HI.NamespaceScope = "";
2970 HI.Definition = "char data";
2971 }},
2972 {
2973 R"cpp(
2974 @interface MYObject
2975 @end
2976 @interface Interface
2977 @property(retain) [[MYOb^ject]] *x;
2978 @end
2979 )cpp",
2980 [](HoverInfo &HI) {
2981 HI.Name = "MYObject";
2982 HI.Kind = index::SymbolKind::Class;
2983 HI.NamespaceScope = "";
2984 HI.Definition = "@interface MYObject\n@end";
2985 }},
2986 {
2987 R"cpp(
2988 @interface MYObject
2989 @end
2990 @interface Interface
2991 - (void)doWith:([[MYOb^ject]] *)object;
2992 @end
2993 )cpp",
2994 [](HoverInfo &HI) {
2995 HI.Name = "MYObject";
2996 HI.Kind = index::SymbolKind::Class;
2997 HI.NamespaceScope = "";
2998 HI.Definition = "@interface MYObject\n@end";
2999 }},
3000 {
3001 R"cpp(// this expr
3002 // comment
3003 namespace ns {
3004 class Foo {
3005 Foo* bar() {
3006 return [[t^his]];
3007 }
3008 };
3009 }
3010 )cpp",
3011 [](HoverInfo &HI) {
3012 HI.Name = "this";
3013 HI.Definition = "ns::Foo *";
3014 }},
3016 R"cpp(// this expr for template class
3017 namespace ns {
3018 template <typename T>
3019 class Foo {
3020 Foo* bar() const {
3021 return [[t^his]];
3022 }
3023 };
3024 }
3025 )cpp",
3026 [](HoverInfo &HI) {
3027 HI.Name = "this";
3028 HI.Definition = "const ns::Foo<T> *";
3029 }},
3030 {
3031 R"cpp(// this expr for specialization class
3032 namespace ns {
3033 template <typename T> class Foo {};
3034 template <>
3035 struct Foo<int> {
3036 Foo* bar() {
3037 return [[thi^s]];
3038 }
3039 };
3040 }
3041 )cpp",
3042 [](HoverInfo &HI) {
3043 HI.Name = "this";
3044 HI.Definition = "ns::Foo<int> *";
3045 }},
3046 {
3047 R"cpp(// this expr for partial specialization struct
3048 namespace ns {
3049 template <typename T, typename F> struct Foo {};
3050 template <typename F>
3051 struct Foo<int, F> {
3052 Foo* bar() const {
3053 return [[thi^s]];
3054 }
3055 };
3056 }
3057 )cpp",
3058 [](HoverInfo &HI) {
3059 HI.Name = "this";
3060 HI.Definition = "const ns::Foo<int, F> *";
3061 }},
3062 {
3063 R"cpp(
3064 @interface MYObject
3065 @end
3066 @interface MYObject (Private)
3067 @property(nonatomic, assign) int privateField;
3068 @end
3069
3070 int someFunction() {
3071 MYObject *obj = [MYObject sharedInstance];
3072 return obj.[[private^Field]];
3073 }
3074 )cpp",
3075 [](HoverInfo &HI) {
3076 HI.Name = "privateField";
3077 HI.Kind = index::SymbolKind::InstanceProperty;
3078 HI.LocalScope = "MYObject(Private)::";
3079 HI.NamespaceScope = "";
3080 HI.Definition = "@property(nonatomic, assign, unsafe_unretained, "
3081 "readwrite) int privateField;";
3082 }},
3083 {
3084 R"cpp(
3085 @protocol MYProtocol
3086 @property(nonatomic, assign) int prop1;
3087 @end
3088
3089 int someFunction() {
3090 id<MYProtocol> obj = 0;
3091 return obj.[[pro^p1]];
3092 }
3093 )cpp",
3094 [](HoverInfo &HI) {
3095 HI.Name = "prop1";
3096 HI.Kind = index::SymbolKind::InstanceProperty;
3097 HI.LocalScope = "MYProtocol::";
3098 HI.NamespaceScope = "";
3099 HI.Definition = "@property(nonatomic, assign, unsafe_unretained, "
3100 "readwrite) int prop1;";
3101 }},
3102 {
3103 R"cpp(
3104 @protocol MYProtocol
3105 @end
3106 @interface MYObject
3107 @end
3108
3109 @interface MYObject (Ext) <[[MYProt^ocol]]>
3110 @end
3111 )cpp",
3112 [](HoverInfo &HI) {
3113 HI.Name = "MYProtocol";
3114 HI.Kind = index::SymbolKind::Protocol;
3115 HI.NamespaceScope = "";
3116 HI.Definition = "@protocol MYProtocol\n@end";
3117 }},
3118 {R"objc(
3119 @interface Foo
3120 @end
3121
3122 @implementation Foo(Private)
3123 + (int)somePrivateMethod {
3124 int [[res^ult]] = 2;
3125 return result;
3126 }
3127 @end
3128 )objc",
3129 [](HoverInfo &HI) {
3130 HI.Name = "result";
3131 HI.Definition = "int result = 2";
3132 HI.Kind = index::SymbolKind::Variable;
3133 HI.Type = "int";
3134 HI.LocalScope = "+[Foo(Private) somePrivateMethod]::";
3135 HI.NamespaceScope = "";
3136 HI.Value = "2";
3137 }},
3138 {R"objc(
3139 @interface Foo
3140 @end
3141
3142 @implementation Foo
3143 - (int)variadicArgMethod:(id)first, ... {
3144 int [[res^ult]] = 0;
3145 return result;
3146 }
3147 @end
3148 )objc",
3149 [](HoverInfo &HI) {
3150 HI.Name = "result";
3151 HI.Definition = "int result = 0";
3152 HI.Kind = index::SymbolKind::Variable;
3153 HI.Type = "int";
3154 HI.LocalScope = "-[Foo variadicArgMethod:, ...]::";
3155 HI.NamespaceScope = "";
3156 HI.Value = "0";
3157 }},
3158 // Should not crash.
3159 {R"objc(
3160 typedef struct MyRect {} MyRect;
3161
3162 @interface IFace
3163 @property(nonatomic) MyRect frame;
3164 @end
3165
3166 MyRect foobar() {
3167 MyRect mr;
3168 return mr;
3169 }
3170 void test() {
3171 IFace *v;
3172 v.frame = [[foo^bar]]();
3173 }
3174 )objc",
3175 [](HoverInfo &HI) {
3176 HI.Name = "foobar";
3177 HI.Kind = index::SymbolKind::Function;
3178 HI.NamespaceScope = "";
3179 HI.Definition = "MyRect foobar()";
3180 HI.Type = {"MyRect ()", "struct MyRect ()"};
3181 HI.ReturnType = {"MyRect", "struct MyRect"};
3182 HI.Parameters.emplace();
3183 }},
3184 {R"cpp(
3185 void foo(int * __attribute__(([[non^null]], noescape)) );
3186 )cpp",
3187 [](HoverInfo &HI) {
3188 HI.Name = "nonnull";
3189 HI.Kind = index::SymbolKind::Unknown; // FIXME: no suitable value
3190 HI.Definition = "__attribute__((nonnull))";
3191 HI.Documentation = Attr::getDocumentation(attr::NonNull).str();
3192 }},
3193 {
3194 R"cpp(
3195 namespace std {
3196 struct strong_ordering {
3197 int n;
3198 constexpr operator int() const { return n; }
3199 static const strong_ordering equal, greater, less;
3200 };
3201 constexpr strong_ordering strong_ordering::equal = {0};
3202 constexpr strong_ordering strong_ordering::greater = {1};
3203 constexpr strong_ordering strong_ordering::less = {-1};
3204 }
3205
3206 struct Foo
3207 {
3208 int x;
3209 // Foo spaceship
3210 auto operator<=>(const Foo&) const = default;
3211 };
3212
3213 bool x = Foo(1) [[!^=]] Foo(2);
3214 )cpp",
3215 [](HoverInfo &HI) {
3216 HI.Type = "bool (const Foo &) const noexcept";
3217 HI.Value = "true";
3218 HI.Name = "operator==";
3219 HI.Parameters = {{{"const Foo &"}, std::nullopt, std::nullopt}};
3220 HI.ReturnType = "bool";
3221 HI.Kind = index::SymbolKind::InstanceMethod;
3222 HI.LocalScope = "Foo::";
3223 HI.NamespaceScope = "";
3224 HI.Definition =
3225 "bool operator==(const Foo &) const noexcept = default";
3226 HI.Documentation = "";
3227 }},
3228 };
3229
3230 // Create a tiny index, so tests above can verify documentation is fetched.
3231 Symbol IndexSym = func("indexSymbol");
3232 IndexSym.Documentation = "comment from index";
3234 Symbols.insert(IndexSym);
3235 auto Index =
3236 MemIndex::build(std::move(Symbols).build(), RefSlab(), RelationSlab());
3237
3238 for (const auto &Case : Cases) {
3239 SCOPED_TRACE(Case.Code);
3240
3241 Annotations T(Case.Code);
3242 TestTU TU = TestTU::withCode(T.code());
3243 TU.ExtraArgs.push_back("-std=c++20");
3244 TU.ExtraArgs.push_back("-xobjective-c++");
3245
3246 TU.ExtraArgs.push_back("-Wno-gnu-designator");
3247 // Types might be different depending on the target triplet, we chose a
3248 // fixed one to make sure tests passes on different platform.
3249 TU.ExtraArgs.push_back("--target=x86_64-pc-linux-gnu");
3250 auto AST = TU.build();
3251 Config Cfg;
3252 Cfg.Hover.ShowAKA = true;
3253 WithContextValue WithCfg(Config::Key, std::move(Cfg));
3254 auto H = getHover(AST, T.point(), format::getLLVMStyle(), Index.get());
3255 ASSERT_TRUE(H);
3256 HoverInfo Expected;
3257 Expected.SymRange = T.range();
3258 Case.ExpectedBuilder(Expected);
3259
3260 SCOPED_TRACE(H->present(MarkupKind::PlainText));
3261 EXPECT_EQ(H->NamespaceScope, Expected.NamespaceScope);
3262 EXPECT_EQ(H->LocalScope, Expected.LocalScope);
3263 EXPECT_EQ(H->Name, Expected.Name);
3264 EXPECT_EQ(H->Kind, Expected.Kind);
3265 EXPECT_EQ(H->Documentation, Expected.Documentation);
3266 EXPECT_EQ(H->Definition, Expected.Definition);
3267 EXPECT_EQ(H->Type, Expected.Type);
3268 EXPECT_EQ(H->ReturnType, Expected.ReturnType);
3269 EXPECT_EQ(H->Parameters, Expected.Parameters);
3270 EXPECT_EQ(H->TemplateParameters, Expected.TemplateParameters);
3271 EXPECT_EQ(H->SymRange, Expected.SymRange);
3272 EXPECT_EQ(H->Value, Expected.Value);
3273 }
3274}
3275
3276TEST(Hover, Providers) {
3277 struct {
3278 const char *Code;
3279 const std::function<void(HoverInfo &)> ExpectedBuilder;
3280 } Cases[] = {{R"cpp(
3281 struct Foo {};
3282 Foo F = Fo^o{};
3283 )cpp",
3284 [](HoverInfo &HI) { HI.Provider = ""; }},
3285 {R"cpp(
3286 #include "foo.h"
3287 Foo F = Fo^o{};
3288 )cpp",
3289 [](HoverInfo &HI) { HI.Provider = "\"foo.h\""; }},
3290 {R"cpp(
3291 #include "all.h"
3292 Foo F = Fo^o{};
3293 )cpp",
3294 [](HoverInfo &HI) { HI.Provider = "\"foo.h\""; }},
3295 {R"cpp(
3296 #define FOO 5
3297 int F = ^FOO;
3298 )cpp",
3299 [](HoverInfo &HI) { HI.Provider = ""; }},
3300 {R"cpp(
3301 #include "foo.h"
3302 int F = ^FOO;
3303 )cpp",
3304 [](HoverInfo &HI) { HI.Provider = "\"foo.h\""; }},
3305 {R"cpp(
3306 #include "all.h"
3307 int F = ^FOO;
3308 )cpp",
3309 [](HoverInfo &HI) { HI.Provider = "\"foo.h\""; }},
3310 {R"cpp(
3311 #include "foo.h"
3312 Foo A;
3313 Foo B;
3314 Foo C = A ^+ B;
3315 )cpp",
3316 [](HoverInfo &HI) { HI.Provider = "\"foo.h\""; }},
3317 // Hover selects the underlying decl of the using decl
3318 {R"cpp(
3319 #include "foo.h"
3320 namespace ns {
3321 using ::Foo;
3322 }
3323 ns::F^oo d;
3324 )cpp",
3325 [](HoverInfo &HI) { HI.Provider = "\"foo.h\""; }},
3326 {R"cpp(
3327 namespace foo {};
3328 using namespace fo^o;
3329 )cpp",
3330 [](HoverInfo &HI) { HI.Provider = ""; }},
3331 };
3332
3333 for (const auto &Case : Cases) {
3334 Annotations Code{Case.Code};
3335 SCOPED_TRACE(Code.code());
3336
3337 TestTU TU;
3338 TU.Filename = "foo.cpp";
3339 TU.Code = Code.code();
3340 TU.AdditionalFiles["foo.h"] = guard(R"cpp(
3341 #define FOO 1
3342 class Foo {};
3343 Foo& operator+(const Foo, const Foo);
3344 )cpp");
3345 TU.AdditionalFiles["all.h"] = guard("#include \"foo.h\"");
3346
3347 auto AST = TU.build();
3348 auto H = getHover(AST, Code.point(), format::getLLVMStyle(), nullptr);
3349 ASSERT_TRUE(H);
3350 HoverInfo Expected;
3351 Case.ExpectedBuilder(Expected);
3352 SCOPED_TRACE(H->present(MarkupKind::Markdown));
3353 EXPECT_EQ(H->Provider, Expected.Provider);
3354 }
3355}
3356
3357TEST(Hover, ParseProviderInfo) {
3358 HoverInfo HIFoo;
3359 HIFoo.Name = "foo";
3360 HIFoo.Provider = "\"foo.h\"";
3361
3362 HoverInfo HIFooBar;
3363 HIFooBar.Name = "foo";
3364 HIFooBar.Provider = "<bar.h>";
3365 struct Case {
3366 HoverInfo HI;
3367 llvm::StringRef ExpectedMarkdown;
3368 } Cases[] = {{HIFoo, "### `foo`\n\nprovided by `\"foo.h\"`"},
3369 {HIFooBar, "### `foo`\n\nprovided by `<bar.h>`"}};
3370
3371 for (const auto &Case : Cases)
3372 EXPECT_EQ(Case.HI.present(MarkupKind::Markdown), Case.ExpectedMarkdown);
3373}
3374
3375TEST(Hover, UsedSymbols) {
3376 struct {
3377 const char *Code;
3378 const std::function<void(HoverInfo &)> ExpectedBuilder;
3379 } Cases[] = {{R"cpp(
3380 #include ^"bar.h"
3381 int fstBar = bar1();
3382 int another= bar1(0);
3383 int sndBar = bar2();
3384 Bar bar;
3385 int macroBar = BAR;
3386 )cpp",
3387 [](HoverInfo &HI) {
3388 HI.UsedSymbolNames = {"BAR", "Bar", "bar1", "bar2"};
3389 }},
3390 {R"cpp(
3391 #in^clude <vector>
3392 std::vector<int> vec;
3393 )cpp",
3394 [](HoverInfo &HI) { HI.UsedSymbolNames = {"vector"}; }}};
3395 for (const auto &Case : Cases) {
3396 Annotations Code{Case.Code};
3397 SCOPED_TRACE(Code.code());
3398
3399 TestTU TU;
3400 TU.Filename = "foo.cpp";
3401 TU.Code = Code.code();
3402 TU.AdditionalFiles["bar.h"] = guard(R"cpp(
3403 #define BAR 5
3404 int bar1();
3405 int bar2();
3406 int bar1(double);
3407 class Bar {};
3408 )cpp");
3409 TU.AdditionalFiles["system/vector"] = guard(R"cpp(
3410 namespace std {
3411 template<typename>
3412 class vector{};
3413 }
3414 )cpp");
3415 TU.ExtraArgs.push_back("-isystem" + testPath("system"));
3416
3417 auto AST = TU.build();
3418 auto H = getHover(AST, Code.point(), format::getLLVMStyle(), nullptr);
3419 ASSERT_TRUE(H);
3420 HoverInfo Expected;
3421 Case.ExpectedBuilder(Expected);
3422 SCOPED_TRACE(H->present(MarkupKind::Markdown));
3423 EXPECT_EQ(H->UsedSymbolNames, Expected.UsedSymbolNames);
3424 }
3425}
3426
3427TEST(Hover, DocsFromIndex) {
3428 Annotations T(R"cpp(
3429 template <typename T> class X {};
3430 void foo() {
3431 auto t = X<int>();
3432 X^<int> w;
3433 (void)w;
3434 })cpp");
3435
3436 TestTU TU = TestTU::withCode(T.code());
3437 auto AST = TU.build();
3438 Symbol IndexSym;
3439 IndexSym.ID = getSymbolID(&findDecl(AST, "X"));
3440 IndexSym.Documentation = "comment from index";
3442 Symbols.insert(IndexSym);
3443 auto Index =
3444 MemIndex::build(std::move(Symbols).build(), RefSlab(), RelationSlab());
3445
3446 for (const auto &P : T.points()) {
3447 auto H = getHover(AST, P, format::getLLVMStyle(), Index.get());
3448 ASSERT_TRUE(H);
3449 EXPECT_EQ(H->Documentation, IndexSym.Documentation);
3450 }
3451}
3452
3453TEST(Hover, DocsFromAST) {
3454 Annotations T(R"cpp(
3455 // doc
3456 template <typename T> class X {};
3457 // doc
3458 template <typename T> void bar() {}
3459 // doc
3460 template <typename T> T baz;
3461 void foo() {
3462 au^to t = X<int>();
3463 X^<int>();
3464 b^ar<int>();
3465 au^to T = ba^z<X<int>>;
3466 ba^z<int> = 0;
3467 })cpp");
3468
3469 TestTU TU = TestTU::withCode(T.code());
3470 auto AST = TU.build();
3471 for (const auto &P : T.points()) {
3472 auto H = getHover(AST, P, format::getLLVMStyle(), nullptr);
3473 ASSERT_TRUE(H);
3474 EXPECT_EQ(H->Documentation, "doc");
3475 }
3476}
3477
3478TEST(Hover, NoCrash) {
3479 Annotations T(R"cpp(
3480 /* error-ok */
3481 template<typename T> T foo(T);
3482
3483 // Setter variable heuristic might fail if the callexpr is broken.
3484 struct X { int Y; void [[^setY]](float) { Y = foo(undefined); } };)cpp");
3485
3486 TestTU TU = TestTU::withCode(T.code());
3487 auto AST = TU.build();
3488 for (const auto &P : T.points())
3489 getHover(AST, P, format::getLLVMStyle(), nullptr);
3490}
3491
3492TEST(Hover, NoCrashAPInt64) {
3493 Annotations T(R"cpp(
3494 constexpr unsigned long value = -1; // wrap around
3495 void foo() { va^lue; }
3496 )cpp");
3497 auto AST = TestTU::withCode(T.code()).build();
3498 getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
3499}
3500
3501TEST(Hover, NoCrashInt128) {
3502 Annotations T(R"cpp(
3503 constexpr __int128_t value = -4;
3504 void foo() { va^lue; }
3505 )cpp");
3506 auto TU = TestTU::withCode(T.code());
3507 // Need a triple that support __int128_t.
3508 TU.ExtraArgs.push_back("--target=x86_64-pc-linux-gnu");
3509 auto AST = TU.build();
3510 auto H = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
3511 ASSERT_TRUE(H);
3512 EXPECT_EQ(H->Value, "-4 (0xfffffffc)");
3513}
3514
3515TEST(Hover, DocsFromMostSpecial) {
3516 Annotations T(R"cpp(
3517 // doc1
3518 template <typename T> class $doc1^X {};
3519 // doc2
3520 template <> class $doc2^X<int> {};
3521 // doc3
3522 template <typename T> class $doc3^X<T*> {};
3523 void foo() {
3524 X$doc1^<char>();
3525 X$doc2^<int>();
3526 X$doc3^<int*>();
3527 })cpp");
3528
3529 TestTU TU = TestTU::withCode(T.code());
3530 auto AST = TU.build();
3531 for (const auto *Comment : {"doc1", "doc2", "doc3"}) {
3532 for (const auto &P : T.points(Comment)) {
3533 auto H = getHover(AST, P, format::getLLVMStyle(), nullptr);
3534 ASSERT_TRUE(H);
3535 EXPECT_EQ(H->Documentation, Comment);
3536 }
3537 }
3538}
3539
3540TEST(Hover, Present) {
3541 struct {
3542 const std::function<void(HoverInfo &)> Builder;
3543 llvm::StringRef ExpectedMarkdownRender;
3544 llvm::StringRef ExpectedDoxygenRender;
3545 } Cases[] = {
3546 {
3547 [](HoverInfo &HI) {
3548 HI.Kind = index::SymbolKind::Unknown;
3549 HI.Name = "X";
3550 },
3551 R"(X)",
3552 R"(### `X`)",
3553 },
3554 {
3555 [](HoverInfo &HI) {
3556 HI.Kind = index::SymbolKind::NamespaceAlias;
3557 HI.Name = "foo";
3558 },
3559 R"(namespace-alias foo)",
3560 R"(### namespace-alias `foo`)",
3561 },
3562 {
3563 [](HoverInfo &HI) {
3564 HI.Kind = index::SymbolKind::Class;
3565 HI.Size = 80;
3566 HI.TemplateParameters = {
3567 {{"typename"}, std::string("T"), std::nullopt},
3568 {{"typename"}, std::string("C"), std::string("bool")},
3569 };
3570 HI.Documentation = "documentation";
3571 HI.Definition =
3572 "template <typename T, typename C = bool> class Foo {}";
3573 HI.Name = "foo";
3574 HI.NamespaceScope.emplace();
3575 },
3576 R"(class foo
3577
3578Size: 10 bytes
3579
3580documentation
3581
3582template <typename T, typename C = bool> class Foo {})",
3583 R"(### class
3584
3585---
3586```cpp
3587template <typename T, typename C = bool> class Foo {}
3588```
3589
3590---
3591### Brief
3592
3593documentation
3594
3595---
3596### Template Parameters
3597
3598- `typename T`
3599- `typename C = bool`
3600
3601---
3602Size: 10 bytes)",
3603 },
3604 {
3605 [](HoverInfo &HI) {
3606 HI.Kind = index::SymbolKind::Function;
3607 HI.Name = "foo";
3608 HI.Type = {"type", "c_type"};
3609 HI.ReturnType = {"ret_type", "can_ret_type"};
3610 HI.Parameters.emplace();
3612 HI.Parameters->push_back(P);
3613 P.Type = {"type", "can_type"};
3614 HI.Parameters->push_back(P);
3615 P.Name = "foo";
3616 HI.Parameters->push_back(P);
3617 P.Default = "default";
3618 HI.Parameters->push_back(P);
3619 HI.NamespaceScope = "ns::";
3620 HI.Definition = "ret_type foo(params) {}";
3621 },
3622 "function foo\n"
3623 "\n"
3624 "→ ret_type (aka can_ret_type)\n\n"
3625 "Parameters:\n\n"
3626 "- \n"
3627 "- type (aka can_type)\n"
3628 "- type foo (aka can_type)\n"
3629 "- type foo = default (aka can_type)\n"
3630 "\n"
3631 "// In namespace ns\n"
3632 "ret_type foo(params) {}",
3633 R"(### function
3634
3635---
3636```cpp
3637// In namespace ns
3638ret_type foo(params) {}
3639```
3640
3641---
3642### Parameters
3643
3644-
3645- `type (aka can_type)`
3646- `type foo (aka can_type)`
3647- `type foo = default (aka can_type)`
3648
3649---
3650### Returns
3651
3652`ret_type (aka can_ret_type)`)",
3653 },
3654 {
3655 [](HoverInfo &HI) {
3656 HI.Kind = index::SymbolKind::Field;
3657 HI.LocalScope = "test::Bar::";
3658 HI.Value = "value";
3659 HI.Name = "foo";
3660 HI.Type = {"type", "can_type"};
3661 HI.Definition = "def";
3662 HI.Size = 32;
3663 HI.Offset = 96;
3664 HI.Padding = 32;
3665 HI.Align = 32;
3666 },
3667 R"(field foo
3668
3669Type: type (aka can_type)
3670
3671Value = value
3672
3673Offset: 12 bytes
3674
3675Size: 4 bytes (+4 bytes padding), alignment 4 bytes
3676
3677// In test::Bar
3678def)",
3679 R"(### field
3680
3681---
3682```cpp
3683// In test::Bar
3684def
3685```
3686
3687---
3688Type: `type (aka can_type)`
3689
3690Value = `value`
3691
3692Offset: 12 bytes
3693
3694Size: 4 bytes (+4 bytes padding), alignment 4 bytes)",
3695 },
3696 {
3697 [](HoverInfo &HI) {
3698 HI.Kind = index::SymbolKind::Field;
3699 HI.LocalScope = "test::Bar::";
3700 HI.Value = "value";
3701 HI.Name = "foo";
3702 HI.Type = {"type", "can_type"};
3703 HI.Definition = "def";
3704 HI.Size = 25;
3705 HI.Offset = 35;
3706 HI.Padding = 4;
3707 HI.Align = 64;
3708 },
3709 R"(field foo
3710
3711Type: type (aka can_type)
3712
3713Value = value
3714
3715Offset: 4 bytes and 3 bits
3716
3717Size: 25 bits (+4 bits padding), alignment 8 bytes
3718
3719// In test::Bar
3720def)",
3721 R"(### field
3722
3723---
3724```cpp
3725// In test::Bar
3726def
3727```
3728
3729---
3730Type: `type (aka can_type)`
3731
3732Value = `value`
3733
3734Offset: 4 bytes and 3 bits
3735
3736Size: 25 bits (+4 bits padding), alignment 8 bytes)",
3737 },
3738 {
3739 [](HoverInfo &HI) {
3740 HI.Kind = index::SymbolKind::Field;
3741 HI.AccessSpecifier = "public";
3742 HI.Name = "foo";
3743 HI.LocalScope = "test::Bar::";
3744 HI.Definition = "def";
3745 },
3746 R"(field foo
3747
3748// In test::Bar
3749public: def)",
3750 R"(### field
3751
3752---
3753```cpp
3754// In test::Bar
3755public: def
3756```)",
3757 },
3758 {
3759 [](HoverInfo &HI) {
3760 HI.Definition = "size_t method()";
3761 HI.AccessSpecifier = "protected";
3762 HI.Kind = index::SymbolKind::InstanceMethod;
3763 HI.NamespaceScope = "";
3764 HI.LocalScope = "cls<int>::";
3765 HI.Name = "method";
3766 HI.Parameters.emplace();
3767 HI.ReturnType = {"size_t", "unsigned long"};
3768 HI.Type = {"size_t ()", "unsigned long ()"};
3769 },
3770 R"(instance-method method
3771
3772→ size_t (aka unsigned long)
3773
3774// In cls<int>
3775protected: size_t method())",
3776 R"(### instance-method
3777
3778---
3779```cpp
3780// In cls<int>
3781protected: size_t method()
3782```
3783
3784---
3785### Returns
3786
3787`size_t (aka unsigned long)`)",
3788 },
3789 {
3790 [](HoverInfo &HI) {
3791 HI.Definition = "cls(int a, int b = 5)";
3792 HI.AccessSpecifier = "public";
3793 HI.Kind = index::SymbolKind::Constructor;
3794 HI.NamespaceScope = "";
3795 HI.LocalScope = "cls";
3796 HI.Name = "cls";
3797 HI.Parameters.emplace();
3798 HI.Parameters->emplace_back();
3799 HI.Parameters->back().Type = "int";
3800 HI.Parameters->back().Name = "a";
3801 HI.Parameters->emplace_back();
3802 HI.Parameters->back().Type = "int";
3803 HI.Parameters->back().Name = "b";
3804 HI.Parameters->back().Default = "5";
3805 },
3806 R"(constructor cls
3807
3808Parameters:
3809
3810- int a
3811- int b = 5
3812
3813// In cls
3814public: cls(int a, int b = 5))",
3815 R"(### constructor
3816
3817---
3818```cpp
3819// In cls
3820public: cls(int a, int b = 5)
3821```
3822
3823---
3824### Parameters
3825
3826- `int a`
3827- `int b = 5`)",
3828 },
3829 {
3830 [](HoverInfo &HI) {
3831 HI.Kind = index::SymbolKind::Union;
3832 HI.AccessSpecifier = "private";
3833 HI.Name = "foo";
3834 HI.NamespaceScope = "ns1::";
3835 HI.Definition = "union foo {}";
3836 },
3837 R"(union foo
3838
3839// In namespace ns1
3840private: union foo {})",
3841 R"(### union
3842
3843---
3844```cpp
3845// In namespace ns1
3846private: union foo {}
3847```)",
3848 },
3849 {
3850 [](HoverInfo &HI) {
3851 HI.Kind = index::SymbolKind::Variable;
3852 HI.Name = "foo";
3853 HI.Definition = "int foo = 3";
3854 HI.LocalScope = "test::Bar::";
3855 HI.Value = "3";
3856 HI.Type = "int";
3857 HI.CalleeArgInfo.emplace();
3858 HI.CalleeArgInfo->Name = "arg_a";
3859 HI.CalleeArgInfo->Type = "int";
3860 HI.CalleeArgInfo->Default = "7";
3861 HI.CallPassType = HoverInfo::PassType{PassMode::Value, false};
3862 },
3863 R"(variable foo
3864
3865Type: int
3866
3867Value = 3
3868
3869Passed as arg_a
3870
3871// In test::Bar
3872int foo = 3)",
3873 R"(### variable
3874
3875---
3876```cpp
3877// In test::Bar
3878int foo = 3
3879```
3880
3881---
3882Type: `int`
3883
3884Value = `3`
3885
3886Passed as arg_a)",
3887 },
3888 {
3889 [](HoverInfo &HI) {
3890 HI.Kind = index::SymbolKind::Variable;
3891 HI.Name = "foo";
3892 HI.CalleeArgInfo.emplace();
3893 HI.CalleeArgInfo->Type = "int";
3894 HI.CallPassType = HoverInfo::PassType{PassMode::Value, false};
3895 },
3896 R"(variable foo
3897
3898Passed by value)",
3899 R"(### variable `foo`
3900
3901---
3902Passed by value)",
3903 },
3904 {
3905 [](HoverInfo &HI) {
3906 HI.Kind = index::SymbolKind::Variable;
3907 HI.Name = "foo";
3908 HI.Definition = "int foo = 3";
3909 HI.LocalScope = "test::Bar::";
3910 HI.Value = "3";
3911 HI.Type = "int";
3912 HI.CalleeArgInfo.emplace();
3913 HI.CalleeArgInfo->Name = "arg_a";
3914 HI.CalleeArgInfo->Type = "int";
3915 HI.CalleeArgInfo->Default = "7";
3916 HI.CallPassType = HoverInfo::PassType{PassMode::Ref, false};
3917 },
3918 R"(variable foo
3919
3920Type: int
3921
3922Value = 3
3923
3924Passed by reference as arg_a
3925
3926// In test::Bar
3927int foo = 3)",
3928 R"(### variable
3929
3930---
3931```cpp
3932// In test::Bar
3933int foo = 3
3934```
3935
3936---
3937Type: `int`
3938
3939Value = `3`
3940
3941Passed by reference as arg_a)",
3942 },
3943 {
3944 [](HoverInfo &HI) {
3945 HI.Kind = index::SymbolKind::Variable;
3946 HI.Name = "foo";
3947 HI.Definition = "int foo = 3";
3948 HI.LocalScope = "test::Bar::";
3949 HI.Value = "3";
3950 HI.Type = "int";
3951 HI.CalleeArgInfo.emplace();
3952 HI.CalleeArgInfo->Name = "arg_a";
3953 HI.CalleeArgInfo->Type = {"alias_int", "int"};
3954 HI.CalleeArgInfo->Default = "7";
3955 HI.CallPassType = HoverInfo::PassType{PassMode::Value, true};
3956 },
3957 R"(variable foo
3958
3959Type: int
3960
3961Value = 3
3962
3963Passed as arg_a (converted to alias_int)
3964
3965// In test::Bar
3966int foo = 3)",
3967 R"(### variable
3968
3969---
3970```cpp
3971// In test::Bar
3972int foo = 3
3973```
3974
3975---
3976Type: `int`
3977
3978Value = `3`
3979
3980Passed as arg_a (converted to alias_int))",
3981 },
3982 {
3983 [](HoverInfo &HI) {
3984 HI.Kind = index::SymbolKind::Macro;
3985 HI.Name = "PLUS_ONE";
3986 HI.Definition = "#define PLUS_ONE(X) (X+1)\n\n"
3987 "// Expands to\n"
3988 "(1 + 1)";
3989 },
3990 R"(macro PLUS_ONE
3991
3992#define PLUS_ONE(X) (X+1)
3993
3994// Expands to
3995(1 + 1))",
3996 R"(### macro
3997
3998---
3999```cpp
4000#define PLUS_ONE(X) (X+1)
4001
4002// Expands to
4003(1 + 1)
4004```)",
4005 },
4006 {
4007 [](HoverInfo &HI) {
4008 HI.Kind = index::SymbolKind::Variable;
4009 HI.Name = "foo";
4010 HI.Definition = "int foo = 3";
4011 HI.LocalScope = "test::Bar::";
4012 HI.Value = "3";
4013 HI.Type = "int";
4014 HI.CalleeArgInfo.emplace();
4015 HI.CalleeArgInfo->Name = "arg_a";
4016 HI.CalleeArgInfo->Type = "int";
4017 HI.CalleeArgInfo->Default = "7";
4018 HI.CallPassType = HoverInfo::PassType{PassMode::ConstRef, true};
4019 },
4020 R"(variable foo
4021
4022Type: int
4023
4024Value = 3
4025
4026Passed by const reference as arg_a (converted to int)
4027
4028// In test::Bar
4029int foo = 3)",
4030 R"(### variable
4031
4032---
4033```cpp
4034// In test::Bar
4035int foo = 3
4036```
4037
4038---
4039Type: `int`
4040
4041Value = `3`
4042
4043Passed by const reference as arg_a (converted to int))",
4044 },
4045 {
4046 [](HoverInfo &HI) {
4047 HI.Name = "stdio.h";
4048 HI.Definition = "/usr/include/stdio.h";
4049 HI.Kind = index::SymbolKind::IncludeDirective;
4050 },
4051 R"(stdio.h
4052
4053/usr/include/stdio.h)",
4054 R"(### `stdio.h`
4055
4056`/usr/include/stdio.h`)",
4057 },
4058 {
4059 [](HoverInfo &HI) {
4060 HI.Name = "foo.h";
4061 HI.UsedSymbolNames = {"Foo", "Bar", "Bar"};
4062 HI.Kind = index::SymbolKind::IncludeDirective;
4063 },
4064 R"(foo.h
4065
4066provides Foo, Bar, Bar)",
4067 R"(### `foo.h`
4068
4069---
4070provides `Foo`, `Bar`, `Bar`)",
4071 },
4072 {[](HoverInfo &HI) {
4073 HI.Name = "foo.h";
4074 HI.UsedSymbolNames = {"Foo", "Bar", "Baz", "Foobar", "Qux", "Quux"};
4075 HI.Kind = index::SymbolKind::IncludeDirective;
4076 },
4077 R"(foo.h
4078
4079provides Foo, Bar, Baz, Foobar, Qux and 1 more)",
4080 R"(### `foo.h`
4081
4082---
4083provides `Foo`, `Bar`, `Baz`, `Foobar`, `Qux` and 1 more)"}};
4084
4085 for (const auto &C : Cases) {
4086 HoverInfo HI;
4087 C.Builder(HI);
4088 Config Cfg;
4089 Cfg.Hover.ShowAKA = true;
4090 Cfg.Documentation.CommentFormat = Config::CommentFormatPolicy::Markdown;
4091 WithContextValue WithCfg(Config::Key, std::move(Cfg));
4092 EXPECT_EQ(HI.present(MarkupKind::PlainText), C.ExpectedMarkdownRender);
4093 }
4094 for (const auto &C : Cases) {
4095 HoverInfo HI;
4096 C.Builder(HI);
4097 Config Cfg;
4098 Cfg.Hover.ShowAKA = true;
4099 Cfg.Documentation.CommentFormat = Config::CommentFormatPolicy::Doxygen;
4100 WithContextValue WithCfg(Config::Key, std::move(Cfg));
4101 EXPECT_EQ(HI.present(MarkupKind::Markdown), C.ExpectedDoxygenRender);
4102 }
4103}
4104
4105TEST(Hover, PresentDocumentation) {
4106 struct {
4107 const std::function<void(HoverInfo &)> Builder;
4108 llvm::StringRef ExpectedMarkdownRender;
4109 llvm::StringRef ExpectedDoxygenRender;
4110 } Cases[] = {
4111 {[](HoverInfo &HI) {
4112 HI.Kind = index::SymbolKind::Function;
4113 HI.Documentation = "@brief brief doc\n\n"
4114 "longer doc";
4115 HI.Definition = "void foo()";
4116 HI.Name = "foo";
4117 },
4118 R"(### function `foo`
4119
4120---
4121@brief brief doc
4122
4123longer doc
4124
4125---
4126```cpp
4127void foo()
4128```)",
4129 R"(### function
4130
4131---
4132```cpp
4133void foo()
4134```
4135
4136---
4137### Brief
4138
4139brief doc
4140
4141---
4142### Details
4143
4144longer doc)"},
4145 {[](HoverInfo &HI) {
4146 HI.Kind = index::SymbolKind::Function;
4147 HI.Documentation = "@brief brief doc\n\n"
4148 "longer doc";
4149 HI.Definition = "int foo()";
4150 HI.ReturnType = "int";
4151 HI.Name = "foo";
4152 },
4153 R"(### function `foo`
4154
4155---
4156→ `int`
4157
4158@brief brief doc
4159
4160longer doc
4161
4162---
4163```cpp
4164int foo()
4165```)",
4166 R"(### function
4167
4168---
4169```cpp
4170int foo()
4171```
4172
4173---
4174### Brief
4175
4176brief doc
4177
4178---
4179### Returns
4180
4181`int`
4182
4183---
4184### Details
4185
4186longer doc)"},
4187 {[](HoverInfo &HI) {
4188 HI.Kind = index::SymbolKind::Function;
4189 HI.Documentation = R"(@brief brief doc
4190
4191longer doc
4192@note this is a note
4193
4194As you see, notes are "inlined".
4195@warning this is a warning
4196
4197As well as warnings
4198@param a this is a param
4199@return it returns something
4200@retval 0 if successful
4201@retval 1 if failed)";
4202 HI.Definition = "int foo(int a)";
4203 HI.ReturnType = "int";
4204 HI.Name = "foo";
4205 HI.Parameters.emplace();
4206 HI.Parameters->emplace_back();
4207 HI.Parameters->back().Type = "int";
4208 HI.Parameters->back().Name = "a";
4209 },
4210 R"(### function `foo`
4211
4212---
4213→ `int`
4214
4215Parameters:
4216
4217- `int a`
4218
4219@brief brief doc
4220
4221longer doc
4222@note this is a note
4223
4224As you see, notes are "inlined".
4225@warning this is a warning
4226
4227As well as warnings
4228@param a this is a param
4229@return it returns something
4230@retval 0 if successful
4231@retval 1 if failed
4232
4233---
4234```cpp
4235int foo(int a)
4236```)",
4237 R"(### function
4238
4239---
4240```cpp
4241int foo(int a)
4242```
4243
4244---
4245### Brief
4246
4247brief doc
4248
4249---
4250### Parameters
4251
4252- `int a` - this is a param
4253
4254---
4255### Returns
4256
4257`int` - it returns something
4258
4259- `0` - if successful
4260- `1` - if failed
4261
4262---
4263### Details
4264
4265longer doc
4266
4267**Note:**
4268this is a note
4269
4270As you see, notes are "inlined".
4271
4272**Warning:**
4273this is a warning
4274
4275As well as warnings)"},
4276 {[](HoverInfo &HI) {
4277 HI.Kind = index::SymbolKind::Function;
4278 HI.Documentation = "@brief brief doc\n\n"
4279 "longer doc\n@param a this is a param\n@param b "
4280 "does not exist\n@return it returns something";
4281 HI.Definition = "int foo(int a)";
4282 HI.ReturnType = "int";
4283 HI.Name = "foo";
4284 HI.Parameters.emplace();
4285 HI.Parameters->emplace_back();
4286 HI.Parameters->back().Type = "int";
4287 HI.Parameters->back().Name = "a";
4288 },
4289 R"(### function `foo`
4290
4291---
4292→ `int`
4293
4294Parameters:
4295
4296- `int a`
4297
4298@brief brief doc
4299
4300longer doc
4301@param a this is a param
4302@param b does not exist
4303@return it returns something
4304
4305---
4306```cpp
4307int foo(int a)
4308```)",
4309 R"(### function
4310
4311---
4312```cpp
4313int foo(int a)
4314```
4315
4316---
4317### Brief
4318
4319brief doc
4320
4321---
4322### Parameters
4323
4324- `int a` - this is a param
4325
4326---
4327### Returns
4328
4329`int` - it returns something
4330
4331---
4332### Details
4333
4334longer doc)"},
4335 };
4336
4337 for (const auto &C : Cases) {
4338 HoverInfo HI;
4339 C.Builder(HI);
4340 Config Cfg;
4341 Cfg.Hover.ShowAKA = true;
4342 Cfg.Documentation.CommentFormat = Config::CommentFormatPolicy::Markdown;
4343 WithContextValue WithCfg(Config::Key, std::move(Cfg));
4344 EXPECT_EQ(HI.present(MarkupKind::Markdown), C.ExpectedMarkdownRender);
4345 }
4346 for (const auto &C : Cases) {
4347 HoverInfo HI;
4348 C.Builder(HI);
4349 Config Cfg;
4350 Cfg.Hover.ShowAKA = true;
4351 Cfg.Documentation.CommentFormat = Config::CommentFormatPolicy::Doxygen;
4352 WithContextValue WithCfg(Config::Key, std::move(Cfg));
4353 EXPECT_EQ(HI.present(MarkupKind::Markdown), C.ExpectedDoxygenRender);
4354 }
4355}
4356
4357TEST(Hover, ParseDocumentation) {
4358 struct Case {
4359 llvm::StringRef Documentation;
4360 llvm::StringRef ExpectedRenderEscapedMarkdown;
4361 llvm::StringRef ExpectedRenderMarkdown;
4362 llvm::StringRef ExpectedRenderPlainText;
4363 } Cases[] = {{
4364 " \n foo\nbar",
4365 "foo\nbar",
4366 "foo\nbar",
4367 "foo bar",
4368 },
4369 {
4370 "foo\nbar \n ",
4371 "foo\nbar",
4372 "foo\nbar",
4373 "foo bar",
4374 },
4375 {
4376 "foo \nbar",
4377 "foo \nbar",
4378 "foo \nbar",
4379 "foo\nbar",
4380 },
4381 {
4382 "foo \nbar",
4383 "foo \nbar",
4384 "foo \nbar",
4385 "foo\nbar",
4386 },
4387 {
4388 "foo\n\n\nbar",
4389 "foo\n\nbar",
4390 "foo\n\nbar",
4391 "foo\n\nbar",
4392 },
4393 {
4394 "foo\n\n\n\tbar",
4395 "foo\n\n\tbar",
4396 "foo\n\n\tbar",
4397 "foo\n\nbar",
4398 },
4399 {
4400 "foo\n\n\n bar",
4401 "foo\n\n bar",
4402 "foo\n\n bar",
4403 "foo\n\nbar",
4404 },
4405 {
4406 "foo\n\n\n bar",
4407 "foo\n\n bar",
4408 "foo\n\n bar",
4409 "foo\n\nbar",
4410 },
4411 {
4412 "foo\n\n\n bar",
4413 "foo\n\n bar",
4414 "foo\n\n bar",
4415 "foo\n\nbar",
4416 },
4417 {
4418 "foo\n\n\n\nbar",
4419 "foo\n\nbar",
4420 "foo\n\nbar",
4421 "foo\n\nbar",
4422 },
4423 {
4424 "foo\n\n\n\n\tbar",
4425 "foo\n\n\tbar",
4426 "foo\n\n\tbar",
4427 "foo\n\nbar",
4428 },
4429 {
4430 "foo\n\n\n\n bar",
4431 "foo\n\n bar",
4432 "foo\n\n bar",
4433 "foo\n\nbar",
4434 },
4435 {
4436 "foo\n\n\n\n bar",
4437 "foo\n\n bar",
4438 "foo\n\n bar",
4439 "foo\n\nbar",
4440 },
4441 {
4442 "foo\n\n\n\n bar",
4443 "foo\n\n bar",
4444 "foo\n\n bar",
4445 "foo\n\nbar",
4446 },
4447 {
4448 "foo.\nbar",
4449 "foo. \nbar",
4450 "foo. \nbar",
4451 "foo.\nbar",
4452 },
4453 {
4454 "foo. \nbar",
4455 "foo. \nbar",
4456 "foo. \nbar",
4457 "foo.\nbar",
4458 },
4459 {
4460 "foo\n*bar",
4461 "foo \n\\*bar",
4462 "foo\n*bar",
4463 "foo\n*bar",
4464 },
4465 {
4466 "foo\nbar",
4467 "foo\nbar",
4468 "foo\nbar",
4469 "foo bar",
4470 },
4471 {
4472 "Tests primality of `p`.",
4473 "Tests primality of `p`.",
4474 "Tests primality of `p`.",
4475 "Tests primality of `p`.",
4476 },
4477 {
4478 "'`' should not occur in `Code`",
4479 "'\\`' should not occur in `Code`",
4480 "'`' should not occur in `Code`",
4481 "'`' should not occur in `Code`",
4482 },
4483 {
4484 "`not\nparsed`",
4485 "\\`not\nparsed\\`",
4486 "`not\nparsed`",
4487 "`not parsed`",
4488 },
4489 {
4490 R"(@brief this is a typical use case
4491@param x this is x
4492\param y this is y
4493@return something)",
4494 R"(@brief this is a typical use case
4495@param x this is x
4496\\param y this is y
4497@return something)",
4498 R"(@brief this is a typical use case
4499@param x this is x
4500\param y this is y
4501@return something)",
4502 R"(@brief this is a typical use case
4503@param x this is x
4504\param y this is y
4505@return something)",
4506 }};
4507
4508 for (const auto &C : Cases) {
4509 markup::Document Output;
4510 parseDocumentation(C.Documentation, Output);
4511
4512 EXPECT_EQ(Output.asEscapedMarkdown(), C.ExpectedRenderEscapedMarkdown);
4513 EXPECT_EQ(Output.asMarkdown(), C.ExpectedRenderMarkdown);
4514 EXPECT_EQ(Output.asPlainText(), C.ExpectedRenderPlainText);
4515 }
4516}
4517
4518// This is a separate test as headings don't create any differences in
4519// plaintext mode.
4520TEST(Hover, PresentHeadings) {
4521 HoverInfo HI;
4522 HI.Kind = index::SymbolKind::Variable;
4523 HI.Name = "foo";
4524
4525 EXPECT_EQ(HI.present(MarkupKind::Markdown), "### variable `foo`");
4526}
4527
4528// This is a separate test as rulers behave differently in markdown vs
4529// plaintext.
4530TEST(Hover, PresentRulers) {
4531 HoverInfo HI;
4532 HI.Kind = index::SymbolKind::Variable;
4533 HI.Name = "foo";
4534 HI.Value = "val";
4535 HI.Definition = "def";
4536
4537 llvm::StringRef ExpectedMarkdown = //
4538 "### variable `foo`\n"
4539 "\n"
4540 "---\n"
4541 "Value = `val`\n"
4542 "\n"
4543 "---\n"
4544 "```cpp\n"
4545 "def\n"
4546 "```";
4547 EXPECT_EQ(HI.present(MarkupKind::Markdown), ExpectedMarkdown);
4548
4549 llvm::StringRef ExpectedDoxygenMarkdown = //
4550 "### variable\n"
4551 "\n"
4552 "---\n"
4553 "```cpp\n"
4554 "def\n"
4555 "```\n\n"
4556 "---\n"
4557 "Value = `val`";
4558 Config Cfg;
4559 Cfg.Hover.ShowAKA = true;
4560 Cfg.Documentation.CommentFormat = Config::CommentFormatPolicy::Doxygen;
4561 WithContextValue WithCfg(Config::Key, std::move(Cfg));
4562 EXPECT_EQ(HI.present(MarkupKind::Markdown), ExpectedDoxygenMarkdown);
4563
4564 llvm::StringRef ExpectedPlaintext = R"pt(variable foo
4565
4566Value = val
4567
4568def)pt";
4569 EXPECT_EQ(HI.present(MarkupKind::PlainText), ExpectedPlaintext);
4570}
4571
4572TEST(Hover, SpaceshipTemplateNoCrash) {
4573 Annotations T(R"cpp(
4574 namespace std {
4575 struct strong_ordering {
4576 int n;
4577 constexpr operator int() const { return n; }
4578 static const strong_ordering equal, greater, less;
4579 };
4580 constexpr strong_ordering strong_ordering::equal = {0};
4581 constexpr strong_ordering strong_ordering::greater = {1};
4582 constexpr strong_ordering strong_ordering::less = {-1};
4583 }
4584
4585 template <typename T>
4586 struct S {
4587 // Foo bar baz
4588 friend auto operator<=>(S, S) = default;
4589 };
4590 static_assert(S<void>() =^= S<void>());
4591 )cpp");
4592
4593 TestTU TU = TestTU::withCode(T.code());
4594 TU.ExtraArgs.push_back("-std=c++20");
4595 auto AST = TU.build();
4596 auto HI = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
4597 EXPECT_EQ(HI->Documentation, "");
4598}
4599
4600TEST(Hover, ForwardStructNoCrash) {
4601 Annotations T(R"cpp(
4602 struct Foo;
4603 int bar;
4604 auto baz = (Fo^o*)&bar;
4605 )cpp");
4606
4607 TestTU TU = TestTU::withCode(T.code());
4608 auto AST = TU.build();
4609 auto HI = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
4610 ASSERT_TRUE(HI);
4611 EXPECT_EQ(*HI->Value, "&bar");
4612}
4613
4614TEST(Hover, FunctionParameterDefaulValueNotEvaluatedOnInvalidDecls) {
4615 struct {
4616 const char *const Code;
4617 const std::optional<std::string> HoverValue;
4618 } Cases[] = {
4619 {R"cpp(
4620 // error-ok testing behavior on invalid decl
4621 class Foo {};
4622 void foo(Foo p^aram = nullptr);
4623 )cpp",
4624 std::nullopt},
4625 {R"cpp(
4626 class Foo {};
4627 void foo(Foo *p^aram = nullptr);
4628 )cpp",
4629 "nullptr"},
4630 };
4631
4632 for (const auto &C : Cases) {
4633 Annotations T(C.Code);
4634 TestTU TU = TestTU::withCode(T.code());
4635 auto AST = TU.build();
4636 auto HI = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
4637 ASSERT_TRUE(HI);
4638 ASSERT_EQ(HI->Value, C.HoverValue);
4639 }
4640}
4641
4642TEST(Hover, DisableShowAKA) {
4643 Annotations T(R"cpp(
4644 using m_int = int;
4645 m_int ^[[a]];
4646 )cpp");
4647
4648 Config Cfg;
4649 Cfg.Hover.ShowAKA = false;
4650 WithContextValue WithCfg(Config::Key, std::move(Cfg));
4651
4652 TestTU TU = TestTU::withCode(T.code());
4653 TU.ExtraArgs.push_back("-std=c++17");
4654 auto AST = TU.build();
4655 auto H = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
4656
4657 ASSERT_TRUE(H);
4658 EXPECT_EQ(H->Type, HoverInfo::PrintedType("m_int"));
4659}
4660
4661TEST(Hover, HideBigInitializers) {
4662 Annotations T(R"cpp(
4663 #define A(x) x, x, x, x
4664 #define B(x) A(A(A(A(x))))
4665 int a^rr[] = {B(0)};
4666 )cpp");
4667
4668 TestTU TU = TestTU::withCode(T.code());
4669 auto AST = TU.build();
4670 auto H = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
4671
4672 ASSERT_TRUE(H);
4673 EXPECT_EQ(H->Definition, "int arr[]");
4674}
4675
4676#if defined(__aarch64__)
4677// FIXME: AARCH64 sanitizer buildbots are broken after 72142fbac4.
4678#define PREDEFINEMACROS_TEST(x) DISABLED_##x
4679#else
4680#define PREDEFINEMACROS_TEST(x) x
4681#endif
4682
4683TEST(Hover, PREDEFINEMACROS_TEST(GlobalVarEnumeralCastNoCrash)) {
4684 Annotations T(R"cpp(
4685 using uintptr_t = __UINTPTR_TYPE__;
4686 enum Test : uintptr_t {};
4687 unsigned global_var;
4688 void foo() {
4689 Test v^al = static_cast<Test>(reinterpret_cast<uintptr_t>(&global_var));
4690 }
4691 )cpp");
4692
4693 TestTU TU = TestTU::withCode(T.code());
4694 TU.PredefineMacros = true;
4695 auto AST = TU.build();
4696 auto HI = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
4697 ASSERT_TRUE(HI);
4698 EXPECT_EQ(*HI->Value, "&global_var");
4699}
4700
4701TEST(Hover, PREDEFINEMACROS_TEST(GlobalVarIntCastNoCrash)) {
4702 Annotations T(R"cpp(
4703 using uintptr_t = __UINTPTR_TYPE__;
4704 unsigned global_var;
4705 void foo() {
4706 uintptr_t a^ddress = reinterpret_cast<uintptr_t>(&global_var);
4707 }
4708 )cpp");
4709
4710 TestTU TU = TestTU::withCode(T.code());
4711 TU.PredefineMacros = true;
4712 auto AST = TU.build();
4713 auto HI = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
4714 ASSERT_TRUE(HI);
4715 EXPECT_EQ(*HI->Value, "&global_var");
4716}
4717
4718TEST(Hover, Typedefs) {
4719 Annotations T(R"cpp(
4720 template <bool X, typename T, typename F>
4721 struct cond { using type = T; };
4722 template <typename T, typename F>
4723 struct cond<false, T, F> { using type = F; };
4724
4725 template <bool X, typename T, typename F>
4726 using type = typename cond<X, T, F>::type;
4727
4728 void foo() {
4729 using f^oo = type<true, int, double>;
4730 }
4731 )cpp");
4732
4733 TestTU TU = TestTU::withCode(T.code());
4734 auto AST = TU.build();
4735 auto H = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
4736
4737 ASSERT_TRUE(H && H->Type);
4738 EXPECT_EQ(H->Type->Type, "int");
4739 EXPECT_EQ(H->Definition, "using foo = type<true, int, double>");
4740}
4741
4742TEST(Hover, EvaluateMacros) {
4743 llvm::StringRef PredefinedCXX = R"cpp(
4744#define X 42
4745#define SizeOf sizeof
4746#define AlignOf alignof
4747#define PLUS_TWO +2
4748#define TWO 2
4749
4750using u64 = unsigned long long;
4751// calculate (a ** b) % p
4752constexpr u64 pow_with_mod(u64 a, u64 b, u64 p) {
4753 u64 ret = 1;
4754 while (b) {
4755 if (b & 1)
4756 ret = (ret * a) % p;
4757 a = (a * a) % p;
4758 b >>= 1;
4759 }
4760 return ret;
4761}
4762#define last_n_digit(x, y, n) \
4763 pow_with_mod(x, y, pow_with_mod(10, n, 2147483647))
4764#define declare_struct(X, name, value) \
4765 struct X { \
4766 constexpr auto name() { return value; } \
4767 }
4768#define gnu_statement_expression(value) \
4769 ({ \
4770 declare_struct(Widget, getter, value); \
4771 Widget().getter(); \
4772 })
4773#define define_lambda_begin(lambda, ...) \
4774 [&](__VA_ARGS__) {
4775#define define_lambda_end() }
4776
4777#define left_bracket [
4778#define right_bracket ]
4779#define dg_left_bracket <:
4780#define dg_right_bracket :>
4781#define array_decl(type, name, size) type name left_bracket size right_bracket
4782 )cpp";
4783
4784 struct {
4785 llvm::StringRef Code;
4786 const std::function<void(std::optional<HoverInfo>, size_t /*Id*/)>
4787 Validator;
4788 } Cases[] = {
4789 {
4790 /*Code=*/R"cpp(
4791 X^;
4792 )cpp",
4793 /*Validator=*/
4794 [](std::optional<HoverInfo> HI, size_t) {
4795 EXPECT_EQ(HI->Value, "42 (0x2a)");
4796 EXPECT_EQ(HI->Type, HoverInfo::PrintedType("int"));
4797 },
4798 },
4799 {
4800 /*Code=*/R"cpp(
4801 Size^Of(int);
4802 )cpp",
4803 /*Validator=*/
4804 [](std::optional<HoverInfo> HI, size_t) {
4805 EXPECT_TRUE(HI->Value);
4806 EXPECT_TRUE(HI->Type);
4807 // Don't validate type or value of `sizeof` and `alignof` as we're
4808 // getting different values or desugared types on different
4809 // platforms. Same as below.
4810 },
4811 },
4812 {
4813 /*Code=*/R"cpp(
4814 struct Y {
4815 int y;
4816 double z;
4817 };
4818 Alig^nOf(Y);
4819 )cpp",
4820 /*Validator=*/
4821 [](std::optional<HoverInfo> HI, size_t) {
4822 EXPECT_TRUE(HI->Value);
4823 EXPECT_TRUE(HI->Type);
4824 },
4825 },
4826 {
4827 /*Code=*/R"cpp(
4828 // 2**32 == 4294967296
4829 last_n_di^git(2, 32, 6);
4830 )cpp",
4831 /*Validator=*/
4832 [](std::optional<HoverInfo> HI, size_t) {
4833 EXPECT_EQ(HI->Value, "967296 (0xec280)");
4834 EXPECT_EQ(HI->Type, "u64");
4835 },
4836 },
4837 {
4838 /*Code=*/R"cpp(
4839 gnu_statement_exp^ression(42);
4840 )cpp",
4841 /*Validator=*/
4842 [](std::optional<HoverInfo> HI, size_t) {
4843 EXPECT_EQ(HI->Value, "42 (0x2a)");
4844 EXPECT_EQ(HI->Type, "int");
4845 },
4846 },
4847 {
4848 /*Code=*/R"cpp(
4849 40 + PLU^S_TWO;
4850 )cpp",
4851 /*Validator=*/
4852 [](std::optional<HoverInfo> HI, size_t) {
4853 EXPECT_EQ(HI->Value, "2");
4854 EXPECT_EQ(HI->Type, "int");
4855 },
4856 },
4857 {
4858 /*Code=*/R"cpp(
4859 40 PLU^S_TWO;
4860 )cpp",
4861 /*Validator=*/
4862 [](std::optional<HoverInfo> HI, size_t) {
4863 EXPECT_FALSE(HI->Value) << HI->Value;
4864 EXPECT_FALSE(HI->Type) << HI->Type;
4865 },
4866 },
4867 {
4868 /*Code=*/R"cpp(
4869 40 + TW^O;
4870 )cpp",
4871 /*Validator=*/
4872 [](std::optional<HoverInfo> HI, size_t) {
4873 EXPECT_EQ(HI->Value, "2");
4874 EXPECT_EQ(HI->Type, "int");
4875 },
4876 },
4877 {
4878 /*Code=*/R"cpp(
4879 arra^y_decl(int, vector, 10);
4880 vector left_b^racket 3 right_b^racket;
4881 vector dg_le^ft_bracket 3 dg_righ^t_bracket;
4882 )cpp",
4883 /*Validator=*/
4884 [](std::optional<HoverInfo> HI, size_t Id) {
4885 switch (Id) {
4886 case 0:
4887 EXPECT_EQ(HI->Type, HoverInfo::PrintedType("int[10]"));
4888 break;
4889 case 1:
4890 case 2:
4891 case 3:
4892 case 4:
4893 EXPECT_FALSE(HI->Type) << HI->Type;
4894 EXPECT_FALSE(HI->Value) << HI->Value;
4895 break;
4896 default:
4897 ASSERT_TRUE(false) << "Unhandled id: " << Id;
4898 }
4899 },
4900 },
4901 {
4902 /*Code=*/R"cpp(
4903 constexpr auto value = define_lamb^da_begin(lambda, int, char)
4904 // Check if the expansion range is right.
4905 return ^last_n_digit(10, 3, 3)^;
4906 define_lam^bda_end();
4907 )cpp",
4908 /*Validator=*/
4909 [](std::optional<HoverInfo> HI, size_t Id) {
4910 switch (Id) {
4911 case 0:
4912 EXPECT_FALSE(HI->Value);
4913 EXPECT_EQ(HI->Type, HoverInfo::PrintedType("const (lambda)"));
4914 break;
4915 case 1:
4916 EXPECT_EQ(HI->Value, "0");
4917 EXPECT_EQ(HI->Type, HoverInfo::PrintedType("u64"));
4918 break;
4919 case 2:
4920 EXPECT_FALSE(HI);
4921 break;
4922 case 3:
4923 EXPECT_FALSE(HI->Type) << HI->Type;
4924 EXPECT_FALSE(HI->Value) << HI->Value;
4925 break;
4926 default:
4927 ASSERT_TRUE(false) << "Unhandled id: " << Id;
4928 }
4929 },
4930 },
4931 };
4932
4933 Config Cfg;
4934 Cfg.Hover.ShowAKA = false;
4935 WithContextValue WithCfg(Config::Key, std::move(Cfg));
4936 for (const auto &C : Cases) {
4937 Annotations Code(
4938 (PredefinedCXX + "void function() {\n" + C.Code + "}\n").str());
4939 auto TU = TestTU::withCode(Code.code());
4940 TU.ExtraArgs.push_back("-std=c++17");
4941 auto AST = TU.build();
4942 for (auto [Index, Position] : llvm::enumerate(Code.points())) {
4943 C.Validator(getHover(AST, Position, format::getLLVMStyle(), nullptr),
4944 Index);
4945 }
4946 }
4947
4948 Annotations C(R"c(
4949 #define alignof _Alignof
4950 void foo() {
4951 al^ignof(struct { int x; char y[10]; });
4952 }
4953 )c");
4954
4955 auto TU = TestTU::withCode(C.code());
4956 TU.Filename = "TestTU.c";
4957 TU.ExtraArgs = {
4958 "-std=c17",
4959 };
4960 auto AST = TU.build();
4961 auto H = getHover(AST, C.point(), format::getLLVMStyle(), nullptr);
4962
4963 ASSERT_TRUE(H);
4964 EXPECT_TRUE(H->Value);
4965 EXPECT_TRUE(H->Type);
4966}
4967
4968TEST(Hover, HoverMacroContentsLimit) {
4969 const char *const Code =
4970 R"cpp(
4971 #define C(A) A##A // Concatenate
4972 #define E(A) C(A) // Expand
4973 #define Z0032 00000000000000000000000000000000
4974 #define Z0064 E(Z0032)
4975 #define Z0128 E(Z0064)
4976 #define Z0256 E(Z0128)
4977 #define Z0512 E(Z0256)
4978 #define Z1024 E(Z0512)
4979 #define Z2048 E(Z1024)
4980 #define Z4096 E(Z2048) // 4096 zeroes
4981 int main() { return [[^Z4096]]; }
4982 )cpp";
4983
4984 struct {
4985 uint32_t MacroContentsLimit;
4986 const std::string ExpectedDefinition;
4987 } Cases[] = {
4988 // With a limit of 2048, the macro expansion should get dropped.
4989 {2048, "#define Z4096 E(Z2048)"},
4990 // With a limit of 8192, the macro expansion should be fully expanded.
4991 {8192, std::string("#define Z4096 E(Z2048)\n\n") +
4992 std::string("// Expands to\n") + std::string(4096, '0')},
4993 };
4994 for (const auto &Case : Cases) {
4995 SCOPED_TRACE(Code);
4996
4997 Annotations T(Code);
4998 TestTU TU = TestTU::withCode(T.code());
4999 auto AST = TU.build();
5000 Config Cfg;
5001 Cfg.Hover.MacroContentsLimit = Case.MacroContentsLimit;
5002 WithContextValue WithCfg(Config::Key, std::move(Cfg));
5003 auto H = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
5004 ASSERT_TRUE(H);
5005
5006 EXPECT_EQ(H->Definition, Case.ExpectedDefinition);
5007 }
5008}
5009
5010TEST(Hover, FunctionParameters) {
5011 struct {
5012 const char *const Code;
5013 const std::function<void(HoverInfo &)> ExpectedBuilder;
5014 std::string ExpectedRender;
5015 } Cases[] = {
5016 {R"cpp(/// Function doc
5017 void foo(int [[^a]]);
5018 )cpp",
5019 [](HoverInfo &HI) {
5020 HI.Name = "a";
5021 HI.Kind = index::SymbolKind::Parameter;
5022 HI.NamespaceScope = "";
5023 HI.LocalScope = "foo::";
5024 HI.Type = "int";
5025 HI.Definition = "int a";
5026 HI.Documentation = "";
5027 },
5028 "### param\n\n---\n```cpp\n// In foo\nint a\n```\n\n---\nType: `int`"},
5029 {R"cpp(/// Function doc
5030 /// @param a this is doc for a
5031 void foo(int [[^a]]);
5032 )cpp",
5033 [](HoverInfo &HI) {
5034 HI.Name = "a";
5035 HI.Kind = index::SymbolKind::Parameter;
5036 HI.NamespaceScope = "";
5037 HI.LocalScope = "foo::";
5038 HI.Type = "int";
5039 HI.Definition = "int a";
5040 HI.Documentation = "this is doc for a";
5041 },
5042 "### param\n\n---\n```cpp\n// In foo\nint a\n```\n\n---\nthis is doc "
5043 "for a\n\n---\nType: `int`"},
5044 {R"cpp(/// Function doc
5045 /// @param b this is doc for b
5046 void foo(int [[^a]], int b);
5047 )cpp",
5048 [](HoverInfo &HI) {
5049 HI.Name = "a";
5050 HI.Kind = index::SymbolKind::Parameter;
5051 HI.NamespaceScope = "";
5052 HI.LocalScope = "foo::";
5053 HI.Type = "int";
5054 HI.Definition = "int a";
5055 HI.Documentation = "";
5056 },
5057 "### param\n\n---\n```cpp\n// In foo\nint a\n```\n\n---\nType: `int`"},
5058 {R"cpp(/// Function doc
5059 /// @param b this is doc for \p b
5060 void foo(int a, int [[^b]]);
5061 )cpp",
5062 [](HoverInfo &HI) {
5063 HI.Name = "b";
5064 HI.Kind = index::SymbolKind::Parameter;
5065 HI.NamespaceScope = "";
5066 HI.LocalScope = "foo::";
5067 HI.Type = "int";
5068 HI.Definition = "int b";
5069 HI.Documentation = "this is doc for \\p b";
5070 },
5071 "### param\n\n---\n```cpp\n// In foo\nint b\n```\n\n---\nthis is doc "
5072 "for `b`\n\n---\nType: `int`"},
5073 {R"cpp(/// Function doc
5074 /// @param b this is doc for \p b
5075 template <typename T>
5076 void foo(T a, T [[^b]]);
5077 )cpp",
5078 [](HoverInfo &HI) {
5079 HI.Name = "b";
5080 HI.Kind = index::SymbolKind::Parameter;
5081 HI.NamespaceScope = "";
5082 HI.LocalScope = "foo::";
5083 HI.Type = "T";
5084 HI.Definition = "T b";
5085 HI.Documentation = "this is doc for \\p b";
5086 },
5087 "### param\n\n---\n```cpp\n// In foo\nT b\n```\n\n---\nthis is doc for "
5088 "`b`\n\n---\nType: `T`"},
5089 {R"cpp(/// Function doc
5090 /// @param b this is <b>doc</b> <html-tag attribute/> <another-html-tag attribute="value">for</another-html-tag> \p b
5091 void foo(int a, int [[^b]]);
5092 )cpp",
5093 [](HoverInfo &HI) {
5094 HI.Name = "b";
5095 HI.Kind = index::SymbolKind::Parameter;
5096 HI.NamespaceScope = "";
5097 HI.LocalScope = "foo::";
5098 HI.Type = "int";
5099 HI.Definition = "int b";
5100 HI.Documentation =
5101 "this is <b>doc</b> <html-tag attribute/> <another-html-tag "
5102 "attribute=\"value\">for</another-html-tag> \\p b";
5103 },
5104 "### param\n\n---\n```cpp\n// In foo\nint b\n```\n\n---\nthis is "
5105 "\\<b>doc\\</b> \\<html-tag attribute/> \\<another-html-tag "
5106 "attribute=\"value\">for\\</another-html-tag> `b`\n\n---\nType: `int`"},
5107 };
5108
5109 // Create a tiny index, so tests above can verify documentation is fetched.
5110 Symbol IndexSym = func("indexSymbol");
5111 IndexSym.Documentation = "comment from index";
5113 Symbols.insert(IndexSym);
5114 auto Index =
5115 MemIndex::build(std::move(Symbols).build(), RefSlab(), RelationSlab());
5116
5117 for (const auto &Case : Cases) {
5118 SCOPED_TRACE(Case.Code);
5119
5120 Annotations T(Case.Code);
5121 TestTU TU = TestTU::withCode(T.code());
5122 auto AST = TU.build();
5123 Config Cfg;
5124 Cfg.Hover.ShowAKA = true;
5125 Cfg.Documentation.CommentFormat = Config::CommentFormatPolicy::Doxygen;
5126 WithContextValue WithCfg(Config::Key, std::move(Cfg));
5127 auto H = getHover(AST, T.point(), format::getLLVMStyle(), Index.get());
5128 ASSERT_TRUE(H);
5129 HoverInfo Expected;
5130 Expected.SymRange = T.range();
5131 Case.ExpectedBuilder(Expected);
5132
5133 EXPECT_EQ(H->present(MarkupKind::Markdown), Case.ExpectedRender);
5134 EXPECT_EQ(H->NamespaceScope, Expected.NamespaceScope);
5135 EXPECT_EQ(H->LocalScope, Expected.LocalScope);
5136 EXPECT_EQ(H->Name, Expected.Name);
5137 EXPECT_EQ(H->Kind, Expected.Kind);
5138 EXPECT_EQ(H->Documentation, Expected.Documentation);
5139 EXPECT_EQ(H->Definition, Expected.Definition);
5140 EXPECT_EQ(H->Type, Expected.Type);
5141 EXPECT_EQ(H->ReturnType, Expected.ReturnType);
5142 EXPECT_EQ(H->Parameters, Expected.Parameters);
5143 EXPECT_EQ(H->TemplateParameters, Expected.TemplateParameters);
5144 EXPECT_EQ(H->SymRange, Expected.SymRange);
5145 EXPECT_EQ(H->Value, Expected.Value);
5146 }
5147}
5148
5149} // namespace
5150} // namespace clangd
5151} // 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:224
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:353
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:93
std::optional< HoverInfo > getHover(ParsedAST &AST, Position Pos, const format::FormatStyle &Style, const SymbolIndex *Index)
Get the hover information when hovering at Pos.
Definition Hover.cpp:1255
TEST(BackgroundQueueTest, Priority)
void parseDocumentation(llvm::StringRef Input, markup::Document &Output)
Definition Hover.cpp:1794
cppcoreguidelines::ProBoundsAvoidUncheckedContainerAccessCheck P
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Settings that express user/project preferences and control clangd behavior.
Definition Config.h:44
static clangd::Key< Config > Key
Context key which can be used to set the current Config.
Definition Config.h:48
@ Markdown
Treat comments as Markdown.
Definition Config.h:215
@ Doxygen
Treat comments as doxygen.
Definition Config.h:217
struct clang::clangd::Config::@124253042262101241326257264241307221112313102042 Hover
Configures hover feature.
bool ShowAKA
Whether hover show a.k.a type.
Definition Config.h:184
uint32_t MacroContentsLimit
Limit the number of characters returned when hovering a macro; 0 is no limit.
Definition Config.h:187
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
The class presents a C++ symbol, e.g.
Definition Symbol.h:39
ParsedAST build() const
Definition TestTU.cpp:115
std::string Filename
Definition TestTU.h:50
static TestTU withCode(llvm::StringRef Code)
Definition TestTU.h:36