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