brintos

brintos / llvm-project-archived public Read only

0
0
Text · 63.2 KiB · feb4404 Raw
2402 lines · cpp
1//===-- InlayHintTests.cpp  -------------------------------*- C++ -*-------===//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#include "Annotations.h"9#include "Config.h"10#include "InlayHints.h"11#include "Protocol.h"12#include "TestTU.h"13#include "TestWorkspace.h"14#include "XRefs.h"15#include "support/Context.h"16#include "llvm/ADT/StringRef.h"17#include "llvm/Support/ScopedPrinter.h"18#include "llvm/Support/raw_ostream.h"19#include "gmock/gmock.h"20#include "gtest/gtest.h"21#include <optional>22#include <string>23#include <utility>24#include <vector>25 26namespace clang {27namespace clangd {28 29llvm::raw_ostream &operator<<(llvm::raw_ostream &Stream,30                              const InlayHint &Hint) {31  return Stream << Hint.joinLabels() << "@" << Hint.range;32}33 34namespace {35 36using ::testing::ElementsAre;37using ::testing::IsEmpty;38 39constexpr InlayHintOptions DefaultOptsForTests{2};40 41std::vector<InlayHint> hintsOfKind(ParsedAST &AST, InlayHintKind Kind,42                                   InlayHintOptions Opts) {43  std::vector<InlayHint> Result;44  for (auto &Hint : inlayHints(AST, /*RestrictRange=*/std::nullopt, Opts)) {45    if (Hint.kind == Kind)46      Result.push_back(Hint);47  }48  return Result;49}50 51enum HintSide { Left, Right };52 53struct ExpectedHint {54  std::string Label;55  std::string RangeName;56  HintSide Side = Left;57 58  friend llvm::raw_ostream &operator<<(llvm::raw_ostream &Stream,59                                       const ExpectedHint &Hint) {60    return Stream << Hint.Label << "@$" << Hint.RangeName;61  }62};63 64MATCHER_P2(HintMatcher, Expected, Code, llvm::to_string(Expected)) {65  llvm::StringRef ExpectedView(Expected.Label);66  std::string ResultLabel = arg.joinLabels();67  if (ResultLabel != ExpectedView.trim(" ") ||68      arg.paddingLeft != ExpectedView.starts_with(" ") ||69      arg.paddingRight != ExpectedView.ends_with(" ")) {70    *result_listener << "label is '" << ResultLabel << "'";71    return false;72  }73  if (arg.range != Code.range(Expected.RangeName)) {74    *result_listener << "range is " << llvm::to_string(arg.range) << " but $"75                     << Expected.RangeName << " is "76                     << llvm::to_string(Code.range(Expected.RangeName));77    return false;78  }79  return true;80}81 82MATCHER_P(labelIs, Label, "") { return arg.joinLabels() == Label; }83 84Config noHintsConfig() {85  Config C;86  C.InlayHints.Parameters = false;87  C.InlayHints.DeducedTypes = false;88  C.InlayHints.Designators = false;89  C.InlayHints.BlockEnd = false;90  C.InlayHints.DefaultArguments = false;91  return C;92}93 94template <typename... ExpectedHints>95void assertHintsWithHeader(InlayHintKind Kind, llvm::StringRef AnnotatedSource,96                           llvm::StringRef HeaderContent, InlayHintOptions Opts,97                           ExpectedHints... Expected) {98  Annotations Source(AnnotatedSource);99  TestTU TU = TestTU::withCode(Source.code());100  TU.ExtraArgs.push_back("-std=c++23");101  TU.HeaderCode = HeaderContent;102  auto AST = TU.build();103 104  EXPECT_THAT(hintsOfKind(AST, Kind, Opts),105              ElementsAre(HintMatcher(Expected, Source)...));106  // Sneak in a cross-cutting check that hints are disabled by config.107  // We'll hit an assertion failure if addInlayHint still gets called.108  WithContextValue WithCfg(Config::Key, noHintsConfig());109  EXPECT_THAT(inlayHints(AST, std::nullopt, Opts), IsEmpty());110}111 112template <typename... ExpectedHints>113void assertHints(InlayHintKind Kind, llvm::StringRef AnnotatedSource,114                 InlayHintOptions Opts, ExpectedHints... Expected) {115  return assertHintsWithHeader(Kind, AnnotatedSource, "", Opts,116                               std::move(Expected)...);117}118 119// Hack to allow expression-statements operating on parameter packs in C++14.120template <typename... T> void ignore(T &&...) {}121 122template <typename... ExpectedHints>123void assertParameterHints(llvm::StringRef AnnotatedSource,124                          ExpectedHints... Expected) {125  ignore(Expected.Side = Left...);126  assertHints(InlayHintKind::Parameter, AnnotatedSource, DefaultOptsForTests,127              Expected...);128}129 130template <typename... ExpectedHints>131void assertTypeHints(llvm::StringRef AnnotatedSource,132                     ExpectedHints... Expected) {133  ignore(Expected.Side = Right...);134  assertHints(InlayHintKind::Type, AnnotatedSource, DefaultOptsForTests,135              Expected...);136}137 138template <typename... ExpectedHints>139void assertDesignatorHints(llvm::StringRef AnnotatedSource,140                           ExpectedHints... Expected) {141  Config Cfg;142  Cfg.InlayHints.Designators = true;143  WithContextValue WithCfg(Config::Key, std::move(Cfg));144  assertHints(InlayHintKind::Designator, AnnotatedSource, DefaultOptsForTests,145              Expected...);146}147 148template <typename... ExpectedHints>149void assertBlockEndHintsWithOpts(llvm::StringRef AnnotatedSource,150                                 InlayHintOptions Opts,151                                 ExpectedHints... Expected) {152  Config Cfg;153  Cfg.InlayHints.BlockEnd = true;154  WithContextValue WithCfg(Config::Key, std::move(Cfg));155  assertHints(InlayHintKind::BlockEnd, AnnotatedSource, Opts, Expected...);156}157 158template <typename... ExpectedHints>159void assertBlockEndHints(llvm::StringRef AnnotatedSource,160                         ExpectedHints... Expected) {161  assertBlockEndHintsWithOpts(AnnotatedSource, DefaultOptsForTests,162                              Expected...);163}164 165TEST(ParameterHints, Smoke) {166  assertParameterHints(R"cpp(167    void foo(int param);168    void bar() {169      foo($param[[42]]);170    }171  )cpp",172                       ExpectedHint{"param: ", "param"});173}174 175TEST(ParameterHints, NoName) {176  // No hint for anonymous parameter.177  assertParameterHints(R"cpp(178    void foo(int);179    void bar() {180      foo(42);181    }182  )cpp");183}184 185TEST(ParameterHints, NoNameConstReference) {186  // No hint for anonymous const l-value ref parameter.187  assertParameterHints(R"cpp(188    void foo(const int&);189    void bar() {190      foo(42);191    }192  )cpp");193}194 195TEST(ParameterHints, NoNameReference) {196  // Reference hint for anonymous l-value ref parameter.197  assertParameterHints(R"cpp(198    void foo(int&);199    void bar() {200      int i;201      foo($param[[i]]);202    }203  )cpp",204                       ExpectedHint{"&: ", "param"});205}206 207TEST(ParameterHints, NoNameRValueReference) {208  // No reference hint for anonymous r-value ref parameter.209  assertParameterHints(R"cpp(210    void foo(int&&);211    void bar() {212      foo(42);213    }214  )cpp");215}216 217TEST(ParameterHints, NoNameVariadicDeclaration) {218  // No hint for anonymous variadic parameter219  assertParameterHints(R"cpp(220    template <typename... Args>221    void foo(Args&& ...);222    void bar() {223      foo(42);224    }225  )cpp");226}227 228TEST(ParameterHints, NoNameVariadicForwarded) {229  // No hint for anonymous variadic parameter230  // This prototype of std::forward is sufficient for clang to recognize it231  assertParameterHints(R"cpp(232    namespace std { template <typename T> T&& forward(T&); }233    void foo(int);234    template <typename... Args>235    void bar(Args&&... args) { return foo(std::forward<Args>(args)...); }236    void baz() {237      bar(42);238    }239  )cpp");240}241 242TEST(ParameterHints, NoNameVariadicPlain) {243  // No hint for anonymous variadic parameter244  assertParameterHints(R"cpp(245    void foo(int);246    template <typename... Args>247    void bar(Args&&... args) { return foo(args...); }248    void baz() {249      bar(42);250    }251  )cpp");252}253 254TEST(ParameterHints, NameInDefinition) {255  // Parameter name picked up from definition if necessary.256  assertParameterHints(R"cpp(257    void foo(int);258    void bar() {259      foo($param[[42]]);260    }261    void foo(int param) {};262  )cpp",263                       ExpectedHint{"param: ", "param"});264}265 266TEST(ParameterHints, NamePartiallyInDefinition) {267  // Parameter name picked up from definition if necessary.268  assertParameterHints(R"cpp(269    void foo(int, int b);270    void bar() {271      foo($param1[[42]], $param2[[42]]);272    }273    void foo(int a, int) {};274  )cpp",275                       ExpectedHint{"a: ", "param1"},276                       ExpectedHint{"b: ", "param2"});277}278 279TEST(ParameterHints, NameInDefinitionVariadic) {280  // Parameter name picked up from definition in a resolved forwarded parameter.281  assertParameterHints(R"cpp(282    void foo(int, int);283    template <typename... Args>284    void bar(Args... args) {285      foo(args...);286    }287    void baz() {288      bar($param1[[42]], $param2[[42]]);289    }290    void foo(int a, int b) {};291  )cpp",292                       ExpectedHint{"a: ", "param1"},293                       ExpectedHint{"b: ", "param2"});294}295 296TEST(ParameterHints, NameMismatch) {297  // Prefer name from declaration.298  assertParameterHints(R"cpp(299    void foo(int good);300    void bar() {301      foo($good[[42]]);302    }303    void foo(int bad) {};304  )cpp",305                       ExpectedHint{"good: ", "good"});306}307 308TEST(ParameterHints, NameConstReference) {309  // Only name hint for const l-value ref parameter.310  assertParameterHints(R"cpp(311    void foo(const int& param);312    void bar() {313      foo($param[[42]]);314    }315  )cpp",316                       ExpectedHint{"param: ", "param"});317}318 319TEST(ParameterHints, NameTypeAliasConstReference) {320  // Only name hint for const l-value ref parameter via type alias.321  assertParameterHints(R"cpp(322    using alias = const int&;323    void foo(alias param);324    void bar() {325      int i;326      foo($param[[i]]);327    }328  )cpp",329                       ExpectedHint{"param: ", "param"});330}331 332TEST(ParameterHints, NameReference) {333  // Reference and name hint for l-value ref parameter.334  assertParameterHints(R"cpp(335    void foo(int& param);336    void bar() {337      int i;338      foo($param[[i]]);339    }340  )cpp",341                       ExpectedHint{"&param: ", "param"});342}343 344TEST(ParameterHints, NameTypeAliasReference) {345  // Reference and name hint for l-value ref parameter via type alias.346  assertParameterHints(R"cpp(347    using alias = int&;348    void foo(alias param);349    void bar() {350      int i;351      foo($param[[i]]);352    }353  )cpp",354                       ExpectedHint{"&param: ", "param"});355}356 357TEST(ParameterHints, NameRValueReference) {358  // Only name hint for r-value ref parameter.359  assertParameterHints(R"cpp(360    void foo(int&& param);361    void bar() {362      foo($param[[42]]);363    }364  )cpp",365                       ExpectedHint{"param: ", "param"});366}367 368TEST(ParameterHints, VariadicForwardedConstructor) {369  // Name hint for variadic parameter using std::forward in a constructor call370  // This prototype of std::forward is sufficient for clang to recognize it371  assertParameterHints(R"cpp(372    namespace std { template <typename T> T&& forward(T&); }373    struct S { S(int a); };374    template <typename T, typename... Args>375    T bar(Args&&... args) { return T{std::forward<Args>(args)...}; }376    void baz() {377      int b;378      bar<S>($param[[b]]);379    }380  )cpp",381                       ExpectedHint{"a: ", "param"});382}383 384TEST(ParameterHints, VariadicPlainConstructor) {385  // Name hint for variadic parameter in a constructor call386  assertParameterHints(R"cpp(387    struct S { S(int a); };388    template <typename T, typename... Args>389    T bar(Args&&... args) { return T{args...}; }390    void baz() {391      int b;392      bar<S>($param[[b]]);393    }394  )cpp",395                       ExpectedHint{"a: ", "param"});396}397 398TEST(ParameterHints, VariadicForwardedNewConstructor) {399  // Name hint for variadic parameter using std::forward in a new expression400  // This prototype of std::forward is sufficient for clang to recognize it401  assertParameterHints(R"cpp(402    namespace std { template <typename T> T&& forward(T&); }403    struct S { S(int a); };404    template <typename T, typename... Args>405    T* bar(Args&&... args) { return new T{std::forward<Args>(args)...}; }406    void baz() {407      int b;408      bar<S>($param[[b]]);409    }410  )cpp",411                       ExpectedHint{"a: ", "param"});412}413 414TEST(ParameterHints, VariadicPlainNewConstructor) {415  // Name hint for variadic parameter in a new expression416  assertParameterHints(R"cpp(417    struct S { S(int a); };418    template <typename T, typename... Args>419    T* bar(Args&&... args) { return new T{args...}; }420    void baz() {421      int b;422      bar<S>($param[[b]]);423    }424  )cpp",425                       ExpectedHint{"a: ", "param"});426}427 428TEST(ParameterHints, VariadicForwarded) {429  // Name for variadic parameter using std::forward430  // This prototype of std::forward is sufficient for clang to recognize it431  assertParameterHints(R"cpp(432    namespace std { template <typename T> T&& forward(T&); }433    void foo(int a);434    template <typename... Args>435    void bar(Args&&... args) { return foo(std::forward<Args>(args)...); }436    void baz() {437      int b;438      bar($param[[b]]);439    }440  )cpp",441                       ExpectedHint{"a: ", "param"});442}443 444TEST(ParameterHints, VariadicPlain) {445  // Name hint for variadic parameter446  assertParameterHints(R"cpp(447    void foo(int a);448    template <typename... Args>449    void bar(Args&&... args) { return foo(args...); }450    void baz() {451      bar($param[[42]]);452    }453  )cpp",454                       ExpectedHint{"a: ", "param"});455}456 457TEST(ParameterHints, VariadicPlainWithPackFirst) {458  // Name hint for variadic parameter when the parameter pack is not the last459  // template parameter460  assertParameterHints(R"cpp(461    void foo(int a);462    template <typename... Args, typename Arg>463    void bar(Arg, Args&&... args) { return foo(args...); }464    void baz() {465      bar(1, $param[[42]]);466    }467  )cpp",468                       ExpectedHint{"a: ", "param"});469}470 471TEST(ParameterHints, VariadicSplitTwolevel) {472  // Name for variadic parameter that involves both head and tail parameters to473  // deal with.474  // This prototype of std::forward is sufficient for clang to recognize it475  assertParameterHints(R"cpp(476    namespace std { template <typename T> T&& forward(T&); }477    void baz(int, int b, double);478    template <typename... Args>479    void foo(int a, Args&&... args) {480      return baz(1, std::forward<Args>(args)..., 1.0);481    }482    template <typename... Args>483    void bar(Args&&... args) { return foo(std::forward<Args>(args)...); }484    void bazz() {485      bar($param1[[32]], $param2[[42]]);486    }487  )cpp",488                       ExpectedHint{"a: ", "param1"},489                       ExpectedHint{"b: ", "param2"});490}491 492TEST(ParameterHints, VariadicNameFromSpecialization) {493  // We don't try to resolve forwarding parameters if the function call uses a494  // specialization.495  assertParameterHints(R"cpp(496    void foo(int a);497    template <typename... Args>498    void bar(Args... args) {499      foo(args...);500    }501    template <>502    void bar<int>(int b);503    void baz() {504      bar($param[[42]]);505    }506  )cpp",507                       ExpectedHint{"b: ", "param"});508}509 510TEST(ParameterHints, VariadicNameFromSpecializationRecursive) {511  // We don't try to resolve forwarding parameters inside a forwarding function512  // call if that function call uses a specialization.513  assertParameterHints(R"cpp(514    void foo2(int a);515    template <typename... Args>516    void foo(Args... args) {517      foo2(args...);518    }519    template <typename... Args>520    void bar(Args... args) {521      foo(args...);522    }523    template <>524    void foo<int>(int b);525    void baz() {526      bar($param[[42]]);527    }528  )cpp",529                       ExpectedHint{"b: ", "param"});530}531 532TEST(ParameterHints, VariadicOverloaded) {533  // Name for variadic parameter for an overloaded function with unique number534  // of parameters.535  // This prototype of std::forward is sufficient for clang to recognize it536  assertParameterHints(537      R"cpp(538    namespace std { template <typename T> T&& forward(T&); }539    void baz(int b, int c);540    void baz(int bb, int cc, int dd);541    template <typename... Args>542    void foo(int a, Args&&... args) {543      return baz(std::forward<Args>(args)...);544    }545    template <typename... Args>546    void bar(Args&&... args) { return foo(std::forward<Args>(args)...); }547    void bazz() {548      bar($param1[[32]], $param2[[42]], $param3[[52]]);549      bar($param4[[1]], $param5[[2]], $param6[[3]], $param7[[4]]);550    }551  )cpp",552      ExpectedHint{"a: ", "param1"}, ExpectedHint{"b: ", "param2"},553      ExpectedHint{"c: ", "param3"}, ExpectedHint{"a: ", "param4"},554      ExpectedHint{"bb: ", "param5"}, ExpectedHint{"cc: ", "param6"},555      ExpectedHint{"dd: ", "param7"});556}557 558TEST(ParameterHints, VariadicRecursive) {559  // make_tuple-like recursive variadic call560  assertParameterHints(561      R"cpp(562    void foo();563 564    template <typename Head, typename... Tail>565    void foo(Head head, Tail... tail) {566      foo(tail...);567    }568 569    template <typename... Args>570    void bar(Args... args) {571      foo(args...);572    }573 574    int main() {575      bar(1, 2, 3);576    }577  )cpp");578}579 580TEST(ParameterHints, VariadicVarargs) {581  // variadic call involving varargs (to make sure we don't crash)582  assertParameterHints(R"cpp(583    void foo(int fixed, ...);584    template <typename... Args>585    void bar(Args&&... args) {586      foo(args...);587    }588 589    void baz() {590      bar($fixed[[41]], 42, 43);591    }592  )cpp");593}594 595TEST(ParameterHints, VariadicTwolevelUnresolved) {596  // the same setting as VariadicVarargs, only with parameter pack597  assertParameterHints(R"cpp(598    template <typename... Args>599    void foo(int fixed, Args&& ... args);600    template <typename... Args>601    void bar(Args&&... args) {602      foo(args...);603    }604 605    void baz() {606      bar($fixed[[41]], 42, 43);607    }608  )cpp",609                       ExpectedHint{"fixed: ", "fixed"});610}611 612TEST(ParameterHints, VariadicTwoCalls) {613  // only the first call using the parameter pack should be picked up614  assertParameterHints(615      R"cpp(616    void f1(int a, int b);617    void f2(int c, int d);618 619    bool cond;620 621    template <typename... Args>622    void foo(Args... args) {623      if (cond) {624        f1(args...);625      } else {626        f2(args...);627      }628    }629 630    int main() {631      foo($param1[[1]], $param2[[2]]);632    }633  )cpp",634      ExpectedHint{"a: ", "param1"}, ExpectedHint{"b: ", "param2"});635}636 637TEST(ParameterHints, VariadicInfinite) {638  // infinite recursion should not break clangd639  assertParameterHints(640      R"cpp(641    template <typename... Args>642    void foo(Args...);643 644    template <typename... Args>645    void bar(Args... args) {646      foo(args...);647    }648 649    template <typename... Args>650    void foo(Args... args) {651      bar(args...);652    }653 654    int main() {655      foo(1, 2);656    }657  )cpp");658}659 660TEST(ParameterHints, VariadicDuplicatePack) {661  // edge cases with multiple adjacent packs should work662  assertParameterHints(663      R"cpp(664    void foo(int a, int b, int c, int);665 666    template <typename... Args>667    void bar(int, Args... args, int d) {668      foo(args..., d);669    }670 671    template <typename... Args>672    void baz(Args... args, Args... args2) {673      bar<Args..., int>(1, args..., args2...);674    }675 676    int main() {677      baz<int, int>($p1[[1]], $p2[[2]], $p3[[3]], $p4[[4]]);678    }679  )cpp",680      ExpectedHint{"a: ", "p1"}, ExpectedHint{"b: ", "p2"},681      ExpectedHint{"c: ", "p3"}, ExpectedHint{"d: ", "p4"});682}683 684TEST(ParameterHints, VariadicEmplace) {685  // emplace-like calls should forward constructor parameters686  // This prototype of std::forward is sufficient for clang to recognize it687  assertParameterHints(688      R"cpp(689    namespace std { template <typename T> T&& forward(T&); }690    using size_t = decltype(sizeof(0));691    void *operator new(size_t, void *);692    struct S {693      S(int A);694      S(int B, int C);695    };696    struct alloc {697      template <typename T>698      T* allocate();699      template <typename T, typename... Args>700      void construct(T* ptr, Args&&... args) {701        ::new ((void*)ptr) T{std::forward<Args>(args)...};702      }703    };704    template <typename T>705    struct container {706      template <typename... Args>707      void emplace(Args&&... args) {708        alloc a;709        auto ptr = a.template allocate<T>();710        a.construct(ptr, std::forward<Args>(args)...);711      }712    };713    void foo() {714      container<S> c;715      c.emplace($param1[[1]]);716      c.emplace($param2[[2]], $param3[[3]]);717    }718  )cpp",719      ExpectedHint{"A: ", "param1"}, ExpectedHint{"B: ", "param2"},720      ExpectedHint{"C: ", "param3"});721}722 723TEST(ParameterHints, VariadicReferenceHint) {724  assertParameterHints(R"cpp(725    void foo(int&);726    template <typename... Args>727    void bar(Args... args) { return foo(args...); }728    void baz() {729      int a;730      bar(a);731      bar(1);732    }733  )cpp");734}735 736TEST(ParameterHints, VariadicReferenceHintForwardingRef) {737  assertParameterHints(R"cpp(738    void foo(int&);739    template <typename... Args>740    void bar(Args&&... args) { return foo(args...); }741    void baz() {742      int a;743      bar($param[[a]]);744      bar(1);745    }746  )cpp",747                       ExpectedHint{"&: ", "param"});748}749 750TEST(ParameterHints, VariadicReferenceHintForwardingRefStdForward) {751  assertParameterHints(R"cpp(752    namespace std { template <typename T> T&& forward(T&); }753    void foo(int&);754    template <typename... Args>755    void bar(Args&&... args) { return foo(std::forward<Args>(args)...); }756    void baz() {757      int a;758      bar($param[[a]]);759    }760  )cpp",761                       ExpectedHint{"&: ", "param"});762}763 764TEST(ParameterHints, VariadicNoReferenceHintForwardingRefStdForward) {765  assertParameterHints(R"cpp(766    namespace std { template <typename T> T&& forward(T&); }767    void foo(int);768    template <typename... Args>769    void bar(Args&&... args) { return foo(std::forward<Args>(args)...); }770    void baz() {771      int a;772      bar(a);773      bar(1);774    }775  )cpp");776}777 778TEST(ParameterHints, VariadicNoReferenceHintUnresolvedForward) {779  assertParameterHints(R"cpp(780    template <typename... Args>781    void foo(Args&&... args);782    void bar() {783      int a;784      foo(a);785    }786  )cpp");787}788 789TEST(ParameterHints, MatchingNameVariadicForwarded) {790  // No name hint for variadic parameter with matching name791  // This prototype of std::forward is sufficient for clang to recognize it792  assertParameterHints(R"cpp(793    namespace std { template <typename T> T&& forward(T&); }794    void foo(int a);795    template <typename... Args>796    void bar(Args&&... args) { return foo(std::forward<Args>(args)...); }797    void baz() {798      int a;799      bar(a);800    }801  )cpp");802}803 804TEST(ParameterHints, MatchingNameVariadicPlain) {805  // No name hint for variadic parameter with matching name806  assertParameterHints(R"cpp(807    void foo(int a);808    template <typename... Args>809    void bar(Args&&... args) { return foo(args...); }810    void baz() {811      int a;812      bar(a);813    }814  )cpp");815}816 817TEST(ParameterHints, Operator) {818  // No hint for operator call with operator syntax.819  assertParameterHints(R"cpp(820    struct S {};821    void operator+(S lhs, S rhs);822    void bar() {823      S a, b;824      a + b;825    }826  )cpp");827}828 829TEST(ParameterHints, FunctionCallOperator) {830  assertParameterHints(R"cpp(831    struct W {832      void operator()(int x);833    };834    struct S : W {835      using W::operator();836      static void operator()(int x, int y);837    };838    void bar() {839      auto l1 = [](int x) {};840      auto l2 = [](int x) static {};841 842      S s;843      s($1[[1]]);844      s.operator()($2[[1]]);845      s.operator()($3[[1]], $4[[2]]);846      S::operator()($5[[1]], $6[[2]]);847 848      l1($7[[1]]);849      l1.operator()($8[[1]]);850      l2($9[[1]]);851      l2.operator()($10[[1]]);852 853      void (*ptr)(int a, int b) = &S::operator();854      ptr($11[[1]], $12[[2]]);855    }856  )cpp",857                       ExpectedHint{"x: ", "1"}, ExpectedHint{"x: ", "2"},858                       ExpectedHint{"x: ", "3"}, ExpectedHint{"y: ", "4"},859                       ExpectedHint{"x: ", "5"}, ExpectedHint{"y: ", "6"},860                       ExpectedHint{"x: ", "7"}, ExpectedHint{"x: ", "8"},861                       ExpectedHint{"x: ", "9"}, ExpectedHint{"x: ", "10"},862                       ExpectedHint{"a: ", "11"}, ExpectedHint{"b: ", "12"});863}864 865TEST(ParameterHints, DeducingThis) {866  assertParameterHints(R"cpp(867    struct S {868      template <typename This>869      auto operator()(this This &&Self, int Param) {870        return 42;871      }872 873      auto function(this auto &Self, int Param) {874        return Param;875      }876    };877    void work() {878      S s;879      s($1[[42]]);880      s.function($2[[42]]);881      S()($3[[42]]);882      auto lambda = [](this auto &Self, char C) -> void {883        return Self(C);884      };885      lambda($4[['A']]);886    }887  )cpp",888                       ExpectedHint{"Param: ", "1"},889                       ExpectedHint{"Param: ", "2"},890                       ExpectedHint{"Param: ", "3"}, ExpectedHint{"C: ", "4"});891}892 893TEST(ParameterHints, Macros) {894  // Handling of macros depends on where the call's argument list comes from.895 896  // If it comes from a macro definition, there's nothing to hint897  // at the invocation site.898  assertParameterHints(R"cpp(899    void foo(int param);900    #define ExpandsToCall() foo(42)901    void bar() {902      ExpandsToCall();903    }904  )cpp");905 906  // The argument expression being a macro invocation shouldn't interfere907  // with hinting.908  assertParameterHints(R"cpp(909    #define PI 3.14910    void foo(double param);911    void bar() {912      foo($param[[PI]]);913    }914  )cpp",915                       ExpectedHint{"param: ", "param"});916 917  // If the whole argument list comes from a macro parameter, hint it.918  assertParameterHints(R"cpp(919    void abort();920    #define ASSERT(expr) if (!expr) abort()921    int foo(int param);922    void bar() {923      ASSERT(foo($param[[42]]) == 0);924    }925  )cpp",926                       ExpectedHint{"param: ", "param"});927 928  // If the macro expands to multiple arguments, don't hint it.929  assertParameterHints(R"cpp(930    void foo(double x, double y);931    #define CONSTANTS 3.14, 2.72932    void bar() {933      foo(CONSTANTS);934    }935  )cpp");936}937 938TEST(ParameterHints, ConstructorParens) {939  assertParameterHints(R"cpp(940    struct S {941      S(int param);942    };943    void bar() {944      S obj($param[[42]]);945    }946  )cpp",947                       ExpectedHint{"param: ", "param"});948}949 950TEST(ParameterHints, ConstructorBraces) {951  assertParameterHints(R"cpp(952    struct S {953      S(int param);954    };955    void bar() {956      S obj{$param[[42]]};957    }958  )cpp",959                       ExpectedHint{"param: ", "param"});960}961 962TEST(ParameterHints, ConstructorStdInitList) {963  // Do not show hints for std::initializer_list constructors.964  assertParameterHints(R"cpp(965    namespace std {966      template <typename E> class initializer_list { const E *a, *b; };967    }968    struct S {969      S(std::initializer_list<int> param);970    };971    void bar() {972      S obj{42, 43};973    }974  )cpp");975}976 977TEST(ParameterHints, MemberInit) {978  assertParameterHints(R"cpp(979    struct S {980      S(int param);981    };982    struct T {983      S member;984      T() : member($param[[42]]) {}985    };986  )cpp",987                       ExpectedHint{"param: ", "param"});988}989 990TEST(ParameterHints, ImplicitConstructor) {991  assertParameterHints(R"cpp(992    struct S {993      S(int param);994    };995    void bar(S);996    S foo() {997      // Do not show hint for implicit constructor call in argument.998      bar(42);999      // Do not show hint for implicit constructor call in return.1000      return 42;1001    }1002  )cpp");1003}1004 1005TEST(ParameterHints, FunctionPointer) {1006  assertParameterHints(1007      R"cpp(1008    void (*f1)(int param);1009    void (__stdcall *f2)(int param);1010    using f3_t = void(*)(int param);1011    f3_t f3;1012    using f4_t = void(__stdcall *)(int param);1013    f4_t f4;1014    __attribute__((noreturn)) f4_t f5;1015    void bar() {1016      f1($f1[[42]]);1017      f2($f2[[42]]);1018      f3($f3[[42]]);1019      f4($f4[[42]]);1020      // This one runs into an edge case in clang's type model1021      // and we can't extract the parameter name. But at least1022      // we shouldn't crash.1023      f5(42);1024    }1025  )cpp",1026      ExpectedHint{"param: ", "f1"}, ExpectedHint{"param: ", "f2"},1027      ExpectedHint{"param: ", "f3"}, ExpectedHint{"param: ", "f4"});1028}1029 1030TEST(ParameterHints, ArgMatchesParam) {1031  assertParameterHints(R"cpp(1032    void foo(int param);1033    struct S {1034      static const int param = 42;1035    };1036    void bar() {1037      int param = 42;1038      // Do not show redundant "param: param".1039      foo(param);1040      // But show it if the argument is qualified.1041      foo($param[[S::param]]);1042    }1043    struct A {1044      int param;1045      void bar() {1046        // Do not show "param: param" for member-expr.1047        foo(param);1048      }1049    };1050  )cpp",1051                       ExpectedHint{"param: ", "param"});1052}1053 1054TEST(ParameterHints, ArgMatchesParamReference) {1055  assertParameterHints(R"cpp(1056    void foo(int& param);1057    void foo2(const int& param);1058    void bar() {1059      int param;1060      // show reference hint on mutable reference1061      foo($param[[param]]);1062      // but not on const reference1063      foo2(param);1064    }1065  )cpp",1066                       ExpectedHint{"&: ", "param"});1067}1068 1069TEST(ParameterHints, LeadingUnderscore) {1070  assertParameterHints(R"cpp(1071    void foo(int p1, int _p2, int __p3);1072    void bar() {1073      foo($p1[[41]], $p2[[42]], $p3[[43]]);1074    }1075  )cpp",1076                       ExpectedHint{"p1: ", "p1"}, ExpectedHint{"p2: ", "p2"},1077                       ExpectedHint{"p3: ", "p3"});1078}1079 1080TEST(ParameterHints, DependentCalls) {1081  assertParameterHints(R"cpp(1082    template <typename T>1083    void nonmember(T par1);1084 1085    template <typename T>1086    struct A {1087      void member(T par2);1088      static void static_member(T par3);1089    };1090 1091    void overload(int anInt);1092    void overload(double aDouble);1093 1094    template <typename T>1095    struct S {1096      void bar(A<T> a, T t) {1097        nonmember($par1[[t]]);1098        a.member($par2[[t]]);1099        A<T>::static_member($par3[[t]]);1100        // We don't want to arbitrarily pick between1101        // "anInt" or "aDouble", so just show no hint.1102        overload(T{});1103      }1104    };1105  )cpp",1106                       ExpectedHint{"par1: ", "par1"},1107                       ExpectedHint{"par2: ", "par2"},1108                       ExpectedHint{"par3: ", "par3"});1109}1110 1111TEST(ParameterHints, VariadicFunction) {1112  assertParameterHints(R"cpp(1113    template <typename... T>1114    void foo(int fixed, T... variadic);1115 1116    void bar() {1117      foo($fixed[[41]], 42, 43);1118    }1119  )cpp",1120                       ExpectedHint{"fixed: ", "fixed"});1121}1122 1123TEST(ParameterHints, VarargsFunction) {1124  assertParameterHints(R"cpp(1125    void foo(int fixed, ...);1126 1127    void bar() {1128      foo($fixed[[41]], 42, 43);1129    }1130  )cpp",1131                       ExpectedHint{"fixed: ", "fixed"});1132}1133 1134TEST(ParameterHints, CopyOrMoveConstructor) {1135  // Do not show hint for parameter of copy or move constructor.1136  assertParameterHints(R"cpp(1137    struct S {1138      S();1139      S(const S& other);1140      S(S&& other);1141    };1142    void bar() {1143      S a;1144      S b(a);    // copy1145      S c(S());  // move1146    }1147  )cpp");1148}1149 1150TEST(ParameterHints, AggregateInit) {1151  // FIXME: This is not implemented yet, but it would be a natural1152  // extension to show member names as hints here.1153  assertParameterHints(R"cpp(1154    struct Point {1155      int x;1156      int y;1157    };1158    void bar() {1159      Point p{41, 42};1160    }1161  )cpp");1162}1163 1164TEST(ParameterHints, UserDefinedLiteral) {1165  // Do not hint call to user-defined literal operator.1166  assertParameterHints(R"cpp(1167    long double operator"" _w(long double param);1168    void bar() {1169      1.2_w;1170    }1171  )cpp");1172}1173 1174TEST(ParameterHints, ParamNameComment) {1175  // Do not hint an argument which already has a comment1176  // with the parameter name preceding it.1177  assertParameterHints(R"cpp(1178    void foo(int param);1179    void bar() {1180      foo(/*param*/42);1181      foo( /* param = */ 42);1182#define X 421183#define Y X1184#define Z(...) Y1185      foo(/*param=*/Z(a));1186      foo($macro[[Z(a)]]);1187      foo(/* the answer */$param[[42]]);1188    }1189  )cpp",1190                       ExpectedHint{"param: ", "macro"},1191                       ExpectedHint{"param: ", "param"});1192}1193 1194TEST(ParameterHints, SetterFunctions) {1195  assertParameterHints(R"cpp(1196    struct S {1197      void setParent(S* parent);1198      void set_parent(S* parent);1199      void setTimeout(int timeoutMillis);1200      void setTimeoutMillis(int timeout_millis);1201    };1202    void bar() {1203      S s;1204      // Parameter name matches setter name - omit hint.1205      s.setParent(nullptr);1206      // Support snake_case1207      s.set_parent(nullptr);1208      // Parameter name may contain extra info - show hint.1209      s.setTimeout($timeoutMillis[[120]]);1210      // FIXME: Ideally we'd want to omit this.1211      s.setTimeoutMillis($timeout_millis[[120]]);1212    }1213  )cpp",1214                       ExpectedHint{"timeoutMillis: ", "timeoutMillis"},1215                       ExpectedHint{"timeout_millis: ", "timeout_millis"});1216}1217 1218TEST(ParameterHints, BuiltinFunctions) {1219  // This prototype of std::forward is sufficient for clang to recognize it1220  assertParameterHints(R"cpp(1221    namespace std { template <typename T> T&& forward(T&); }1222    void foo() {1223      int i;1224      std::forward(i);1225    }1226  )cpp");1227}1228 1229TEST(ParameterHints, IncludeAtNonGlobalScope) {1230  Annotations FooInc(R"cpp(1231    void bar() { foo(42); }1232  )cpp");1233  Annotations FooCC(R"cpp(1234    struct S {1235      void foo(int param);1236      #include "foo.inc"1237    };1238  )cpp");1239 1240  TestWorkspace Workspace;1241  Workspace.addSource("foo.inc", FooInc.code());1242  Workspace.addMainFile("foo.cc", FooCC.code());1243 1244  auto AST = Workspace.openFile("foo.cc");1245  ASSERT_TRUE(bool(AST));1246 1247  // Ensure the hint for the call in foo.inc is NOT materialized in foo.cc.1248  EXPECT_EQ(1249      hintsOfKind(*AST, InlayHintKind::Parameter, DefaultOptsForTests).size(),1250      0u);1251}1252 1253TEST(TypeHints, Smoke) {1254  assertTypeHints(R"cpp(1255    auto $waldo[[waldo]] = 42;1256  )cpp",1257                  ExpectedHint{": int", "waldo"});1258}1259 1260TEST(TypeHints, Decorations) {1261  assertTypeHints(R"cpp(1262    int x = 42;1263    auto* $var1[[var1]] = &x;1264    auto&& $var2[[var2]] = x;1265    const auto& $var3[[var3]] = x;1266  )cpp",1267                  ExpectedHint{": int *", "var1"},1268                  ExpectedHint{": int &", "var2"},1269                  ExpectedHint{": const int &", "var3"});1270}1271 1272TEST(TypeHints, DecltypeAuto) {1273  assertTypeHints(R"cpp(1274    int x = 42;1275    int& y = x;1276    decltype(auto) $z[[z]] = y;1277  )cpp",1278                  ExpectedHint{": int &", "z"});1279}1280 1281TEST(TypeHints, NoQualifiers) {1282  assertTypeHints(R"cpp(1283    namespace A {1284      namespace B {1285        struct S1 {};1286        S1 foo();1287        auto $x[[x]] = foo();1288 1289        struct S2 {1290          template <typename T>1291          struct Inner {};1292        };1293        S2::Inner<int> bar();1294        auto $y[[y]] = bar();1295      }1296    }1297  )cpp",1298                  ExpectedHint{": S1", "x"}, ExpectedHint{": Inner<int>", "y"});1299}1300 1301TEST(TypeHints, Lambda) {1302  // Do not print something overly verbose like the lambda's location.1303  // Show hints for init-captures (but not regular captures).1304  assertTypeHints(R"cpp(1305    void f() {1306      int cap = 42;1307      auto $L[[L]] = [cap, $init[[init]] = 1 + 1](int a$ret[[)]] { 1308        return a + cap + init; 1309      };1310    }1311  )cpp",1312                  ExpectedHint{": (lambda)", "L"},1313                  ExpectedHint{": int", "init"}, ExpectedHint{"-> int", "ret"});1314 1315  // Lambda return hint shown even if no param list.1316  // (The digraph :> is just a ] that doesn't conflict with the annotations).1317  assertTypeHints("auto $L[[x]] = <:$ret[[:>]]{return 42;};",1318                  ExpectedHint{": (lambda)", "L"},1319                  ExpectedHint{"-> int", "ret"});1320}1321 1322// Structured bindings tests.1323// Note, we hint the individual bindings, not the aggregate.1324 1325TEST(TypeHints, StructuredBindings_PublicStruct) {1326  assertTypeHints(R"cpp(1327    // Struct with public fields.1328    struct Point {1329      int x;1330      int y;1331    };1332    Point foo();1333    auto [$x[[x]], $y[[y]]] = foo();1334  )cpp",1335                  ExpectedHint{": int", "x"}, ExpectedHint{": int", "y"});1336}1337 1338TEST(TypeHints, StructuredBindings_Array) {1339  assertTypeHints(R"cpp(1340    int arr[2];1341    auto [$x[[x]], $y[[y]]] = arr;1342  )cpp",1343                  ExpectedHint{": int", "x"}, ExpectedHint{": int", "y"});1344}1345 1346TEST(TypeHints, StructuredBindings_TupleLike) {1347  assertTypeHints(R"cpp(1348    // Tuple-like type.1349    struct IntPair {1350      int a;1351      int b;1352    };1353    namespace std {1354      template <typename T>1355      struct tuple_size {};1356      template <>1357      struct tuple_size<IntPair> {1358        constexpr static unsigned value = 2;1359      };1360      template <unsigned I, typename T>1361      struct tuple_element {};1362      template <unsigned I>1363      struct tuple_element<I, IntPair> {1364        using type = int;1365      };1366    }1367    template <unsigned I>1368    int get(const IntPair& p) {1369      if constexpr (I == 0) {1370        return p.a;1371      } else if constexpr (I == 1) {1372        return p.b;1373      }1374    }1375    IntPair bar();1376    auto [$x[[x]], $y[[y]]] = bar();1377  )cpp",1378                  ExpectedHint{": int", "x"}, ExpectedHint{": int", "y"});1379}1380 1381TEST(TypeHints, StructuredBindings_NoInitializer) {1382  assertTypeHints(R"cpp(1383    // No initializer (ill-formed).1384    // Do not show useless "NULL TYPE" hint.    1385    auto [x, y];  /*error-ok*/1386  )cpp");1387}1388 1389TEST(TypeHints, InvalidType) {1390  assertTypeHints(R"cpp(1391    auto x = (unknown_type)42; /*error-ok*/1392    auto *y = (unknown_ptr)nullptr;1393  )cpp");1394}1395 1396TEST(TypeHints, ReturnTypeDeduction) {1397  assertTypeHints(1398      R"cpp(1399    auto f1(int x$ret1a[[)]];  // Hint forward declaration too1400    auto f1(int x$ret1b[[)]] { return x + 1; }1401 1402    // Include pointer operators in hint1403    int s;1404    auto& f2($ret2[[)]] { return s; }1405 1406    // Do not hint `auto` for trailing return type.1407    auto f3() -> int;1408 1409    // Do not hint when a trailing return type is specified.1410    auto f4() -> auto* { return "foo"; }1411 1412    auto f5($noreturn[[)]] {}1413 1414    // `auto` conversion operator1415    struct A {1416      operator auto($retConv[[)]] { return 42; }1417    };1418 1419    // FIXME: Dependent types do not work yet.1420    template <typename T>1421    struct S {1422      auto method() { return T(); }1423    };1424  )cpp",1425      ExpectedHint{"-> int", "ret1a"}, ExpectedHint{"-> int", "ret1b"},1426      ExpectedHint{"-> int &", "ret2"}, ExpectedHint{"-> void", "noreturn"},1427      ExpectedHint{"-> int", "retConv"});1428}1429 1430TEST(TypeHints, DependentType) {1431  assertTypeHints(R"cpp(1432    template <typename T>1433    void foo(T arg) {1434      // The hint would just be "auto" and we can't do any better.1435      auto var1 = arg.method();1436      // FIXME: It would be nice to show "T" as the hint.1437      auto $var2[[var2]] = arg;1438    }1439 1440    template <typename T>1441    void bar(T arg) {1442      auto [a, b] = arg;1443    }1444  )cpp",1445                  ExpectedHint{": T", "var2"});1446}1447 1448TEST(TypeHints, LongTypeName) {1449  assertTypeHints(R"cpp(1450    template <typename, typename, typename>1451    struct A {};1452    struct MultipleWords {};1453    A<MultipleWords, MultipleWords, MultipleWords> foo();1454    // Omit type hint past a certain length (currently 32)1455    auto var = foo();1456  )cpp");1457 1458  Config Cfg;1459  Cfg.InlayHints.TypeNameLimit = 0;1460  WithContextValue WithCfg(Config::Key, std::move(Cfg));1461 1462  assertTypeHints(1463      R"cpp(1464    template <typename, typename, typename>1465    struct A {};1466    struct MultipleWords {};1467    A<MultipleWords, MultipleWords, MultipleWords> foo();1468    // Should have type hint with TypeNameLimit = 01469    auto $var[[var]] = foo();1470  )cpp",1471      ExpectedHint{": A<MultipleWords, MultipleWords, MultipleWords>", "var"});1472}1473 1474TEST(TypeHints, DefaultTemplateArgs) {1475  assertTypeHints(R"cpp(1476    template <typename, typename = int>1477    struct A {};1478    A<float> foo();1479    auto $var[[var]] = foo();1480    A<float> bar[1];1481    auto [$binding[[value]]] = bar;1482  )cpp",1483                  ExpectedHint{": A<float>", "var"},1484                  ExpectedHint{": A<float>", "binding"});1485}1486 1487TEST(DefaultArguments, Smoke) {1488  Config Cfg;1489  Cfg.InlayHints.Parameters =1490      true; // To test interplay of parameters and default parameters1491  Cfg.InlayHints.DeducedTypes = false;1492  Cfg.InlayHints.Designators = false;1493  Cfg.InlayHints.BlockEnd = false;1494 1495  Cfg.InlayHints.DefaultArguments = true;1496  WithContextValue WithCfg(Config::Key, std::move(Cfg));1497 1498  const auto *Code = R"cpp(1499    int foo(int A = 4) { return A; }1500    int bar(int A, int B = 1, bool C = foo($default1[[)]]) { return A; }1501    int A = bar($explicit[[2]]$default2[[)]];1502 1503    void baz(int = 5) { if (false) baz($unnamed[[)]]; };1504  )cpp";1505 1506  assertHints(InlayHintKind::DefaultArgument, Code, DefaultOptsForTests,1507              ExpectedHint{"A: 4", "default1", Left},1508              ExpectedHint{", B: 1, C: foo()", "default2", Left},1509              ExpectedHint{"5", "unnamed", Left});1510 1511  assertHints(InlayHintKind::Parameter, Code, DefaultOptsForTests,1512              ExpectedHint{"A: ", "explicit", Left});1513}1514 1515TEST(DefaultArguments, WithoutParameterNames) {1516  Config Cfg;1517  Cfg.InlayHints.Parameters = false; // To test just default args this time1518  Cfg.InlayHints.DeducedTypes = false;1519  Cfg.InlayHints.Designators = false;1520  Cfg.InlayHints.BlockEnd = false;1521 1522  Cfg.InlayHints.DefaultArguments = true;1523  WithContextValue WithCfg(Config::Key, std::move(Cfg));1524 1525  const auto *Code = R"cpp(1526    struct Baz {1527      Baz(float a = 3 //1528                    + 2);1529    };1530    struct Foo {1531      Foo(int, Baz baz = //1532              Baz{$abbreviated[[}]]1533 1534          //1535      ) {}1536    };1537 1538    int main() {1539      Foo foo1(1$paren[[)]];1540      Foo foo2{2$brace1[[}]];1541      Foo foo3 = {3$brace2[[}]];1542      auto foo4 = Foo{4$brace3[[}]];1543    }1544  )cpp";1545 1546  assertHints(InlayHintKind::DefaultArgument, Code, DefaultOptsForTests,1547              ExpectedHint{"...", "abbreviated", Left},1548              ExpectedHint{", Baz{}", "paren", Left},1549              ExpectedHint{", Baz{}", "brace1", Left},1550              ExpectedHint{", Baz{}", "brace2", Left},1551              ExpectedHint{", Baz{}", "brace3", Left});1552 1553  assertHints(InlayHintKind::Parameter, Code, DefaultOptsForTests);1554}1555 1556TEST(TypeHints, Deduplication) {1557  assertTypeHints(R"cpp(1558    template <typename T>1559    void foo() {1560      auto $var[[var]] = 42;1561    }1562    template void foo<int>();1563    template void foo<float>();1564  )cpp",1565                  ExpectedHint{": int", "var"});1566}1567 1568TEST(TypeHints, SinglyInstantiatedTemplate) {1569  assertTypeHints(R"cpp(1570    auto $lambda[[x]] = [](auto *$param[[y]], auto) { return 42; };1571    int m = x("foo", 3);1572  )cpp",1573                  ExpectedHint{": (lambda)", "lambda"},1574                  ExpectedHint{": const char *", "param"});1575 1576  // No hint for packs, or auto params following packs1577  assertTypeHints(R"cpp(1578    int x(auto $a[[a]], auto... b, auto c) { return 42; }1579    int m = x<void*, char, float>(nullptr, 'c', 2.0, 2);1580  )cpp",1581                  ExpectedHint{": void *", "a"});1582}1583 1584TEST(TypeHints, Aliased) {1585  // Check that we don't crash for functions without a FunctionTypeLoc.1586  // https://github.com/clangd/clangd/issues/11401587  TestTU TU = TestTU::withCode("void foo(void){} extern typeof(foo) foo;");1588  TU.ExtraArgs.push_back("-xc");1589  auto AST = TU.build();1590 1591  EXPECT_THAT(hintsOfKind(AST, InlayHintKind::Type, DefaultOptsForTests),1592              IsEmpty());1593}1594 1595TEST(TypeHints, CallingConvention) {1596  // Check that we don't crash for lambdas with an annotation1597  // https://github.com/clangd/clangd/issues/22231598  Annotations Source(R"cpp(1599    void test() {1600      []($lambda[[)]]__cdecl {};1601    }1602  )cpp");1603  TestTU TU = TestTU::withCode(Source.code());1604  TU.ExtraArgs.push_back("--target=x86_64-w64-mingw32");1605  TU.PredefineMacros = true; // for the __cdecl1606  auto AST = TU.build();1607 1608  EXPECT_THAT(1609      hintsOfKind(AST, InlayHintKind::Type, DefaultOptsForTests),1610      ElementsAre(HintMatcher(ExpectedHint{"-> void", "lambda"}, Source)));1611}1612 1613TEST(TypeHints, Decltype) {1614  assertTypeHints(R"cpp(1615    $a[[decltype(0)]] a;1616    $b[[decltype(a)]] b;1617    const $c[[decltype(0)]] &c = b;1618 1619    // Don't show for dependent type1620    template <class T>1621    constexpr decltype(T{}) d;1622 1623    $e[[decltype(0)]] e();1624    auto f() -> $f[[decltype(0)]];1625 1626    template <class, class> struct Foo;1627    using G = Foo<$g[[decltype(0)]], float>;1628 1629    auto $h[[h]] = $i[[decltype(0)]]{};1630 1631    // No crash1632    /* error-ok */1633    auto $j[[s]];1634  )cpp",1635                  ExpectedHint{": int", "a"}, ExpectedHint{": int", "b"},1636                  ExpectedHint{": int", "c"}, ExpectedHint{": int", "e"},1637                  ExpectedHint{": int", "f"}, ExpectedHint{": int", "g"},1638                  ExpectedHint{": int", "h"}, ExpectedHint{": int", "i"});1639}1640 1641TEST(TypeHints, SubstTemplateParameterAliases) {1642  llvm::StringRef Header = R"cpp(1643  template <class T> struct allocator {};1644 1645  template <class T, class A>1646  struct vector_base {1647    using pointer = T*;1648  };1649 1650  template <class T, class A>1651  struct internal_iterator_type_template_we_dont_expect {};1652 1653  struct my_iterator {};1654 1655  template <class T, class A = allocator<T>>1656  struct vector : vector_base<T, A> {1657    using base = vector_base<T, A>;1658    typedef T value_type;1659    typedef base::pointer pointer;1660    using allocator_type = A;1661    using size_type = int;1662    using iterator = internal_iterator_type_template_we_dont_expect<T, A>;1663    using non_template_iterator = my_iterator;1664 1665    value_type& operator[](int index) { return elements[index]; }1666    const value_type& at(int index) const { return elements[index]; }1667    pointer data() { return &elements[0]; }1668    allocator_type get_allocator() { return A(); }1669    size_type size() const { return 10; }1670    iterator begin() { return iterator(); }1671    non_template_iterator end() { return non_template_iterator(); }1672 1673    T elements[10];1674  };1675  )cpp";1676 1677  llvm::StringRef VectorIntPtr = R"cpp(1678    vector<int *> array;1679    auto $no_modifier[[x]] = array[3];1680    auto* $ptr_modifier[[ptr]] = &array[3];1681    auto& $ref_modifier[[ref]] = array[3];1682    auto& $at[[immutable]] = array.at(3);1683 1684    auto $data[[data]] = array.data();1685    auto $allocator[[alloc]] = array.get_allocator();1686    auto $size[[size]] = array.size();1687    auto $begin[[begin]] = array.begin();1688    auto $end[[end]] = array.end();1689  )cpp";1690 1691  assertHintsWithHeader(1692      InlayHintKind::Type, VectorIntPtr, Header, DefaultOptsForTests,1693      ExpectedHint{": int *", "no_modifier"},1694      ExpectedHint{": int **", "ptr_modifier"},1695      ExpectedHint{": int *&", "ref_modifier"},1696      ExpectedHint{": int *const &", "at"}, ExpectedHint{": int **", "data"},1697      ExpectedHint{": allocator<int *>", "allocator"},1698      ExpectedHint{": size_type", "size"}, ExpectedHint{": iterator", "begin"},1699      ExpectedHint{": non_template_iterator", "end"});1700 1701  llvm::StringRef VectorInt = R"cpp(1702  vector<int> array;1703  auto $no_modifier[[by_value]] = array[3];1704  auto* $ptr_modifier[[ptr]] = &array[3];1705  auto& $ref_modifier[[ref]] = array[3];1706  auto& $at[[immutable]] = array.at(3);1707 1708  auto $data[[data]] = array.data();1709  auto $allocator[[alloc]] = array.get_allocator();1710  auto $size[[size]] = array.size();1711  auto $begin[[begin]] = array.begin();1712  auto $end[[end]] = array.end();1713  )cpp";1714 1715  assertHintsWithHeader(1716      InlayHintKind::Type, VectorInt, Header, DefaultOptsForTests,1717      ExpectedHint{": int", "no_modifier"},1718      ExpectedHint{": int *", "ptr_modifier"},1719      ExpectedHint{": int &", "ref_modifier"},1720      ExpectedHint{": const int &", "at"}, ExpectedHint{": int *", "data"},1721      ExpectedHint{": allocator<int>", "allocator"},1722      ExpectedHint{": size_type", "size"}, ExpectedHint{": iterator", "begin"},1723      ExpectedHint{": non_template_iterator", "end"});1724 1725  llvm::StringRef TypeAlias = R"cpp(1726  // If the type alias is not of substituted template parameter type,1727  // do not show desugared type.1728  using VeryLongLongTypeName = my_iterator;1729  using Short = VeryLongLongTypeName;1730 1731  auto $short_name[[my_value]] = Short();1732 1733  // Same applies with templates.1734  template <typename T, typename A>1735  using basic_static_vector = vector<T, A>;1736  template <typename T>1737  using static_vector = basic_static_vector<T, allocator<T>>;1738 1739  auto $vector_name[[vec]] = static_vector<int>();1740  )cpp";1741 1742  assertHintsWithHeader(InlayHintKind::Type, TypeAlias, Header,1743                        DefaultOptsForTests,1744                        ExpectedHint{": Short", "short_name"},1745                        ExpectedHint{": static_vector<int>", "vector_name"});1746}1747 1748TEST(DesignatorHints, Basic) {1749  assertDesignatorHints(R"cpp(1750    struct S { int x, y, z; };1751    S s {$x[[1]], $y[[2+2]]};1752 1753    int x[] = {$0[[0]], $1[[1]]};1754  )cpp",1755                        ExpectedHint{".x=", "x"}, ExpectedHint{".y=", "y"},1756                        ExpectedHint{"[0]=", "0"}, ExpectedHint{"[1]=", "1"});1757}1758 1759TEST(DesignatorHints, Nested) {1760  assertDesignatorHints(R"cpp(1761    struct Inner { int x, y; };1762    struct Outer { Inner a, b; };1763    Outer o{ $a[[{ $x[[1]], $y[[2]] }]], $bx[[3]] };1764  )cpp",1765                        ExpectedHint{".a=", "a"}, ExpectedHint{".x=", "x"},1766                        ExpectedHint{".y=", "y"}, ExpectedHint{".b.x=", "bx"});1767}1768 1769TEST(DesignatorHints, AnonymousRecord) {1770  assertDesignatorHints(R"cpp(1771    struct S {1772      union {1773        struct {1774          struct {1775            int y;1776          };1777        } x;1778      };1779    };1780    S s{$xy[[42]]};1781  )cpp",1782                        ExpectedHint{".x.y=", "xy"});1783}1784 1785TEST(DesignatorHints, Suppression) {1786  assertDesignatorHints(R"cpp(1787    struct Point { int a, b, c, d, e, f, g, h; };1788    Point p{/*a=*/1, .c=2, /* .d = */3, $e[[4]]};1789  )cpp",1790                        ExpectedHint{".e=", "e"});1791}1792 1793TEST(DesignatorHints, StdArray) {1794  // Designators for std::array should be [0] rather than .__elements[0].1795  // While technically correct, the designator is useless and horrible to read.1796  assertDesignatorHints(R"cpp(1797    template <typename T, int N> struct Array { T __elements[N]; };1798    Array<int, 2> x = {$0[[0]], $1[[1]]};1799  )cpp",1800                        ExpectedHint{"[0]=", "0"}, ExpectedHint{"[1]=", "1"});1801}1802 1803TEST(DesignatorHints, OnlyAggregateInit) {1804  assertDesignatorHints(R"cpp(1805    struct Copyable { int x; } c;1806    Copyable d{c};1807 1808    struct Constructible { Constructible(int x); };1809    Constructible x{42};1810  )cpp" /*no designator hints expected (but param hints!)*/);1811}1812 1813TEST(DesignatorHints, NoCrash) {1814  assertDesignatorHints(R"cpp(1815    /*error-ok*/1816    struct A {};1817    struct Foo {int a; int b;};1818    void test() {1819      Foo f{A(), $b[[1]]};1820    }1821  )cpp",1822                        ExpectedHint{".b=", "b"});1823}1824 1825TEST(InlayHints, RestrictRange) {1826  Annotations Code(R"cpp(1827    auto a = false;1828    [[auto b = 1;1829    auto c = '2';]]1830    auto d = 3.f;1831  )cpp");1832  auto AST = TestTU::withCode(Code.code()).build();1833  EXPECT_THAT(inlayHints(AST, Code.range()),1834              ElementsAre(labelIs(": int"), labelIs(": char")));1835}1836 1837TEST(ParameterHints, PseudoObjectExpr) {1838  Annotations Code(R"cpp(1839    struct S {1840      __declspec(property(get=GetX, put=PutX)) int x[];1841      int GetX(int y, int z) { return 42 + y; }1842      void PutX(int) { }1843 1844      // This is a PseudoObjectExpression whose syntactic form is a binary1845      // operator.1846      void Work(int y) { x = y; } // Not `x = y: y`.1847    };1848 1849    int printf(const char *Format, ...);1850 1851    int main() {1852      S s;1853      __builtin_dump_struct(&s, printf); // Not `Format: __builtin_dump_struct()`1854      printf($Param[["Hello, %d"]], 42); // Normal calls are not affected.1855      // This builds a PseudoObjectExpr, but here it's useful for showing the1856      // arguments from the semantic form.1857      return s.x[ $one[[1]] ][ $two[[2]] ]; // `x[y: 1][z: 2]`1858    }1859  )cpp");1860  auto TU = TestTU::withCode(Code.code());1861  TU.ExtraArgs.push_back("-fms-extensions");1862  auto AST = TU.build();1863  EXPECT_THAT(inlayHints(AST, std::nullopt),1864              ElementsAre(HintMatcher(ExpectedHint{"Format: ", "Param"}, Code),1865                          HintMatcher(ExpectedHint{"y: ", "one"}, Code),1866                          HintMatcher(ExpectedHint{"z: ", "two"}, Code)));1867}1868 1869TEST(ParameterHints, ArgPacksAndConstructors) {1870  assertParameterHints(1871      R"cpp(1872    struct Foo{ Foo(); Foo(int x); };1873    void foo(Foo a, int b);1874    template <typename... Args>1875    void bar(Args... args) {1876      foo(args...);1877    }1878    template <typename... Args>1879    void baz(Args... args) { foo($param1[[Foo{args...}]], $param2[[1]]); }1880 1881    template <typename... Args>1882    void bax(Args... args) { foo($param3[[{args...}]], args...); }1883 1884    void foo() {1885      bar($param4[[Foo{}]], $param5[[42]]);1886      bar($param6[[42]], $param7[[42]]);1887      baz($param8[[42]]);1888      bax($param9[[42]]);1889    }1890  )cpp",1891      ExpectedHint{"a: ", "param1"}, ExpectedHint{"b: ", "param2"},1892      ExpectedHint{"a: ", "param3"}, ExpectedHint{"a: ", "param4"},1893      ExpectedHint{"b: ", "param5"}, ExpectedHint{"a: ", "param6"},1894      ExpectedHint{"b: ", "param7"}, ExpectedHint{"x: ", "param8"},1895      ExpectedHint{"b: ", "param9"});1896}1897 1898TEST(ParameterHints, DoesntExpandAllArgs) {1899  assertParameterHints(1900      R"cpp(1901    void foo(int x, int y);1902    int id(int a, int b, int c);1903    template <typename... Args>1904    void bar(Args... args) {1905      foo(id($param1[[args]], $param2[[1]], $param3[[args]])...);1906    }1907    void foo() {1908      bar(1, 2); // FIXME: We could have `bar(a: 1, a: 2)` here.1909    }1910  )cpp",1911      ExpectedHint{"a: ", "param1"}, ExpectedHint{"b: ", "param2"},1912      ExpectedHint{"c: ", "param3"});1913}1914 1915TEST(BlockEndHints, Functions) {1916  assertBlockEndHints(R"cpp(1917    int foo() {1918      return 41;1919    $foo[[}]]1920 1921    template<int X> 1922    int bar() { 1923      // No hint for lambda for now1924      auto f = []() { 1925        return X; 1926      };1927      return f(); 1928    $bar[[}]]1929 1930    // No hint because this isn't a definition1931    int buz();1932 1933    struct S{};1934    bool operator==(S, S) {1935      return true;1936    $opEqual[[}]]1937  )cpp",1938                      ExpectedHint{" // foo", "foo"},1939                      ExpectedHint{" // bar", "bar"},1940                      ExpectedHint{" // operator==", "opEqual"});1941}1942 1943TEST(BlockEndHints, Methods) {1944  assertBlockEndHints(R"cpp(1945    struct Test {1946      // No hint because there's no function body1947      Test() = default;1948      1949      ~Test() {1950      $dtor[[}]]1951 1952      void method1() {1953      $method1[[}]]1954 1955      // No hint because this isn't a definition1956      void method2();1957 1958      template <typename T>1959      void method3() {1960      $method3[[}]]1961 1962      // No hint because this isn't a definition1963      template <typename T>1964      void method4();1965 1966      Test operator+(int) const {1967        return *this;1968      $opIdentity[[}]]1969 1970      operator bool() const {1971        return true;1972      $opBool[[}]]1973 1974      // No hint because there's no function body1975      operator int() const = delete;1976    } x;1977 1978    void Test::method2() {1979    $method2[[}]]1980 1981    template <typename T>1982    void Test::method4() {1983    $method4[[}]]1984  )cpp",1985                      ExpectedHint{" // ~Test", "dtor"},1986                      ExpectedHint{" // method1", "method1"},1987                      ExpectedHint{" // method3", "method3"},1988                      ExpectedHint{" // operator+", "opIdentity"},1989                      ExpectedHint{" // operator bool", "opBool"},1990                      ExpectedHint{" // Test::method2", "method2"},1991                      ExpectedHint{" // Test::method4", "method4"});1992}1993 1994TEST(BlockEndHints, Namespaces) {1995  assertBlockEndHints(1996      R"cpp(1997    namespace {1998      void foo();1999    $anon[[}]]2000 2001    namespace ns {2002      void bar();2003    $ns[[}]]2004  )cpp",2005      ExpectedHint{" // namespace", "anon"},2006      ExpectedHint{" // namespace ns", "ns"});2007}2008 2009TEST(BlockEndHints, Types) {2010  assertBlockEndHints(2011      R"cpp(2012    struct S {2013    $S[[};]]2014 2015    class C {2016    $C[[};]]2017 2018    union U {2019    $U[[};]]2020 2021    enum E1 {2022    $E1[[};]]2023 2024    enum class E2 {2025    $E2[[};]]2026  )cpp",2027      ExpectedHint{" // struct S", "S"}, ExpectedHint{" // class C", "C"},2028      ExpectedHint{" // union U", "U"}, ExpectedHint{" // enum E1", "E1"},2029      ExpectedHint{" // enum class E2", "E2"});2030}2031 2032TEST(BlockEndHints, If) {2033  assertBlockEndHints(2034      R"cpp(2035    void foo(bool cond) {2036       void* ptr;2037       if (cond)2038          ;2039 2040       if (cond) {2041       $simple[[}]]2042 2043       if (cond) {2044       } else {2045       $ifelse[[}]]2046 2047       if (cond) {2048       } else if (!cond) {2049       $elseif[[}]]2050 2051       if (cond) {2052       } else {2053         if (!cond) {2054         $inner[[}]]2055       $outer[[}]]2056 2057       if (auto X = cond) {2058       $init[[}]]2059 2060       if (int i = 0; i > 10) {2061       $init_cond[[}]]2062 2063       if (ptr != nullptr) {2064       $null_check[[}]]2065    } // suppress2066  )cpp",2067      ExpectedHint{" // if cond", "simple"},2068      ExpectedHint{" // if cond", "ifelse"}, ExpectedHint{" // if", "elseif"},2069      ExpectedHint{" // if !cond", "inner"},2070      ExpectedHint{" // if cond", "outer"}, ExpectedHint{" // if X", "init"},2071      ExpectedHint{" // if i > 10", "init_cond"},2072      ExpectedHint{" // if ptr != nullptr", "null_check"});2073}2074 2075TEST(BlockEndHints, Loops) {2076  assertBlockEndHints(2077      R"cpp(2078    void foo() {2079       while (true)2080          ;2081 2082       while (true) {2083       $while[[}]]2084 2085       do {2086       } while (true);2087 2088       for (;true;) {2089       $forcond[[}]]2090 2091       for (int I = 0; I < 10; ++I) {2092       $forvar[[}]]2093 2094       int Vs[] = {1,2,3};2095       for (auto V : Vs) {2096       $foreach[[}]]2097    } // suppress2098  )cpp",2099      ExpectedHint{" // while true", "while"},2100      ExpectedHint{" // for true", "forcond"},2101      ExpectedHint{" // for I", "forvar"},2102      ExpectedHint{" // for V", "foreach"});2103}2104 2105TEST(BlockEndHints, Switch) {2106  assertBlockEndHints(2107      R"cpp(2108    void foo(int I) {2109      switch (I) {2110        case 0: break;2111      $switch[[}]]2112    } // suppress2113  )cpp",2114      ExpectedHint{" // switch I", "switch"});2115}2116 2117TEST(BlockEndHints, PrintLiterals) {2118  assertBlockEndHints(2119      R"cpp(2120    void foo() {2121      while ("foo") {2122      $string[[}]]2123 2124      while ("foo but this time it is very long") {2125      $string_long[[}]]2126 2127      while (true) {2128      $boolean[[}]]2129 2130      while (1) {2131      $integer[[}]]2132 2133      while (1.5) {2134      $float[[}]]2135    } // suppress2136  )cpp",2137      ExpectedHint{" // while \"foo\"", "string"},2138      ExpectedHint{" // while \"foo but...\"", "string_long"},2139      ExpectedHint{" // while true", "boolean"},2140      ExpectedHint{" // while 1", "integer"},2141      ExpectedHint{" // while 1.5", "float"});2142}2143 2144TEST(BlockEndHints, PrintRefs) {2145  assertBlockEndHints(2146      R"cpp(2147    namespace ns {2148      int Var;2149      int func1();2150      int func2(int, int);2151      struct S {2152        int Field;2153        int method1() const;2154        int method2(int, int) const;2155      }; // suppress2156    } // suppress2157    void foo() {2158      int int_a {};2159      while (ns::Var) {2160      $var[[}]]2161 2162      while (ns::func1()) {2163      $func1[[}]]2164 2165      while (ns::func2(int_a, int_a)) {2166      $func2[[}]]2167 2168      while (ns::S{}.Field) {2169      $field[[}]]2170 2171      while (ns::S{}.method1()) {2172      $method1[[}]]2173      2174      while (ns::S{}.method2(int_a, int_a)) {2175      $method2[[}]]2176    } // suppress2177  )cpp",2178      ExpectedHint{" // while Var", "var"},2179      ExpectedHint{" // while func1()", "func1"},2180      ExpectedHint{" // while func2(...)", "func2"},2181      ExpectedHint{" // while Field", "field"},2182      ExpectedHint{" // while method1()", "method1"},2183      ExpectedHint{" // while method2(...)", "method2"});2184}2185 2186TEST(BlockEndHints, PrintConversions) {2187  assertBlockEndHints(2188      R"cpp(2189    struct S {2190      S(int);2191      S(int, int);2192      explicit operator bool();2193    }; // suppress2194    void foo(int I) {2195      while (float(I)) {2196      $convert_primitive[[}]]2197 2198      while (S(I)) {2199      $convert_class[[}]]2200 2201      while (S(I, I)) {2202      $construct_class[[}]]2203    } // suppress2204  )cpp",2205      ExpectedHint{" // while float", "convert_primitive"},2206      ExpectedHint{" // while S", "convert_class"},2207      ExpectedHint{" // while S", "construct_class"});2208}2209 2210TEST(BlockEndHints, PrintOperators) {2211  std::string AnnotatedCode = R"cpp(2212    void foo(Integer I) {2213      while(++I){2214      $preinc[[}]]2215 2216      while(I++){2217      $postinc[[}]]2218 2219      while(+(I + I)){2220      $unary_complex[[}]]2221 2222      while(I < 0){2223      $compare[[}]]2224 2225      while((I + I) < I){2226      $lhs_complex[[}]]2227 2228      while(I < (I + I)){2229      $rhs_complex[[}]]2230 2231      while((I + I) < (I + I)){2232      $binary_complex[[}]]2233    } // suppress2234  )cpp";2235 2236  // We can't store shared expectations in a vector, assertHints uses varargs.2237  auto AssertExpectedHints = [&](llvm::StringRef Code) {2238    assertBlockEndHints(Code, ExpectedHint{" // while ++I", "preinc"},2239                        ExpectedHint{" // while I++", "postinc"},2240                        ExpectedHint{" // while", "unary_complex"},2241                        ExpectedHint{" // while I < 0", "compare"},2242                        ExpectedHint{" // while ... < I", "lhs_complex"},2243                        ExpectedHint{" // while I < ...", "rhs_complex"},2244                        ExpectedHint{" // while", "binary_complex"});2245  };2246 2247  // First with built-in operators.2248  AssertExpectedHints("using Integer = int;" + AnnotatedCode);2249  // And now with overloading!2250  AssertExpectedHints(R"cpp(2251    struct Integer {2252      explicit operator bool();2253      Integer operator++();2254      Integer operator++(int);2255      Integer operator+(Integer);2256      Integer operator+();2257      bool operator<(Integer);2258      bool operator<(int);2259    }; // suppress2260  )cpp" + AnnotatedCode);2261}2262 2263TEST(BlockEndHints, TrailingSemicolon) {2264  assertBlockEndHints(R"cpp(2265    // The hint is placed after the trailing ';'2266    struct S1 {2267    $S1[[}  ;]]   2268 2269    // The hint is always placed in the same line with the closing '}'.2270    // So in this case where ';' is missing, it is attached to '}'.2271    struct S2 {2272    $S2[[}]]2273 2274    ;2275 2276    // No hint because only one trailing ';' is allowed2277    struct S3 {2278    };;2279 2280    // No hint because trailing ';' is only allowed for class/struct/union/enum2281    void foo() {2282    };2283 2284    // Rare case, but yes we'll have a hint here.2285    struct {2286      int x;2287    $anon[[}]]2288    2289    s2;2290  )cpp",2291                      ExpectedHint{" // struct S1", "S1"},2292                      ExpectedHint{" // struct S2", "S2"},2293                      ExpectedHint{" // struct", "anon"});2294}2295 2296TEST(BlockEndHints, TrailingText) {2297  assertBlockEndHints(R"cpp(2298    struct S1 {2299    $S1[[}      ;]]2300 2301    // No hint for S2 because of the trailing comment2302    struct S2 {2303    }; /* Put anything here */2304 2305    struct S3 {2306      // No hint for S4 because of the trailing source code2307      struct S4 {2308      };$S3[[};]]2309 2310    // No hint for ns because of the trailing comment2311    namespace ns {2312    } // namespace ns2313  )cpp",2314                      ExpectedHint{" // struct S1", "S1"},2315                      ExpectedHint{" // struct S3", "S3"});2316}2317 2318TEST(BlockEndHints, Macro) {2319  assertBlockEndHints(R"cpp(2320    #define DECL_STRUCT(NAME) struct NAME {2321    #define RBRACE }2322 2323    DECL_STRUCT(S1)2324    $S1[[};]]2325 2326    // No hint because we require a '}'2327    DECL_STRUCT(S2)2328    RBRACE;2329  )cpp",2330                      ExpectedHint{" // struct S1", "S1"});2331}2332 2333TEST(BlockEndHints, PointerToMemberFunction) {2334  // Do not crash trying to summarize `a->*p`.2335  assertBlockEndHints(R"cpp(2336    class A {};2337    using Predicate = bool(A::*)();2338    void foo(A* a, Predicate p) {2339      if ((a->*p)()) {2340      $ptrmem[[}]]2341    } // suppress2342  )cpp",2343                      ExpectedHint{" // if ()", "ptrmem"});2344}2345 2346TEST(BlockEndHints, MinLineLimit) {2347  InlayHintOptions Opts;2348  Opts.HintMinLineLimit = 10;2349 2350  // namespace ns below is exactly 10 lines2351  assertBlockEndHintsWithOpts(2352      R"cpp(2353    namespace ns {2354      int Var;2355      int func1();2356      int func2(int, int);2357      struct S {2358        int Field;2359        int method1() const;2360        int method2(int, int) const;2361      };2362    $namespace[[}]]2363    void foo() {2364      int int_a {};2365      while (ns::Var) {2366      }2367 2368      while (ns::func1()) {2369      }2370 2371      while (ns::func2(int_a, int_a)) {2372      }2373 2374      while (ns::S{}.Field) {2375      }2376 2377      while (ns::S{}.method1()) {2378      }2379      2380      while (ns::S{}.method2(int_a, int_a)) {2381      }2382    $foo[[}]]2383  )cpp",2384      Opts, ExpectedHint{" // namespace ns", "namespace"},2385      ExpectedHint{" // foo", "foo"});2386}2387 2388// FIXME: Low-hanging fruit where we could omit a type hint:2389//  - auto x = TypeName(...);2390//  - auto x = (TypeName) (...);2391//  - auto x = static_cast<TypeName>(...);  // and other built-in casts2392 2393// Annoyances for which a heuristic is not obvious:2394//  - auto x = llvm::dyn_cast<LongTypeName>(y);  // and similar2395//  - stdlib algos return unwieldy __normal_iterator<X*, ...> type2396//    (For this one, perhaps we should omit type hints that start2397//     with a double underscore.)2398 2399} // namespace2400} // namespace clangd2401} // namespace clang2402