xref: /llvm-project/clang-tools-extra/clangd/unittests/InlayHintTests.cpp (revision 5518bb215b51cc339c3ecac064032f6791ae6476)
1cbc9c4eaSNathan Ridge //===-- InlayHintTests.cpp  -------------------------------*- C++ -*-------===//
2cbc9c4eaSNathan Ridge //
3cbc9c4eaSNathan Ridge // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4cbc9c4eaSNathan Ridge // See https://llvm.org/LICENSE.txt for license information.
5cbc9c4eaSNathan Ridge // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6cbc9c4eaSNathan Ridge //
7cbc9c4eaSNathan Ridge //===----------------------------------------------------------------------===//
8cbc9c4eaSNathan Ridge #include "Annotations.h"
916fd5c27SSam McCall #include "Config.h"
10cbc9c4eaSNathan Ridge #include "InlayHints.h"
11cbc9c4eaSNathan Ridge #include "Protocol.h"
12cbc9c4eaSNathan Ridge #include "TestTU.h"
1347d9d55cSNathan Ridge #include "TestWorkspace.h"
14cbc9c4eaSNathan Ridge #include "XRefs.h"
1516fd5c27SSam McCall #include "support/Context.h"
163137ca80SKadir Cetinkaya #include "llvm/ADT/StringRef.h"
17ce944327SSam McCall #include "llvm/Support/ScopedPrinter.h"
182eb16991STor Shepherd #include "llvm/Support/raw_ostream.h"
19cbc9c4eaSNathan Ridge #include "gmock/gmock.h"
20cbc9c4eaSNathan Ridge #include "gtest/gtest.h"
212eb16991STor Shepherd #include <optional>
22ee032bccSSam McCall #include <string>
232eb16991STor Shepherd #include <utility>
24ee032bccSSam McCall #include <vector>
25cbc9c4eaSNathan Ridge 
26cbc9c4eaSNathan Ridge namespace clang {
27cbc9c4eaSNathan Ridge namespace clangd {
280be2657cSNathan Ridge 
29ce944327SSam McCall llvm::raw_ostream &operator<<(llvm::raw_ostream &Stream,
30ce944327SSam McCall                               const InlayHint &Hint) {
31c6a65e4bSYounan Zhang   return Stream << Hint.joinLabels() << "@" << Hint.range;
320be2657cSNathan Ridge }
330be2657cSNathan Ridge 
34cbc9c4eaSNathan Ridge namespace {
35cbc9c4eaSNathan Ridge 
367c19fdd5SSam McCall using ::testing::ElementsAre;
3716fd5c27SSam McCall using ::testing::IsEmpty;
38cbc9c4eaSNathan Ridge 
390be2657cSNathan Ridge std::vector<InlayHint> hintsOfKind(ParsedAST &AST, InlayHintKind Kind) {
40cbc9c4eaSNathan Ridge   std::vector<InlayHint> Result;
41649ef338SKazu Hirata   for (auto &Hint : inlayHints(AST, /*RestrictRange=*/std::nullopt)) {
420be2657cSNathan Ridge     if (Hint.kind == Kind)
43cbc9c4eaSNathan Ridge       Result.push_back(Hint);
44cbc9c4eaSNathan Ridge   }
45cbc9c4eaSNathan Ridge   return Result;
46cbc9c4eaSNathan Ridge }
47cbc9c4eaSNathan Ridge 
487c19fdd5SSam McCall enum HintSide { Left, Right };
497c19fdd5SSam McCall 
50cbc9c4eaSNathan Ridge struct ExpectedHint {
51cbc9c4eaSNathan Ridge   std::string Label;
52cbc9c4eaSNathan Ridge   std::string RangeName;
537c19fdd5SSam McCall   HintSide Side = Left;
540be2657cSNathan Ridge 
55ce944327SSam McCall   friend llvm::raw_ostream &operator<<(llvm::raw_ostream &Stream,
560be2657cSNathan Ridge                                        const ExpectedHint &Hint) {
57ce944327SSam McCall     return Stream << Hint.Label << "@$" << Hint.RangeName;
580be2657cSNathan Ridge   }
59cbc9c4eaSNathan Ridge };
60cbc9c4eaSNathan Ridge 
61ce944327SSam McCall MATCHER_P2(HintMatcher, Expected, Code, llvm::to_string(Expected)) {
623137ca80SKadir Cetinkaya   llvm::StringRef ExpectedView(Expected.Label);
63c6a65e4bSYounan Zhang   std::string ResultLabel = arg.joinLabels();
64c6a65e4bSYounan Zhang   if (ResultLabel != ExpectedView.trim(" ") ||
65d5953e3eSKazu Hirata       arg.paddingLeft != ExpectedView.starts_with(" ") ||
66d5953e3eSKazu Hirata       arg.paddingRight != ExpectedView.ends_with(" ")) {
67c6a65e4bSYounan Zhang     *result_listener << "label is '" << ResultLabel << "'";
68ce944327SSam McCall     return false;
69ce944327SSam McCall   }
70ce944327SSam McCall   if (arg.range != Code.range(Expected.RangeName)) {
712da5c578SSam McCall     *result_listener << "range is " << llvm::to_string(arg.range) << " but $"
72ce944327SSam McCall                      << Expected.RangeName << " is "
73ce944327SSam McCall                      << llvm::to_string(Code.range(Expected.RangeName));
74ce944327SSam McCall     return false;
75ce944327SSam McCall   }
76ce944327SSam McCall   return true;
77cbc9c4eaSNathan Ridge }
78cbc9c4eaSNathan Ridge 
79c6a65e4bSYounan Zhang MATCHER_P(labelIs, Label, "") { return arg.joinLabels() == Label; }
807c19fdd5SSam McCall 
8116fd5c27SSam McCall Config noHintsConfig() {
8216fd5c27SSam McCall   Config C;
8316fd5c27SSam McCall   C.InlayHints.Parameters = false;
8416fd5c27SSam McCall   C.InlayHints.DeducedTypes = false;
85ce944327SSam McCall   C.InlayHints.Designators = false;
869e6a342fSdaiyousei-qz   C.InlayHints.BlockEnd = false;
872eb16991STor Shepherd   C.InlayHints.DefaultArguments = false;
8816fd5c27SSam McCall   return C;
8916fd5c27SSam McCall }
9016fd5c27SSam McCall 
91cbc9c4eaSNathan Ridge template <typename... ExpectedHints>
92b1193c13SYounan Zhang void assertHintsWithHeader(InlayHintKind Kind, llvm::StringRef AnnotatedSource,
93b1193c13SYounan Zhang                            llvm::StringRef HeaderContent,
94cbc9c4eaSNathan Ridge                            ExpectedHints... Expected) {
95cbc9c4eaSNathan Ridge   Annotations Source(AnnotatedSource);
96cbc9c4eaSNathan Ridge   TestTU TU = TestTU::withCode(Source.code());
97cbd6ac61SYounan Zhang   TU.ExtraArgs.push_back("-std=c++23");
98b1193c13SYounan Zhang   TU.HeaderCode = HeaderContent;
99cbc9c4eaSNathan Ridge   auto AST = TU.build();
100cbc9c4eaSNathan Ridge 
1010be2657cSNathan Ridge   EXPECT_THAT(hintsOfKind(AST, Kind),
1027c19fdd5SSam McCall               ElementsAre(HintMatcher(Expected, Source)...));
10316fd5c27SSam McCall   // Sneak in a cross-cutting check that hints are disabled by config.
10416fd5c27SSam McCall   // We'll hit an assertion failure if addInlayHint still gets called.
10516fd5c27SSam McCall   WithContextValue WithCfg(Config::Key, noHintsConfig());
106649ef338SKazu Hirata   EXPECT_THAT(inlayHints(AST, std::nullopt), IsEmpty());
107cbc9c4eaSNathan Ridge }
108cbc9c4eaSNathan Ridge 
109b1193c13SYounan Zhang template <typename... ExpectedHints>
110b1193c13SYounan Zhang void assertHints(InlayHintKind Kind, llvm::StringRef AnnotatedSource,
111b1193c13SYounan Zhang                  ExpectedHints... Expected) {
112b1193c13SYounan Zhang   return assertHintsWithHeader(Kind, AnnotatedSource, "",
113b1193c13SYounan Zhang                                std::move(Expected)...);
114b1193c13SYounan Zhang }
115b1193c13SYounan Zhang 
1167c19fdd5SSam McCall // Hack to allow expression-statements operating on parameter packs in C++14.
1177c19fdd5SSam McCall template <typename... T> void ignore(T &&...) {}
1187c19fdd5SSam McCall 
1190be2657cSNathan Ridge template <typename... ExpectedHints>
1200be2657cSNathan Ridge void assertParameterHints(llvm::StringRef AnnotatedSource,
1210be2657cSNathan Ridge                           ExpectedHints... Expected) {
1227c19fdd5SSam McCall   ignore(Expected.Side = Left...);
1233137ca80SKadir Cetinkaya   assertHints(InlayHintKind::Parameter, AnnotatedSource, Expected...);
1240be2657cSNathan Ridge }
1250be2657cSNathan Ridge 
1260be2657cSNathan Ridge template <typename... ExpectedHints>
1270be2657cSNathan Ridge void assertTypeHints(llvm::StringRef AnnotatedSource,
1280be2657cSNathan Ridge                      ExpectedHints... Expected) {
1297c19fdd5SSam McCall   ignore(Expected.Side = Right...);
1303137ca80SKadir Cetinkaya   assertHints(InlayHintKind::Type, AnnotatedSource, Expected...);
1310be2657cSNathan Ridge }
1320be2657cSNathan Ridge 
133ce944327SSam McCall template <typename... ExpectedHints>
134ce944327SSam McCall void assertDesignatorHints(llvm::StringRef AnnotatedSource,
135ce944327SSam McCall                            ExpectedHints... Expected) {
136ce944327SSam McCall   Config Cfg;
137ce944327SSam McCall   Cfg.InlayHints.Designators = true;
138ce944327SSam McCall   WithContextValue WithCfg(Config::Key, std::move(Cfg));
1393137ca80SKadir Cetinkaya   assertHints(InlayHintKind::Designator, AnnotatedSource, Expected...);
140ce944327SSam McCall }
141ce944327SSam McCall 
1429e6a342fSdaiyousei-qz template <typename... ExpectedHints>
1439e6a342fSdaiyousei-qz void assertBlockEndHints(llvm::StringRef AnnotatedSource,
1449e6a342fSdaiyousei-qz                          ExpectedHints... Expected) {
1459e6a342fSdaiyousei-qz   Config Cfg;
1469e6a342fSdaiyousei-qz   Cfg.InlayHints.BlockEnd = true;
1479e6a342fSdaiyousei-qz   WithContextValue WithCfg(Config::Key, std::move(Cfg));
1489e6a342fSdaiyousei-qz   assertHints(InlayHintKind::BlockEnd, AnnotatedSource, Expected...);
1499e6a342fSdaiyousei-qz }
1509e6a342fSdaiyousei-qz 
151cbc9c4eaSNathan Ridge TEST(ParameterHints, Smoke) {
152cbc9c4eaSNathan Ridge   assertParameterHints(R"cpp(
153cbc9c4eaSNathan Ridge     void foo(int param);
154cbc9c4eaSNathan Ridge     void bar() {
155cbc9c4eaSNathan Ridge       foo($param[[42]]);
156cbc9c4eaSNathan Ridge     }
157cbc9c4eaSNathan Ridge   )cpp",
158cbc9c4eaSNathan Ridge                        ExpectedHint{"param: ", "param"});
159cbc9c4eaSNathan Ridge }
160cbc9c4eaSNathan Ridge 
161cbc9c4eaSNathan Ridge TEST(ParameterHints, NoName) {
162cbc9c4eaSNathan Ridge   // No hint for anonymous parameter.
163cbc9c4eaSNathan Ridge   assertParameterHints(R"cpp(
164cbc9c4eaSNathan Ridge     void foo(int);
165cbc9c4eaSNathan Ridge     void bar() {
166cbc9c4eaSNathan Ridge       foo(42);
167cbc9c4eaSNathan Ridge     }
168cbc9c4eaSNathan Ridge   )cpp");
169cbc9c4eaSNathan Ridge }
170cbc9c4eaSNathan Ridge 
171043e9650STobias Ribizel TEST(ParameterHints, NoNameConstReference) {
172043e9650STobias Ribizel   // No hint for anonymous const l-value ref parameter.
173043e9650STobias Ribizel   assertParameterHints(R"cpp(
174043e9650STobias Ribizel     void foo(const int&);
175043e9650STobias Ribizel     void bar() {
176043e9650STobias Ribizel       foo(42);
177043e9650STobias Ribizel     }
178043e9650STobias Ribizel   )cpp");
179043e9650STobias Ribizel }
180043e9650STobias Ribizel 
181043e9650STobias Ribizel TEST(ParameterHints, NoNameReference) {
182043e9650STobias Ribizel   // Reference hint for anonymous l-value ref parameter.
183043e9650STobias Ribizel   assertParameterHints(R"cpp(
184043e9650STobias Ribizel     void foo(int&);
185043e9650STobias Ribizel     void bar() {
186043e9650STobias Ribizel       int i;
187043e9650STobias Ribizel       foo($param[[i]]);
188043e9650STobias Ribizel     }
189043e9650STobias Ribizel   )cpp",
190043e9650STobias Ribizel                        ExpectedHint{"&: ", "param"});
191043e9650STobias Ribizel }
192043e9650STobias Ribizel 
193043e9650STobias Ribizel TEST(ParameterHints, NoNameRValueReference) {
194043e9650STobias Ribizel   // No reference hint for anonymous r-value ref parameter.
195043e9650STobias Ribizel   assertParameterHints(R"cpp(
196043e9650STobias Ribizel     void foo(int&&);
197043e9650STobias Ribizel     void bar() {
198043e9650STobias Ribizel       foo(42);
199043e9650STobias Ribizel     }
200043e9650STobias Ribizel   )cpp");
201043e9650STobias Ribizel }
202043e9650STobias Ribizel 
203a638648fSTobias Ribizel TEST(ParameterHints, NoNameVariadicDeclaration) {
204a638648fSTobias Ribizel   // No hint for anonymous variadic parameter
205a638648fSTobias Ribizel   assertParameterHints(R"cpp(
206a638648fSTobias Ribizel     template <typename... Args>
207a638648fSTobias Ribizel     void foo(Args&& ...);
208a638648fSTobias Ribizel     void bar() {
209a638648fSTobias Ribizel       foo(42);
210a638648fSTobias Ribizel     }
211a638648fSTobias Ribizel   )cpp");
212a638648fSTobias Ribizel }
213a638648fSTobias Ribizel 
214a638648fSTobias Ribizel TEST(ParameterHints, NoNameVariadicForwarded) {
215a638648fSTobias Ribizel   // No hint for anonymous variadic parameter
216a638648fSTobias Ribizel   // This prototype of std::forward is sufficient for clang to recognize it
217a638648fSTobias Ribizel   assertParameterHints(R"cpp(
218a638648fSTobias Ribizel     namespace std { template <typename T> T&& forward(T&); }
219a638648fSTobias Ribizel     void foo(int);
220a638648fSTobias Ribizel     template <typename... Args>
221a638648fSTobias Ribizel     void bar(Args&&... args) { return foo(std::forward<Args>(args)...); }
222a638648fSTobias Ribizel     void baz() {
223a638648fSTobias Ribizel       bar(42);
224a638648fSTobias Ribizel     }
225a638648fSTobias Ribizel   )cpp");
226a638648fSTobias Ribizel }
227a638648fSTobias Ribizel 
228a638648fSTobias Ribizel TEST(ParameterHints, NoNameVariadicPlain) {
229a638648fSTobias Ribizel   // No hint for anonymous variadic parameter
230a638648fSTobias Ribizel   assertParameterHints(R"cpp(
231a638648fSTobias Ribizel     void foo(int);
232a638648fSTobias Ribizel     template <typename... Args>
233a638648fSTobias Ribizel     void bar(Args&&... args) { return foo(args...); }
234a638648fSTobias Ribizel     void baz() {
235a638648fSTobias Ribizel       bar(42);
236a638648fSTobias Ribizel     }
237a638648fSTobias Ribizel   )cpp");
238a638648fSTobias Ribizel }
239a638648fSTobias Ribizel 
240cbc9c4eaSNathan Ridge TEST(ParameterHints, NameInDefinition) {
241cbc9c4eaSNathan Ridge   // Parameter name picked up from definition if necessary.
242cbc9c4eaSNathan Ridge   assertParameterHints(R"cpp(
243cbc9c4eaSNathan Ridge     void foo(int);
244cbc9c4eaSNathan Ridge     void bar() {
245cbc9c4eaSNathan Ridge       foo($param[[42]]);
246cbc9c4eaSNathan Ridge     }
247cbc9c4eaSNathan Ridge     void foo(int param) {};
248cbc9c4eaSNathan Ridge   )cpp",
249cbc9c4eaSNathan Ridge                        ExpectedHint{"param: ", "param"});
250cbc9c4eaSNathan Ridge }
251cbc9c4eaSNathan Ridge 
252a638648fSTobias Ribizel TEST(ParameterHints, NamePartiallyInDefinition) {
253a638648fSTobias Ribizel   // Parameter name picked up from definition if necessary.
254a638648fSTobias Ribizel   assertParameterHints(R"cpp(
255a638648fSTobias Ribizel     void foo(int, int b);
256a638648fSTobias Ribizel     void bar() {
257a638648fSTobias Ribizel       foo($param1[[42]], $param2[[42]]);
258a638648fSTobias Ribizel     }
259a638648fSTobias Ribizel     void foo(int a, int) {};
260a638648fSTobias Ribizel   )cpp",
261a638648fSTobias Ribizel                        ExpectedHint{"a: ", "param1"},
262a638648fSTobias Ribizel                        ExpectedHint{"b: ", "param2"});
263a638648fSTobias Ribizel }
264a638648fSTobias Ribizel 
265a638648fSTobias Ribizel TEST(ParameterHints, NameInDefinitionVariadic) {
266a638648fSTobias Ribizel   // Parameter name picked up from definition in a resolved forwarded parameter.
267a638648fSTobias Ribizel   assertParameterHints(R"cpp(
268a638648fSTobias Ribizel     void foo(int, int);
269a638648fSTobias Ribizel     template <typename... Args>
270a638648fSTobias Ribizel     void bar(Args... args) {
271a638648fSTobias Ribizel       foo(args...);
272a638648fSTobias Ribizel     }
273a638648fSTobias Ribizel     void baz() {
274a638648fSTobias Ribizel       bar($param1[[42]], $param2[[42]]);
275a638648fSTobias Ribizel     }
276a638648fSTobias Ribizel     void foo(int a, int b) {};
277a638648fSTobias Ribizel   )cpp",
278a638648fSTobias Ribizel                        ExpectedHint{"a: ", "param1"},
279a638648fSTobias Ribizel                        ExpectedHint{"b: ", "param2"});
280a638648fSTobias Ribizel }
281a638648fSTobias Ribizel 
282cbc9c4eaSNathan Ridge TEST(ParameterHints, NameMismatch) {
283cbc9c4eaSNathan Ridge   // Prefer name from declaration.
284cbc9c4eaSNathan Ridge   assertParameterHints(R"cpp(
285cbc9c4eaSNathan Ridge     void foo(int good);
286cbc9c4eaSNathan Ridge     void bar() {
287cbc9c4eaSNathan Ridge       foo($good[[42]]);
288cbc9c4eaSNathan Ridge     }
289cbc9c4eaSNathan Ridge     void foo(int bad) {};
290cbc9c4eaSNathan Ridge   )cpp",
291cbc9c4eaSNathan Ridge                        ExpectedHint{"good: ", "good"});
292cbc9c4eaSNathan Ridge }
293cbc9c4eaSNathan Ridge 
294043e9650STobias Ribizel TEST(ParameterHints, NameConstReference) {
295043e9650STobias Ribizel   // Only name hint for const l-value ref parameter.
296043e9650STobias Ribizel   assertParameterHints(R"cpp(
297043e9650STobias Ribizel     void foo(const int& param);
298043e9650STobias Ribizel     void bar() {
299043e9650STobias Ribizel       foo($param[[42]]);
300043e9650STobias Ribizel     }
301043e9650STobias Ribizel   )cpp",
302043e9650STobias Ribizel                        ExpectedHint{"param: ", "param"});
303043e9650STobias Ribizel }
304043e9650STobias Ribizel 
305043e9650STobias Ribizel TEST(ParameterHints, NameTypeAliasConstReference) {
306043e9650STobias Ribizel   // Only name hint for const l-value ref parameter via type alias.
307043e9650STobias Ribizel   assertParameterHints(R"cpp(
308043e9650STobias Ribizel     using alias = const int&;
309043e9650STobias Ribizel     void foo(alias param);
310043e9650STobias Ribizel     void bar() {
311043e9650STobias Ribizel       int i;
312043e9650STobias Ribizel       foo($param[[i]]);
313043e9650STobias Ribizel     }
314043e9650STobias Ribizel   )cpp",
315043e9650STobias Ribizel                        ExpectedHint{"param: ", "param"});
316043e9650STobias Ribizel }
317043e9650STobias Ribizel 
318043e9650STobias Ribizel TEST(ParameterHints, NameReference) {
319043e9650STobias Ribizel   // Reference and name hint for l-value ref parameter.
320043e9650STobias Ribizel   assertParameterHints(R"cpp(
321043e9650STobias Ribizel     void foo(int& param);
322043e9650STobias Ribizel     void bar() {
323043e9650STobias Ribizel       int i;
324043e9650STobias Ribizel       foo($param[[i]]);
325043e9650STobias Ribizel     }
326043e9650STobias Ribizel   )cpp",
327043e9650STobias Ribizel                        ExpectedHint{"&param: ", "param"});
328043e9650STobias Ribizel }
329043e9650STobias Ribizel 
330043e9650STobias Ribizel TEST(ParameterHints, NameTypeAliasReference) {
331043e9650STobias Ribizel   // Reference and name hint for l-value ref parameter via type alias.
332043e9650STobias Ribizel   assertParameterHints(R"cpp(
333043e9650STobias Ribizel     using alias = int&;
334043e9650STobias Ribizel     void foo(alias param);
335043e9650STobias Ribizel     void bar() {
336043e9650STobias Ribizel       int i;
337043e9650STobias Ribizel       foo($param[[i]]);
338043e9650STobias Ribizel     }
339043e9650STobias Ribizel   )cpp",
340043e9650STobias Ribizel                        ExpectedHint{"&param: ", "param"});
341043e9650STobias Ribizel }
342043e9650STobias Ribizel 
343043e9650STobias Ribizel TEST(ParameterHints, NameRValueReference) {
344043e9650STobias Ribizel   // Only name hint for r-value ref parameter.
345043e9650STobias Ribizel   assertParameterHints(R"cpp(
346043e9650STobias Ribizel     void foo(int&& param);
347043e9650STobias Ribizel     void bar() {
348043e9650STobias Ribizel       foo($param[[42]]);
349043e9650STobias Ribizel     }
350043e9650STobias Ribizel   )cpp",
351043e9650STobias Ribizel                        ExpectedHint{"param: ", "param"});
352043e9650STobias Ribizel }
353043e9650STobias Ribizel 
354a638648fSTobias Ribizel TEST(ParameterHints, VariadicForwardedConstructor) {
355a638648fSTobias Ribizel   // Name hint for variadic parameter using std::forward in a constructor call
356a638648fSTobias Ribizel   // This prototype of std::forward is sufficient for clang to recognize it
357a638648fSTobias Ribizel   assertParameterHints(R"cpp(
358a638648fSTobias Ribizel     namespace std { template <typename T> T&& forward(T&); }
359a638648fSTobias Ribizel     struct S { S(int a); };
360a638648fSTobias Ribizel     template <typename T, typename... Args>
361a638648fSTobias Ribizel     T bar(Args&&... args) { return T{std::forward<Args>(args)...}; }
362a638648fSTobias Ribizel     void baz() {
363a638648fSTobias Ribizel       int b;
364a638648fSTobias Ribizel       bar<S>($param[[b]]);
365a638648fSTobias Ribizel     }
366a638648fSTobias Ribizel   )cpp",
367a638648fSTobias Ribizel                        ExpectedHint{"a: ", "param"});
368a638648fSTobias Ribizel }
369a638648fSTobias Ribizel 
370a638648fSTobias Ribizel TEST(ParameterHints, VariadicPlainConstructor) {
371a638648fSTobias Ribizel   // Name hint for variadic parameter in a constructor call
372a638648fSTobias Ribizel   assertParameterHints(R"cpp(
373a638648fSTobias Ribizel     struct S { S(int a); };
374a638648fSTobias Ribizel     template <typename T, typename... Args>
375a638648fSTobias Ribizel     T bar(Args&&... args) { return T{args...}; }
376a638648fSTobias Ribizel     void baz() {
377a638648fSTobias Ribizel       int b;
378a638648fSTobias Ribizel       bar<S>($param[[b]]);
379a638648fSTobias Ribizel     }
380a638648fSTobias Ribizel   )cpp",
381a638648fSTobias Ribizel                        ExpectedHint{"a: ", "param"});
382a638648fSTobias Ribizel }
383a638648fSTobias Ribizel 
384a638648fSTobias Ribizel TEST(ParameterHints, VariadicForwardedNewConstructor) {
385a638648fSTobias Ribizel   // Name hint for variadic parameter using std::forward in a new expression
386a638648fSTobias Ribizel   // This prototype of std::forward is sufficient for clang to recognize it
387a638648fSTobias Ribizel   assertParameterHints(R"cpp(
388a638648fSTobias Ribizel     namespace std { template <typename T> T&& forward(T&); }
389a638648fSTobias Ribizel     struct S { S(int a); };
390a638648fSTobias Ribizel     template <typename T, typename... Args>
391a638648fSTobias Ribizel     T* bar(Args&&... args) { return new T{std::forward<Args>(args)...}; }
392a638648fSTobias Ribizel     void baz() {
393a638648fSTobias Ribizel       int b;
394a638648fSTobias Ribizel       bar<S>($param[[b]]);
395a638648fSTobias Ribizel     }
396a638648fSTobias Ribizel   )cpp",
397a638648fSTobias Ribizel                        ExpectedHint{"a: ", "param"});
398a638648fSTobias Ribizel }
399a638648fSTobias Ribizel 
400a638648fSTobias Ribizel TEST(ParameterHints, VariadicPlainNewConstructor) {
401a638648fSTobias Ribizel   // Name hint for variadic parameter in a new expression
402a638648fSTobias Ribizel   assertParameterHints(R"cpp(
403a638648fSTobias Ribizel     struct S { S(int a); };
404a638648fSTobias Ribizel     template <typename T, typename... Args>
405a638648fSTobias Ribizel     T* bar(Args&&... args) { return new T{args...}; }
406a638648fSTobias Ribizel     void baz() {
407a638648fSTobias Ribizel       int b;
408a638648fSTobias Ribizel       bar<S>($param[[b]]);
409a638648fSTobias Ribizel     }
410a638648fSTobias Ribizel   )cpp",
411a638648fSTobias Ribizel                        ExpectedHint{"a: ", "param"});
412a638648fSTobias Ribizel }
413a638648fSTobias Ribizel 
414a638648fSTobias Ribizel TEST(ParameterHints, VariadicForwarded) {
415a638648fSTobias Ribizel   // Name for variadic parameter using std::forward
416a638648fSTobias Ribizel   // This prototype of std::forward is sufficient for clang to recognize it
417a638648fSTobias Ribizel   assertParameterHints(R"cpp(
418a638648fSTobias Ribizel     namespace std { template <typename T> T&& forward(T&); }
419a638648fSTobias Ribizel     void foo(int a);
420a638648fSTobias Ribizel     template <typename... Args>
421a638648fSTobias Ribizel     void bar(Args&&... args) { return foo(std::forward<Args>(args)...); }
422a638648fSTobias Ribizel     void baz() {
423a638648fSTobias Ribizel       int b;
424a638648fSTobias Ribizel       bar($param[[b]]);
425a638648fSTobias Ribizel     }
426a638648fSTobias Ribizel   )cpp",
427a638648fSTobias Ribizel                        ExpectedHint{"a: ", "param"});
428a638648fSTobias Ribizel }
429a638648fSTobias Ribizel 
430a638648fSTobias Ribizel TEST(ParameterHints, VariadicPlain) {
431a638648fSTobias Ribizel   // Name hint for variadic parameter
432a638648fSTobias Ribizel   assertParameterHints(R"cpp(
433a638648fSTobias Ribizel     void foo(int a);
434a638648fSTobias Ribizel     template <typename... Args>
435a638648fSTobias Ribizel     void bar(Args&&... args) { return foo(args...); }
436a638648fSTobias Ribizel     void baz() {
437a638648fSTobias Ribizel       bar($param[[42]]);
438a638648fSTobias Ribizel     }
439a638648fSTobias Ribizel   )cpp",
440a638648fSTobias Ribizel                        ExpectedHint{"a: ", "param"});
441a638648fSTobias Ribizel }
442a638648fSTobias Ribizel 
443a638648fSTobias Ribizel TEST(ParameterHints, VariadicPlainWithPackFirst) {
444a638648fSTobias Ribizel   // Name hint for variadic parameter when the parameter pack is not the last
445a638648fSTobias Ribizel   // template parameter
446a638648fSTobias Ribizel   assertParameterHints(R"cpp(
447a638648fSTobias Ribizel     void foo(int a);
448a638648fSTobias Ribizel     template <typename... Args, typename Arg>
449a638648fSTobias Ribizel     void bar(Arg, Args&&... args) { return foo(args...); }
450a638648fSTobias Ribizel     void baz() {
451a638648fSTobias Ribizel       bar(1, $param[[42]]);
452a638648fSTobias Ribizel     }
453a638648fSTobias Ribizel   )cpp",
454a638648fSTobias Ribizel                        ExpectedHint{"a: ", "param"});
455a638648fSTobias Ribizel }
456a638648fSTobias Ribizel 
457a638648fSTobias Ribizel TEST(ParameterHints, VariadicSplitTwolevel) {
458a638648fSTobias Ribizel   // Name for variadic parameter that involves both head and tail parameters to
459a638648fSTobias Ribizel   // deal with.
460a638648fSTobias Ribizel   // This prototype of std::forward is sufficient for clang to recognize it
461a638648fSTobias Ribizel   assertParameterHints(R"cpp(
462a638648fSTobias Ribizel     namespace std { template <typename T> T&& forward(T&); }
463a638648fSTobias Ribizel     void baz(int, int b, double);
464a638648fSTobias Ribizel     template <typename... Args>
465a638648fSTobias Ribizel     void foo(int a, Args&&... args) {
466a638648fSTobias Ribizel       return baz(1, std::forward<Args>(args)..., 1.0);
467a638648fSTobias Ribizel     }
468a638648fSTobias Ribizel     template <typename... Args>
469a638648fSTobias Ribizel     void bar(Args&&... args) { return foo(std::forward<Args>(args)...); }
470a638648fSTobias Ribizel     void bazz() {
471a638648fSTobias Ribizel       bar($param1[[32]], $param2[[42]]);
472a638648fSTobias Ribizel     }
473a638648fSTobias Ribizel   )cpp",
474a638648fSTobias Ribizel                        ExpectedHint{"a: ", "param1"},
475a638648fSTobias Ribizel                        ExpectedHint{"b: ", "param2"});
476a638648fSTobias Ribizel }
477a638648fSTobias Ribizel 
478a638648fSTobias Ribizel TEST(ParameterHints, VariadicNameFromSpecialization) {
479a638648fSTobias Ribizel   // We don't try to resolve forwarding parameters if the function call uses a
480a638648fSTobias Ribizel   // specialization.
481a638648fSTobias Ribizel   assertParameterHints(R"cpp(
482a638648fSTobias Ribizel     void foo(int a);
483a638648fSTobias Ribizel     template <typename... Args>
484a638648fSTobias Ribizel     void bar(Args... args) {
485a638648fSTobias Ribizel       foo(args...);
486a638648fSTobias Ribizel     }
487a638648fSTobias Ribizel     template <>
488a638648fSTobias Ribizel     void bar<int>(int b);
489a638648fSTobias Ribizel     void baz() {
490a638648fSTobias Ribizel       bar($param[[42]]);
491a638648fSTobias Ribizel     }
492a638648fSTobias Ribizel   )cpp",
493a638648fSTobias Ribizel                        ExpectedHint{"b: ", "param"});
494a638648fSTobias Ribizel }
495a638648fSTobias Ribizel 
496a638648fSTobias Ribizel TEST(ParameterHints, VariadicNameFromSpecializationRecursive) {
497a638648fSTobias Ribizel   // We don't try to resolve forwarding parameters inside a forwarding function
498a638648fSTobias Ribizel   // call if that function call uses a specialization.
499a638648fSTobias Ribizel   assertParameterHints(R"cpp(
500a638648fSTobias Ribizel     void foo2(int a);
501a638648fSTobias Ribizel     template <typename... Args>
502a638648fSTobias Ribizel     void foo(Args... args) {
503a638648fSTobias Ribizel       foo2(args...);
504a638648fSTobias Ribizel     }
505a638648fSTobias Ribizel     template <typename... Args>
506a638648fSTobias Ribizel     void bar(Args... args) {
507a638648fSTobias Ribizel       foo(args...);
508a638648fSTobias Ribizel     }
509a638648fSTobias Ribizel     template <>
510a638648fSTobias Ribizel     void foo<int>(int b);
511a638648fSTobias Ribizel     void baz() {
512a638648fSTobias Ribizel       bar($param[[42]]);
513a638648fSTobias Ribizel     }
514a638648fSTobias Ribizel   )cpp",
515a638648fSTobias Ribizel                        ExpectedHint{"b: ", "param"});
516a638648fSTobias Ribizel }
517a638648fSTobias Ribizel 
518a638648fSTobias Ribizel TEST(ParameterHints, VariadicOverloaded) {
519a638648fSTobias Ribizel   // Name for variadic parameter for an overloaded function with unique number
520a638648fSTobias Ribizel   // of parameters.
521a638648fSTobias Ribizel   // This prototype of std::forward is sufficient for clang to recognize it
522a638648fSTobias Ribizel   assertParameterHints(
523a638648fSTobias Ribizel       R"cpp(
524a638648fSTobias Ribizel     namespace std { template <typename T> T&& forward(T&); }
525a638648fSTobias Ribizel     void baz(int b, int c);
526a638648fSTobias Ribizel     void baz(int bb, int cc, int dd);
527a638648fSTobias Ribizel     template <typename... Args>
528a638648fSTobias Ribizel     void foo(int a, Args&&... args) {
529a638648fSTobias Ribizel       return baz(std::forward<Args>(args)...);
530a638648fSTobias Ribizel     }
531a638648fSTobias Ribizel     template <typename... Args>
532a638648fSTobias Ribizel     void bar(Args&&... args) { return foo(std::forward<Args>(args)...); }
533a638648fSTobias Ribizel     void bazz() {
534a638648fSTobias Ribizel       bar($param1[[32]], $param2[[42]], $param3[[52]]);
535a638648fSTobias Ribizel       bar($param4[[1]], $param5[[2]], $param6[[3]], $param7[[4]]);
536a638648fSTobias Ribizel     }
537a638648fSTobias Ribizel   )cpp",
538a638648fSTobias Ribizel       ExpectedHint{"a: ", "param1"}, ExpectedHint{"b: ", "param2"},
539a638648fSTobias Ribizel       ExpectedHint{"c: ", "param3"}, ExpectedHint{"a: ", "param4"},
540a638648fSTobias Ribizel       ExpectedHint{"bb: ", "param5"}, ExpectedHint{"cc: ", "param6"},
541a638648fSTobias Ribizel       ExpectedHint{"dd: ", "param7"});
542a638648fSTobias Ribizel }
543a638648fSTobias Ribizel 
544a638648fSTobias Ribizel TEST(ParameterHints, VariadicRecursive) {
545a638648fSTobias Ribizel   // make_tuple-like recursive variadic call
546a638648fSTobias Ribizel   assertParameterHints(
547a638648fSTobias Ribizel       R"cpp(
548a638648fSTobias Ribizel     void foo();
549a638648fSTobias Ribizel 
550a638648fSTobias Ribizel     template <typename Head, typename... Tail>
551a638648fSTobias Ribizel     void foo(Head head, Tail... tail) {
552a638648fSTobias Ribizel       foo(tail...);
553a638648fSTobias Ribizel     }
554a638648fSTobias Ribizel 
555a638648fSTobias Ribizel     template <typename... Args>
556a638648fSTobias Ribizel     void bar(Args... args) {
557a638648fSTobias Ribizel       foo(args...);
558a638648fSTobias Ribizel     }
559a638648fSTobias Ribizel 
560a638648fSTobias Ribizel     int main() {
561a638648fSTobias Ribizel       bar(1, 2, 3);
562a638648fSTobias Ribizel     }
563a638648fSTobias Ribizel   )cpp");
564a638648fSTobias Ribizel }
565a638648fSTobias Ribizel 
566a638648fSTobias Ribizel TEST(ParameterHints, VariadicVarargs) {
567a638648fSTobias Ribizel   // variadic call involving varargs (to make sure we don't crash)
568a638648fSTobias Ribizel   assertParameterHints(R"cpp(
569a638648fSTobias Ribizel     void foo(int fixed, ...);
570a638648fSTobias Ribizel     template <typename... Args>
571a638648fSTobias Ribizel     void bar(Args&&... args) {
572a638648fSTobias Ribizel       foo(args...);
573a638648fSTobias Ribizel     }
574a638648fSTobias Ribizel 
575a638648fSTobias Ribizel     void baz() {
576a638648fSTobias Ribizel       bar($fixed[[41]], 42, 43);
577a638648fSTobias Ribizel     }
578a638648fSTobias Ribizel   )cpp");
579a638648fSTobias Ribizel }
580a638648fSTobias Ribizel 
581a638648fSTobias Ribizel TEST(ParameterHints, VariadicTwolevelUnresolved) {
582a638648fSTobias Ribizel   // the same setting as VariadicVarargs, only with parameter pack
583a638648fSTobias Ribizel   assertParameterHints(R"cpp(
584a638648fSTobias Ribizel     template <typename... Args>
585a638648fSTobias Ribizel     void foo(int fixed, Args&& ... args);
586a638648fSTobias Ribizel     template <typename... Args>
587a638648fSTobias Ribizel     void bar(Args&&... args) {
588a638648fSTobias Ribizel       foo(args...);
589a638648fSTobias Ribizel     }
590a638648fSTobias Ribizel 
591a638648fSTobias Ribizel     void baz() {
592a638648fSTobias Ribizel       bar($fixed[[41]], 42, 43);
593a638648fSTobias Ribizel     }
594a638648fSTobias Ribizel   )cpp",
595a638648fSTobias Ribizel                        ExpectedHint{"fixed: ", "fixed"});
596a638648fSTobias Ribizel }
597a638648fSTobias Ribizel 
598a638648fSTobias Ribizel TEST(ParameterHints, VariadicTwoCalls) {
599a638648fSTobias Ribizel   // only the first call using the parameter pack should be picked up
600a638648fSTobias Ribizel   assertParameterHints(
601a638648fSTobias Ribizel       R"cpp(
602a638648fSTobias Ribizel     void f1(int a, int b);
603a638648fSTobias Ribizel     void f2(int c, int d);
604a638648fSTobias Ribizel 
605a638648fSTobias Ribizel     bool cond;
606a638648fSTobias Ribizel 
607a638648fSTobias Ribizel     template <typename... Args>
608a638648fSTobias Ribizel     void foo(Args... args) {
609a638648fSTobias Ribizel       if (cond) {
610a638648fSTobias Ribizel         f1(args...);
611a638648fSTobias Ribizel       } else {
612a638648fSTobias Ribizel         f2(args...);
613a638648fSTobias Ribizel       }
614a638648fSTobias Ribizel     }
615a638648fSTobias Ribizel 
616a638648fSTobias Ribizel     int main() {
617a638648fSTobias Ribizel       foo($param1[[1]], $param2[[2]]);
618a638648fSTobias Ribizel     }
619a638648fSTobias Ribizel   )cpp",
620a638648fSTobias Ribizel       ExpectedHint{"a: ", "param1"}, ExpectedHint{"b: ", "param2"});
621a638648fSTobias Ribizel }
622a638648fSTobias Ribizel 
623a638648fSTobias Ribizel TEST(ParameterHints, VariadicInfinite) {
624a638648fSTobias Ribizel   // infinite recursion should not break clangd
625a638648fSTobias Ribizel   assertParameterHints(
626a638648fSTobias Ribizel       R"cpp(
627a638648fSTobias Ribizel     template <typename... Args>
628a638648fSTobias Ribizel     void foo(Args...);
629a638648fSTobias Ribizel 
630a638648fSTobias Ribizel     template <typename... Args>
631a638648fSTobias Ribizel     void bar(Args... args) {
632a638648fSTobias Ribizel       foo(args...);
633a638648fSTobias Ribizel     }
634a638648fSTobias Ribizel 
635a638648fSTobias Ribizel     template <typename... Args>
636a638648fSTobias Ribizel     void foo(Args... args) {
637a638648fSTobias Ribizel       bar(args...);
638a638648fSTobias Ribizel     }
639a638648fSTobias Ribizel 
640a638648fSTobias Ribizel     int main() {
641a638648fSTobias Ribizel       foo(1, 2);
642a638648fSTobias Ribizel     }
643a638648fSTobias Ribizel   )cpp");
644a638648fSTobias Ribizel }
645a638648fSTobias Ribizel 
646a638648fSTobias Ribizel TEST(ParameterHints, VariadicDuplicatePack) {
647a638648fSTobias Ribizel   // edge cases with multiple adjacent packs should work
648a638648fSTobias Ribizel   assertParameterHints(
649a638648fSTobias Ribizel       R"cpp(
650a638648fSTobias Ribizel     void foo(int a, int b, int c, int);
651a638648fSTobias Ribizel 
652a638648fSTobias Ribizel     template <typename... Args>
653a638648fSTobias Ribizel     void bar(int, Args... args, int d) {
654a638648fSTobias Ribizel       foo(args..., d);
655a638648fSTobias Ribizel     }
656a638648fSTobias Ribizel 
657a638648fSTobias Ribizel     template <typename... Args>
658a638648fSTobias Ribizel     void baz(Args... args, Args... args2) {
659a638648fSTobias Ribizel       bar<Args..., int>(1, args..., args2...);
660a638648fSTobias Ribizel     }
661a638648fSTobias Ribizel 
662a638648fSTobias Ribizel     int main() {
663a638648fSTobias Ribizel       baz<int, int>($p1[[1]], $p2[[2]], $p3[[3]], $p4[[4]]);
664a638648fSTobias Ribizel     }
665a638648fSTobias Ribizel   )cpp",
666a638648fSTobias Ribizel       ExpectedHint{"a: ", "p1"}, ExpectedHint{"b: ", "p2"},
667a638648fSTobias Ribizel       ExpectedHint{"c: ", "p3"}, ExpectedHint{"d: ", "p4"});
668a638648fSTobias Ribizel }
669a638648fSTobias Ribizel 
670a638648fSTobias Ribizel TEST(ParameterHints, VariadicEmplace) {
671a638648fSTobias Ribizel   // emplace-like calls should forward constructor parameters
672a638648fSTobias Ribizel   // This prototype of std::forward is sufficient for clang to recognize it
673a638648fSTobias Ribizel   assertParameterHints(
674a638648fSTobias Ribizel       R"cpp(
675a638648fSTobias Ribizel     namespace std { template <typename T> T&& forward(T&); }
676a638648fSTobias Ribizel     using size_t = decltype(sizeof(0));
677a638648fSTobias Ribizel     void *operator new(size_t, void *);
678a638648fSTobias Ribizel     struct S {
679a638648fSTobias Ribizel       S(int A);
680a638648fSTobias Ribizel       S(int B, int C);
681a638648fSTobias Ribizel     };
682a638648fSTobias Ribizel     struct alloc {
683a638648fSTobias Ribizel       template <typename T>
684a638648fSTobias Ribizel       T* allocate();
685a638648fSTobias Ribizel       template <typename T, typename... Args>
686a638648fSTobias Ribizel       void construct(T* ptr, Args&&... args) {
687a638648fSTobias Ribizel         ::new ((void*)ptr) T{std::forward<Args>(args)...};
688a638648fSTobias Ribizel       }
689a638648fSTobias Ribizel     };
690a638648fSTobias Ribizel     template <typename T>
691a638648fSTobias Ribizel     struct container {
692a638648fSTobias Ribizel       template <typename... Args>
693a638648fSTobias Ribizel       void emplace(Args&&... args) {
694a638648fSTobias Ribizel         alloc a;
695a638648fSTobias Ribizel         auto ptr = a.template allocate<T>();
696a638648fSTobias Ribizel         a.construct(ptr, std::forward<Args>(args)...);
697a638648fSTobias Ribizel       }
698a638648fSTobias Ribizel     };
699a638648fSTobias Ribizel     void foo() {
700a638648fSTobias Ribizel       container<S> c;
701a638648fSTobias Ribizel       c.emplace($param1[[1]]);
702a638648fSTobias Ribizel       c.emplace($param2[[2]], $param3[[3]]);
703a638648fSTobias Ribizel     }
704a638648fSTobias Ribizel   )cpp",
705a638648fSTobias Ribizel       ExpectedHint{"A: ", "param1"}, ExpectedHint{"B: ", "param2"},
706a638648fSTobias Ribizel       ExpectedHint{"C: ", "param3"});
707a638648fSTobias Ribizel }
708a638648fSTobias Ribizel 
709a638648fSTobias Ribizel TEST(ParameterHints, VariadicReferenceHint) {
710a638648fSTobias Ribizel   assertParameterHints(R"cpp(
711a638648fSTobias Ribizel     void foo(int&);
712a638648fSTobias Ribizel     template <typename... Args>
713a638648fSTobias Ribizel     void bar(Args... args) { return foo(args...); }
714a638648fSTobias Ribizel     void baz() {
715a638648fSTobias Ribizel       int a;
716a638648fSTobias Ribizel       bar(a);
717a638648fSTobias Ribizel       bar(1);
718a638648fSTobias Ribizel     }
719a638648fSTobias Ribizel   )cpp");
720a638648fSTobias Ribizel }
721a638648fSTobias Ribizel 
722a638648fSTobias Ribizel TEST(ParameterHints, VariadicReferenceHintForwardingRef) {
723a638648fSTobias Ribizel   assertParameterHints(R"cpp(
724a638648fSTobias Ribizel     void foo(int&);
725a638648fSTobias Ribizel     template <typename... Args>
726a638648fSTobias Ribizel     void bar(Args&&... args) { return foo(args...); }
727a638648fSTobias Ribizel     void baz() {
728a638648fSTobias Ribizel       int a;
729a638648fSTobias Ribizel       bar($param[[a]]);
730a638648fSTobias Ribizel       bar(1);
731a638648fSTobias Ribizel     }
732a638648fSTobias Ribizel   )cpp",
733a638648fSTobias Ribizel                        ExpectedHint{"&: ", "param"});
734a638648fSTobias Ribizel }
735a638648fSTobias Ribizel 
736a638648fSTobias Ribizel TEST(ParameterHints, VariadicReferenceHintForwardingRefStdForward) {
737a638648fSTobias Ribizel   assertParameterHints(R"cpp(
738a638648fSTobias Ribizel     namespace std { template <typename T> T&& forward(T&); }
739a638648fSTobias Ribizel     void foo(int&);
740a638648fSTobias Ribizel     template <typename... Args>
741a638648fSTobias Ribizel     void bar(Args&&... args) { return foo(std::forward<Args>(args)...); }
742a638648fSTobias Ribizel     void baz() {
743a638648fSTobias Ribizel       int a;
744a638648fSTobias Ribizel       bar($param[[a]]);
745a638648fSTobias Ribizel     }
746a638648fSTobias Ribizel   )cpp",
747a638648fSTobias Ribizel                        ExpectedHint{"&: ", "param"});
748a638648fSTobias Ribizel }
749a638648fSTobias Ribizel 
750a638648fSTobias Ribizel TEST(ParameterHints, VariadicNoReferenceHintForwardingRefStdForward) {
751a638648fSTobias Ribizel   assertParameterHints(R"cpp(
752a638648fSTobias Ribizel     namespace std { template <typename T> T&& forward(T&); }
753a638648fSTobias Ribizel     void foo(int);
754a638648fSTobias Ribizel     template <typename... Args>
755a638648fSTobias Ribizel     void bar(Args&&... args) { return foo(std::forward<Args>(args)...); }
756a638648fSTobias Ribizel     void baz() {
757a638648fSTobias Ribizel       int a;
758a638648fSTobias Ribizel       bar(a);
759a638648fSTobias Ribizel       bar(1);
760a638648fSTobias Ribizel     }
761a638648fSTobias Ribizel   )cpp");
762a638648fSTobias Ribizel }
763a638648fSTobias Ribizel 
764a638648fSTobias Ribizel TEST(ParameterHints, VariadicNoReferenceHintUnresolvedForward) {
765a638648fSTobias Ribizel   assertParameterHints(R"cpp(
766a638648fSTobias Ribizel     template <typename... Args>
767a638648fSTobias Ribizel     void foo(Args&&... args);
768a638648fSTobias Ribizel     void bar() {
769a638648fSTobias Ribizel       int a;
770a638648fSTobias Ribizel       foo(a);
771a638648fSTobias Ribizel     }
772a638648fSTobias Ribizel   )cpp");
773a638648fSTobias Ribizel }
774a638648fSTobias Ribizel 
775a638648fSTobias Ribizel TEST(ParameterHints, MatchingNameVariadicForwarded) {
776a638648fSTobias Ribizel   // No name hint for variadic parameter with matching name
777a638648fSTobias Ribizel   // This prototype of std::forward is sufficient for clang to recognize it
778a638648fSTobias Ribizel   assertParameterHints(R"cpp(
779a638648fSTobias Ribizel     namespace std { template <typename T> T&& forward(T&); }
780a638648fSTobias Ribizel     void foo(int a);
781a638648fSTobias Ribizel     template <typename... Args>
782a638648fSTobias Ribizel     void bar(Args&&... args) { return foo(std::forward<Args>(args)...); }
783a638648fSTobias Ribizel     void baz() {
784a638648fSTobias Ribizel       int a;
785a638648fSTobias Ribizel       bar(a);
786a638648fSTobias Ribizel     }
787a638648fSTobias Ribizel   )cpp");
788a638648fSTobias Ribizel }
789a638648fSTobias Ribizel 
790a638648fSTobias Ribizel TEST(ParameterHints, MatchingNameVariadicPlain) {
791a638648fSTobias Ribizel   // No name hint for variadic parameter with matching name
792a638648fSTobias Ribizel   assertParameterHints(R"cpp(
793a638648fSTobias Ribizel     void foo(int a);
794a638648fSTobias Ribizel     template <typename... Args>
795a638648fSTobias Ribizel     void bar(Args&&... args) { return foo(args...); }
796a638648fSTobias Ribizel     void baz() {
797a638648fSTobias Ribizel       int a;
798a638648fSTobias Ribizel       bar(a);
799a638648fSTobias Ribizel     }
800a638648fSTobias Ribizel   )cpp");
801a638648fSTobias Ribizel }
802a638648fSTobias Ribizel 
803cbc9c4eaSNathan Ridge TEST(ParameterHints, Operator) {
804cbc9c4eaSNathan Ridge   // No hint for operator call with operator syntax.
805cbc9c4eaSNathan Ridge   assertParameterHints(R"cpp(
806cbc9c4eaSNathan Ridge     struct S {};
807cbc9c4eaSNathan Ridge     void operator+(S lhs, S rhs);
808cbc9c4eaSNathan Ridge     void bar() {
809cbc9c4eaSNathan Ridge       S a, b;
810cbc9c4eaSNathan Ridge       a + b;
811cbc9c4eaSNathan Ridge     }
812cbc9c4eaSNathan Ridge   )cpp");
813cbc9c4eaSNathan Ridge }
814cbc9c4eaSNathan Ridge 
815cbd6ac61SYounan Zhang TEST(ParameterHints, FunctionCallOperator) {
816cbd6ac61SYounan Zhang   assertParameterHints(R"cpp(
817cbd6ac61SYounan Zhang     struct W {
818cbd6ac61SYounan Zhang       void operator()(int x);
819cbd6ac61SYounan Zhang     };
820cbd6ac61SYounan Zhang     struct S : W {
821cbd6ac61SYounan Zhang       using W::operator();
822cbd6ac61SYounan Zhang       static void operator()(int x, int y);
823cbd6ac61SYounan Zhang     };
824cbd6ac61SYounan Zhang     void bar() {
825cbd6ac61SYounan Zhang       auto l1 = [](int x) {};
826cbd6ac61SYounan Zhang       auto l2 = [](int x) static {};
827cbd6ac61SYounan Zhang 
828cbd6ac61SYounan Zhang       S s;
829cbd6ac61SYounan Zhang       s($1[[1]]);
830cbd6ac61SYounan Zhang       s.operator()($2[[1]]);
831cbd6ac61SYounan Zhang       s.operator()($3[[1]], $4[[2]]);
832cbd6ac61SYounan Zhang       S::operator()($5[[1]], $6[[2]]);
833cbd6ac61SYounan Zhang 
834cbd6ac61SYounan Zhang       l1($7[[1]]);
835cbd6ac61SYounan Zhang       l1.operator()($8[[1]]);
836cbd6ac61SYounan Zhang       l2($9[[1]]);
837cbd6ac61SYounan Zhang       l2.operator()($10[[1]]);
838cbd6ac61SYounan Zhang 
839cbd6ac61SYounan Zhang       void (*ptr)(int a, int b) = &S::operator();
840cbd6ac61SYounan Zhang       ptr($11[[1]], $12[[2]]);
841cbd6ac61SYounan Zhang     }
842cbd6ac61SYounan Zhang   )cpp",
843cbd6ac61SYounan Zhang                        ExpectedHint{"x: ", "1"}, ExpectedHint{"x: ", "2"},
844cbd6ac61SYounan Zhang                        ExpectedHint{"x: ", "3"}, ExpectedHint{"y: ", "4"},
845cbd6ac61SYounan Zhang                        ExpectedHint{"x: ", "5"}, ExpectedHint{"y: ", "6"},
846cbd6ac61SYounan Zhang                        ExpectedHint{"x: ", "7"}, ExpectedHint{"x: ", "8"},
847cbd6ac61SYounan Zhang                        ExpectedHint{"x: ", "9"}, ExpectedHint{"x: ", "10"},
848cbd6ac61SYounan Zhang                        ExpectedHint{"a: ", "11"}, ExpectedHint{"b: ", "12"});
849cbd6ac61SYounan Zhang }
850cbd6ac61SYounan Zhang 
8514a540ceeSYounan Zhang TEST(ParameterHints, DeducingThis) {
8524a540ceeSYounan Zhang   assertParameterHints(R"cpp(
8534a540ceeSYounan Zhang     struct S {
8544a540ceeSYounan Zhang       template <typename This>
8554a540ceeSYounan Zhang       auto operator()(this This &&Self, int Param) {
8564a540ceeSYounan Zhang         return 42;
8574a540ceeSYounan Zhang       }
8584a540ceeSYounan Zhang 
8594a540ceeSYounan Zhang       auto function(this auto &Self, int Param) {
8604a540ceeSYounan Zhang         return Param;
8614a540ceeSYounan Zhang       }
8624a540ceeSYounan Zhang     };
8634a540ceeSYounan Zhang     void work() {
8644a540ceeSYounan Zhang       S s;
8654a540ceeSYounan Zhang       s($1[[42]]);
8664a540ceeSYounan Zhang       s.function($2[[42]]);
8674a540ceeSYounan Zhang       S()($3[[42]]);
8684a540ceeSYounan Zhang       auto lambda = [](this auto &Self, char C) -> void {
8694a540ceeSYounan Zhang         return Self(C);
8704a540ceeSYounan Zhang       };
8714a540ceeSYounan Zhang       lambda($4[['A']]);
8724a540ceeSYounan Zhang     }
8734a540ceeSYounan Zhang   )cpp",
8744a540ceeSYounan Zhang                        ExpectedHint{"Param: ", "1"},
8754a540ceeSYounan Zhang                        ExpectedHint{"Param: ", "2"},
8764a540ceeSYounan Zhang                        ExpectedHint{"Param: ", "3"}, ExpectedHint{"C: ", "4"});
8774a540ceeSYounan Zhang }
8784a540ceeSYounan Zhang 
879cbc9c4eaSNathan Ridge TEST(ParameterHints, Macros) {
880cbc9c4eaSNathan Ridge   // Handling of macros depends on where the call's argument list comes from.
881cbc9c4eaSNathan Ridge 
882cbc9c4eaSNathan Ridge   // If it comes from a macro definition, there's nothing to hint
883cbc9c4eaSNathan Ridge   // at the invocation site.
884cbc9c4eaSNathan Ridge   assertParameterHints(R"cpp(
885cbc9c4eaSNathan Ridge     void foo(int param);
886cbc9c4eaSNathan Ridge     #define ExpandsToCall() foo(42)
887cbc9c4eaSNathan Ridge     void bar() {
888cbc9c4eaSNathan Ridge       ExpandsToCall();
889cbc9c4eaSNathan Ridge     }
890cbc9c4eaSNathan Ridge   )cpp");
891cbc9c4eaSNathan Ridge 
892cbc9c4eaSNathan Ridge   // The argument expression being a macro invocation shouldn't interfere
893cbc9c4eaSNathan Ridge   // with hinting.
894cbc9c4eaSNathan Ridge   assertParameterHints(R"cpp(
895cbc9c4eaSNathan Ridge     #define PI 3.14
896cbc9c4eaSNathan Ridge     void foo(double param);
897cbc9c4eaSNathan Ridge     void bar() {
898cbc9c4eaSNathan Ridge       foo($param[[PI]]);
899cbc9c4eaSNathan Ridge     }
900cbc9c4eaSNathan Ridge   )cpp",
901cbc9c4eaSNathan Ridge                        ExpectedHint{"param: ", "param"});
902cbc9c4eaSNathan Ridge 
903cbc9c4eaSNathan Ridge   // If the whole argument list comes from a macro parameter, hint it.
904cbc9c4eaSNathan Ridge   assertParameterHints(R"cpp(
905cbc9c4eaSNathan Ridge     void abort();
906cbc9c4eaSNathan Ridge     #define ASSERT(expr) if (!expr) abort()
907cbc9c4eaSNathan Ridge     int foo(int param);
908cbc9c4eaSNathan Ridge     void bar() {
909cbc9c4eaSNathan Ridge       ASSERT(foo($param[[42]]) == 0);
910cbc9c4eaSNathan Ridge     }
911cbc9c4eaSNathan Ridge   )cpp",
912cbc9c4eaSNathan Ridge                        ExpectedHint{"param: ", "param"});
913924974a3SSam McCall 
914924974a3SSam McCall   // If the macro expands to multiple arguments, don't hint it.
915924974a3SSam McCall   assertParameterHints(R"cpp(
916924974a3SSam McCall     void foo(double x, double y);
917924974a3SSam McCall     #define CONSTANTS 3.14, 2.72
918924974a3SSam McCall     void bar() {
919924974a3SSam McCall       foo(CONSTANTS);
920924974a3SSam McCall     }
921924974a3SSam McCall   )cpp");
922cbc9c4eaSNathan Ridge }
923cbc9c4eaSNathan Ridge 
924cbc9c4eaSNathan Ridge TEST(ParameterHints, ConstructorParens) {
925cbc9c4eaSNathan Ridge   assertParameterHints(R"cpp(
926cbc9c4eaSNathan Ridge     struct S {
927cbc9c4eaSNathan Ridge       S(int param);
928cbc9c4eaSNathan Ridge     };
929cbc9c4eaSNathan Ridge     void bar() {
930cbc9c4eaSNathan Ridge       S obj($param[[42]]);
931cbc9c4eaSNathan Ridge     }
932cbc9c4eaSNathan Ridge   )cpp",
933cbc9c4eaSNathan Ridge                        ExpectedHint{"param: ", "param"});
934cbc9c4eaSNathan Ridge }
935cbc9c4eaSNathan Ridge 
936cbc9c4eaSNathan Ridge TEST(ParameterHints, ConstructorBraces) {
937cbc9c4eaSNathan Ridge   assertParameterHints(R"cpp(
938cbc9c4eaSNathan Ridge     struct S {
939cbc9c4eaSNathan Ridge       S(int param);
940cbc9c4eaSNathan Ridge     };
941cbc9c4eaSNathan Ridge     void bar() {
942cbc9c4eaSNathan Ridge       S obj{$param[[42]]};
943cbc9c4eaSNathan Ridge     }
944cbc9c4eaSNathan Ridge   )cpp",
945cbc9c4eaSNathan Ridge                        ExpectedHint{"param: ", "param"});
946cbc9c4eaSNathan Ridge }
947cbc9c4eaSNathan Ridge 
948cbc9c4eaSNathan Ridge TEST(ParameterHints, ConstructorStdInitList) {
949cbc9c4eaSNathan Ridge   // Do not show hints for std::initializer_list constructors.
950cbc9c4eaSNathan Ridge   assertParameterHints(R"cpp(
951cbc9c4eaSNathan Ridge     namespace std {
952482c41e9SMital Ashok       template <typename E> class initializer_list { const E *a, *b; };
953cbc9c4eaSNathan Ridge     }
954cbc9c4eaSNathan Ridge     struct S {
955cbc9c4eaSNathan Ridge       S(std::initializer_list<int> param);
956cbc9c4eaSNathan Ridge     };
957cbc9c4eaSNathan Ridge     void bar() {
958cbc9c4eaSNathan Ridge       S obj{42, 43};
959cbc9c4eaSNathan Ridge     }
960cbc9c4eaSNathan Ridge   )cpp");
961cbc9c4eaSNathan Ridge }
962cbc9c4eaSNathan Ridge 
963cbc9c4eaSNathan Ridge TEST(ParameterHints, MemberInit) {
964cbc9c4eaSNathan Ridge   assertParameterHints(R"cpp(
965cbc9c4eaSNathan Ridge     struct S {
966cbc9c4eaSNathan Ridge       S(int param);
967cbc9c4eaSNathan Ridge     };
968cbc9c4eaSNathan Ridge     struct T {
969cbc9c4eaSNathan Ridge       S member;
970cbc9c4eaSNathan Ridge       T() : member($param[[42]]) {}
971cbc9c4eaSNathan Ridge     };
972cbc9c4eaSNathan Ridge   )cpp",
973cbc9c4eaSNathan Ridge                        ExpectedHint{"param: ", "param"});
974cbc9c4eaSNathan Ridge }
975cbc9c4eaSNathan Ridge 
976cbc9c4eaSNathan Ridge TEST(ParameterHints, ImplicitConstructor) {
977cbc9c4eaSNathan Ridge   assertParameterHints(R"cpp(
978cbc9c4eaSNathan Ridge     struct S {
979cbc9c4eaSNathan Ridge       S(int param);
980cbc9c4eaSNathan Ridge     };
981cbc9c4eaSNathan Ridge     void bar(S);
982cbc9c4eaSNathan Ridge     S foo() {
983cbc9c4eaSNathan Ridge       // Do not show hint for implicit constructor call in argument.
984cbc9c4eaSNathan Ridge       bar(42);
985cbc9c4eaSNathan Ridge       // Do not show hint for implicit constructor call in return.
986cbc9c4eaSNathan Ridge       return 42;
987cbc9c4eaSNathan Ridge     }
988cbc9c4eaSNathan Ridge   )cpp");
989cbc9c4eaSNathan Ridge }
990cbc9c4eaSNathan Ridge 
9918ee710a4SNathan Ridge TEST(ParameterHints, FunctionPointer) {
9928ee710a4SNathan Ridge   assertParameterHints(
9938ee710a4SNathan Ridge       R"cpp(
9948ee710a4SNathan Ridge     void (*f1)(int param);
9958ee710a4SNathan Ridge     void (__stdcall *f2)(int param);
9968ee710a4SNathan Ridge     using f3_t = void(*)(int param);
9978ee710a4SNathan Ridge     f3_t f3;
9988ee710a4SNathan Ridge     using f4_t = void(__stdcall *)(int param);
9998ee710a4SNathan Ridge     f4_t f4;
10008ee710a4SNathan Ridge     void bar() {
10018ee710a4SNathan Ridge       f1($f1[[42]]);
10028ee710a4SNathan Ridge       f2($f2[[42]]);
10038ee710a4SNathan Ridge       f3($f3[[42]]);
10048ee710a4SNathan Ridge       f4($f4[[42]]);
10058ee710a4SNathan Ridge     }
10068ee710a4SNathan Ridge   )cpp",
10078ee710a4SNathan Ridge       ExpectedHint{"param: ", "f1"}, ExpectedHint{"param: ", "f2"},
10088ee710a4SNathan Ridge       ExpectedHint{"param: ", "f3"}, ExpectedHint{"param: ", "f4"});
10098ee710a4SNathan Ridge }
10108ee710a4SNathan Ridge 
1011cbc9c4eaSNathan Ridge TEST(ParameterHints, ArgMatchesParam) {
1012cbc9c4eaSNathan Ridge   assertParameterHints(R"cpp(
1013cbc9c4eaSNathan Ridge     void foo(int param);
1014cbc9c4eaSNathan Ridge     struct S {
1015cbc9c4eaSNathan Ridge       static const int param = 42;
1016cbc9c4eaSNathan Ridge     };
1017cbc9c4eaSNathan Ridge     void bar() {
1018cbc9c4eaSNathan Ridge       int param = 42;
1019cbc9c4eaSNathan Ridge       // Do not show redundant "param: param".
1020cbc9c4eaSNathan Ridge       foo(param);
1021cbc9c4eaSNathan Ridge       // But show it if the argument is qualified.
1022cbc9c4eaSNathan Ridge       foo($param[[S::param]]);
1023cbc9c4eaSNathan Ridge     }
1024cbc9c4eaSNathan Ridge     struct A {
1025cbc9c4eaSNathan Ridge       int param;
1026cbc9c4eaSNathan Ridge       void bar() {
1027cbc9c4eaSNathan Ridge         // Do not show "param: param" for member-expr.
1028cbc9c4eaSNathan Ridge         foo(param);
1029cbc9c4eaSNathan Ridge       }
1030cbc9c4eaSNathan Ridge     };
1031cbc9c4eaSNathan Ridge   )cpp",
1032cbc9c4eaSNathan Ridge                        ExpectedHint{"param: ", "param"});
1033cbc9c4eaSNathan Ridge }
1034cbc9c4eaSNathan Ridge 
1035043e9650STobias Ribizel TEST(ParameterHints, ArgMatchesParamReference) {
1036043e9650STobias Ribizel   assertParameterHints(R"cpp(
1037043e9650STobias Ribizel     void foo(int& param);
1038043e9650STobias Ribizel     void foo2(const int& param);
1039043e9650STobias Ribizel     void bar() {
1040043e9650STobias Ribizel       int param;
1041043e9650STobias Ribizel       // show reference hint on mutable reference
1042043e9650STobias Ribizel       foo($param[[param]]);
1043043e9650STobias Ribizel       // but not on const reference
1044043e9650STobias Ribizel       foo2(param);
1045043e9650STobias Ribizel     }
1046043e9650STobias Ribizel   )cpp",
1047043e9650STobias Ribizel                        ExpectedHint{"&: ", "param"});
1048043e9650STobias Ribizel }
1049043e9650STobias Ribizel 
1050cbc9c4eaSNathan Ridge TEST(ParameterHints, LeadingUnderscore) {
1051cbc9c4eaSNathan Ridge   assertParameterHints(R"cpp(
1052cbc9c4eaSNathan Ridge     void foo(int p1, int _p2, int __p3);
1053cbc9c4eaSNathan Ridge     void bar() {
1054cbc9c4eaSNathan Ridge       foo($p1[[41]], $p2[[42]], $p3[[43]]);
1055cbc9c4eaSNathan Ridge     }
1056cbc9c4eaSNathan Ridge   )cpp",
1057cbc9c4eaSNathan Ridge                        ExpectedHint{"p1: ", "p1"}, ExpectedHint{"p2: ", "p2"},
1058cbc9c4eaSNathan Ridge                        ExpectedHint{"p3: ", "p3"});
1059cbc9c4eaSNathan Ridge }
1060cbc9c4eaSNathan Ridge 
10611f8963c8SNathan Ridge TEST(ParameterHints, DependentCalls) {
1062cbc9c4eaSNathan Ridge   assertParameterHints(R"cpp(
1063cbc9c4eaSNathan Ridge     template <typename T>
10641f8963c8SNathan Ridge     void nonmember(T par1);
10651f8963c8SNathan Ridge 
10661f8963c8SNathan Ridge     template <typename T>
10671f8963c8SNathan Ridge     struct A {
10681f8963c8SNathan Ridge       void member(T par2);
10691f8963c8SNathan Ridge       static void static_member(T par3);
10701f8963c8SNathan Ridge     };
10711f8963c8SNathan Ridge 
10721f8963c8SNathan Ridge     void overload(int anInt);
10731f8963c8SNathan Ridge     void overload(double aDouble);
1074cbc9c4eaSNathan Ridge 
1075cbc9c4eaSNathan Ridge     template <typename T>
1076cbc9c4eaSNathan Ridge     struct S {
10771f8963c8SNathan Ridge       void bar(A<T> a, T t) {
10781f8963c8SNathan Ridge         nonmember($par1[[t]]);
10791f8963c8SNathan Ridge         a.member($par2[[t]]);
10801f8963c8SNathan Ridge         A<T>::static_member($par3[[t]]);
10811f8963c8SNathan Ridge         // We don't want to arbitrarily pick between
10821f8963c8SNathan Ridge         // "anInt" or "aDouble", so just show no hint.
10831f8963c8SNathan Ridge         overload(T{});
1084cbc9c4eaSNathan Ridge       }
1085cbc9c4eaSNathan Ridge     };
10861f8963c8SNathan Ridge   )cpp",
10871f8963c8SNathan Ridge                        ExpectedHint{"par1: ", "par1"},
1088f976b999SNathan Ridge                        ExpectedHint{"par2: ", "par2"},
1089f976b999SNathan Ridge                        ExpectedHint{"par3: ", "par3"});
1090cbc9c4eaSNathan Ridge }
1091cbc9c4eaSNathan Ridge 
1092cbc9c4eaSNathan Ridge TEST(ParameterHints, VariadicFunction) {
1093cbc9c4eaSNathan Ridge   assertParameterHints(R"cpp(
1094cbc9c4eaSNathan Ridge     template <typename... T>
1095cbc9c4eaSNathan Ridge     void foo(int fixed, T... variadic);
1096cbc9c4eaSNathan Ridge 
1097cbc9c4eaSNathan Ridge     void bar() {
1098cbc9c4eaSNathan Ridge       foo($fixed[[41]], 42, 43);
1099cbc9c4eaSNathan Ridge     }
1100cbc9c4eaSNathan Ridge   )cpp",
1101cbc9c4eaSNathan Ridge                        ExpectedHint{"fixed: ", "fixed"});
1102cbc9c4eaSNathan Ridge }
1103cbc9c4eaSNathan Ridge 
1104cbc9c4eaSNathan Ridge TEST(ParameterHints, VarargsFunction) {
1105cbc9c4eaSNathan Ridge   assertParameterHints(R"cpp(
1106cbc9c4eaSNathan Ridge     void foo(int fixed, ...);
1107cbc9c4eaSNathan Ridge 
1108cbc9c4eaSNathan Ridge     void bar() {
1109cbc9c4eaSNathan Ridge       foo($fixed[[41]], 42, 43);
1110cbc9c4eaSNathan Ridge     }
1111cbc9c4eaSNathan Ridge   )cpp",
1112cbc9c4eaSNathan Ridge                        ExpectedHint{"fixed: ", "fixed"});
1113cbc9c4eaSNathan Ridge }
1114cbc9c4eaSNathan Ridge 
1115cbc9c4eaSNathan Ridge TEST(ParameterHints, CopyOrMoveConstructor) {
1116cbc9c4eaSNathan Ridge   // Do not show hint for parameter of copy or move constructor.
1117cbc9c4eaSNathan Ridge   assertParameterHints(R"cpp(
1118cbc9c4eaSNathan Ridge     struct S {
1119cbc9c4eaSNathan Ridge       S();
1120cbc9c4eaSNathan Ridge       S(const S& other);
1121cbc9c4eaSNathan Ridge       S(S&& other);
1122cbc9c4eaSNathan Ridge     };
1123cbc9c4eaSNathan Ridge     void bar() {
1124cbc9c4eaSNathan Ridge       S a;
1125cbc9c4eaSNathan Ridge       S b(a);    // copy
1126cbc9c4eaSNathan Ridge       S c(S());  // move
1127cbc9c4eaSNathan Ridge     }
1128cbc9c4eaSNathan Ridge   )cpp");
1129cbc9c4eaSNathan Ridge }
1130cbc9c4eaSNathan Ridge 
1131cbc9c4eaSNathan Ridge TEST(ParameterHints, AggregateInit) {
1132cbc9c4eaSNathan Ridge   // FIXME: This is not implemented yet, but it would be a natural
1133cbc9c4eaSNathan Ridge   // extension to show member names as hints here.
1134cbc9c4eaSNathan Ridge   assertParameterHints(R"cpp(
1135cbc9c4eaSNathan Ridge     struct Point {
1136cbc9c4eaSNathan Ridge       int x;
1137cbc9c4eaSNathan Ridge       int y;
1138cbc9c4eaSNathan Ridge     };
1139cbc9c4eaSNathan Ridge     void bar() {
1140cbc9c4eaSNathan Ridge       Point p{41, 42};
1141cbc9c4eaSNathan Ridge     }
1142cbc9c4eaSNathan Ridge   )cpp");
1143cbc9c4eaSNathan Ridge }
1144cbc9c4eaSNathan Ridge 
1145cbc9c4eaSNathan Ridge TEST(ParameterHints, UserDefinedLiteral) {
1146cbc9c4eaSNathan Ridge   // Do not hint call to user-defined literal operator.
1147cbc9c4eaSNathan Ridge   assertParameterHints(R"cpp(
1148cbc9c4eaSNathan Ridge     long double operator"" _w(long double param);
1149cbc9c4eaSNathan Ridge     void bar() {
1150cbc9c4eaSNathan Ridge       1.2_w;
1151cbc9c4eaSNathan Ridge     }
1152cbc9c4eaSNathan Ridge   )cpp");
1153cbc9c4eaSNathan Ridge }
1154cbc9c4eaSNathan Ridge 
1155753b247dSNathan Ridge TEST(ParameterHints, ParamNameComment) {
1156753b247dSNathan Ridge   // Do not hint an argument which already has a comment
1157753b247dSNathan Ridge   // with the parameter name preceding it.
1158753b247dSNathan Ridge   assertParameterHints(R"cpp(
1159753b247dSNathan Ridge     void foo(int param);
1160753b247dSNathan Ridge     void bar() {
1161753b247dSNathan Ridge       foo(/*param*/42);
1162753b247dSNathan Ridge       foo( /* param = */ 42);
1163cb2d04d4SYounan Zhang #define X 42
1164cb2d04d4SYounan Zhang #define Y X
1165cb2d04d4SYounan Zhang #define Z(...) Y
1166cb2d04d4SYounan Zhang       foo(/*param=*/Z(a));
1167cb2d04d4SYounan Zhang       foo($macro[[Z(a)]]);
1168753b247dSNathan Ridge       foo(/* the answer */$param[[42]]);
1169753b247dSNathan Ridge     }
1170753b247dSNathan Ridge   )cpp",
1171cb2d04d4SYounan Zhang                        ExpectedHint{"param: ", "macro"},
1172753b247dSNathan Ridge                        ExpectedHint{"param: ", "param"});
1173753b247dSNathan Ridge }
1174753b247dSNathan Ridge 
11756f6cf2daSNathan Ridge TEST(ParameterHints, SetterFunctions) {
11766f6cf2daSNathan Ridge   assertParameterHints(R"cpp(
11776f6cf2daSNathan Ridge     struct S {
11786f6cf2daSNathan Ridge       void setParent(S* parent);
11796f6cf2daSNathan Ridge       void set_parent(S* parent);
11806f6cf2daSNathan Ridge       void setTimeout(int timeoutMillis);
11816f6cf2daSNathan Ridge       void setTimeoutMillis(int timeout_millis);
11826f6cf2daSNathan Ridge     };
11836f6cf2daSNathan Ridge     void bar() {
11846f6cf2daSNathan Ridge       S s;
11856f6cf2daSNathan Ridge       // Parameter name matches setter name - omit hint.
11866f6cf2daSNathan Ridge       s.setParent(nullptr);
11876f6cf2daSNathan Ridge       // Support snake_case
11886f6cf2daSNathan Ridge       s.set_parent(nullptr);
11896f6cf2daSNathan Ridge       // Parameter name may contain extra info - show hint.
11906f6cf2daSNathan Ridge       s.setTimeout($timeoutMillis[[120]]);
11916f6cf2daSNathan Ridge       // FIXME: Ideally we'd want to omit this.
11926f6cf2daSNathan Ridge       s.setTimeoutMillis($timeout_millis[[120]]);
11936f6cf2daSNathan Ridge     }
11946f6cf2daSNathan Ridge   )cpp",
11956f6cf2daSNathan Ridge                        ExpectedHint{"timeoutMillis: ", "timeoutMillis"},
11966f6cf2daSNathan Ridge                        ExpectedHint{"timeout_millis: ", "timeout_millis"});
11976f6cf2daSNathan Ridge }
11986f6cf2daSNathan Ridge 
1199e984e1cdSTobias Ribizel TEST(ParameterHints, BuiltinFunctions) {
1200e984e1cdSTobias Ribizel   // This prototype of std::forward is sufficient for clang to recognize it
1201e984e1cdSTobias Ribizel   assertParameterHints(R"cpp(
1202e984e1cdSTobias Ribizel     namespace std { template <typename T> T&& forward(T&); }
1203e984e1cdSTobias Ribizel     void foo() {
1204e984e1cdSTobias Ribizel       int i;
1205e984e1cdSTobias Ribizel       std::forward(i);
1206e984e1cdSTobias Ribizel     }
1207e984e1cdSTobias Ribizel   )cpp");
1208e984e1cdSTobias Ribizel }
1209e984e1cdSTobias Ribizel 
121047d9d55cSNathan Ridge TEST(ParameterHints, IncludeAtNonGlobalScope) {
121147d9d55cSNathan Ridge   Annotations FooInc(R"cpp(
121247d9d55cSNathan Ridge     void bar() { foo(42); }
121347d9d55cSNathan Ridge   )cpp");
121447d9d55cSNathan Ridge   Annotations FooCC(R"cpp(
121547d9d55cSNathan Ridge     struct S {
121647d9d55cSNathan Ridge       void foo(int param);
121747d9d55cSNathan Ridge       #include "foo.inc"
121847d9d55cSNathan Ridge     };
121947d9d55cSNathan Ridge   )cpp");
122047d9d55cSNathan Ridge 
122147d9d55cSNathan Ridge   TestWorkspace Workspace;
122247d9d55cSNathan Ridge   Workspace.addSource("foo.inc", FooInc.code());
122347d9d55cSNathan Ridge   Workspace.addMainFile("foo.cc", FooCC.code());
122447d9d55cSNathan Ridge 
122547d9d55cSNathan Ridge   auto AST = Workspace.openFile("foo.cc");
122647d9d55cSNathan Ridge   ASSERT_TRUE(bool(AST));
122747d9d55cSNathan Ridge 
122847d9d55cSNathan Ridge   // Ensure the hint for the call in foo.inc is NOT materialized in foo.cc.
12293137ca80SKadir Cetinkaya   EXPECT_EQ(hintsOfKind(*AST, InlayHintKind::Parameter).size(), 0u);
123047d9d55cSNathan Ridge }
123147d9d55cSNathan Ridge 
12320be2657cSNathan Ridge TEST(TypeHints, Smoke) {
12330be2657cSNathan Ridge   assertTypeHints(R"cpp(
12340be2657cSNathan Ridge     auto $waldo[[waldo]] = 42;
12350be2657cSNathan Ridge   )cpp",
12360be2657cSNathan Ridge                   ExpectedHint{": int", "waldo"});
12370be2657cSNathan Ridge }
12380be2657cSNathan Ridge 
12390be2657cSNathan Ridge TEST(TypeHints, Decorations) {
12400be2657cSNathan Ridge   assertTypeHints(R"cpp(
12410be2657cSNathan Ridge     int x = 42;
12420be2657cSNathan Ridge     auto* $var1[[var1]] = &x;
12430be2657cSNathan Ridge     auto&& $var2[[var2]] = x;
12440be2657cSNathan Ridge     const auto& $var3[[var3]] = x;
12450be2657cSNathan Ridge   )cpp",
12460be2657cSNathan Ridge                   ExpectedHint{": int *", "var1"},
12470be2657cSNathan Ridge                   ExpectedHint{": int &", "var2"},
12480be2657cSNathan Ridge                   ExpectedHint{": const int &", "var3"});
12490be2657cSNathan Ridge }
12500be2657cSNathan Ridge 
12510be2657cSNathan Ridge TEST(TypeHints, DecltypeAuto) {
12520be2657cSNathan Ridge   assertTypeHints(R"cpp(
12530be2657cSNathan Ridge     int x = 42;
12540be2657cSNathan Ridge     int& y = x;
12550be2657cSNathan Ridge     decltype(auto) $z[[z]] = y;
12560be2657cSNathan Ridge   )cpp",
12570be2657cSNathan Ridge                   ExpectedHint{": int &", "z"});
12580be2657cSNathan Ridge }
12590be2657cSNathan Ridge 
12600be2657cSNathan Ridge TEST(TypeHints, NoQualifiers) {
12610be2657cSNathan Ridge   assertTypeHints(R"cpp(
12620be2657cSNathan Ridge     namespace A {
12630be2657cSNathan Ridge       namespace B {
12640be2657cSNathan Ridge         struct S1 {};
12650be2657cSNathan Ridge         S1 foo();
12660be2657cSNathan Ridge         auto $x[[x]] = foo();
12670be2657cSNathan Ridge 
12680be2657cSNathan Ridge         struct S2 {
12690be2657cSNathan Ridge           template <typename T>
12700be2657cSNathan Ridge           struct Inner {};
12710be2657cSNathan Ridge         };
12720be2657cSNathan Ridge         S2::Inner<int> bar();
12730be2657cSNathan Ridge         auto $y[[y]] = bar();
12740be2657cSNathan Ridge       }
12750be2657cSNathan Ridge     }
12760be2657cSNathan Ridge   )cpp",
1277c9e46219SMatheus Izvekov                   ExpectedHint{": S1", "x"},
1278c9e46219SMatheus Izvekov                   // FIXME: We want to suppress scope specifiers
1279c9e46219SMatheus Izvekov                   //        here because we are into the whole
1280c9e46219SMatheus Izvekov                   //        brevity thing, but the ElaboratedType
1281c9e46219SMatheus Izvekov                   //        printer does not honor the SuppressScope
1282c9e46219SMatheus Izvekov                   //        flag by design, so we need to extend the
1283c9e46219SMatheus Izvekov                   //        PrintingPolicy to support this use case.
1284c9e46219SMatheus Izvekov                   ExpectedHint{": S2::Inner<int>", "y"});
12850be2657cSNathan Ridge }
12860be2657cSNathan Ridge 
12870be2657cSNathan Ridge TEST(TypeHints, Lambda) {
12880be2657cSNathan Ridge   // Do not print something overly verbose like the lambda's location.
12890be2657cSNathan Ridge   // Show hints for init-captures (but not regular captures).
12900be2657cSNathan Ridge   assertTypeHints(R"cpp(
12910be2657cSNathan Ridge     void f() {
12920be2657cSNathan Ridge       int cap = 42;
1293257559edSSam McCall       auto $L[[L]] = [cap, $init[[init]] = 1 + 1](int a$ret[[)]] {
12940be2657cSNathan Ridge         return a + cap + init;
12950be2657cSNathan Ridge       };
12960be2657cSNathan Ridge     }
12970be2657cSNathan Ridge   )cpp",
12980be2657cSNathan Ridge                   ExpectedHint{": (lambda)", "L"},
1299257559edSSam McCall                   ExpectedHint{": int", "init"}, ExpectedHint{"-> int", "ret"});
1300257559edSSam McCall 
1301257559edSSam McCall   // Lambda return hint shown even if no param list.
130242cb812dSSam McCall   // (The digraph :> is just a ] that doesn't conflict with the annotations).
1303257559edSSam McCall   assertTypeHints("auto $L[[x]] = <:$ret[[:>]]{return 42;};",
1304257559edSSam McCall                   ExpectedHint{": (lambda)", "L"},
1305257559edSSam McCall                   ExpectedHint{"-> int", "ret"});
13060be2657cSNathan Ridge }
13070be2657cSNathan Ridge 
1308a15adbcdSNathan Ridge // Structured bindings tests.
1309a15adbcdSNathan Ridge // Note, we hint the individual bindings, not the aggregate.
1310a15adbcdSNathan Ridge 
1311a15adbcdSNathan Ridge TEST(TypeHints, StructuredBindings_PublicStruct) {
13120be2657cSNathan Ridge   assertTypeHints(R"cpp(
1313a15adbcdSNathan Ridge     // Struct with public fields.
13140be2657cSNathan Ridge     struct Point {
13150be2657cSNathan Ridge       int x;
13160be2657cSNathan Ridge       int y;
13170be2657cSNathan Ridge     };
13180be2657cSNathan Ridge     Point foo();
1319a15adbcdSNathan Ridge     auto [$x[[x]], $y[[y]]] = foo();
1320a15adbcdSNathan Ridge   )cpp",
1321a15adbcdSNathan Ridge                   ExpectedHint{": int", "x"}, ExpectedHint{": int", "y"});
1322a15adbcdSNathan Ridge }
1323a15adbcdSNathan Ridge 
1324a15adbcdSNathan Ridge TEST(TypeHints, StructuredBindings_Array) {
1325a15adbcdSNathan Ridge   assertTypeHints(R"cpp(
1326a15adbcdSNathan Ridge     int arr[2];
1327a15adbcdSNathan Ridge     auto [$x[[x]], $y[[y]]] = arr;
1328a15adbcdSNathan Ridge   )cpp",
1329a15adbcdSNathan Ridge                   ExpectedHint{": int", "x"}, ExpectedHint{": int", "y"});
1330a15adbcdSNathan Ridge }
1331a15adbcdSNathan Ridge 
1332a15adbcdSNathan Ridge TEST(TypeHints, StructuredBindings_TupleLike) {
1333a15adbcdSNathan Ridge   assertTypeHints(R"cpp(
1334a15adbcdSNathan Ridge     // Tuple-like type.
1335a15adbcdSNathan Ridge     struct IntPair {
1336a15adbcdSNathan Ridge       int a;
1337a15adbcdSNathan Ridge       int b;
1338a15adbcdSNathan Ridge     };
1339a15adbcdSNathan Ridge     namespace std {
1340a15adbcdSNathan Ridge       template <typename T>
1341a15adbcdSNathan Ridge       struct tuple_size {};
1342a15adbcdSNathan Ridge       template <>
1343a15adbcdSNathan Ridge       struct tuple_size<IntPair> {
1344a15adbcdSNathan Ridge         constexpr static unsigned value = 2;
1345a15adbcdSNathan Ridge       };
1346a15adbcdSNathan Ridge       template <unsigned I, typename T>
1347a15adbcdSNathan Ridge       struct tuple_element {};
1348a15adbcdSNathan Ridge       template <unsigned I>
1349a15adbcdSNathan Ridge       struct tuple_element<I, IntPair> {
1350a15adbcdSNathan Ridge         using type = int;
1351a15adbcdSNathan Ridge       };
1352a15adbcdSNathan Ridge     }
1353a15adbcdSNathan Ridge     template <unsigned I>
1354a15adbcdSNathan Ridge     int get(const IntPair& p) {
1355a15adbcdSNathan Ridge       if constexpr (I == 0) {
1356a15adbcdSNathan Ridge         return p.a;
1357a15adbcdSNathan Ridge       } else if constexpr (I == 1) {
1358a15adbcdSNathan Ridge         return p.b;
1359a15adbcdSNathan Ridge       }
1360a15adbcdSNathan Ridge     }
1361a15adbcdSNathan Ridge     IntPair bar();
1362a15adbcdSNathan Ridge     auto [$x[[x]], $y[[y]]] = bar();
1363a15adbcdSNathan Ridge   )cpp",
1364a15adbcdSNathan Ridge                   ExpectedHint{": int", "x"}, ExpectedHint{": int", "y"});
1365a15adbcdSNathan Ridge }
1366a15adbcdSNathan Ridge 
1367a15adbcdSNathan Ridge TEST(TypeHints, StructuredBindings_NoInitializer) {
1368a15adbcdSNathan Ridge   assertTypeHints(R"cpp(
1369a15adbcdSNathan Ridge     // No initializer (ill-formed).
1370a15adbcdSNathan Ridge     // Do not show useless "NULL TYPE" hint.
1371a15adbcdSNathan Ridge     auto [x, y];  /*error-ok*/
13720be2657cSNathan Ridge   )cpp");
13730be2657cSNathan Ridge }
13740be2657cSNathan Ridge 
137568d7f690SNathan Ridge TEST(TypeHints, InvalidType) {
137668d7f690SNathan Ridge   assertTypeHints(R"cpp(
137768d7f690SNathan Ridge     auto x = (unknown_type)42; /*error-ok*/
137868d7f690SNathan Ridge     auto *y = (unknown_ptr)nullptr;
137968d7f690SNathan Ridge   )cpp");
138068d7f690SNathan Ridge }
138168d7f690SNathan Ridge 
13820be2657cSNathan Ridge TEST(TypeHints, ReturnTypeDeduction) {
1383e37653daSNathan Ridge   assertTypeHints(
1384e37653daSNathan Ridge       R"cpp(
1385e37653daSNathan Ridge     auto f1(int x$ret1a[[)]];  // Hint forward declaration too
1386e37653daSNathan Ridge     auto f1(int x$ret1b[[)]] { return x + 1; }
1387e37653daSNathan Ridge 
1388e37653daSNathan Ridge     // Include pointer operators in hint
1389e37653daSNathan Ridge     int s;
1390e37653daSNathan Ridge     auto& f2($ret2[[)]] { return s; }
1391e37653daSNathan Ridge 
1392e37653daSNathan Ridge     // Do not hint `auto` for trailing return type.
1393e37653daSNathan Ridge     auto f3() -> int;
1394e37653daSNathan Ridge 
1395257559edSSam McCall     // Do not hint when a trailing return type is specified.
1396257559edSSam McCall     auto f4() -> auto* { return "foo"; }
1397257559edSSam McCall 
139842cb812dSSam McCall     auto f5($noreturn[[)]] {}
139942cb812dSSam McCall 
1400e37653daSNathan Ridge     // `auto` conversion operator
1401e37653daSNathan Ridge     struct A {
1402e37653daSNathan Ridge       operator auto($retConv[[)]] { return 42; }
1403e37653daSNathan Ridge     };
1404e37653daSNathan Ridge 
1405e37653daSNathan Ridge     // FIXME: Dependent types do not work yet.
1406e37653daSNathan Ridge     template <typename T>
1407e37653daSNathan Ridge     struct S {
1408e37653daSNathan Ridge       auto method() { return T(); }
1409e37653daSNathan Ridge     };
1410e37653daSNathan Ridge   )cpp",
1411e37653daSNathan Ridge       ExpectedHint{"-> int", "ret1a"}, ExpectedHint{"-> int", "ret1b"},
141242cb812dSSam McCall       ExpectedHint{"-> int &", "ret2"}, ExpectedHint{"-> void", "noreturn"},
141342cb812dSSam McCall       ExpectedHint{"-> int", "retConv"});
14140be2657cSNathan Ridge }
14150be2657cSNathan Ridge 
14160be2657cSNathan Ridge TEST(TypeHints, DependentType) {
14170be2657cSNathan Ridge   assertTypeHints(R"cpp(
14180be2657cSNathan Ridge     template <typename T>
14190be2657cSNathan Ridge     void foo(T arg) {
14200be2657cSNathan Ridge       // The hint would just be "auto" and we can't do any better.
14210be2657cSNathan Ridge       auto var1 = arg.method();
14220be2657cSNathan Ridge       // FIXME: It would be nice to show "T" as the hint.
14230be2657cSNathan Ridge       auto $var2[[var2]] = arg;
14240be2657cSNathan Ridge     }
1425dc10bd43SYuanjing Hong 
1426dc10bd43SYuanjing Hong     template <typename T>
1427dc10bd43SYuanjing Hong     void bar(T arg) {
1428dc10bd43SYuanjing Hong       auto [a, b] = arg;
1429dc10bd43SYuanjing Hong     }
14300be2657cSNathan Ridge   )cpp");
14310be2657cSNathan Ridge }
14320be2657cSNathan Ridge 
1433c2810f2cSNathan Ridge TEST(TypeHints, LongTypeName) {
1434c2810f2cSNathan Ridge   assertTypeHints(R"cpp(
1435c2810f2cSNathan Ridge     template <typename, typename, typename>
1436c2810f2cSNathan Ridge     struct A {};
1437c2810f2cSNathan Ridge     struct MultipleWords {};
1438c2810f2cSNathan Ridge     A<MultipleWords, MultipleWords, MultipleWords> foo();
1439c2810f2cSNathan Ridge     // Omit type hint past a certain length (currently 32)
1440c2810f2cSNathan Ridge     auto var = foo();
1441c2810f2cSNathan Ridge   )cpp");
14422ae1aa9dSzhangyi1357 
14432ae1aa9dSzhangyi1357   Config Cfg;
14442ae1aa9dSzhangyi1357   Cfg.InlayHints.TypeNameLimit = 0;
14452ae1aa9dSzhangyi1357   WithContextValue WithCfg(Config::Key, std::move(Cfg));
14462ae1aa9dSzhangyi1357 
14472ae1aa9dSzhangyi1357   assertTypeHints(
14482ae1aa9dSzhangyi1357       R"cpp(
14492ae1aa9dSzhangyi1357     template <typename, typename, typename>
14502ae1aa9dSzhangyi1357     struct A {};
14512ae1aa9dSzhangyi1357     struct MultipleWords {};
14522ae1aa9dSzhangyi1357     A<MultipleWords, MultipleWords, MultipleWords> foo();
14532ae1aa9dSzhangyi1357     // Should have type hint with TypeNameLimit = 0
14542ae1aa9dSzhangyi1357     auto $var[[var]] = foo();
14552ae1aa9dSzhangyi1357   )cpp",
14562ae1aa9dSzhangyi1357       ExpectedHint{": A<MultipleWords, MultipleWords, MultipleWords>", "var"});
1457c2810f2cSNathan Ridge }
1458c2810f2cSNathan Ridge 
14593e03d92eSNathan Ridge TEST(TypeHints, DefaultTemplateArgs) {
14603e03d92eSNathan Ridge   assertTypeHints(R"cpp(
14613e03d92eSNathan Ridge     template <typename, typename = int>
14623e03d92eSNathan Ridge     struct A {};
14633e03d92eSNathan Ridge     A<float> foo();
14643e03d92eSNathan Ridge     auto $var[[var]] = foo();
14655cdb906fSYounan Zhang     A<float> bar[1];
14665cdb906fSYounan Zhang     auto [$binding[[value]]] = bar;
14673e03d92eSNathan Ridge   )cpp",
14685cdb906fSYounan Zhang                   ExpectedHint{": A<float>", "var"},
14695cdb906fSYounan Zhang                   ExpectedHint{": A<float>", "binding"});
14703e03d92eSNathan Ridge }
14713e03d92eSNathan Ridge 
14722eb16991STor Shepherd TEST(DefaultArguments, Smoke) {
14732eb16991STor Shepherd   Config Cfg;
14742eb16991STor Shepherd   Cfg.InlayHints.Parameters =
14752eb16991STor Shepherd       true; // To test interplay of parameters and default parameters
14762eb16991STor Shepherd   Cfg.InlayHints.DeducedTypes = false;
14772eb16991STor Shepherd   Cfg.InlayHints.Designators = false;
14782eb16991STor Shepherd   Cfg.InlayHints.BlockEnd = false;
14792eb16991STor Shepherd 
14802eb16991STor Shepherd   Cfg.InlayHints.DefaultArguments = true;
14812eb16991STor Shepherd   WithContextValue WithCfg(Config::Key, std::move(Cfg));
14822eb16991STor Shepherd 
14832eb16991STor Shepherd   const auto *Code = R"cpp(
14842eb16991STor Shepherd     int foo(int A = 4) { return A; }
14852eb16991STor Shepherd     int bar(int A, int B = 1, bool C = foo($default1[[)]]) { return A; }
14862eb16991STor Shepherd     int A = bar($explicit[[2]]$default2[[)]];
14872eb16991STor Shepherd 
14882eb16991STor Shepherd     void baz(int = 5) { if (false) baz($unnamed[[)]]; };
14892eb16991STor Shepherd   )cpp";
14902eb16991STor Shepherd 
14912eb16991STor Shepherd   assertHints(InlayHintKind::DefaultArgument, Code,
14922eb16991STor Shepherd               ExpectedHint{"A: 4", "default1", Left},
14932eb16991STor Shepherd               ExpectedHint{", B: 1, C: foo()", "default2", Left},
14942eb16991STor Shepherd               ExpectedHint{"5", "unnamed", Left});
14952eb16991STor Shepherd 
14962eb16991STor Shepherd   assertHints(InlayHintKind::Parameter, Code,
14972eb16991STor Shepherd               ExpectedHint{"A: ", "explicit", Left});
14982eb16991STor Shepherd }
14992eb16991STor Shepherd 
15002eb16991STor Shepherd TEST(DefaultArguments, WithoutParameterNames) {
15012eb16991STor Shepherd   Config Cfg;
15022eb16991STor Shepherd   Cfg.InlayHints.Parameters = false; // To test just default args this time
15032eb16991STor Shepherd   Cfg.InlayHints.DeducedTypes = false;
15042eb16991STor Shepherd   Cfg.InlayHints.Designators = false;
15052eb16991STor Shepherd   Cfg.InlayHints.BlockEnd = false;
15062eb16991STor Shepherd 
15072eb16991STor Shepherd   Cfg.InlayHints.DefaultArguments = true;
15082eb16991STor Shepherd   WithContextValue WithCfg(Config::Key, std::move(Cfg));
15092eb16991STor Shepherd 
15102eb16991STor Shepherd   const auto *Code = R"cpp(
15112eb16991STor Shepherd     struct Baz {
15122eb16991STor Shepherd       Baz(float a = 3 //
15132eb16991STor Shepherd                     + 2);
15142eb16991STor Shepherd     };
15152eb16991STor Shepherd     struct Foo {
15162eb16991STor Shepherd       Foo(int, Baz baz = //
15172eb16991STor Shepherd               Baz{$abbreviated[[}]]
15182eb16991STor Shepherd 
15192eb16991STor Shepherd           //
15202eb16991STor Shepherd       ) {}
15212eb16991STor Shepherd     };
15222eb16991STor Shepherd 
15232eb16991STor Shepherd     int main() {
15242eb16991STor Shepherd       Foo foo1(1$paren[[)]];
15252eb16991STor Shepherd       Foo foo2{2$brace1[[}]];
15262eb16991STor Shepherd       Foo foo3 = {3$brace2[[}]];
15272eb16991STor Shepherd       auto foo4 = Foo{4$brace3[[}]];
15282eb16991STor Shepherd     }
15292eb16991STor Shepherd   )cpp";
15302eb16991STor Shepherd 
15312eb16991STor Shepherd   assertHints(InlayHintKind::DefaultArgument, Code,
15322eb16991STor Shepherd               ExpectedHint{"...", "abbreviated", Left},
15332eb16991STor Shepherd               ExpectedHint{", Baz{}", "paren", Left},
15342eb16991STor Shepherd               ExpectedHint{", Baz{}", "brace1", Left},
15352eb16991STor Shepherd               ExpectedHint{", Baz{}", "brace2", Left},
15362eb16991STor Shepherd               ExpectedHint{", Baz{}", "brace3", Left});
15372eb16991STor Shepherd 
15382eb16991STor Shepherd   assertHints(InlayHintKind::Parameter, Code);
15392eb16991STor Shepherd }
15402eb16991STor Shepherd 
1541d87d1aa0SNathan Ridge TEST(TypeHints, Deduplication) {
1542d87d1aa0SNathan Ridge   assertTypeHints(R"cpp(
1543d87d1aa0SNathan Ridge     template <typename T>
1544d87d1aa0SNathan Ridge     void foo() {
1545d87d1aa0SNathan Ridge       auto $var[[var]] = 42;
1546d87d1aa0SNathan Ridge     }
1547d87d1aa0SNathan Ridge     template void foo<int>();
1548d87d1aa0SNathan Ridge     template void foo<float>();
1549d87d1aa0SNathan Ridge   )cpp",
1550d87d1aa0SNathan Ridge                   ExpectedHint{": int", "var"});
1551d87d1aa0SNathan Ridge }
1552d87d1aa0SNathan Ridge 
15532da5c578SSam McCall TEST(TypeHints, SinglyInstantiatedTemplate) {
15542da5c578SSam McCall   assertTypeHints(R"cpp(
15552da5c578SSam McCall     auto $lambda[[x]] = [](auto *$param[[y]], auto) { return 42; };
15562da5c578SSam McCall     int m = x("foo", 3);
15572da5c578SSam McCall   )cpp",
15582da5c578SSam McCall                   ExpectedHint{": (lambda)", "lambda"},
15592da5c578SSam McCall                   ExpectedHint{": const char *", "param"});
15602da5c578SSam McCall 
15612da5c578SSam McCall   // No hint for packs, or auto params following packs
15622da5c578SSam McCall   assertTypeHints(R"cpp(
15632da5c578SSam McCall     int x(auto $a[[a]], auto... b, auto c) { return 42; }
15642da5c578SSam McCall     int m = x<void*, char, float>(nullptr, 'c', 2.0, 2);
15652da5c578SSam McCall   )cpp",
15662da5c578SSam McCall                   ExpectedHint{": void *", "a"});
15672da5c578SSam McCall }
15682da5c578SSam McCall 
15696385c039SSam McCall TEST(TypeHints, Aliased) {
15706385c039SSam McCall   // Check that we don't crash for functions without a FunctionTypeLoc.
15716385c039SSam McCall   // https://github.com/clangd/clangd/issues/1140
15726385c039SSam McCall   TestTU TU = TestTU::withCode("void foo(void){} extern typeof(foo) foo;");
15736385c039SSam McCall   TU.ExtraArgs.push_back("-xc");
15746385c039SSam McCall   auto AST = TU.build();
15756385c039SSam McCall 
15763137ca80SKadir Cetinkaya   EXPECT_THAT(hintsOfKind(AST, InlayHintKind::Type), IsEmpty());
15776385c039SSam McCall }
15786385c039SSam McCall 
1579*5518bb21SNathan Ridge TEST(TypeHints, CallingConvention) {
1580*5518bb21SNathan Ridge   // Check that we don't crash for lambdas without a FunctionTypeLoc
1581*5518bb21SNathan Ridge   // https://github.com/clangd/clangd/issues/2223
1582*5518bb21SNathan Ridge   std::string Code = R"cpp(
1583*5518bb21SNathan Ridge     void test() {
1584*5518bb21SNathan Ridge       []() __cdecl {};
1585*5518bb21SNathan Ridge     }
1586*5518bb21SNathan Ridge   )cpp";
1587*5518bb21SNathan Ridge   TestTU TU = TestTU::withCode(Code);
1588*5518bb21SNathan Ridge   TU.ExtraArgs.push_back("--target=x86_64-w64-mingw32");
1589*5518bb21SNathan Ridge   TU.PredefineMacros = true; // for the __cdecl
1590*5518bb21SNathan Ridge   auto AST = TU.build();
1591*5518bb21SNathan Ridge 
1592*5518bb21SNathan Ridge   EXPECT_THAT(hintsOfKind(AST, InlayHintKind::Type), IsEmpty());
1593*5518bb21SNathan Ridge }
1594*5518bb21SNathan Ridge 
15954b2cf982Sv1nh1shungry TEST(TypeHints, Decltype) {
15964b2cf982Sv1nh1shungry   assertTypeHints(R"cpp(
15974b2cf982Sv1nh1shungry     $a[[decltype(0)]] a;
15984b2cf982Sv1nh1shungry     $b[[decltype(a)]] b;
15994b2cf982Sv1nh1shungry     const $c[[decltype(0)]] &c = b;
16004b2cf982Sv1nh1shungry 
16014b2cf982Sv1nh1shungry     // Don't show for dependent type
16024b2cf982Sv1nh1shungry     template <class T>
16034b2cf982Sv1nh1shungry     constexpr decltype(T{}) d;
16044b2cf982Sv1nh1shungry 
16054b2cf982Sv1nh1shungry     $e[[decltype(0)]] e();
16064b2cf982Sv1nh1shungry     auto f() -> $f[[decltype(0)]];
16074b2cf982Sv1nh1shungry 
16084b2cf982Sv1nh1shungry     template <class, class> struct Foo;
16094b2cf982Sv1nh1shungry     using G = Foo<$g[[decltype(0)]], float>;
1610dde8a0feSv1nh1shungry 
1611dde8a0feSv1nh1shungry     auto $h[[h]] = $i[[decltype(0)]]{};
1612f7e9d5b4SHaojian Wu 
1613f7e9d5b4SHaojian Wu     // No crash
1614f7e9d5b4SHaojian Wu     /* error-ok */
1615f7e9d5b4SHaojian Wu     auto $j[[s]];
16164b2cf982Sv1nh1shungry   )cpp",
1617dde8a0feSv1nh1shungry                   ExpectedHint{": int", "a"}, ExpectedHint{": int", "b"},
16184b2cf982Sv1nh1shungry                   ExpectedHint{": int", "c"}, ExpectedHint{": int", "e"},
1619dde8a0feSv1nh1shungry                   ExpectedHint{": int", "f"}, ExpectedHint{": int", "g"},
162089590cd1SNathan Ridge                   ExpectedHint{": int", "h"}, ExpectedHint{": int", "i"});
16214b2cf982Sv1nh1shungry }
16224b2cf982Sv1nh1shungry 
16237d68f2efSYounan Zhang TEST(TypeHints, SubstTemplateParameterAliases) {
1624b1193c13SYounan Zhang   llvm::StringRef Header = R"cpp(
16257d68f2efSYounan Zhang   template <class T> struct allocator {};
16267d68f2efSYounan Zhang 
16277d68f2efSYounan Zhang   template <class T, class A>
16287d68f2efSYounan Zhang   struct vector_base {
16297d68f2efSYounan Zhang     using pointer = T*;
16307d68f2efSYounan Zhang   };
16317d68f2efSYounan Zhang 
16327d68f2efSYounan Zhang   template <class T, class A>
16337d68f2efSYounan Zhang   struct internal_iterator_type_template_we_dont_expect {};
16347d68f2efSYounan Zhang 
16357d68f2efSYounan Zhang   struct my_iterator {};
16367d68f2efSYounan Zhang 
16377d68f2efSYounan Zhang   template <class T, class A = allocator<T>>
16387d68f2efSYounan Zhang   struct vector : vector_base<T, A> {
16397d68f2efSYounan Zhang     using base = vector_base<T, A>;
16407d68f2efSYounan Zhang     typedef T value_type;
16417d68f2efSYounan Zhang     typedef base::pointer pointer;
16427d68f2efSYounan Zhang     using allocator_type = A;
16437d68f2efSYounan Zhang     using size_type = int;
16447d68f2efSYounan Zhang     using iterator = internal_iterator_type_template_we_dont_expect<T, A>;
16457d68f2efSYounan Zhang     using non_template_iterator = my_iterator;
16467d68f2efSYounan Zhang 
16477d68f2efSYounan Zhang     value_type& operator[](int index) { return elements[index]; }
16487d68f2efSYounan Zhang     const value_type& at(int index) const { return elements[index]; }
16497d68f2efSYounan Zhang     pointer data() { return &elements[0]; }
16507d68f2efSYounan Zhang     allocator_type get_allocator() { return A(); }
16517d68f2efSYounan Zhang     size_type size() const { return 10; }
16527d68f2efSYounan Zhang     iterator begin() { return iterator(); }
16537d68f2efSYounan Zhang     non_template_iterator end() { return non_template_iterator(); }
16547d68f2efSYounan Zhang 
16557d68f2efSYounan Zhang     T elements[10];
16567d68f2efSYounan Zhang   };
1657b1193c13SYounan Zhang   )cpp";
16587d68f2efSYounan Zhang 
1659b1193c13SYounan Zhang   llvm::StringRef VectorIntPtr = R"cpp(
1660b1193c13SYounan Zhang     vector<int *> array;
1661b1193c13SYounan Zhang     auto $no_modifier[[x]] = array[3];
1662b1193c13SYounan Zhang     auto* $ptr_modifier[[ptr]] = &array[3];
1663b1193c13SYounan Zhang     auto& $ref_modifier[[ref]] = array[3];
1664b1193c13SYounan Zhang     auto& $at[[immutable]] = array.at(3);
1665b1193c13SYounan Zhang 
1666b1193c13SYounan Zhang     auto $data[[data]] = array.data();
1667b1193c13SYounan Zhang     auto $allocator[[alloc]] = array.get_allocator();
1668b1193c13SYounan Zhang     auto $size[[size]] = array.size();
1669b1193c13SYounan Zhang     auto $begin[[begin]] = array.begin();
1670b1193c13SYounan Zhang     auto $end[[end]] = array.end();
1671b1193c13SYounan Zhang   )cpp";
1672b1193c13SYounan Zhang 
1673b1193c13SYounan Zhang   assertHintsWithHeader(
1674b1193c13SYounan Zhang       InlayHintKind::Type, VectorIntPtr, Header,
1675b1193c13SYounan Zhang       ExpectedHint{": int *", "no_modifier"},
1676b1193c13SYounan Zhang       ExpectedHint{": int **", "ptr_modifier"},
1677b1193c13SYounan Zhang       ExpectedHint{": int *&", "ref_modifier"},
1678b1193c13SYounan Zhang       ExpectedHint{": int *const &", "at"}, ExpectedHint{": int **", "data"},
1679b1193c13SYounan Zhang       ExpectedHint{": allocator<int *>", "allocator"},
1680b1193c13SYounan Zhang       ExpectedHint{": size_type", "size"}, ExpectedHint{": iterator", "begin"},
1681b1193c13SYounan Zhang       ExpectedHint{": non_template_iterator", "end"});
1682b1193c13SYounan Zhang 
1683b1193c13SYounan Zhang   llvm::StringRef VectorInt = R"cpp(
16847d68f2efSYounan Zhang   vector<int> array;
16857d68f2efSYounan Zhang   auto $no_modifier[[by_value]] = array[3];
16867d68f2efSYounan Zhang   auto* $ptr_modifier[[ptr]] = &array[3];
16877d68f2efSYounan Zhang   auto& $ref_modifier[[ref]] = array[3];
16887d68f2efSYounan Zhang   auto& $at[[immutable]] = array.at(3);
16897d68f2efSYounan Zhang 
16907d68f2efSYounan Zhang   auto $data[[data]] = array.data();
16917d68f2efSYounan Zhang   auto $allocator[[alloc]] = array.get_allocator();
16927d68f2efSYounan Zhang   auto $size[[size]] = array.size();
16937d68f2efSYounan Zhang   auto $begin[[begin]] = array.begin();
16947d68f2efSYounan Zhang   auto $end[[end]] = array.end();
1695b1193c13SYounan Zhang   )cpp";
16967d68f2efSYounan Zhang 
1697b1193c13SYounan Zhang   assertHintsWithHeader(
1698b1193c13SYounan Zhang       InlayHintKind::Type, VectorInt, Header,
1699b1193c13SYounan Zhang       ExpectedHint{": int", "no_modifier"},
1700b1193c13SYounan Zhang       ExpectedHint{": int *", "ptr_modifier"},
1701b1193c13SYounan Zhang       ExpectedHint{": int &", "ref_modifier"},
1702b1193c13SYounan Zhang       ExpectedHint{": const int &", "at"}, ExpectedHint{": int *", "data"},
1703b1193c13SYounan Zhang       ExpectedHint{": allocator<int>", "allocator"},
1704b1193c13SYounan Zhang       ExpectedHint{": size_type", "size"}, ExpectedHint{": iterator", "begin"},
1705b1193c13SYounan Zhang       ExpectedHint{": non_template_iterator", "end"});
17067d68f2efSYounan Zhang 
1707b1193c13SYounan Zhang   llvm::StringRef TypeAlias = R"cpp(
17087d68f2efSYounan Zhang   // If the type alias is not of substituted template parameter type,
17097d68f2efSYounan Zhang   // do not show desugared type.
17107d68f2efSYounan Zhang   using VeryLongLongTypeName = my_iterator;
17117d68f2efSYounan Zhang   using Short = VeryLongLongTypeName;
17127d68f2efSYounan Zhang 
17137d68f2efSYounan Zhang   auto $short_name[[my_value]] = Short();
17147d68f2efSYounan Zhang 
17157d68f2efSYounan Zhang   // Same applies with templates.
17167d68f2efSYounan Zhang   template <typename T, typename A>
17177d68f2efSYounan Zhang   using basic_static_vector = vector<T, A>;
17187d68f2efSYounan Zhang   template <typename T>
17197d68f2efSYounan Zhang   using static_vector = basic_static_vector<T, allocator<T>>;
17207d68f2efSYounan Zhang 
17217d68f2efSYounan Zhang   auto $vector_name[[vec]] = static_vector<int>();
1722b1193c13SYounan Zhang   )cpp";
1723b1193c13SYounan Zhang 
1724b1193c13SYounan Zhang   assertHintsWithHeader(InlayHintKind::Type, TypeAlias, Header,
17257d68f2efSYounan Zhang                         ExpectedHint{": Short", "short_name"},
17267d68f2efSYounan Zhang                         ExpectedHint{": static_vector<int>", "vector_name"});
17277d68f2efSYounan Zhang }
17287d68f2efSYounan Zhang 
1729ce944327SSam McCall TEST(DesignatorHints, Basic) {
1730ce944327SSam McCall   assertDesignatorHints(R"cpp(
1731ce944327SSam McCall     struct S { int x, y, z; };
1732ce944327SSam McCall     S s {$x[[1]], $y[[2+2]]};
1733ce944327SSam McCall 
1734ce944327SSam McCall     int x[] = {$0[[0]], $1[[1]]};
1735ce944327SSam McCall   )cpp",
1736ce944327SSam McCall                         ExpectedHint{".x=", "x"}, ExpectedHint{".y=", "y"},
1737ce944327SSam McCall                         ExpectedHint{"[0]=", "0"}, ExpectedHint{"[1]=", "1"});
1738ce944327SSam McCall }
1739ce944327SSam McCall 
1740ce944327SSam McCall TEST(DesignatorHints, Nested) {
1741ce944327SSam McCall   assertDesignatorHints(R"cpp(
1742ce944327SSam McCall     struct Inner { int x, y; };
1743ce944327SSam McCall     struct Outer { Inner a, b; };
1744ce944327SSam McCall     Outer o{ $a[[{ $x[[1]], $y[[2]] }]], $bx[[3]] };
1745ce944327SSam McCall   )cpp",
1746ce944327SSam McCall                         ExpectedHint{".a=", "a"}, ExpectedHint{".x=", "x"},
1747ce944327SSam McCall                         ExpectedHint{".y=", "y"}, ExpectedHint{".b.x=", "bx"});
1748ce944327SSam McCall }
1749ce944327SSam McCall 
1750ce944327SSam McCall TEST(DesignatorHints, AnonymousRecord) {
1751ce944327SSam McCall   assertDesignatorHints(R"cpp(
1752ce944327SSam McCall     struct S {
1753ce944327SSam McCall       union {
1754ce944327SSam McCall         struct {
1755ce944327SSam McCall           struct {
1756ce944327SSam McCall             int y;
1757ce944327SSam McCall           };
1758ce944327SSam McCall         } x;
1759ce944327SSam McCall       };
1760ce944327SSam McCall     };
1761ce944327SSam McCall     S s{$xy[[42]]};
1762ce944327SSam McCall   )cpp",
1763ce944327SSam McCall                         ExpectedHint{".x.y=", "xy"});
1764ce944327SSam McCall }
1765ce944327SSam McCall 
1766ce944327SSam McCall TEST(DesignatorHints, Suppression) {
1767ce944327SSam McCall   assertDesignatorHints(R"cpp(
1768ce944327SSam McCall     struct Point { int a, b, c, d, e, f, g, h; };
1769ce944327SSam McCall     Point p{/*a=*/1, .c=2, /* .d = */3, $e[[4]]};
1770ce944327SSam McCall   )cpp",
1771ce944327SSam McCall                         ExpectedHint{".e=", "e"});
1772ce944327SSam McCall }
1773ce944327SSam McCall 
1774ce944327SSam McCall TEST(DesignatorHints, StdArray) {
1775ce944327SSam McCall   // Designators for std::array should be [0] rather than .__elements[0].
1776ce944327SSam McCall   // While technically correct, the designator is useless and horrible to read.
1777ce944327SSam McCall   assertDesignatorHints(R"cpp(
1778ce944327SSam McCall     template <typename T, int N> struct Array { T __elements[N]; };
1779ce944327SSam McCall     Array<int, 2> x = {$0[[0]], $1[[1]]};
1780ce944327SSam McCall   )cpp",
1781ce944327SSam McCall                         ExpectedHint{"[0]=", "0"}, ExpectedHint{"[1]=", "1"});
1782ce944327SSam McCall }
1783ce944327SSam McCall 
1784ce944327SSam McCall TEST(DesignatorHints, OnlyAggregateInit) {
1785ce944327SSam McCall   assertDesignatorHints(R"cpp(
1786ce944327SSam McCall     struct Copyable { int x; } c;
1787ce944327SSam McCall     Copyable d{c};
1788ce944327SSam McCall 
1789ce944327SSam McCall     struct Constructible { Constructible(int x); };
1790ce944327SSam McCall     Constructible x{42};
1791ce944327SSam McCall   )cpp" /*no designator hints expected (but param hints!)*/);
1792ce944327SSam McCall }
1793ce944327SSam McCall 
179406b97b49SHaojian Wu TEST(DesignatorHints, NoCrash) {
179506b97b49SHaojian Wu   assertDesignatorHints(R"cpp(
179606b97b49SHaojian Wu     /*error-ok*/
179706b97b49SHaojian Wu     struct A {};
179806b97b49SHaojian Wu     struct Foo {int a; int b;};
179906b97b49SHaojian Wu     void test() {
180006b97b49SHaojian Wu       Foo f{A(), $b[[1]]};
180106b97b49SHaojian Wu     }
18020fc69b14SYounan Zhang   )cpp",
18030fc69b14SYounan Zhang                         ExpectedHint{".b=", "b"});
180406b97b49SHaojian Wu }
180506b97b49SHaojian Wu 
18067c19fdd5SSam McCall TEST(InlayHints, RestrictRange) {
18077c19fdd5SSam McCall   Annotations Code(R"cpp(
18087c19fdd5SSam McCall     auto a = false;
18097c19fdd5SSam McCall     [[auto b = 1;
18107c19fdd5SSam McCall     auto c = '2';]]
18117c19fdd5SSam McCall     auto d = 3.f;
18127c19fdd5SSam McCall   )cpp");
18137c19fdd5SSam McCall   auto AST = TestTU::withCode(Code.code()).build();
18147c19fdd5SSam McCall   EXPECT_THAT(inlayHints(AST, Code.range()),
18157c19fdd5SSam McCall               ElementsAre(labelIs(": int"), labelIs(": char")));
18167c19fdd5SSam McCall }
18177c19fdd5SSam McCall 
18180fc69b14SYounan Zhang TEST(ParameterHints, PseudoObjectExpr) {
18190fc69b14SYounan Zhang   Annotations Code(R"cpp(
18200fc69b14SYounan Zhang     struct S {
18210fc69b14SYounan Zhang       __declspec(property(get=GetX, put=PutX)) int x[];
18220fc69b14SYounan Zhang       int GetX(int y, int z) { return 42 + y; }
18230fc69b14SYounan Zhang       void PutX(int) { }
18240fc69b14SYounan Zhang 
18250fc69b14SYounan Zhang       // This is a PseudoObjectExpression whose syntactic form is a binary
18260fc69b14SYounan Zhang       // operator.
18270fc69b14SYounan Zhang       void Work(int y) { x = y; } // Not `x = y: y`.
18280fc69b14SYounan Zhang     };
18290fc69b14SYounan Zhang 
18300fc69b14SYounan Zhang     int printf(const char *Format, ...);
18310fc69b14SYounan Zhang 
18320fc69b14SYounan Zhang     int main() {
18330fc69b14SYounan Zhang       S s;
18340fc69b14SYounan Zhang       __builtin_dump_struct(&s, printf); // Not `Format: __builtin_dump_struct()`
18350fc69b14SYounan Zhang       printf($Param[["Hello, %d"]], 42); // Normal calls are not affected.
18360fc69b14SYounan Zhang       // This builds a PseudoObjectExpr, but here it's useful for showing the
18370fc69b14SYounan Zhang       // arguments from the semantic form.
18380fc69b14SYounan Zhang       return s.x[ $one[[1]] ][ $two[[2]] ]; // `x[y: 1][z: 2]`
18390fc69b14SYounan Zhang     }
18400fc69b14SYounan Zhang   )cpp");
18410fc69b14SYounan Zhang   auto TU = TestTU::withCode(Code.code());
18420fc69b14SYounan Zhang   TU.ExtraArgs.push_back("-fms-extensions");
18430fc69b14SYounan Zhang   auto AST = TU.build();
18440fc69b14SYounan Zhang   EXPECT_THAT(inlayHints(AST, std::nullopt),
18450fc69b14SYounan Zhang               ElementsAre(HintMatcher(ExpectedHint{"Format: ", "Param"}, Code),
18460fc69b14SYounan Zhang                           HintMatcher(ExpectedHint{"y: ", "one"}, Code),
18470fc69b14SYounan Zhang                           HintMatcher(ExpectedHint{"z: ", "two"}, Code)));
18480fc69b14SYounan Zhang }
18490fc69b14SYounan Zhang 
18504839929bSKadir Cetinkaya TEST(ParameterHints, ArgPacksAndConstructors) {
18514839929bSKadir Cetinkaya   assertParameterHints(
18524839929bSKadir Cetinkaya       R"cpp(
18534839929bSKadir Cetinkaya     struct Foo{ Foo(); Foo(int x); };
18544839929bSKadir Cetinkaya     void foo(Foo a, int b);
18554839929bSKadir Cetinkaya     template <typename... Args>
18564839929bSKadir Cetinkaya     void bar(Args... args) {
18574839929bSKadir Cetinkaya       foo(args...);
18584839929bSKadir Cetinkaya     }
18594839929bSKadir Cetinkaya     template <typename... Args>
18604839929bSKadir Cetinkaya     void baz(Args... args) { foo($param1[[Foo{args...}]], $param2[[1]]); }
18614839929bSKadir Cetinkaya 
18624839929bSKadir Cetinkaya     template <typename... Args>
18634839929bSKadir Cetinkaya     void bax(Args... args) { foo($param3[[{args...}]], args...); }
18644839929bSKadir Cetinkaya 
18654839929bSKadir Cetinkaya     void foo() {
18664839929bSKadir Cetinkaya       bar($param4[[Foo{}]], $param5[[42]]);
18674839929bSKadir Cetinkaya       bar($param6[[42]], $param7[[42]]);
18684839929bSKadir Cetinkaya       baz($param8[[42]]);
18694839929bSKadir Cetinkaya       bax($param9[[42]]);
18704839929bSKadir Cetinkaya     }
18714839929bSKadir Cetinkaya   )cpp",
18724839929bSKadir Cetinkaya       ExpectedHint{"a: ", "param1"}, ExpectedHint{"b: ", "param2"},
18734839929bSKadir Cetinkaya       ExpectedHint{"a: ", "param3"}, ExpectedHint{"a: ", "param4"},
18744839929bSKadir Cetinkaya       ExpectedHint{"b: ", "param5"}, ExpectedHint{"a: ", "param6"},
18754839929bSKadir Cetinkaya       ExpectedHint{"b: ", "param7"}, ExpectedHint{"x: ", "param8"},
18764839929bSKadir Cetinkaya       ExpectedHint{"b: ", "param9"});
18774839929bSKadir Cetinkaya }
18784839929bSKadir Cetinkaya 
18794839929bSKadir Cetinkaya TEST(ParameterHints, DoesntExpandAllArgs) {
18804839929bSKadir Cetinkaya   assertParameterHints(
18814839929bSKadir Cetinkaya       R"cpp(
18824839929bSKadir Cetinkaya     void foo(int x, int y);
18834839929bSKadir Cetinkaya     int id(int a, int b, int c);
18844839929bSKadir Cetinkaya     template <typename... Args>
18854839929bSKadir Cetinkaya     void bar(Args... args) {
18864839929bSKadir Cetinkaya       foo(id($param1[[args]], $param2[[1]], $param3[[args]])...);
18874839929bSKadir Cetinkaya     }
18884839929bSKadir Cetinkaya     void foo() {
18894839929bSKadir Cetinkaya       bar(1, 2); // FIXME: We could have `bar(a: 1, a: 2)` here.
18904839929bSKadir Cetinkaya     }
18914839929bSKadir Cetinkaya   )cpp",
18924839929bSKadir Cetinkaya       ExpectedHint{"a: ", "param1"}, ExpectedHint{"b: ", "param2"},
18934839929bSKadir Cetinkaya       ExpectedHint{"c: ", "param3"});
18944839929bSKadir Cetinkaya }
18959e6a342fSdaiyousei-qz 
18969e6a342fSdaiyousei-qz TEST(BlockEndHints, Functions) {
18979e6a342fSdaiyousei-qz   assertBlockEndHints(R"cpp(
18989e6a342fSdaiyousei-qz     int foo() {
18999e6a342fSdaiyousei-qz       return 41;
19009e6a342fSdaiyousei-qz     $foo[[}]]
19019e6a342fSdaiyousei-qz 
19029e6a342fSdaiyousei-qz     template<int X>
19039e6a342fSdaiyousei-qz     int bar() {
19049e6a342fSdaiyousei-qz       // No hint for lambda for now
19059e6a342fSdaiyousei-qz       auto f = []() {
19069e6a342fSdaiyousei-qz         return X;
19079e6a342fSdaiyousei-qz       };
19089e6a342fSdaiyousei-qz       return f();
19099e6a342fSdaiyousei-qz     $bar[[}]]
19109e6a342fSdaiyousei-qz 
19119e6a342fSdaiyousei-qz     // No hint because this isn't a definition
19129e6a342fSdaiyousei-qz     int buz();
19139e6a342fSdaiyousei-qz 
19149e6a342fSdaiyousei-qz     struct S{};
19159e6a342fSdaiyousei-qz     bool operator==(S, S) {
19169e6a342fSdaiyousei-qz       return true;
19179e6a342fSdaiyousei-qz     $opEqual[[}]]
19189e6a342fSdaiyousei-qz   )cpp",
19199e6a342fSdaiyousei-qz                       ExpectedHint{" // foo", "foo"},
19209e6a342fSdaiyousei-qz                       ExpectedHint{" // bar", "bar"},
19219e6a342fSdaiyousei-qz                       ExpectedHint{" // operator==", "opEqual"});
19229e6a342fSdaiyousei-qz }
19239e6a342fSdaiyousei-qz 
19249e6a342fSdaiyousei-qz TEST(BlockEndHints, Methods) {
19259e6a342fSdaiyousei-qz   assertBlockEndHints(R"cpp(
19269e6a342fSdaiyousei-qz     struct Test {
19279e6a342fSdaiyousei-qz       // No hint because there's no function body
19289e6a342fSdaiyousei-qz       Test() = default;
19299e6a342fSdaiyousei-qz 
19309e6a342fSdaiyousei-qz       ~Test() {
19319e6a342fSdaiyousei-qz       $dtor[[}]]
19329e6a342fSdaiyousei-qz 
19339e6a342fSdaiyousei-qz       void method1() {
19349e6a342fSdaiyousei-qz       $method1[[}]]
19359e6a342fSdaiyousei-qz 
19369e6a342fSdaiyousei-qz       // No hint because this isn't a definition
19379e6a342fSdaiyousei-qz       void method2();
19389e6a342fSdaiyousei-qz 
19399e6a342fSdaiyousei-qz       template <typename T>
19409e6a342fSdaiyousei-qz       void method3() {
19419e6a342fSdaiyousei-qz       $method3[[}]]
19429e6a342fSdaiyousei-qz 
19439e6a342fSdaiyousei-qz       // No hint because this isn't a definition
19449e6a342fSdaiyousei-qz       template <typename T>
19459e6a342fSdaiyousei-qz       void method4();
19469e6a342fSdaiyousei-qz 
19479e6a342fSdaiyousei-qz       Test operator+(int) const {
19489e6a342fSdaiyousei-qz         return *this;
19499e6a342fSdaiyousei-qz       $opIdentity[[}]]
19509e6a342fSdaiyousei-qz 
19519e6a342fSdaiyousei-qz       operator bool() const {
19529e6a342fSdaiyousei-qz         return true;
19539e6a342fSdaiyousei-qz       $opBool[[}]]
19549e6a342fSdaiyousei-qz 
19559e6a342fSdaiyousei-qz       // No hint because there's no function body
19569e6a342fSdaiyousei-qz       operator int() const = delete;
19579e6a342fSdaiyousei-qz     } x;
19589e6a342fSdaiyousei-qz 
19599e6a342fSdaiyousei-qz     void Test::method2() {
19609e6a342fSdaiyousei-qz     $method2[[}]]
19619e6a342fSdaiyousei-qz 
19629e6a342fSdaiyousei-qz     template <typename T>
19639e6a342fSdaiyousei-qz     void Test::method4() {
19649e6a342fSdaiyousei-qz     $method4[[}]]
19659e6a342fSdaiyousei-qz   )cpp",
19669e6a342fSdaiyousei-qz                       ExpectedHint{" // ~Test", "dtor"},
19679e6a342fSdaiyousei-qz                       ExpectedHint{" // method1", "method1"},
19689e6a342fSdaiyousei-qz                       ExpectedHint{" // method3", "method3"},
19699e6a342fSdaiyousei-qz                       ExpectedHint{" // operator+", "opIdentity"},
19709e6a342fSdaiyousei-qz                       ExpectedHint{" // operator bool", "opBool"},
19719e6a342fSdaiyousei-qz                       ExpectedHint{" // Test::method2", "method2"},
19729e6a342fSdaiyousei-qz                       ExpectedHint{" // Test::method4", "method4"});
19739e6a342fSdaiyousei-qz }
19749e6a342fSdaiyousei-qz 
19759e6a342fSdaiyousei-qz TEST(BlockEndHints, Namespaces) {
19769e6a342fSdaiyousei-qz   assertBlockEndHints(
19779e6a342fSdaiyousei-qz       R"cpp(
19789e6a342fSdaiyousei-qz     namespace {
19799e6a342fSdaiyousei-qz       void foo();
19809e6a342fSdaiyousei-qz     $anon[[}]]
19819e6a342fSdaiyousei-qz 
19829e6a342fSdaiyousei-qz     namespace ns {
19839e6a342fSdaiyousei-qz       void bar();
19849e6a342fSdaiyousei-qz     $ns[[}]]
19859e6a342fSdaiyousei-qz   )cpp",
19869e6a342fSdaiyousei-qz       ExpectedHint{" // namespace", "anon"},
19879e6a342fSdaiyousei-qz       ExpectedHint{" // namespace ns", "ns"});
19889e6a342fSdaiyousei-qz }
19899e6a342fSdaiyousei-qz 
19909e6a342fSdaiyousei-qz TEST(BlockEndHints, Types) {
19919e6a342fSdaiyousei-qz   assertBlockEndHints(
19929e6a342fSdaiyousei-qz       R"cpp(
19939e6a342fSdaiyousei-qz     struct S {
19949e6a342fSdaiyousei-qz     $S[[};]]
19959e6a342fSdaiyousei-qz 
19969e6a342fSdaiyousei-qz     class C {
19979e6a342fSdaiyousei-qz     $C[[};]]
19989e6a342fSdaiyousei-qz 
19999e6a342fSdaiyousei-qz     union U {
20009e6a342fSdaiyousei-qz     $U[[};]]
20019e6a342fSdaiyousei-qz 
20029e6a342fSdaiyousei-qz     enum E1 {
20039e6a342fSdaiyousei-qz     $E1[[};]]
20049e6a342fSdaiyousei-qz 
20059e6a342fSdaiyousei-qz     enum class E2 {
20069e6a342fSdaiyousei-qz     $E2[[};]]
20079e6a342fSdaiyousei-qz   )cpp",
20089e6a342fSdaiyousei-qz       ExpectedHint{" // struct S", "S"}, ExpectedHint{" // class C", "C"},
20099e6a342fSdaiyousei-qz       ExpectedHint{" // union U", "U"}, ExpectedHint{" // enum E1", "E1"},
20109e6a342fSdaiyousei-qz       ExpectedHint{" // enum class E2", "E2"});
20119e6a342fSdaiyousei-qz }
20129e6a342fSdaiyousei-qz 
2013ee032bccSSam McCall TEST(BlockEndHints, If) {
2014ee032bccSSam McCall   assertBlockEndHints(
2015ee032bccSSam McCall       R"cpp(
2016ee032bccSSam McCall     void foo(bool cond) {
2017ee032bccSSam McCall        if (cond)
2018ee032bccSSam McCall           ;
2019ee032bccSSam McCall 
2020ee032bccSSam McCall        if (cond) {
2021ee032bccSSam McCall        $simple[[}]]
2022ee032bccSSam McCall 
2023ee032bccSSam McCall        if (cond) {
2024ee032bccSSam McCall        } else {
2025ee032bccSSam McCall        $ifelse[[}]]
2026ee032bccSSam McCall 
2027ee032bccSSam McCall        if (cond) {
2028ee032bccSSam McCall        } else if (!cond) {
2029ee032bccSSam McCall        $elseif[[}]]
2030ee032bccSSam McCall 
2031ee032bccSSam McCall        if (cond) {
2032ee032bccSSam McCall        } else {
2033ee032bccSSam McCall          if (!cond) {
2034ee032bccSSam McCall          $inner[[}]]
2035ee032bccSSam McCall        $outer[[}]]
2036ee032bccSSam McCall 
2037ee032bccSSam McCall        if (auto X = cond) {
2038ee032bccSSam McCall        $init[[}]]
2039ee032bccSSam McCall 
2040ee032bccSSam McCall        if (int i = 0; i > 10) {
2041ee032bccSSam McCall        $init_cond[[}]]
2042ee032bccSSam McCall     } // suppress
2043ee032bccSSam McCall   )cpp",
2044ee032bccSSam McCall       ExpectedHint{" // if cond", "simple"},
2045ee032bccSSam McCall       ExpectedHint{" // if cond", "ifelse"}, ExpectedHint{" // if", "elseif"},
2046ee032bccSSam McCall       ExpectedHint{" // if !cond", "inner"},
2047ee032bccSSam McCall       ExpectedHint{" // if cond", "outer"}, ExpectedHint{" // if X", "init"},
2048ee032bccSSam McCall       ExpectedHint{" // if i > 10", "init_cond"});
2049ee032bccSSam McCall }
2050ee032bccSSam McCall 
2051ee032bccSSam McCall TEST(BlockEndHints, Loops) {
2052ee032bccSSam McCall   assertBlockEndHints(
2053ee032bccSSam McCall       R"cpp(
2054ee032bccSSam McCall     void foo() {
2055ee032bccSSam McCall        while (true)
2056ee032bccSSam McCall           ;
2057ee032bccSSam McCall 
2058ee032bccSSam McCall        while (true) {
2059ee032bccSSam McCall        $while[[}]]
2060ee032bccSSam McCall 
2061ee032bccSSam McCall        do {
2062ee032bccSSam McCall        } while (true);
2063ee032bccSSam McCall 
2064ee032bccSSam McCall        for (;true;) {
2065ee032bccSSam McCall        $forcond[[}]]
2066ee032bccSSam McCall 
2067ee032bccSSam McCall        for (int I = 0; I < 10; ++I) {
2068ee032bccSSam McCall        $forvar[[}]]
2069ee032bccSSam McCall 
2070ee032bccSSam McCall        int Vs[] = {1,2,3};
2071ee032bccSSam McCall        for (auto V : Vs) {
2072ee032bccSSam McCall        $foreach[[}]]
2073ee032bccSSam McCall     } // suppress
2074ee032bccSSam McCall   )cpp",
2075ee032bccSSam McCall       ExpectedHint{" // while true", "while"},
2076ee032bccSSam McCall       ExpectedHint{" // for true", "forcond"},
2077ee032bccSSam McCall       ExpectedHint{" // for I", "forvar"},
2078ee032bccSSam McCall       ExpectedHint{" // for V", "foreach"});
2079ee032bccSSam McCall }
2080ee032bccSSam McCall 
2081ee032bccSSam McCall TEST(BlockEndHints, Switch) {
2082ee032bccSSam McCall   assertBlockEndHints(
2083ee032bccSSam McCall       R"cpp(
2084ee032bccSSam McCall     void foo(int I) {
2085ee032bccSSam McCall       switch (I) {
2086ee032bccSSam McCall         case 0: break;
2087ee032bccSSam McCall       $switch[[}]]
2088ee032bccSSam McCall     } // suppress
2089ee032bccSSam McCall   )cpp",
2090ee032bccSSam McCall       ExpectedHint{" // switch I", "switch"});
2091ee032bccSSam McCall }
2092ee032bccSSam McCall 
2093ee032bccSSam McCall TEST(BlockEndHints, PrintLiterals) {
2094ee032bccSSam McCall   assertBlockEndHints(
2095ee032bccSSam McCall       R"cpp(
2096ee032bccSSam McCall     void foo() {
2097ee032bccSSam McCall       while ("foo") {
2098ee032bccSSam McCall       $string[[}]]
2099ee032bccSSam McCall 
2100ee032bccSSam McCall       while ("foo but this time it is very long") {
2101ee032bccSSam McCall       $string_long[[}]]
2102ee032bccSSam McCall 
2103ee032bccSSam McCall       while (true) {
2104ee032bccSSam McCall       $boolean[[}]]
2105ee032bccSSam McCall 
2106ee032bccSSam McCall       while (1) {
2107ee032bccSSam McCall       $integer[[}]]
2108ee032bccSSam McCall 
2109ee032bccSSam McCall       while (1.5) {
2110ee032bccSSam McCall       $float[[}]]
2111ee032bccSSam McCall     } // suppress
2112ee032bccSSam McCall   )cpp",
2113ee032bccSSam McCall       ExpectedHint{" // while \"foo\"", "string"},
2114ee032bccSSam McCall       ExpectedHint{" // while \"foo but...\"", "string_long"},
2115ee032bccSSam McCall       ExpectedHint{" // while true", "boolean"},
2116ee032bccSSam McCall       ExpectedHint{" // while 1", "integer"},
2117ee032bccSSam McCall       ExpectedHint{" // while 1.5", "float"});
2118ee032bccSSam McCall }
2119ee032bccSSam McCall 
2120ee032bccSSam McCall TEST(BlockEndHints, PrintRefs) {
2121ee032bccSSam McCall   assertBlockEndHints(
2122ee032bccSSam McCall       R"cpp(
2123ee032bccSSam McCall     namespace ns {
2124ee032bccSSam McCall       int Var;
2125ee032bccSSam McCall       int func();
2126ee032bccSSam McCall       struct S {
2127ee032bccSSam McCall         int Field;
2128ee032bccSSam McCall         int method() const;
2129ee032bccSSam McCall       }; // suppress
2130ee032bccSSam McCall     } // suppress
2131ee032bccSSam McCall     void foo() {
2132ee032bccSSam McCall       while (ns::Var) {
2133ee032bccSSam McCall       $var[[}]]
2134ee032bccSSam McCall 
2135ee032bccSSam McCall       while (ns::func()) {
2136ee032bccSSam McCall       $func[[}]]
2137ee032bccSSam McCall 
2138ee032bccSSam McCall       while (ns::S{}.Field) {
2139ee032bccSSam McCall       $field[[}]]
2140ee032bccSSam McCall 
2141ee032bccSSam McCall       while (ns::S{}.method()) {
2142ee032bccSSam McCall       $method[[}]]
2143ee032bccSSam McCall     } // suppress
2144ee032bccSSam McCall   )cpp",
2145ee032bccSSam McCall       ExpectedHint{" // while Var", "var"},
2146ee032bccSSam McCall       ExpectedHint{" // while func", "func"},
2147ee032bccSSam McCall       ExpectedHint{" // while Field", "field"},
2148ee032bccSSam McCall       ExpectedHint{" // while method", "method"});
2149ee032bccSSam McCall }
2150ee032bccSSam McCall 
2151ee032bccSSam McCall TEST(BlockEndHints, PrintConversions) {
2152ee032bccSSam McCall   assertBlockEndHints(
2153ee032bccSSam McCall       R"cpp(
2154ee032bccSSam McCall     struct S {
2155ee032bccSSam McCall       S(int);
2156ee032bccSSam McCall       S(int, int);
2157ee032bccSSam McCall       explicit operator bool();
2158ee032bccSSam McCall     }; // suppress
2159ee032bccSSam McCall     void foo(int I) {
2160ee032bccSSam McCall       while (float(I)) {
2161ee032bccSSam McCall       $convert_primitive[[}]]
2162ee032bccSSam McCall 
2163ee032bccSSam McCall       while (S(I)) {
2164ee032bccSSam McCall       $convert_class[[}]]
2165ee032bccSSam McCall 
2166ee032bccSSam McCall       while (S(I, I)) {
2167ee032bccSSam McCall       $construct_class[[}]]
2168ee032bccSSam McCall     } // suppress
2169ee032bccSSam McCall   )cpp",
2170ee032bccSSam McCall       ExpectedHint{" // while float", "convert_primitive"},
2171ee032bccSSam McCall       ExpectedHint{" // while S", "convert_class"},
2172ee032bccSSam McCall       ExpectedHint{" // while S", "construct_class"});
2173ee032bccSSam McCall }
2174ee032bccSSam McCall 
2175ee032bccSSam McCall TEST(BlockEndHints, PrintOperators) {
2176ee032bccSSam McCall   std::string AnnotatedCode = R"cpp(
2177ee032bccSSam McCall     void foo(Integer I) {
2178ee032bccSSam McCall       while(++I){
2179ee032bccSSam McCall       $preinc[[}]]
2180ee032bccSSam McCall 
2181ee032bccSSam McCall       while(I++){
2182ee032bccSSam McCall       $postinc[[}]]
2183ee032bccSSam McCall 
2184ee032bccSSam McCall       while(+(I + I)){
2185ee032bccSSam McCall       $unary_complex[[}]]
2186ee032bccSSam McCall 
2187ee032bccSSam McCall       while(I < 0){
2188ee032bccSSam McCall       $compare[[}]]
2189ee032bccSSam McCall 
2190ee032bccSSam McCall       while((I + I) < I){
2191ee032bccSSam McCall       $lhs_complex[[}]]
2192ee032bccSSam McCall 
2193ee032bccSSam McCall       while(I < (I + I)){
2194ee032bccSSam McCall       $rhs_complex[[}]]
2195ee032bccSSam McCall 
2196ee032bccSSam McCall       while((I + I) < (I + I)){
2197ee032bccSSam McCall       $binary_complex[[}]]
2198ee032bccSSam McCall     } // suppress
2199ee032bccSSam McCall   )cpp";
2200ee032bccSSam McCall 
2201ee032bccSSam McCall   // We can't store shared expectations in a vector, assertHints uses varargs.
2202ee032bccSSam McCall   auto AssertExpectedHints = [&](llvm::StringRef Code) {
2203ee032bccSSam McCall     assertBlockEndHints(Code, ExpectedHint{" // while ++I", "preinc"},
2204ee032bccSSam McCall                         ExpectedHint{" // while I++", "postinc"},
2205ee032bccSSam McCall                         ExpectedHint{" // while", "unary_complex"},
2206ee032bccSSam McCall                         ExpectedHint{" // while I < 0", "compare"},
2207ee032bccSSam McCall                         ExpectedHint{" // while ... < I", "lhs_complex"},
2208ee032bccSSam McCall                         ExpectedHint{" // while I < ...", "rhs_complex"},
2209ee032bccSSam McCall                         ExpectedHint{" // while", "binary_complex"});
2210ee032bccSSam McCall   };
2211ee032bccSSam McCall 
2212ee032bccSSam McCall   // First with built-in operators.
2213ee032bccSSam McCall   AssertExpectedHints("using Integer = int;" + AnnotatedCode);
2214ee032bccSSam McCall   // And now with overloading!
2215ee032bccSSam McCall   AssertExpectedHints(R"cpp(
2216ee032bccSSam McCall     struct Integer {
2217ee032bccSSam McCall       explicit operator bool();
2218ee032bccSSam McCall       Integer operator++();
2219ee032bccSSam McCall       Integer operator++(int);
2220ee032bccSSam McCall       Integer operator+(Integer);
2221ee032bccSSam McCall       Integer operator+();
2222ee032bccSSam McCall       bool operator<(Integer);
2223ee032bccSSam McCall       bool operator<(int);
2224ee032bccSSam McCall     }; // suppress
2225ee032bccSSam McCall   )cpp" + AnnotatedCode);
2226ee032bccSSam McCall }
2227ee032bccSSam McCall 
22289e6a342fSdaiyousei-qz TEST(BlockEndHints, TrailingSemicolon) {
22299e6a342fSdaiyousei-qz   assertBlockEndHints(R"cpp(
22309e6a342fSdaiyousei-qz     // The hint is placed after the trailing ';'
22319e6a342fSdaiyousei-qz     struct S1 {
22329e6a342fSdaiyousei-qz     $S1[[}  ;]]
22339e6a342fSdaiyousei-qz 
22349e6a342fSdaiyousei-qz     // The hint is always placed in the same line with the closing '}'.
22359e6a342fSdaiyousei-qz     // So in this case where ';' is missing, it is attached to '}'.
22369e6a342fSdaiyousei-qz     struct S2 {
22379e6a342fSdaiyousei-qz     $S2[[}]]
22389e6a342fSdaiyousei-qz 
22399e6a342fSdaiyousei-qz     ;
22409e6a342fSdaiyousei-qz 
22419e6a342fSdaiyousei-qz     // No hint because only one trailing ';' is allowed
22429e6a342fSdaiyousei-qz     struct S3 {
22439e6a342fSdaiyousei-qz     };;
22449e6a342fSdaiyousei-qz 
22459e6a342fSdaiyousei-qz     // No hint because trailing ';' is only allowed for class/struct/union/enum
22469e6a342fSdaiyousei-qz     void foo() {
22479e6a342fSdaiyousei-qz     };
22489e6a342fSdaiyousei-qz 
22499e6a342fSdaiyousei-qz     // Rare case, but yes we'll have a hint here.
22509e6a342fSdaiyousei-qz     struct {
22519e6a342fSdaiyousei-qz       int x;
22529e6a342fSdaiyousei-qz     $anon[[}]]
22539e6a342fSdaiyousei-qz 
22549e6a342fSdaiyousei-qz     s2;
22559e6a342fSdaiyousei-qz   )cpp",
22569e6a342fSdaiyousei-qz                       ExpectedHint{" // struct S1", "S1"},
22579e6a342fSdaiyousei-qz                       ExpectedHint{" // struct S2", "S2"},
22589e6a342fSdaiyousei-qz                       ExpectedHint{" // struct", "anon"});
22599e6a342fSdaiyousei-qz }
22609e6a342fSdaiyousei-qz 
22619e6a342fSdaiyousei-qz TEST(BlockEndHints, TrailingText) {
22629e6a342fSdaiyousei-qz   assertBlockEndHints(R"cpp(
22639e6a342fSdaiyousei-qz     struct S1 {
22649e6a342fSdaiyousei-qz     $S1[[}      ;]]
22659e6a342fSdaiyousei-qz 
22669e6a342fSdaiyousei-qz     // No hint for S2 because of the trailing comment
22679e6a342fSdaiyousei-qz     struct S2 {
22689e6a342fSdaiyousei-qz     }; /* Put anything here */
22699e6a342fSdaiyousei-qz 
22709e6a342fSdaiyousei-qz     struct S3 {
22719e6a342fSdaiyousei-qz       // No hint for S4 because of the trailing source code
22729e6a342fSdaiyousei-qz       struct S4 {
22739e6a342fSdaiyousei-qz       };$S3[[};]]
22749e6a342fSdaiyousei-qz 
22759e6a342fSdaiyousei-qz     // No hint for ns because of the trailing comment
22769e6a342fSdaiyousei-qz     namespace ns {
22779e6a342fSdaiyousei-qz     } // namespace ns
22789e6a342fSdaiyousei-qz   )cpp",
22799e6a342fSdaiyousei-qz                       ExpectedHint{" // struct S1", "S1"},
22809e6a342fSdaiyousei-qz                       ExpectedHint{" // struct S3", "S3"});
22819e6a342fSdaiyousei-qz }
22829e6a342fSdaiyousei-qz 
22839e6a342fSdaiyousei-qz TEST(BlockEndHints, Macro) {
22849e6a342fSdaiyousei-qz   assertBlockEndHints(R"cpp(
22859e6a342fSdaiyousei-qz     #define DECL_STRUCT(NAME) struct NAME {
22869e6a342fSdaiyousei-qz     #define RBRACE }
22879e6a342fSdaiyousei-qz 
22889e6a342fSdaiyousei-qz     DECL_STRUCT(S1)
22899e6a342fSdaiyousei-qz     $S1[[};]]
22909e6a342fSdaiyousei-qz 
22919e6a342fSdaiyousei-qz     // No hint because we require a '}'
22929e6a342fSdaiyousei-qz     DECL_STRUCT(S2)
22939e6a342fSdaiyousei-qz     RBRACE;
22949e6a342fSdaiyousei-qz   )cpp",
22959e6a342fSdaiyousei-qz                       ExpectedHint{" // struct S1", "S1"});
22969e6a342fSdaiyousei-qz }
22979e6a342fSdaiyousei-qz 
2298dbd1fb8eSNathan Ridge TEST(BlockEndHints, PointerToMemberFunction) {
2299dbd1fb8eSNathan Ridge   // Do not crash trying to summarize `a->*p`.
2300dbd1fb8eSNathan Ridge   assertBlockEndHints(R"cpp(
2301dbd1fb8eSNathan Ridge     class A {};
2302dbd1fb8eSNathan Ridge     using Predicate = bool(A::*)();
2303dbd1fb8eSNathan Ridge     void foo(A* a, Predicate p) {
2304dbd1fb8eSNathan Ridge       if ((a->*p)()) {
2305dbd1fb8eSNathan Ridge       $ptrmem[[}]]
2306dbd1fb8eSNathan Ridge     } // suppress
2307dbd1fb8eSNathan Ridge   )cpp",
2308dbd1fb8eSNathan Ridge                       ExpectedHint{" // if", "ptrmem"});
2309dbd1fb8eSNathan Ridge }
2310dbd1fb8eSNathan Ridge 
23110be2657cSNathan Ridge // FIXME: Low-hanging fruit where we could omit a type hint:
23120be2657cSNathan Ridge //  - auto x = TypeName(...);
23130be2657cSNathan Ridge //  - auto x = (TypeName) (...);
23140be2657cSNathan Ridge //  - auto x = static_cast<TypeName>(...);  // and other built-in casts
23150be2657cSNathan Ridge 
23160be2657cSNathan Ridge // Annoyances for which a heuristic is not obvious:
23170be2657cSNathan Ridge //  - auto x = llvm::dyn_cast<LongTypeName>(y);  // and similar
23180be2657cSNathan Ridge //  - stdlib algos return unwieldy __normal_iterator<X*, ...> type
23190be2657cSNathan Ridge //    (For this one, perhaps we should omit type hints that start
23200be2657cSNathan Ridge //     with a double underscore.)
23210be2657cSNathan Ridge 
2322cbc9c4eaSNathan Ridge } // namespace
2323cbc9c4eaSNathan Ridge } // namespace clangd
2324cbc9c4eaSNathan Ridge } // namespace clang
2325