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