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 };
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### Brief
3461
3462documentation
3463
3464---
3465### Template Parameters
3466
3467- `typename T`
3468- `typename C = bool`
3469
3470---
3471Size: 10 bytes)",
3472 },
3473 {
3474 [](HoverInfo &HI) {
3475 HI.Kind = index::SymbolKind::Function;
3476 HI.Name = "foo";
3477 HI.Type = {"type", "c_type"};
3478 HI.ReturnType = {"ret_type", "can_ret_type"};
3479 HI.Parameters.emplace();
3481 HI.Parameters->push_back(P);
3482 P.Type = {"type", "can_type"};
3483 HI.Parameters->push_back(P);
3484 P.Name = "foo";
3485 HI.Parameters->push_back(P);
3486 P.Default = "default";
3487 HI.Parameters->push_back(P);
3488 HI.NamespaceScope = "ns::";
3489 HI.Definition = "ret_type foo(params) {}";
3490 },
3491 "function foo\n"
3492 "\n"
3493 "→ ret_type (aka can_ret_type)\n\n"
3494 "Parameters:\n\n"
3495 "- \n"
3496 "- type (aka can_type)\n"
3497 "- type foo (aka can_type)\n"
3498 "- type foo = default (aka can_type)\n"
3499 "\n"
3500 "// In namespace ns\n"
3501 "ret_type foo(params) {}",
3502 R"(### function
3503
3504---
3505```cpp
3506// In namespace ns
3507ret_type foo(params) {}
3508```
3509
3510---
3511### Parameters
3512
3513-
3514- `type (aka can_type)`
3515- `type foo (aka can_type)`
3516- `type foo = default (aka can_type)`
3517
3518---
3519### Returns
3520
3521`ret_type (aka can_ret_type)`)",
3522 },
3523 {
3524 [](HoverInfo &HI) {
3525 HI.Kind = index::SymbolKind::Field;
3526 HI.LocalScope = "test::Bar::";
3527 HI.Value = "value";
3528 HI.Name = "foo";
3529 HI.Type = {"type", "can_type"};
3530 HI.Definition = "def";
3531 HI.Size = 32;
3532 HI.Offset = 96;
3533 HI.Padding = 32;
3534 HI.Align = 32;
3535 },
3536 R"(field foo
3537
3538Type: type (aka can_type)
3539
3540Value = value
3541
3542Offset: 12 bytes
3543
3544Size: 4 bytes (+4 bytes padding), alignment 4 bytes
3545
3546// In test::Bar
3547def)",
3548 R"(### field
3549
3550---
3551```cpp
3552// In test::Bar
3553def
3554```
3555
3556---
3557Type: `type (aka can_type)`
3558
3559Value = `value`
3560
3561Offset: 12 bytes
3562
3563Size: 4 bytes (+4 bytes padding), alignment 4 bytes)",
3564 },
3565 {
3566 [](HoverInfo &HI) {
3567 HI.Kind = index::SymbolKind::Field;
3568 HI.LocalScope = "test::Bar::";
3569 HI.Value = "value";
3570 HI.Name = "foo";
3571 HI.Type = {"type", "can_type"};
3572 HI.Definition = "def";
3573 HI.Size = 25;
3574 HI.Offset = 35;
3575 HI.Padding = 4;
3576 HI.Align = 64;
3577 },
3578 R"(field foo
3579
3580Type: type (aka can_type)
3581
3582Value = value
3583
3584Offset: 4 bytes and 3 bits
3585
3586Size: 25 bits (+4 bits padding), alignment 8 bytes
3587
3588// In test::Bar
3589def)",
3590 R"(### field
3591
3592---
3593```cpp
3594// In test::Bar
3595def
3596```
3597
3598---
3599Type: `type (aka can_type)`
3600
3601Value = `value`
3602
3603Offset: 4 bytes and 3 bits
3604
3605Size: 25 bits (+4 bits padding), alignment 8 bytes)",
3606 },
3607 {
3608 [](HoverInfo &HI) {
3609 HI.Kind = index::SymbolKind::Field;
3610 HI.AccessSpecifier = "public";
3611 HI.Name = "foo";
3612 HI.LocalScope = "test::Bar::";
3613 HI.Definition = "def";
3614 },
3615 R"(field foo
3616
3617// In test::Bar
3618public: def)",
3619 R"(### field
3620
3621---
3622```cpp
3623// In test::Bar
3624public: def
3625```)",
3626 },
3627 {
3628 [](HoverInfo &HI) {
3629 HI.Definition = "size_t method()";
3630 HI.AccessSpecifier = "protected";
3631 HI.Kind = index::SymbolKind::InstanceMethod;
3632 HI.NamespaceScope = "";
3633 HI.LocalScope = "cls<int>::";
3634 HI.Name = "method";
3635 HI.Parameters.emplace();
3636 HI.ReturnType = {"size_t", "unsigned long"};
3637 HI.Type = {"size_t ()", "unsigned long ()"};
3638 },
3639 R"(instance-method method
3640
3641→ size_t (aka unsigned long)
3642
3643// In cls<int>
3644protected: size_t method())",
3645 R"(### instance-method
3646
3647---
3648```cpp
3649// In cls<int>
3650protected: size_t method()
3651```
3652
3653---
3654### Returns
3655
3656`size_t (aka unsigned long)`)",
3657 },
3658 {
3659 [](HoverInfo &HI) {
3660 HI.Definition = "cls(int a, int b = 5)";
3661 HI.AccessSpecifier = "public";
3662 HI.Kind = index::SymbolKind::Constructor;
3663 HI.NamespaceScope = "";
3664 HI.LocalScope = "cls";
3665 HI.Name = "cls";
3666 HI.Parameters.emplace();
3667 HI.Parameters->emplace_back();
3668 HI.Parameters->back().Type = "int";
3669 HI.Parameters->back().Name = "a";
3670 HI.Parameters->emplace_back();
3671 HI.Parameters->back().Type = "int";
3672 HI.Parameters->back().Name = "b";
3673 HI.Parameters->back().Default = "5";
3674 },
3675 R"(constructor cls
3676
3677Parameters:
3678
3679- int a
3680- int b = 5
3681
3682// In cls
3683public: cls(int a, int b = 5))",
3684 R"(### constructor
3685
3686---
3687```cpp
3688// In cls
3689public: cls(int a, int b = 5)
3690```
3691
3692---
3693### Parameters
3694
3695- `int a`
3696- `int b = 5`)",
3697 },
3698 {
3699 [](HoverInfo &HI) {
3700 HI.Kind = index::SymbolKind::Union;
3701 HI.AccessSpecifier = "private";
3702 HI.Name = "foo";
3703 HI.NamespaceScope = "ns1::";
3704 HI.Definition = "union foo {}";
3705 },
3706 R"(union foo
3707
3708// In namespace ns1
3709private: union foo {})",
3710 R"(### union
3711
3712---
3713```cpp
3714// In namespace ns1
3715private: union foo {}
3716```)",
3717 },
3718 {
3719 [](HoverInfo &HI) {
3720 HI.Kind = index::SymbolKind::Variable;
3721 HI.Name = "foo";
3722 HI.Definition = "int foo = 3";
3723 HI.LocalScope = "test::Bar::";
3724 HI.Value = "3";
3725 HI.Type = "int";
3726 HI.CalleeArgInfo.emplace();
3727 HI.CalleeArgInfo->Name = "arg_a";
3728 HI.CalleeArgInfo->Type = "int";
3729 HI.CalleeArgInfo->Default = "7";
3730 HI.CallPassType = HoverInfo::PassType{PassMode::Value, false};
3731 },
3732 R"(variable foo
3733
3734Type: int
3735
3736Value = 3
3737
3738Passed as arg_a
3739
3740// In test::Bar
3741int foo = 3)",
3742 R"(### variable
3743
3744---
3745```cpp
3746// In test::Bar
3747int foo = 3
3748```
3749
3750---
3751Type: `int`
3752
3753Value = `3`
3754
3755Passed as arg_a)",
3756 },
3757 {
3758 [](HoverInfo &HI) {
3759 HI.Kind = index::SymbolKind::Variable;
3760 HI.Name = "foo";
3761 HI.CalleeArgInfo.emplace();
3762 HI.CalleeArgInfo->Type = "int";
3763 HI.CallPassType = HoverInfo::PassType{PassMode::Value, false};
3764 },
3765 R"(variable foo
3766
3767Passed by value)",
3768 R"(### variable `foo`
3769
3770---
3771Passed by value)",
3772 },
3773 {
3774 [](HoverInfo &HI) {
3775 HI.Kind = index::SymbolKind::Variable;
3776 HI.Name = "foo";
3777 HI.Definition = "int foo = 3";
3778 HI.LocalScope = "test::Bar::";
3779 HI.Value = "3";
3780 HI.Type = "int";
3781 HI.CalleeArgInfo.emplace();
3782 HI.CalleeArgInfo->Name = "arg_a";
3783 HI.CalleeArgInfo->Type = "int";
3784 HI.CalleeArgInfo->Default = "7";
3785 HI.CallPassType = HoverInfo::PassType{PassMode::Ref, false};
3786 },
3787 R"(variable foo
3788
3789Type: int
3790
3791Value = 3
3792
3793Passed by reference as arg_a
3794
3795// In test::Bar
3796int foo = 3)",
3797 R"(### variable
3798
3799---
3800```cpp
3801// In test::Bar
3802int foo = 3
3803```
3804
3805---
3806Type: `int`
3807
3808Value = `3`
3809
3810Passed by reference as arg_a)",
3811 },
3812 {
3813 [](HoverInfo &HI) {
3814 HI.Kind = index::SymbolKind::Variable;
3815 HI.Name = "foo";
3816 HI.Definition = "int foo = 3";
3817 HI.LocalScope = "test::Bar::";
3818 HI.Value = "3";
3819 HI.Type = "int";
3820 HI.CalleeArgInfo.emplace();
3821 HI.CalleeArgInfo->Name = "arg_a";
3822 HI.CalleeArgInfo->Type = {"alias_int", "int"};
3823 HI.CalleeArgInfo->Default = "7";
3824 HI.CallPassType = HoverInfo::PassType{PassMode::Value, true};
3825 },
3826 R"(variable foo
3827
3828Type: int
3829
3830Value = 3
3831
3832Passed as arg_a (converted to alias_int)
3833
3834// In test::Bar
3835int foo = 3)",
3836 R"(### variable
3837
3838---
3839```cpp
3840// In test::Bar
3841int foo = 3
3842```
3843
3844---
3845Type: `int`
3846
3847Value = `3`
3848
3849Passed as arg_a (converted to alias_int))",
3850 },
3851 {
3852 [](HoverInfo &HI) {
3853 HI.Kind = index::SymbolKind::Macro;
3854 HI.Name = "PLUS_ONE";
3855 HI.Definition = "#define PLUS_ONE(X) (X+1)\n\n"
3856 "// Expands to\n"
3857 "(1 + 1)";
3858 },
3859 R"(macro PLUS_ONE
3860
3861#define PLUS_ONE(X) (X+1)
3862
3863// Expands to
3864(1 + 1))",
3865 R"(### macro
3866
3867---
3868```cpp
3869#define PLUS_ONE(X) (X+1)
3870
3871// Expands to
3872(1 + 1)
3873```)",
3874 },
3875 {
3876 [](HoverInfo &HI) {
3877 HI.Kind = index::SymbolKind::Variable;
3878 HI.Name = "foo";
3879 HI.Definition = "int foo = 3";
3880 HI.LocalScope = "test::Bar::";
3881 HI.Value = "3";
3882 HI.Type = "int";
3883 HI.CalleeArgInfo.emplace();
3884 HI.CalleeArgInfo->Name = "arg_a";
3885 HI.CalleeArgInfo->Type = "int";
3886 HI.CalleeArgInfo->Default = "7";
3887 HI.CallPassType = HoverInfo::PassType{PassMode::ConstRef, true};
3888 },
3889 R"(variable foo
3890
3891Type: int
3892
3893Value = 3
3894
3895Passed by const reference as arg_a (converted to int)
3896
3897// In test::Bar
3898int foo = 3)",
3899 R"(### variable
3900
3901---
3902```cpp
3903// In test::Bar
3904int foo = 3
3905```
3906
3907---
3908Type: `int`
3909
3910Value = `3`
3911
3912Passed by const reference as arg_a (converted to int))",
3913 },
3914 {
3915 [](HoverInfo &HI) {
3916 HI.Name = "stdio.h";
3917 HI.Definition = "/usr/include/stdio.h";
3918 HI.Kind = index::SymbolKind::IncludeDirective;
3919 },
3920 R"(stdio.h
3921
3922/usr/include/stdio.h)",
3923 R"(### `stdio.h`
3924
3925`/usr/include/stdio.h`)",
3926 },
3927 {
3928 [](HoverInfo &HI) {
3929 HI.Name = "foo.h";
3930 HI.UsedSymbolNames = {"Foo", "Bar", "Bar"};
3931 HI.Kind = index::SymbolKind::IncludeDirective;
3932 },
3933 R"(foo.h
3934
3935provides Foo, Bar, Bar)",
3936 R"(### `foo.h`
3937
3938---
3939provides `Foo`, `Bar`, `Bar`)",
3940 },
3941 {[](HoverInfo &HI) {
3942 HI.Name = "foo.h";
3943 HI.UsedSymbolNames = {"Foo", "Bar", "Baz", "Foobar", "Qux", "Quux"};
3944 HI.Kind = index::SymbolKind::IncludeDirective;
3945 },
3946 R"(foo.h
3947
3948provides Foo, Bar, Baz, Foobar, Qux and 1 more)",
3949 R"(### `foo.h`
3950
3951---
3952provides `Foo`, `Bar`, `Baz`, `Foobar`, `Qux` and 1 more)"}};
3953
3954 for (const auto &C : Cases) {
3955 HoverInfo HI;
3956 C.Builder(HI);
3957 Config Cfg;
3958 Cfg.Hover.ShowAKA = true;
3959 Cfg.Documentation.CommentFormat = Config::CommentFormatPolicy::Markdown;
3960 WithContextValue WithCfg(Config::Key, std::move(Cfg));
3961 EXPECT_EQ(HI.present(MarkupKind::PlainText), C.ExpectedMarkdownRender);
3962 }
3963 for (const auto &C : Cases) {
3964 HoverInfo HI;
3965 C.Builder(HI);
3966 Config Cfg;
3967 Cfg.Hover.ShowAKA = true;
3968 Cfg.Documentation.CommentFormat = Config::CommentFormatPolicy::Doxygen;
3969 WithContextValue WithCfg(Config::Key, std::move(Cfg));
3970 EXPECT_EQ(HI.present(MarkupKind::Markdown), C.ExpectedDoxygenRender);
3971 }
3972}
3973
3974TEST(Hover, PresentDocumentation) {
3975 struct {
3976 const std::function<void(HoverInfo &)> Builder;
3977 llvm::StringRef ExpectedMarkdownRender;
3978 llvm::StringRef ExpectedDoxygenRender;
3979 } Cases[] = {
3980 {[](HoverInfo &HI) {
3981 HI.Kind = index::SymbolKind::Function;
3982 HI.Documentation = "@brief brief doc\n\n"
3983 "longer doc";
3984 HI.Definition = "void foo()";
3985 HI.Name = "foo";
3986 },
3987 R"(### function `foo`
3988
3989---
3990@brief brief doc
3991
3992longer doc
3993
3994---
3995```cpp
3996void foo()
3997```)",
3998 R"(### function
3999
4000---
4001```cpp
4002void foo()
4003```
4004
4005---
4006### Brief
4007
4008brief doc
4009
4010---
4011### Details
4012
4013longer doc)"},
4014 {[](HoverInfo &HI) {
4015 HI.Kind = index::SymbolKind::Function;
4016 HI.Documentation = "@brief brief doc\n\n"
4017 "longer doc";
4018 HI.Definition = "int foo()";
4019 HI.ReturnType = "int";
4020 HI.Name = "foo";
4021 },
4022 R"(### function `foo`
4023
4024---
4025→ `int`
4026
4027@brief brief doc
4028
4029longer doc
4030
4031---
4032```cpp
4033int foo()
4034```)",
4035 R"(### function
4036
4037---
4038```cpp
4039int foo()
4040```
4041
4042---
4043### Brief
4044
4045brief doc
4046
4047---
4048### Returns
4049
4050`int`
4051
4052---
4053### Details
4054
4055longer doc)"},
4056 {[](HoverInfo &HI) {
4057 HI.Kind = index::SymbolKind::Function;
4058 HI.Documentation = R"(@brief brief doc
4059
4060longer doc
4061@note this is a note
4062
4063As you see, notes are "inlined".
4064@warning this is a warning
4065
4066As well as warnings
4067@param a this is a param
4068@return it returns something
4069@retval 0 if successful
4070@retval 1 if failed)";
4071 HI.Definition = "int foo(int a)";
4072 HI.ReturnType = "int";
4073 HI.Name = "foo";
4074 HI.Parameters.emplace();
4075 HI.Parameters->emplace_back();
4076 HI.Parameters->back().Type = "int";
4077 HI.Parameters->back().Name = "a";
4078 },
4079 R"(### function `foo`
4080
4081---
4082→ `int`
4083
4084Parameters:
4085
4086- `int a`
4087
4088@brief brief doc
4089
4090longer doc
4091@note this is a note
4092
4093As you see, notes are "inlined".
4094@warning this is a warning
4095
4096As well as warnings
4097@param a this is a param
4098@return it returns something
4099@retval 0 if successful
4100@retval 1 if failed
4101
4102---
4103```cpp
4104int foo(int a)
4105```)",
4106 R"(### function
4107
4108---
4109```cpp
4110int foo(int a)
4111```
4112
4113---
4114### Brief
4115
4116brief doc
4117
4118---
4119### Parameters
4120
4121- `int a` - this is a param
4122
4123---
4124### Returns
4125
4126`int` - it returns something
4127
4128- `0` - if successful
4129- `1` - if failed
4130
4131---
4132### Details
4133
4134longer doc
4135
4136**Note:**
4137this is a note
4138
4139As you see, notes are "inlined".
4140
4141**Warning:**
4142this is a warning
4143
4144As well as warnings)"},
4145 {[](HoverInfo &HI) {
4146 HI.Kind = index::SymbolKind::Function;
4147 HI.Documentation = "@brief brief doc\n\n"
4148 "longer doc\n@param a this is a param\n@param b "
4149 "does not exist\n@return it returns something";
4150 HI.Definition = "int foo(int a)";
4151 HI.ReturnType = "int";
4152 HI.Name = "foo";
4153 HI.Parameters.emplace();
4154 HI.Parameters->emplace_back();
4155 HI.Parameters->back().Type = "int";
4156 HI.Parameters->back().Name = "a";
4157 },
4158 R"(### function `foo`
4159
4160---
4161→ `int`
4162
4163Parameters:
4164
4165- `int a`
4166
4167@brief brief doc
4168
4169longer doc
4170@param a this is a param
4171@param b does not exist
4172@return it returns something
4173
4174---
4175```cpp
4176int foo(int a)
4177```)",
4178 R"(### function
4179
4180---
4181```cpp
4182int foo(int a)
4183```
4184
4185---
4186### Brief
4187
4188brief doc
4189
4190---
4191### Parameters
4192
4193- `int a` - this is a param
4194
4195---
4196### Returns
4197
4198`int` - it returns something
4199
4200---
4201### Details
4202
4203longer doc)"},
4204 };
4205
4206 for (const auto &C : Cases) {
4207 HoverInfo HI;
4208 C.Builder(HI);
4209 Config Cfg;
4210 Cfg.Hover.ShowAKA = true;
4211 Cfg.Documentation.CommentFormat = Config::CommentFormatPolicy::Markdown;
4212 WithContextValue WithCfg(Config::Key, std::move(Cfg));
4213 EXPECT_EQ(HI.present(MarkupKind::Markdown), C.ExpectedMarkdownRender);
4214 }
4215 for (const auto &C : Cases) {
4216 HoverInfo HI;
4217 C.Builder(HI);
4218 Config Cfg;
4219 Cfg.Hover.ShowAKA = true;
4220 Cfg.Documentation.CommentFormat = Config::CommentFormatPolicy::Doxygen;
4221 WithContextValue WithCfg(Config::Key, std::move(Cfg));
4222 EXPECT_EQ(HI.present(MarkupKind::Markdown), C.ExpectedDoxygenRender);
4223 }
4224}
4225
4226TEST(Hover, ParseDocumentation) {
4227 struct Case {
4228 llvm::StringRef Documentation;
4229 llvm::StringRef ExpectedRenderEscapedMarkdown;
4230 llvm::StringRef ExpectedRenderMarkdown;
4231 llvm::StringRef ExpectedRenderPlainText;
4232 } Cases[] = {{
4233 " \n foo\nbar",
4234 "foo\nbar",
4235 "foo\nbar",
4236 "foo bar",
4237 },
4238 {
4239 "foo\nbar \n ",
4240 "foo\nbar",
4241 "foo\nbar",
4242 "foo bar",
4243 },
4244 {
4245 "foo \nbar",
4246 "foo \nbar",
4247 "foo \nbar",
4248 "foo\nbar",
4249 },
4250 {
4251 "foo \nbar",
4252 "foo \nbar",
4253 "foo \nbar",
4254 "foo\nbar",
4255 },
4256 {
4257 "foo\n\n\nbar",
4258 "foo\n\nbar",
4259 "foo\n\nbar",
4260 "foo\n\nbar",
4261 },
4262 {
4263 "foo\n\n\n\tbar",
4264 "foo\n\n\tbar",
4265 "foo\n\n\tbar",
4266 "foo\n\nbar",
4267 },
4268 {
4269 "foo\n\n\n bar",
4270 "foo\n\n bar",
4271 "foo\n\n bar",
4272 "foo\n\nbar",
4273 },
4274 {
4275 "foo\n\n\n bar",
4276 "foo\n\n bar",
4277 "foo\n\n bar",
4278 "foo\n\nbar",
4279 },
4280 {
4281 "foo\n\n\n bar",
4282 "foo\n\n bar",
4283 "foo\n\n bar",
4284 "foo\n\nbar",
4285 },
4286 {
4287 "foo\n\n\n\nbar",
4288 "foo\n\nbar",
4289 "foo\n\nbar",
4290 "foo\n\nbar",
4291 },
4292 {
4293 "foo\n\n\n\n\tbar",
4294 "foo\n\n\tbar",
4295 "foo\n\n\tbar",
4296 "foo\n\nbar",
4297 },
4298 {
4299 "foo\n\n\n\n bar",
4300 "foo\n\n bar",
4301 "foo\n\n bar",
4302 "foo\n\nbar",
4303 },
4304 {
4305 "foo\n\n\n\n bar",
4306 "foo\n\n bar",
4307 "foo\n\n bar",
4308 "foo\n\nbar",
4309 },
4310 {
4311 "foo\n\n\n\n bar",
4312 "foo\n\n bar",
4313 "foo\n\n bar",
4314 "foo\n\nbar",
4315 },
4316 {
4317 "foo.\nbar",
4318 "foo.\nbar",
4319 "foo.\nbar",
4320 "foo.\nbar",
4321 },
4322 {
4323 "foo. \nbar",
4324 "foo. \nbar",
4325 "foo. \nbar",
4326 "foo.\nbar",
4327 },
4328 {
4329 "foo\n*bar",
4330 "foo\n\\*bar",
4331 "foo\n*bar",
4332 "foo\n*bar",
4333 },
4334 {
4335 "foo\nbar",
4336 "foo\nbar",
4337 "foo\nbar",
4338 "foo bar",
4339 },
4340 {
4341 "Tests primality of `p`.",
4342 "Tests primality of `p`.",
4343 "Tests primality of `p`.",
4344 "Tests primality of `p`.",
4345 },
4346 {
4347 "'`' should not occur in `Code`",
4348 "'\\`' should not occur in `Code`",
4349 "'`' should not occur in `Code`",
4350 "'`' should not occur in `Code`",
4351 },
4352 {
4353 "`not\nparsed`",
4354 "\\`not\nparsed\\`",
4355 "`not\nparsed`",
4356 "`not parsed`",
4357 }};
4358
4359 for (const auto &C : Cases) {
4360 markup::Document Output;
4361 parseDocumentation(C.Documentation, Output);
4362
4363 EXPECT_EQ(Output.asEscapedMarkdown(), C.ExpectedRenderEscapedMarkdown);
4364 EXPECT_EQ(Output.asMarkdown(), C.ExpectedRenderMarkdown);
4365 EXPECT_EQ(Output.asPlainText(), C.ExpectedRenderPlainText);
4366 }
4367}
4368
4369// This is a separate test as headings don't create any differences in
4370// plaintext mode.
4371TEST(Hover, PresentHeadings) {
4372 HoverInfo HI;
4373 HI.Kind = index::SymbolKind::Variable;
4374 HI.Name = "foo";
4375
4376 EXPECT_EQ(HI.present(MarkupKind::Markdown), "### variable `foo`");
4377}
4378
4379// This is a separate test as rulers behave differently in markdown vs
4380// plaintext.
4381TEST(Hover, PresentRulers) {
4382 HoverInfo HI;
4383 HI.Kind = index::SymbolKind::Variable;
4384 HI.Name = "foo";
4385 HI.Value = "val";
4386 HI.Definition = "def";
4387
4388 llvm::StringRef ExpectedMarkdown = //
4389 "### variable `foo`\n"
4390 "\n"
4391 "---\n"
4392 "Value = `val`\n"
4393 "\n"
4394 "---\n"
4395 "```cpp\n"
4396 "def\n"
4397 "```";
4398 EXPECT_EQ(HI.present(MarkupKind::Markdown), ExpectedMarkdown);
4399
4400 llvm::StringRef ExpectedDoxygenMarkdown = //
4401 "### variable\n"
4402 "\n"
4403 "---\n"
4404 "```cpp\n"
4405 "def\n"
4406 "```\n\n"
4407 "---\n"
4408 "Value = `val`";
4409 Config Cfg;
4410 Cfg.Hover.ShowAKA = true;
4411 Cfg.Documentation.CommentFormat = Config::CommentFormatPolicy::Doxygen;
4412 WithContextValue WithCfg(Config::Key, std::move(Cfg));
4413 EXPECT_EQ(HI.present(MarkupKind::Markdown), ExpectedDoxygenMarkdown);
4414
4415 llvm::StringRef ExpectedPlaintext = R"pt(variable foo
4416
4417Value = val
4418
4419def)pt";
4420 EXPECT_EQ(HI.present(MarkupKind::PlainText), ExpectedPlaintext);
4421}
4422
4423TEST(Hover, SpaceshipTemplateNoCrash) {
4424 Annotations T(R"cpp(
4425 namespace std {
4426 struct strong_ordering {
4427 int n;
4428 constexpr operator int() const { return n; }
4429 static const strong_ordering equal, greater, less;
4430 };
4431 constexpr strong_ordering strong_ordering::equal = {0};
4432 constexpr strong_ordering strong_ordering::greater = {1};
4433 constexpr strong_ordering strong_ordering::less = {-1};
4434 }
4435
4436 template <typename T>
4437 struct S {
4438 // Foo bar baz
4439 friend auto operator<=>(S, S) = default;
4440 };
4441 static_assert(S<void>() =^= S<void>());
4442 )cpp");
4443
4444 TestTU TU = TestTU::withCode(T.code());
4445 TU.ExtraArgs.push_back("-std=c++20");
4446 auto AST = TU.build();
4447 auto HI = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
4448 EXPECT_EQ(HI->Documentation, "");
4449}
4450
4451TEST(Hover, ForwardStructNoCrash) {
4452 Annotations T(R"cpp(
4453 struct Foo;
4454 int bar;
4455 auto baz = (Fo^o*)&bar;
4456 )cpp");
4457
4458 TestTU TU = TestTU::withCode(T.code());
4459 auto AST = TU.build();
4460 auto HI = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
4461 ASSERT_TRUE(HI);
4462 EXPECT_EQ(*HI->Value, "&bar");
4463}
4464
4465TEST(Hover, FunctionParameterDefaulValueNotEvaluatedOnInvalidDecls) {
4466 struct {
4467 const char *const Code;
4468 const std::optional<std::string> HoverValue;
4469 } Cases[] = {
4470 {R"cpp(
4471 // error-ok testing behavior on invalid decl
4472 class Foo {};
4473 void foo(Foo p^aram = nullptr);
4474 )cpp",
4475 std::nullopt},
4476 {R"cpp(
4477 class Foo {};
4478 void foo(Foo *p^aram = nullptr);
4479 )cpp",
4480 "nullptr"},
4481 };
4482
4483 for (const auto &C : Cases) {
4484 Annotations T(C.Code);
4485 TestTU TU = TestTU::withCode(T.code());
4486 auto AST = TU.build();
4487 auto HI = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
4488 ASSERT_TRUE(HI);
4489 ASSERT_EQ(HI->Value, C.HoverValue);
4490 }
4491}
4492
4493TEST(Hover, DisableShowAKA) {
4494 Annotations T(R"cpp(
4495 using m_int = int;
4496 m_int ^[[a]];
4497 )cpp");
4498
4499 Config Cfg;
4500 Cfg.Hover.ShowAKA = false;
4501 WithContextValue WithCfg(Config::Key, std::move(Cfg));
4502
4503 TestTU TU = TestTU::withCode(T.code());
4504 TU.ExtraArgs.push_back("-std=c++17");
4505 auto AST = TU.build();
4506 auto H = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
4507
4508 ASSERT_TRUE(H);
4509 EXPECT_EQ(H->Type, HoverInfo::PrintedType("m_int"));
4510}
4511
4512TEST(Hover, HideBigInitializers) {
4513 Annotations T(R"cpp(
4514 #define A(x) x, x, x, x
4515 #define B(x) A(A(A(A(x))))
4516 int a^rr[] = {B(0)};
4517 )cpp");
4518
4519 TestTU TU = TestTU::withCode(T.code());
4520 auto AST = TU.build();
4521 auto H = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
4522
4523 ASSERT_TRUE(H);
4524 EXPECT_EQ(H->Definition, "int arr[]");
4525}
4526
4527#if defined(__aarch64__)
4528// FIXME: AARCH64 sanitizer buildbots are broken after 72142fbac4.
4529#define PREDEFINEMACROS_TEST(x) DISABLED_##x
4530#else
4531#define PREDEFINEMACROS_TEST(x) x
4532#endif
4533
4534TEST(Hover, PREDEFINEMACROS_TEST(GlobalVarEnumeralCastNoCrash)) {
4535 Annotations T(R"cpp(
4536 using uintptr_t = __UINTPTR_TYPE__;
4537 enum Test : uintptr_t {};
4538 unsigned global_var;
4539 void foo() {
4540 Test v^al = static_cast<Test>(reinterpret_cast<uintptr_t>(&global_var));
4541 }
4542 )cpp");
4543
4544 TestTU TU = TestTU::withCode(T.code());
4545 TU.PredefineMacros = true;
4546 auto AST = TU.build();
4547 auto HI = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
4548 ASSERT_TRUE(HI);
4549 EXPECT_EQ(*HI->Value, "&global_var");
4550}
4551
4552TEST(Hover, PREDEFINEMACROS_TEST(GlobalVarIntCastNoCrash)) {
4553 Annotations T(R"cpp(
4554 using uintptr_t = __UINTPTR_TYPE__;
4555 unsigned global_var;
4556 void foo() {
4557 uintptr_t a^ddress = reinterpret_cast<uintptr_t>(&global_var);
4558 }
4559 )cpp");
4560
4561 TestTU TU = TestTU::withCode(T.code());
4562 TU.PredefineMacros = true;
4563 auto AST = TU.build();
4564 auto HI = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
4565 ASSERT_TRUE(HI);
4566 EXPECT_EQ(*HI->Value, "&global_var");
4567}
4568
4569TEST(Hover, Typedefs) {
4570 Annotations T(R"cpp(
4571 template <bool X, typename T, typename F>
4572 struct cond { using type = T; };
4573 template <typename T, typename F>
4574 struct cond<false, T, F> { using type = F; };
4575
4576 template <bool X, typename T, typename F>
4577 using type = typename cond<X, T, F>::type;
4578
4579 void foo() {
4580 using f^oo = type<true, int, double>;
4581 }
4582 )cpp");
4583
4584 TestTU TU = TestTU::withCode(T.code());
4585 auto AST = TU.build();
4586 auto H = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
4587
4588 ASSERT_TRUE(H && H->Type);
4589 EXPECT_EQ(H->Type->Type, "int");
4590 EXPECT_EQ(H->Definition, "using foo = type<true, int, double>");
4591}
4592
4593TEST(Hover, EvaluateMacros) {
4594 llvm::StringRef PredefinedCXX = R"cpp(
4595#define X 42
4596#define SizeOf sizeof
4597#define AlignOf alignof
4598#define PLUS_TWO +2
4599#define TWO 2
4600
4601using u64 = unsigned long long;
4602// calculate (a ** b) % p
4603constexpr u64 pow_with_mod(u64 a, u64 b, u64 p) {
4604 u64 ret = 1;
4605 while (b) {
4606 if (b & 1)
4607 ret = (ret * a) % p;
4608 a = (a * a) % p;
4609 b >>= 1;
4610 }
4611 return ret;
4612}
4613#define last_n_digit(x, y, n) \
4614 pow_with_mod(x, y, pow_with_mod(10, n, 2147483647))
4615#define declare_struct(X, name, value) \
4616 struct X { \
4617 constexpr auto name() { return value; } \
4618 }
4619#define gnu_statement_expression(value) \
4620 ({ \
4621 declare_struct(Widget, getter, value); \
4622 Widget().getter(); \
4623 })
4624#define define_lambda_begin(lambda, ...) \
4625 [&](__VA_ARGS__) {
4626#define define_lambda_end() }
4627
4628#define left_bracket [
4629#define right_bracket ]
4630#define dg_left_bracket <:
4631#define dg_right_bracket :>
4632#define array_decl(type, name, size) type name left_bracket size right_bracket
4633 )cpp";
4634
4635 struct {
4636 llvm::StringRef Code;
4637 const std::function<void(std::optional<HoverInfo>, size_t /*Id*/)>
4638 Validator;
4639 } Cases[] = {
4640 {
4641 /*Code=*/R"cpp(
4642 X^;
4643 )cpp",
4644 /*Validator=*/
4645 [](std::optional<HoverInfo> HI, size_t) {
4646 EXPECT_EQ(HI->Value, "42 (0x2a)");
4647 EXPECT_EQ(HI->Type, HoverInfo::PrintedType("int"));
4648 },
4649 },
4650 {
4651 /*Code=*/R"cpp(
4652 Size^Of(int);
4653 )cpp",
4654 /*Validator=*/
4655 [](std::optional<HoverInfo> HI, size_t) {
4656 EXPECT_TRUE(HI->Value);
4657 EXPECT_TRUE(HI->Type);
4658 // Don't validate type or value of `sizeof` and `alignof` as we're
4659 // getting different values or desugared types on different
4660 // platforms. Same as below.
4661 },
4662 },
4663 {
4664 /*Code=*/R"cpp(
4665 struct Y {
4666 int y;
4667 double z;
4668 };
4669 Alig^nOf(Y);
4670 )cpp",
4671 /*Validator=*/
4672 [](std::optional<HoverInfo> HI, size_t) {
4673 EXPECT_TRUE(HI->Value);
4674 EXPECT_TRUE(HI->Type);
4675 },
4676 },
4677 {
4678 /*Code=*/R"cpp(
4679 // 2**32 == 4294967296
4680 last_n_di^git(2, 32, 6);
4681 )cpp",
4682 /*Validator=*/
4683 [](std::optional<HoverInfo> HI, size_t) {
4684 EXPECT_EQ(HI->Value, "967296 (0xec280)");
4685 EXPECT_EQ(HI->Type, "u64");
4686 },
4687 },
4688 {
4689 /*Code=*/R"cpp(
4690 gnu_statement_exp^ression(42);
4691 )cpp",
4692 /*Validator=*/
4693 [](std::optional<HoverInfo> HI, size_t) {
4694 EXPECT_EQ(HI->Value, "42 (0x2a)");
4695 EXPECT_EQ(HI->Type, "int");
4696 },
4697 },
4698 {
4699 /*Code=*/R"cpp(
4700 40 + PLU^S_TWO;
4701 )cpp",
4702 /*Validator=*/
4703 [](std::optional<HoverInfo> HI, size_t) {
4704 EXPECT_EQ(HI->Value, "2");
4705 EXPECT_EQ(HI->Type, "int");
4706 },
4707 },
4708 {
4709 /*Code=*/R"cpp(
4710 40 PLU^S_TWO;
4711 )cpp",
4712 /*Validator=*/
4713 [](std::optional<HoverInfo> HI, size_t) {
4714 EXPECT_FALSE(HI->Value) << HI->Value;
4715 EXPECT_FALSE(HI->Type) << HI->Type;
4716 },
4717 },
4718 {
4719 /*Code=*/R"cpp(
4720 40 + TW^O;
4721 )cpp",
4722 /*Validator=*/
4723 [](std::optional<HoverInfo> HI, size_t) {
4724 EXPECT_EQ(HI->Value, "2");
4725 EXPECT_EQ(HI->Type, "int");
4726 },
4727 },
4728 {
4729 /*Code=*/R"cpp(
4730 arra^y_decl(int, vector, 10);
4731 vector left_b^racket 3 right_b^racket;
4732 vector dg_le^ft_bracket 3 dg_righ^t_bracket;
4733 )cpp",
4734 /*Validator=*/
4735 [](std::optional<HoverInfo> HI, size_t Id) {
4736 switch (Id) {
4737 case 0:
4738 EXPECT_EQ(HI->Type, HoverInfo::PrintedType("int[10]"));
4739 break;
4740 case 1:
4741 case 2:
4742 case 3:
4743 case 4:
4744 EXPECT_FALSE(HI->Type) << HI->Type;
4745 EXPECT_FALSE(HI->Value) << HI->Value;
4746 break;
4747 default:
4748 ASSERT_TRUE(false) << "Unhandled id: " << Id;
4749 }
4750 },
4751 },
4752 {
4753 /*Code=*/R"cpp(
4754 constexpr auto value = define_lamb^da_begin(lambda, int, char)
4755 // Check if the expansion range is right.
4756 return ^last_n_digit(10, 3, 3)^;
4757 define_lam^bda_end();
4758 )cpp",
4759 /*Validator=*/
4760 [](std::optional<HoverInfo> HI, size_t Id) {
4761 switch (Id) {
4762 case 0:
4763 EXPECT_FALSE(HI->Value);
4764 EXPECT_EQ(HI->Type, HoverInfo::PrintedType("const (lambda)"));
4765 break;
4766 case 1:
4767 EXPECT_EQ(HI->Value, "0");
4768 EXPECT_EQ(HI->Type, HoverInfo::PrintedType("u64"));
4769 break;
4770 case 2:
4771 EXPECT_FALSE(HI);
4772 break;
4773 case 3:
4774 EXPECT_FALSE(HI->Type) << HI->Type;
4775 EXPECT_FALSE(HI->Value) << HI->Value;
4776 break;
4777 default:
4778 ASSERT_TRUE(false) << "Unhandled id: " << Id;
4779 }
4780 },
4781 },
4782 };
4783
4784 Config Cfg;
4785 Cfg.Hover.ShowAKA = false;
4786 WithContextValue WithCfg(Config::Key, std::move(Cfg));
4787 for (const auto &C : Cases) {
4788 Annotations Code(
4789 (PredefinedCXX + "void function() {\n" + C.Code + "}\n").str());
4790 auto TU = TestTU::withCode(Code.code());
4791 TU.ExtraArgs.push_back("-std=c++17");
4792 auto AST = TU.build();
4793 for (auto [Index, Position] : llvm::enumerate(Code.points())) {
4794 C.Validator(getHover(AST, Position, format::getLLVMStyle(), nullptr),
4795 Index);
4796 }
4797 }
4798
4799 Annotations C(R"c(
4800 #define alignof _Alignof
4801 void foo() {
4802 al^ignof(struct { int x; char y[10]; });
4803 }
4804 )c");
4805
4806 auto TU = TestTU::withCode(C.code());
4807 TU.Filename = "TestTU.c";
4808 TU.ExtraArgs = {
4809 "-std=c17",
4810 };
4811 auto AST = TU.build();
4812 auto H = getHover(AST, C.point(), format::getLLVMStyle(), nullptr);
4813
4814 ASSERT_TRUE(H);
4815 EXPECT_TRUE(H->Value);
4816 EXPECT_TRUE(H->Type);
4817}
4818
4819TEST(Hover, HoverMacroContentsLimit) {
4820 const char *const Code =
4821 R"cpp(
4822 #define C(A) A##A // Concatenate
4823 #define E(A) C(A) // Expand
4824 #define Z0032 00000000000000000000000000000000
4825 #define Z0064 E(Z0032)
4826 #define Z0128 E(Z0064)
4827 #define Z0256 E(Z0128)
4828 #define Z0512 E(Z0256)
4829 #define Z1024 E(Z0512)
4830 #define Z2048 E(Z1024)
4831 #define Z4096 E(Z2048) // 4096 zeroes
4832 int main() { return [[^Z4096]]; }
4833 )cpp";
4834
4835 struct {
4836 uint32_t MacroContentsLimit;
4837 const std::string ExpectedDefinition;
4838 } Cases[] = {
4839 // With a limit of 2048, the macro expansion should get dropped.
4840 {2048, "#define Z4096 E(Z2048)"},
4841 // With a limit of 8192, the macro expansion should be fully expanded.
4842 {8192, std::string("#define Z4096 E(Z2048)\n\n") +
4843 std::string("// Expands to\n") + std::string(4096, '0')},
4844 };
4845 for (const auto &Case : Cases) {
4846 SCOPED_TRACE(Code);
4847
4848 Annotations T(Code);
4849 TestTU TU = TestTU::withCode(T.code());
4850 auto AST = TU.build();
4851 Config Cfg;
4852 Cfg.Hover.MacroContentsLimit = Case.MacroContentsLimit;
4853 WithContextValue WithCfg(Config::Key, std::move(Cfg));
4854 auto H = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
4855 ASSERT_TRUE(H);
4856
4857 EXPECT_EQ(H->Definition, Case.ExpectedDefinition);
4858 }
4859}
4860
4861TEST(Hover, FunctionParameters) {
4862 struct {
4863 const char *const Code;
4864 const std::function<void(HoverInfo &)> ExpectedBuilder;
4865 std::string ExpectedRender;
4866 } Cases[] = {
4867 {R"cpp(/// Function doc
4868 void foo(int [[^a]]);
4869 )cpp",
4870 [](HoverInfo &HI) {
4871 HI.Name = "a";
4872 HI.Kind = index::SymbolKind::Parameter;
4873 HI.NamespaceScope = "";
4874 HI.LocalScope = "foo::";
4875 HI.Type = "int";
4876 HI.Definition = "int a";
4877 HI.Documentation = "";
4878 },
4879 "### param\n\n---\n```cpp\n// In foo\nint a\n```\n\n---\nType: `int`"},
4880 {R"cpp(/// Function doc
4881 /// @param a this is doc for a
4882 void foo(int [[^a]]);
4883 )cpp",
4884 [](HoverInfo &HI) {
4885 HI.Name = "a";
4886 HI.Kind = index::SymbolKind::Parameter;
4887 HI.NamespaceScope = "";
4888 HI.LocalScope = "foo::";
4889 HI.Type = "int";
4890 HI.Definition = "int a";
4891 HI.Documentation = "this is doc for a";
4892 },
4893 "### param\n\n---\n```cpp\n// In foo\nint a\n```\n\n---\nthis is doc "
4894 "for a\n\n---\nType: `int`"},
4895 {R"cpp(/// Function doc
4896 /// @param b this is doc for b
4897 void foo(int [[^a]], int b);
4898 )cpp",
4899 [](HoverInfo &HI) {
4900 HI.Name = "a";
4901 HI.Kind = index::SymbolKind::Parameter;
4902 HI.NamespaceScope = "";
4903 HI.LocalScope = "foo::";
4904 HI.Type = "int";
4905 HI.Definition = "int a";
4906 HI.Documentation = "";
4907 },
4908 "### param\n\n---\n```cpp\n// In foo\nint a\n```\n\n---\nType: `int`"},
4909 {R"cpp(/// Function doc
4910 /// @param b this is doc for \p b
4911 void foo(int a, int [[^b]]);
4912 )cpp",
4913 [](HoverInfo &HI) {
4914 HI.Name = "b";
4915 HI.Kind = index::SymbolKind::Parameter;
4916 HI.NamespaceScope = "";
4917 HI.LocalScope = "foo::";
4918 HI.Type = "int";
4919 HI.Definition = "int b";
4920 HI.Documentation = "this is doc for \\p b";
4921 },
4922 "### param\n\n---\n```cpp\n// In foo\nint b\n```\n\n---\nthis is doc "
4923 "for `b`\n\n---\nType: `int`"},
4924 {R"cpp(/// Function doc
4925 /// @param b this is doc for \p b
4926 template <typename T>
4927 void foo(T a, T [[^b]]);
4928 )cpp",
4929 [](HoverInfo &HI) {
4930 HI.Name = "b";
4931 HI.Kind = index::SymbolKind::Parameter;
4932 HI.NamespaceScope = "";
4933 HI.LocalScope = "foo::";
4934 HI.Type = "T";
4935 HI.Definition = "T b";
4936 HI.Documentation = "this is doc for \\p b";
4937 },
4938 "### param\n\n---\n```cpp\n// In foo\nT b\n```\n\n---\nthis is doc for "
4939 "`b`\n\n---\nType: `T`"},
4940 {R"cpp(/// Function doc
4941 /// @param b this is <b>doc</b> <html-tag attribute/> <another-html-tag attribute="value">for</another-html-tag> \p b
4942 void foo(int a, int [[^b]]);
4943 )cpp",
4944 [](HoverInfo &HI) {
4945 HI.Name = "b";
4946 HI.Kind = index::SymbolKind::Parameter;
4947 HI.NamespaceScope = "";
4948 HI.LocalScope = "foo::";
4949 HI.Type = "int";
4950 HI.Definition = "int b";
4951 HI.Documentation =
4952 "this is <b>doc</b> <html-tag attribute/> <another-html-tag "
4953 "attribute=\"value\">for</another-html-tag> \\p b";
4954 },
4955 "### param\n\n---\n```cpp\n// In foo\nint b\n```\n\n---\nthis is "
4956 "\\<b>doc\\</b> \\<html-tag attribute/> \\<another-html-tag "
4957 "attribute=\"value\">for\\</another-html-tag> `b`\n\n---\nType: `int`"},
4958 };
4959
4960 // Create a tiny index, so tests above can verify documentation is fetched.
4961 Symbol IndexSym = func("indexSymbol");
4962 IndexSym.Documentation = "comment from index";
4964 Symbols.insert(IndexSym);
4965 auto Index =
4966 MemIndex::build(std::move(Symbols).build(), RefSlab(), RelationSlab());
4967
4968 for (const auto &Case : Cases) {
4969 SCOPED_TRACE(Case.Code);
4970
4971 Annotations T(Case.Code);
4972 TestTU TU = TestTU::withCode(T.code());
4973 auto AST = TU.build();
4974 Config Cfg;
4975 Cfg.Hover.ShowAKA = true;
4976 Cfg.Documentation.CommentFormat = Config::CommentFormatPolicy::Doxygen;
4977 WithContextValue WithCfg(Config::Key, std::move(Cfg));
4978 auto H = getHover(AST, T.point(), format::getLLVMStyle(), Index.get());
4979 ASSERT_TRUE(H);
4980 HoverInfo Expected;
4981 Expected.SymRange = T.range();
4982 Case.ExpectedBuilder(Expected);
4983
4984 EXPECT_EQ(H->present(MarkupKind::Markdown), Case.ExpectedRender);
4985 EXPECT_EQ(H->NamespaceScope, Expected.NamespaceScope);
4986 EXPECT_EQ(H->LocalScope, Expected.LocalScope);
4987 EXPECT_EQ(H->Name, Expected.Name);
4988 EXPECT_EQ(H->Kind, Expected.Kind);
4989 EXPECT_EQ(H->Documentation, Expected.Documentation);
4990 EXPECT_EQ(H->Definition, Expected.Definition);
4991 EXPECT_EQ(H->Type, Expected.Type);
4992 EXPECT_EQ(H->ReturnType, Expected.ReturnType);
4993 EXPECT_EQ(H->Parameters, Expected.Parameters);
4994 EXPECT_EQ(H->TemplateParameters, Expected.TemplateParameters);
4995 EXPECT_EQ(H->SymRange, Expected.SymRange);
4996 EXPECT_EQ(H->Value, Expected.Value);
4997 }
4998}
4999
5000} // namespace
5001} // namespace clangd
5002} // 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:1791
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