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