5021 lines · cpp
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-exception6//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 namespace61 {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 // Field78 {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 field100 {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 // Bitfield119 {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 variable156 {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 type215 {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 instantiation227 {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 template238 {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 template266 {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 decl288 {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 lambdas309 {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 reference331 {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 decltype352 {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 variable374 {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 lambda396 {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 template421 {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 bindings463 {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 auto475 {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 auto487 {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 lambda507 {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 instantiation518 {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 template530 {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 parameter543 {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 reference579 {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 macro592 {R"cpp(593 #define MACRO594 [[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 macro603 {R"cpp(604 #define MACRO 41605 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 macro618 {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 macro632 {R"cpp(633 #define STRINGIFY_AUX(s) #s634 #define STRINGIFY(s) STRINGIFY_AUX(s)635 #define DECL_STR(NAME, VALUE) const char *v_##NAME = STRINGIFY(VALUE)636 #define FOO 41637 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 // constexprs651 {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 crash757 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_ns2784 } // b785 } // anon786 } // a787 } // in_ns788 } // ns789 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 primary816 template <typename T> class Foo {};817 // comment from specialization818 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 template829 // pattern.830 HI.Documentation = "comment from primary";831 }},832 {// Template Type Parameter833 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 Parameter846 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 Parameter859 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 {// Getter873 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 {// Setter889 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-ok973 )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 call1004 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 call1077 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 call1093 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 decl1192 R"cpp(1193 // error-ok1194 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-ok1208 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 decl1237 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 specialization1251 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 type1266 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 type1285 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 Template1301 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 Template1316 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 array1334 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 array1348 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 array1362 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 padding1380 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 a1407 // 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;1509 HoverInfo::PassType::PassMode PassBy;1510 bool Converted;1511 } Tests[] = {1512 // Integer tests1513 {"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 tests1523 {"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 tests1532 {"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 tests1537 {"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 hover1566 "decltype(au^to) x = 0;",1567 // FIXME: not supported yet1568 R"cpp(// Lambda auto parameter1569 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 expr1575 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 // literals1589 "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 variable1628 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 method1644 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(// Struct1661 namespace ns1 {1662 struct MyClass {};1663 } // namespace ns11664 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(// Class1676 namespace ns1 {1677 class MyClass {};1678 } // namespace ns11679 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(// Union1691 namespace ns1 {1692 union MyUnion { int x; int y; };1693 } // namespace ns11694 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 pointer1706 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 call1725 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(// Field1744 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 initialization1760 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 field1776 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 initializer1791 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 designator1806 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 is1819 // of struct type and omitted.1820 }},1821 {1822 R"cpp(// Field, field designator1823 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 call1838 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 call1856 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(// Typedef1873 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 definition1888 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(// Namespace1903 namespace ns {1904 struct Foo { static void bar(); };1905 } // namespace ns1906 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 namespace1916 namespace ns {1917 namespace {1918 int foo;1919 } // anonymous namespace1920 } // namespace ns1921 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 declaration1932 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 declarations1952 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(// Macro1964 #define MACRO 01965 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(// Macro1978 #define MACRO 01979 #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't1986 // expanded here1987 }},1988 {1989 R"cpp(// Macro1990 #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 to2005{2006 return 0;2007})cpp";2008 }},2009 {2010 R"cpp(// Forward class declaration2011 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 declaration2024 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 declaration2040 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(// Enumerator2056 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 enum2074 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 enum2093 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 variable2112 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 case2125 HI.Value = "10 (0xa)";2126 }},2127 {2128 R"cpp(// Global variable in namespace2129 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 bits2143 }},2144 {2145 R"cpp(// Field in anonymous struct2146 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 function2163 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 in2179 // case of instantiations.2180 }},2181 {2182 R"cpp(// Anonymous union2183 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 index2200 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 auto2216 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 auto2227 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 pointer2273 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 std2286 {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 auto2301 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 type2361 ^[[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 type2372 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 type2385 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 return2398 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 return2411 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 return2425 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 return2439 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 return2453 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 return2466 ^[[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 reference2478 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 reference2490 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 parenthesis2503 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 reference2515 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 call2527 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 type2570 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-ok2606 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 alias2618 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 alias2628 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 alias2640 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 declaration2652 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 type2664 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 parameter2676 template<[[a^uto]] T>2677 void func() {2678 }2679 )cpp",2680 [](HoverInfo &HI) {2681 // FIXME: not sure this is what we want, but this2682 // is what we currently get with getDeducedType2683 HI.Name = "auto";2684 HI.Kind = index::SymbolKind::TypeAlias;2685 HI.Definition = "/* not deduced */";2686 }},2687 {2688 R"cpp(// Undeduced decltype(auto) return type2689 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 decltype2743 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 decltype2754 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 decltype2766 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 decltype2777 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 printing2785 // 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 expr2793 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 expr2803 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 crash2829 @interface ObjC {2830 char [[da^ta]];2831 }@end2832 )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 MYObject2844 @end2845 @interface Interface2846 @property(retain) [[MYOb^ject]] *x;2847 @end2848 )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 MYObject2858 @end2859 @interface Interface2860 - (void)doWith:([[MYOb^ject]] *)object;2861 @end2862 )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 expr2871 // comment2872 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 class2886 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 class2901 namespace ns {2902 template <typename T> class Foo {};2903 template <>2904 struct Foo<int> {2905 Foo* bar() {2906 return [[thi^s]];2907 }2908 };2909 }2910 )cpp",2911 [](HoverInfo &HI) {2912 HI.Name = "this";2913 HI.Definition = "ns::Foo<int> *";2914 }},2915 {2916 R"cpp(// this expr for partial specialization struct2917 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 MYObject2934 @end2935 @interface MYObject (Private)2936 @property(nonatomic, assign) int privateField;2937 @end2938 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 MYProtocol2955 @property(nonatomic, assign) int prop1;2956 @end2957 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 MYProtocol2974 @end2975 @interface MYObject2976 @end2977 2978 @interface MYObject (Ext) <[[MYProt^ocol]]>2979 @end2980 )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 Foo2989 @end2990 2991 @implementation Foo(Private)2992 + (int)somePrivateMethod {2993 int [[res^ult]] = 2;2994 return result;2995 }2996 @end2997 )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 Foo3009 @end3010 3011 @implementation Foo3012 - (int)variadicArgMethod:(id)first, ... {3013 int [[res^ult]] = 0;3014 return result;3015 }3016 @end3017 )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 IFace3032 @property(nonatomic) MyRect frame;3033 @end3034 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 value3059 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 Foo3076 {3077 int x;3078 // Foo spaceship3079 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";3102 SymbolSlab::Builder Symbols;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 a3117 // 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 53166 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 decl3187 {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 13211 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 53273 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";3310 SymbolSlab::Builder Symbols;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 // doc3325 template <typename T> class X {};3326 // doc3327 template <typename T> void bar() {}3328 // doc3329 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 around3364 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 // doc13387 template <typename T> class $doc1^X {};3388 // doc23389 template <> class $doc2^X<int> {};3390 // doc33391 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 foo3446 3447Size: 10 bytes3448 3449documentation3450 3451template <typename T, typename C = bool> class Foo {})",3452 R"(### class3453 3454---3455```cpp3456template <typename T, typename C = bool> class Foo {}3457```3458 3459---3460### Brief3461 3462documentation3463 3464---3465### Template Parameters3466 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();3480 HoverInfo::Param P;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"(### function3503 3504---3505```cpp3506// In namespace ns3507ret_type foo(params) {}3508```3509 3510---3511### Parameters3512 3513- 3514- `type (aka can_type)`3515- `type foo (aka can_type)`3516- `type foo = default (aka can_type)`3517 3518---3519### Returns3520 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 foo3537 3538Type: type (aka can_type)3539 3540Value = value3541 3542Offset: 12 bytes3543 3544Size: 4 bytes (+4 bytes padding), alignment 4 bytes3545 3546// In test::Bar3547def)",3548 R"(### field3549 3550---3551```cpp3552// In test::Bar3553def3554```3555 3556---3557Type: `type (aka can_type)`3558 3559Value = `value`3560 3561Offset: 12 bytes3562 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 foo3579 3580Type: type (aka can_type)3581 3582Value = value3583 3584Offset: 4 bytes and 3 bits3585 3586Size: 25 bits (+4 bits padding), alignment 8 bytes3587 3588// In test::Bar3589def)",3590 R"(### field3591 3592---3593```cpp3594// In test::Bar3595def3596```3597 3598---3599Type: `type (aka can_type)`3600 3601Value = `value`3602 3603Offset: 4 bytes and 3 bits3604 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 foo3616 3617// In test::Bar3618public: def)",3619 R"(### field3620 3621---3622```cpp3623// In test::Bar3624public: def3625```)",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 method3640 3641→ size_t (aka unsigned long)3642 3643// In cls<int>3644protected: size_t method())",3645 R"(### instance-method3646 3647---3648```cpp3649// In cls<int>3650protected: size_t method()3651```3652 3653---3654### Returns3655 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 cls3676 3677Parameters:3678 3679- int a3680- int b = 53681 3682// In cls3683public: cls(int a, int b = 5))",3684 R"(### constructor3685 3686---3687```cpp3688// In cls3689public: cls(int a, int b = 5)3690```3691 3692---3693### Parameters3694 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 foo3707 3708// In namespace ns13709private: union foo {})",3710 R"(### union3711 3712---3713```cpp3714// In namespace ns13715private: 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 foo3733 3734Type: int3735 3736Value = 33737 3738Passed as arg_a3739 3740// In test::Bar3741int foo = 3)",3742 R"(### variable3743 3744---3745```cpp3746// In test::Bar3747int foo = 33748```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 foo3766 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 foo3788 3789Type: int3790 3791Value = 33792 3793Passed by reference as arg_a3794 3795// In test::Bar3796int foo = 3)",3797 R"(### variable3798 3799---3800```cpp3801// In test::Bar3802int foo = 33803```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 foo3827 3828Type: int3829 3830Value = 33831 3832Passed as arg_a (converted to alias_int)3833 3834// In test::Bar3835int foo = 3)",3836 R"(### variable3837 3838---3839```cpp3840// In test::Bar3841int foo = 33842```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_ONE3860 3861#define PLUS_ONE(X) (X+1)3862 3863// Expands to3864(1 + 1))",3865 R"(### macro3866 3867---3868```cpp3869#define PLUS_ONE(X) (X+1)3870 3871// Expands to3872(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 foo3890 3891Type: int3892 3893Value = 33894 3895Passed by const reference as arg_a (converted to int)3896 3897// In test::Bar3898int foo = 3)",3899 R"(### variable3900 3901---3902```cpp3903// In test::Bar3904int foo = 33905```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.h3921 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.h3934 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.h3947 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 doc3991 3992longer doc3993 3994---3995```cpp3996void foo()3997```)",3998 R"(### function3999 4000---4001```cpp4002void foo()4003```4004 4005---4006### Brief4007 4008brief doc4009 4010---4011### Details4012 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 doc4028 4029longer doc4030 4031---4032```cpp4033int foo()4034```)",4035 R"(### function4036 4037---4038```cpp4039int foo()4040```4041 4042---4043### Brief4044 4045brief doc4046 4047---4048### Returns4049 4050`int`4051 4052---4053### Details4054 4055longer doc)"},4056 {[](HoverInfo &HI) {4057 HI.Kind = index::SymbolKind::Function;4058 HI.Documentation = R"(@brief brief doc4059 4060longer doc4061@note this is a note4062 4063As you see, notes are "inlined".4064@warning this is a warning4065 4066As well as warnings4067@param a this is a param4068@return it returns something4069@retval 0 if successful4070@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 doc4089 4090longer doc 4091@note this is a note4092 4093As you see, notes are "inlined". 4094@warning this is a warning4095 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 failed4101 4102---4103```cpp4104int foo(int a)4105```)",4106 R"(### function4107 4108---4109```cpp4110int foo(int a)4111```4112 4113---4114### Brief4115 4116brief doc4117 4118---4119### Parameters4120 4121- `int a` - this is a param4122 4123---4124### Returns4125 4126`int` - it returns something4127 4128- `0` - if successful4129- `1` - if failed4130 4131---4132### Details4133 4134longer doc4135 4136**Note:** 4137this is a note4138 4139As you see, notes are "inlined".4140 4141**Warning:** 4142this is a warning4143 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 doc4168 4169longer doc 4170@param a this is a param 4171@param b does not exist 4172@return it returns something4173 4174---4175```cpp4176int foo(int a)4177```)",4178 R"(### function4179 4180---4181```cpp4182int foo(int a)4183```4184 4185---4186### Brief4187 4188brief doc4189 4190---4191### Parameters4192 4193- `int a` - this is a param4194 4195---4196### Returns4197 4198`int` - it returns something4199 4200---4201### Details4202 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 R"(@brief this is a typical use case4360@param x this is x4361\param y this is y4362@return something)",4363 R"(@brief this is a typical use case 4364@param x this is x 4365\\param y this is y 4366@return something)",4367 R"(@brief this is a typical use case 4368@param x this is x 4369\param y this is y 4370@return something)",4371 R"(@brief this is a typical use case4372@param x this is x4373\param y this is y4374@return something)",4375 }};4376 4377 for (const auto &C : Cases) {4378 markup::Document Output;4379 parseDocumentation(C.Documentation, Output);4380 4381 EXPECT_EQ(Output.asEscapedMarkdown(), C.ExpectedRenderEscapedMarkdown);4382 EXPECT_EQ(Output.asMarkdown(), C.ExpectedRenderMarkdown);4383 EXPECT_EQ(Output.asPlainText(), C.ExpectedRenderPlainText);4384 }4385}4386 4387// This is a separate test as headings don't create any differences in4388// plaintext mode.4389TEST(Hover, PresentHeadings) {4390 HoverInfo HI;4391 HI.Kind = index::SymbolKind::Variable;4392 HI.Name = "foo";4393 4394 EXPECT_EQ(HI.present(MarkupKind::Markdown), "### variable `foo`");4395}4396 4397// This is a separate test as rulers behave differently in markdown vs4398// plaintext.4399TEST(Hover, PresentRulers) {4400 HoverInfo HI;4401 HI.Kind = index::SymbolKind::Variable;4402 HI.Name = "foo";4403 HI.Value = "val";4404 HI.Definition = "def";4405 4406 llvm::StringRef ExpectedMarkdown = //4407 "### variable `foo`\n"4408 "\n"4409 "---\n"4410 "Value = `val`\n"4411 "\n"4412 "---\n"4413 "```cpp\n"4414 "def\n"4415 "```";4416 EXPECT_EQ(HI.present(MarkupKind::Markdown), ExpectedMarkdown);4417 4418 llvm::StringRef ExpectedDoxygenMarkdown = //4419 "### variable\n"4420 "\n"4421 "---\n"4422 "```cpp\n"4423 "def\n"4424 "```\n\n"4425 "---\n"4426 "Value = `val`";4427 Config Cfg;4428 Cfg.Hover.ShowAKA = true;4429 Cfg.Documentation.CommentFormat = Config::CommentFormatPolicy::Doxygen;4430 WithContextValue WithCfg(Config::Key, std::move(Cfg));4431 EXPECT_EQ(HI.present(MarkupKind::Markdown), ExpectedDoxygenMarkdown);4432 4433 llvm::StringRef ExpectedPlaintext = R"pt(variable foo4434 4435Value = val4436 4437def)pt";4438 EXPECT_EQ(HI.present(MarkupKind::PlainText), ExpectedPlaintext);4439}4440 4441TEST(Hover, SpaceshipTemplateNoCrash) {4442 Annotations T(R"cpp(4443 namespace std {4444 struct strong_ordering {4445 int n;4446 constexpr operator int() const { return n; }4447 static const strong_ordering equal, greater, less;4448 };4449 constexpr strong_ordering strong_ordering::equal = {0};4450 constexpr strong_ordering strong_ordering::greater = {1};4451 constexpr strong_ordering strong_ordering::less = {-1};4452 }4453 4454 template <typename T>4455 struct S {4456 // Foo bar baz4457 friend auto operator<=>(S, S) = default;4458 };4459 static_assert(S<void>() =^= S<void>());4460 )cpp");4461 4462 TestTU TU = TestTU::withCode(T.code());4463 TU.ExtraArgs.push_back("-std=c++20");4464 auto AST = TU.build();4465 auto HI = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);4466 EXPECT_EQ(HI->Documentation, "");4467}4468 4469TEST(Hover, ForwardStructNoCrash) {4470 Annotations T(R"cpp(4471 struct Foo;4472 int bar;4473 auto baz = (Fo^o*)&bar;4474 )cpp");4475 4476 TestTU TU = TestTU::withCode(T.code());4477 auto AST = TU.build();4478 auto HI = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);4479 ASSERT_TRUE(HI);4480 EXPECT_EQ(*HI->Value, "&bar");4481}4482 4483TEST(Hover, FunctionParameterDefaulValueNotEvaluatedOnInvalidDecls) {4484 struct {4485 const char *const Code;4486 const std::optional<std::string> HoverValue;4487 } Cases[] = {4488 {R"cpp(4489 // error-ok testing behavior on invalid decl4490 class Foo {};4491 void foo(Foo p^aram = nullptr);4492 )cpp",4493 std::nullopt},4494 {R"cpp(4495 class Foo {};4496 void foo(Foo *p^aram = nullptr);4497 )cpp",4498 "nullptr"},4499 };4500 4501 for (const auto &C : Cases) {4502 Annotations T(C.Code);4503 TestTU TU = TestTU::withCode(T.code());4504 auto AST = TU.build();4505 auto HI = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);4506 ASSERT_TRUE(HI);4507 ASSERT_EQ(HI->Value, C.HoverValue);4508 }4509}4510 4511TEST(Hover, DisableShowAKA) {4512 Annotations T(R"cpp(4513 using m_int = int;4514 m_int ^[[a]];4515 )cpp");4516 4517 Config Cfg;4518 Cfg.Hover.ShowAKA = false;4519 WithContextValue WithCfg(Config::Key, std::move(Cfg));4520 4521 TestTU TU = TestTU::withCode(T.code());4522 TU.ExtraArgs.push_back("-std=c++17");4523 auto AST = TU.build();4524 auto H = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);4525 4526 ASSERT_TRUE(H);4527 EXPECT_EQ(H->Type, HoverInfo::PrintedType("m_int"));4528}4529 4530TEST(Hover, HideBigInitializers) {4531 Annotations T(R"cpp(4532 #define A(x) x, x, x, x4533 #define B(x) A(A(A(A(x))))4534 int a^rr[] = {B(0)};4535 )cpp");4536 4537 TestTU TU = TestTU::withCode(T.code());4538 auto AST = TU.build();4539 auto H = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);4540 4541 ASSERT_TRUE(H);4542 EXPECT_EQ(H->Definition, "int arr[]");4543}4544 4545#if defined(__aarch64__)4546// FIXME: AARCH64 sanitizer buildbots are broken after 72142fbac4.4547#define PREDEFINEMACROS_TEST(x) DISABLED_##x4548#else4549#define PREDEFINEMACROS_TEST(x) x4550#endif4551 4552TEST(Hover, PREDEFINEMACROS_TEST(GlobalVarEnumeralCastNoCrash)) {4553 Annotations T(R"cpp(4554 using uintptr_t = __UINTPTR_TYPE__;4555 enum Test : uintptr_t {};4556 unsigned global_var;4557 void foo() {4558 Test v^al = static_cast<Test>(reinterpret_cast<uintptr_t>(&global_var));4559 }4560 )cpp");4561 4562 TestTU TU = TestTU::withCode(T.code());4563 TU.PredefineMacros = true;4564 auto AST = TU.build();4565 auto HI = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);4566 ASSERT_TRUE(HI);4567 EXPECT_EQ(*HI->Value, "&global_var");4568}4569 4570TEST(Hover, PREDEFINEMACROS_TEST(GlobalVarIntCastNoCrash)) {4571 Annotations T(R"cpp(4572 using uintptr_t = __UINTPTR_TYPE__;4573 unsigned global_var;4574 void foo() {4575 uintptr_t a^ddress = reinterpret_cast<uintptr_t>(&global_var);4576 }4577 )cpp");4578 4579 TestTU TU = TestTU::withCode(T.code());4580 TU.PredefineMacros = true;4581 auto AST = TU.build();4582 auto HI = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);4583 ASSERT_TRUE(HI);4584 EXPECT_EQ(*HI->Value, "&global_var");4585}4586 4587TEST(Hover, Typedefs) {4588 Annotations T(R"cpp(4589 template <bool X, typename T, typename F>4590 struct cond { using type = T; };4591 template <typename T, typename F>4592 struct cond<false, T, F> { using type = F; };4593 4594 template <bool X, typename T, typename F>4595 using type = typename cond<X, T, F>::type;4596 4597 void foo() {4598 using f^oo = type<true, int, double>;4599 }4600 )cpp");4601 4602 TestTU TU = TestTU::withCode(T.code());4603 auto AST = TU.build();4604 auto H = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);4605 4606 ASSERT_TRUE(H && H->Type);4607 EXPECT_EQ(H->Type->Type, "int");4608 EXPECT_EQ(H->Definition, "using foo = type<true, int, double>");4609}4610 4611TEST(Hover, EvaluateMacros) {4612 llvm::StringRef PredefinedCXX = R"cpp(4613#define X 424614#define SizeOf sizeof4615#define AlignOf alignof4616#define PLUS_TWO +24617#define TWO 24618 4619using u64 = unsigned long long;4620// calculate (a ** b) % p4621constexpr u64 pow_with_mod(u64 a, u64 b, u64 p) {4622 u64 ret = 1;4623 while (b) {4624 if (b & 1)4625 ret = (ret * a) % p;4626 a = (a * a) % p;4627 b >>= 1;4628 }4629 return ret;4630}4631#define last_n_digit(x, y, n) \4632 pow_with_mod(x, y, pow_with_mod(10, n, 2147483647))4633#define declare_struct(X, name, value) \4634 struct X { \4635 constexpr auto name() { return value; } \4636 }4637#define gnu_statement_expression(value) \4638 ({ \4639 declare_struct(Widget, getter, value); \4640 Widget().getter(); \4641 })4642#define define_lambda_begin(lambda, ...) \4643 [&](__VA_ARGS__) {4644#define define_lambda_end() }4645 4646#define left_bracket [4647#define right_bracket ]4648#define dg_left_bracket <:4649#define dg_right_bracket :>4650#define array_decl(type, name, size) type name left_bracket size right_bracket4651 )cpp";4652 4653 struct {4654 llvm::StringRef Code;4655 const std::function<void(std::optional<HoverInfo>, size_t /*Id*/)>4656 Validator;4657 } Cases[] = {4658 {4659 /*Code=*/R"cpp(4660 X^;4661 )cpp",4662 /*Validator=*/4663 [](std::optional<HoverInfo> HI, size_t) {4664 EXPECT_EQ(HI->Value, "42 (0x2a)");4665 EXPECT_EQ(HI->Type, HoverInfo::PrintedType("int"));4666 },4667 },4668 {4669 /*Code=*/R"cpp(4670 Size^Of(int);4671 )cpp",4672 /*Validator=*/4673 [](std::optional<HoverInfo> HI, size_t) {4674 EXPECT_TRUE(HI->Value);4675 EXPECT_TRUE(HI->Type);4676 // Don't validate type or value of `sizeof` and `alignof` as we're4677 // getting different values or desugared types on different4678 // platforms. Same as below.4679 },4680 },4681 {4682 /*Code=*/R"cpp(4683 struct Y {4684 int y;4685 double z;4686 };4687 Alig^nOf(Y);4688 )cpp",4689 /*Validator=*/4690 [](std::optional<HoverInfo> HI, size_t) {4691 EXPECT_TRUE(HI->Value);4692 EXPECT_TRUE(HI->Type);4693 },4694 },4695 {4696 /*Code=*/R"cpp(4697 // 2**32 == 42949672964698 last_n_di^git(2, 32, 6);4699 )cpp",4700 /*Validator=*/4701 [](std::optional<HoverInfo> HI, size_t) {4702 EXPECT_EQ(HI->Value, "967296 (0xec280)");4703 EXPECT_EQ(HI->Type, "u64");4704 },4705 },4706 {4707 /*Code=*/R"cpp(4708 gnu_statement_exp^ression(42);4709 )cpp",4710 /*Validator=*/4711 [](std::optional<HoverInfo> HI, size_t) {4712 EXPECT_EQ(HI->Value, "42 (0x2a)");4713 EXPECT_EQ(HI->Type, "int");4714 },4715 },4716 {4717 /*Code=*/R"cpp(4718 40 + PLU^S_TWO;4719 )cpp",4720 /*Validator=*/4721 [](std::optional<HoverInfo> HI, size_t) {4722 EXPECT_EQ(HI->Value, "2");4723 EXPECT_EQ(HI->Type, "int");4724 },4725 },4726 {4727 /*Code=*/R"cpp(4728 40 PLU^S_TWO;4729 )cpp",4730 /*Validator=*/4731 [](std::optional<HoverInfo> HI, size_t) {4732 EXPECT_FALSE(HI->Value) << HI->Value;4733 EXPECT_FALSE(HI->Type) << HI->Type;4734 },4735 },4736 {4737 /*Code=*/R"cpp(4738 40 + TW^O;4739 )cpp",4740 /*Validator=*/4741 [](std::optional<HoverInfo> HI, size_t) {4742 EXPECT_EQ(HI->Value, "2");4743 EXPECT_EQ(HI->Type, "int");4744 },4745 },4746 {4747 /*Code=*/R"cpp(4748 arra^y_decl(int, vector, 10);4749 vector left_b^racket 3 right_b^racket;4750 vector dg_le^ft_bracket 3 dg_righ^t_bracket;4751 )cpp",4752 /*Validator=*/4753 [](std::optional<HoverInfo> HI, size_t Id) {4754 switch (Id) {4755 case 0:4756 EXPECT_EQ(HI->Type, HoverInfo::PrintedType("int[10]"));4757 break;4758 case 1:4759 case 2:4760 case 3:4761 case 4:4762 EXPECT_FALSE(HI->Type) << HI->Type;4763 EXPECT_FALSE(HI->Value) << HI->Value;4764 break;4765 default:4766 ASSERT_TRUE(false) << "Unhandled id: " << Id;4767 }4768 },4769 },4770 {4771 /*Code=*/R"cpp(4772 constexpr auto value = define_lamb^da_begin(lambda, int, char)4773 // Check if the expansion range is right.4774 return ^last_n_digit(10, 3, 3)^;4775 define_lam^bda_end();4776 )cpp",4777 /*Validator=*/4778 [](std::optional<HoverInfo> HI, size_t Id) {4779 switch (Id) {4780 case 0:4781 EXPECT_FALSE(HI->Value);4782 EXPECT_EQ(HI->Type, HoverInfo::PrintedType("const (lambda)"));4783 break;4784 case 1:4785 EXPECT_EQ(HI->Value, "0");4786 EXPECT_EQ(HI->Type, HoverInfo::PrintedType("u64"));4787 break;4788 case 2:4789 EXPECT_FALSE(HI);4790 break;4791 case 3:4792 EXPECT_FALSE(HI->Type) << HI->Type;4793 EXPECT_FALSE(HI->Value) << HI->Value;4794 break;4795 default:4796 ASSERT_TRUE(false) << "Unhandled id: " << Id;4797 }4798 },4799 },4800 };4801 4802 Config Cfg;4803 Cfg.Hover.ShowAKA = false;4804 WithContextValue WithCfg(Config::Key, std::move(Cfg));4805 for (const auto &C : Cases) {4806 Annotations Code(4807 (PredefinedCXX + "void function() {\n" + C.Code + "}\n").str());4808 auto TU = TestTU::withCode(Code.code());4809 TU.ExtraArgs.push_back("-std=c++17");4810 auto AST = TU.build();4811 for (auto [Index, Position] : llvm::enumerate(Code.points())) {4812 C.Validator(getHover(AST, Position, format::getLLVMStyle(), nullptr),4813 Index);4814 }4815 }4816 4817 Annotations C(R"c(4818 #define alignof _Alignof4819 void foo() {4820 al^ignof(struct { int x; char y[10]; });4821 }4822 )c");4823 4824 auto TU = TestTU::withCode(C.code());4825 TU.Filename = "TestTU.c";4826 TU.ExtraArgs = {4827 "-std=c17",4828 };4829 auto AST = TU.build();4830 auto H = getHover(AST, C.point(), format::getLLVMStyle(), nullptr);4831 4832 ASSERT_TRUE(H);4833 EXPECT_TRUE(H->Value);4834 EXPECT_TRUE(H->Type);4835}4836 4837TEST(Hover, HoverMacroContentsLimit) {4838 const char *const Code =4839 R"cpp(4840 #define C(A) A##A // Concatenate4841 #define E(A) C(A) // Expand4842 #define Z0032 000000000000000000000000000000004843 #define Z0064 E(Z0032)4844 #define Z0128 E(Z0064)4845 #define Z0256 E(Z0128)4846 #define Z0512 E(Z0256)4847 #define Z1024 E(Z0512)4848 #define Z2048 E(Z1024)4849 #define Z4096 E(Z2048) // 4096 zeroes4850 int main() { return [[^Z4096]]; }4851 )cpp";4852 4853 struct {4854 uint32_t MacroContentsLimit;4855 const std::string ExpectedDefinition;4856 } Cases[] = {4857 // With a limit of 2048, the macro expansion should get dropped.4858 {2048, "#define Z4096 E(Z2048)"},4859 // With a limit of 8192, the macro expansion should be fully expanded.4860 {8192, std::string("#define Z4096 E(Z2048)\n\n") +4861 std::string("// Expands to\n") + std::string(4096, '0')},4862 };4863 for (const auto &Case : Cases) {4864 SCOPED_TRACE(Code);4865 4866 Annotations T(Code);4867 TestTU TU = TestTU::withCode(T.code());4868 auto AST = TU.build();4869 Config Cfg;4870 Cfg.Hover.MacroContentsLimit = Case.MacroContentsLimit;4871 WithContextValue WithCfg(Config::Key, std::move(Cfg));4872 auto H = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);4873 ASSERT_TRUE(H);4874 4875 EXPECT_EQ(H->Definition, Case.ExpectedDefinition);4876 }4877}4878 4879TEST(Hover, FunctionParameters) {4880 struct {4881 const char *const Code;4882 const std::function<void(HoverInfo &)> ExpectedBuilder;4883 std::string ExpectedRender;4884 } Cases[] = {4885 {R"cpp(/// Function doc4886 void foo(int [[^a]]);4887 )cpp",4888 [](HoverInfo &HI) {4889 HI.Name = "a";4890 HI.Kind = index::SymbolKind::Parameter;4891 HI.NamespaceScope = "";4892 HI.LocalScope = "foo::";4893 HI.Type = "int";4894 HI.Definition = "int a";4895 HI.Documentation = "";4896 },4897 "### param\n\n---\n```cpp\n// In foo\nint a\n```\n\n---\nType: `int`"},4898 {R"cpp(/// Function doc4899 /// @param a this is doc for a4900 void foo(int [[^a]]);4901 )cpp",4902 [](HoverInfo &HI) {4903 HI.Name = "a";4904 HI.Kind = index::SymbolKind::Parameter;4905 HI.NamespaceScope = "";4906 HI.LocalScope = "foo::";4907 HI.Type = "int";4908 HI.Definition = "int a";4909 HI.Documentation = "this is doc for a";4910 },4911 "### param\n\n---\n```cpp\n// In foo\nint a\n```\n\n---\nthis is doc "4912 "for a\n\n---\nType: `int`"},4913 {R"cpp(/// Function doc4914 /// @param b this is doc for b4915 void foo(int [[^a]], int b);4916 )cpp",4917 [](HoverInfo &HI) {4918 HI.Name = "a";4919 HI.Kind = index::SymbolKind::Parameter;4920 HI.NamespaceScope = "";4921 HI.LocalScope = "foo::";4922 HI.Type = "int";4923 HI.Definition = "int a";4924 HI.Documentation = "";4925 },4926 "### param\n\n---\n```cpp\n// In foo\nint a\n```\n\n---\nType: `int`"},4927 {R"cpp(/// Function doc4928 /// @param b this is doc for \p b4929 void foo(int a, int [[^b]]);4930 )cpp",4931 [](HoverInfo &HI) {4932 HI.Name = "b";4933 HI.Kind = index::SymbolKind::Parameter;4934 HI.NamespaceScope = "";4935 HI.LocalScope = "foo::";4936 HI.Type = "int";4937 HI.Definition = "int b";4938 HI.Documentation = "this is doc for \\p b";4939 },4940 "### param\n\n---\n```cpp\n// In foo\nint b\n```\n\n---\nthis is doc "4941 "for `b`\n\n---\nType: `int`"},4942 {R"cpp(/// Function doc4943 /// @param b this is doc for \p b4944 template <typename T>4945 void foo(T a, T [[^b]]);4946 )cpp",4947 [](HoverInfo &HI) {4948 HI.Name = "b";4949 HI.Kind = index::SymbolKind::Parameter;4950 HI.NamespaceScope = "";4951 HI.LocalScope = "foo::";4952 HI.Type = "T";4953 HI.Definition = "T b";4954 HI.Documentation = "this is doc for \\p b";4955 },4956 "### param\n\n---\n```cpp\n// In foo\nT b\n```\n\n---\nthis is doc for "4957 "`b`\n\n---\nType: `T`"},4958 {R"cpp(/// Function doc4959 /// @param b this is <b>doc</b> <html-tag attribute/> <another-html-tag attribute="value">for</another-html-tag> \p b4960 void foo(int a, int [[^b]]);4961 )cpp",4962 [](HoverInfo &HI) {4963 HI.Name = "b";4964 HI.Kind = index::SymbolKind::Parameter;4965 HI.NamespaceScope = "";4966 HI.LocalScope = "foo::";4967 HI.Type = "int";4968 HI.Definition = "int b";4969 HI.Documentation =4970 "this is <b>doc</b> <html-tag attribute/> <another-html-tag "4971 "attribute=\"value\">for</another-html-tag> \\p b";4972 },4973 "### param\n\n---\n```cpp\n// In foo\nint b\n```\n\n---\nthis is "4974 "\\<b>doc\\</b> \\<html-tag attribute/> \\<another-html-tag "4975 "attribute=\"value\">for\\</another-html-tag> `b`\n\n---\nType: `int`"},4976 };4977 4978 // Create a tiny index, so tests above can verify documentation is fetched.4979 Symbol IndexSym = func("indexSymbol");4980 IndexSym.Documentation = "comment from index";4981 SymbolSlab::Builder Symbols;4982 Symbols.insert(IndexSym);4983 auto Index =4984 MemIndex::build(std::move(Symbols).build(), RefSlab(), RelationSlab());4985 4986 for (const auto &Case : Cases) {4987 SCOPED_TRACE(Case.Code);4988 4989 Annotations T(Case.Code);4990 TestTU TU = TestTU::withCode(T.code());4991 auto AST = TU.build();4992 Config Cfg;4993 Cfg.Hover.ShowAKA = true;4994 Cfg.Documentation.CommentFormat = Config::CommentFormatPolicy::Doxygen;4995 WithContextValue WithCfg(Config::Key, std::move(Cfg));4996 auto H = getHover(AST, T.point(), format::getLLVMStyle(), Index.get());4997 ASSERT_TRUE(H);4998 HoverInfo Expected;4999 Expected.SymRange = T.range();5000 Case.ExpectedBuilder(Expected);5001 5002 EXPECT_EQ(H->present(MarkupKind::Markdown), Case.ExpectedRender);5003 EXPECT_EQ(H->NamespaceScope, Expected.NamespaceScope);5004 EXPECT_EQ(H->LocalScope, Expected.LocalScope);5005 EXPECT_EQ(H->Name, Expected.Name);5006 EXPECT_EQ(H->Kind, Expected.Kind);5007 EXPECT_EQ(H->Documentation, Expected.Documentation);5008 EXPECT_EQ(H->Definition, Expected.Definition);5009 EXPECT_EQ(H->Type, Expected.Type);5010 EXPECT_EQ(H->ReturnType, Expected.ReturnType);5011 EXPECT_EQ(H->Parameters, Expected.Parameters);5012 EXPECT_EQ(H->TemplateParameters, Expected.TemplateParameters);5013 EXPECT_EQ(H->SymRange, Expected.SymRange);5014 EXPECT_EQ(H->Value, Expected.Value);5015 }5016}5017 5018} // namespace5019} // namespace clangd5020} // namespace clang5021