1 //===-- InlayHintTests.cpp  -------------------------------*- C++ -*-------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 #include "Annotations.h"
9 #include "Config.h"
10 #include "InlayHints.h"
11 #include "Protocol.h"
12 #include "TestTU.h"
13 #include "TestWorkspace.h"
14 #include "XRefs.h"
15 #include "support/Context.h"
16 #include "llvm/ADT/StringRef.h"
17 #include "llvm/Support/ScopedPrinter.h"
18 #include "gmock/gmock.h"
19 #include "gtest/gtest.h"
20 
21 namespace clang {
22 namespace clangd {
23 
operator <<(llvm::raw_ostream & Stream,const InlayHint & Hint)24 llvm::raw_ostream &operator<<(llvm::raw_ostream &Stream,
25                               const InlayHint &Hint) {
26   return Stream << Hint.label << "@" << Hint.range;
27 }
28 
29 namespace {
30 
31 using ::testing::ElementsAre;
32 using ::testing::IsEmpty;
33 
hintsOfKind(ParsedAST & AST,InlayHintKind Kind)34 std::vector<InlayHint> hintsOfKind(ParsedAST &AST, InlayHintKind Kind) {
35   std::vector<InlayHint> Result;
36   for (auto &Hint : inlayHints(AST, /*RestrictRange=*/llvm::None)) {
37     if (Hint.kind == Kind)
38       Result.push_back(Hint);
39   }
40   return Result;
41 }
42 
43 enum HintSide { Left, Right };
44 
45 struct ExpectedHint {
46   std::string Label;
47   std::string RangeName;
48   HintSide Side = Left;
49 
operator <<(llvm::raw_ostream & Stream,const ExpectedHint & Hint)50   friend llvm::raw_ostream &operator<<(llvm::raw_ostream &Stream,
51                                        const ExpectedHint &Hint) {
52     return Stream << Hint.Label << "@$" << Hint.RangeName;
53   }
54 };
55 
MATCHER_P2(HintMatcher,Expected,Code,llvm::to_string (Expected))56 MATCHER_P2(HintMatcher, Expected, Code, llvm::to_string(Expected)) {
57   llvm::StringRef ExpectedView(Expected.Label);
58   if (arg.label != ExpectedView.trim(" ") ||
59       arg.paddingLeft != ExpectedView.startswith(" ") ||
60       arg.paddingRight != ExpectedView.endswith(" ")) {
61     *result_listener << "label is '" << arg.label << "'";
62     return false;
63   }
64   if (arg.range != Code.range(Expected.RangeName)) {
65     *result_listener << "range is " << llvm::to_string(arg.range) << " but $"
66                      << Expected.RangeName << " is "
67                      << llvm::to_string(Code.range(Expected.RangeName));
68     return false;
69   }
70   return true;
71 }
72 
73 MATCHER_P(labelIs, Label, "") { return arg.label == Label; }
74 
noHintsConfig()75 Config noHintsConfig() {
76   Config C;
77   C.InlayHints.Parameters = false;
78   C.InlayHints.DeducedTypes = false;
79   C.InlayHints.Designators = false;
80   return C;
81 }
82 
83 template <typename... ExpectedHints>
assertHints(InlayHintKind Kind,llvm::StringRef AnnotatedSource,ExpectedHints...Expected)84 void assertHints(InlayHintKind Kind, llvm::StringRef AnnotatedSource,
85                  ExpectedHints... Expected) {
86   Annotations Source(AnnotatedSource);
87   TestTU TU = TestTU::withCode(Source.code());
88   TU.ExtraArgs.push_back("-std=c++20");
89   auto AST = TU.build();
90 
91   EXPECT_THAT(hintsOfKind(AST, Kind),
92               ElementsAre(HintMatcher(Expected, Source)...));
93   // Sneak in a cross-cutting check that hints are disabled by config.
94   // We'll hit an assertion failure if addInlayHint still gets called.
95   WithContextValue WithCfg(Config::Key, noHintsConfig());
96   EXPECT_THAT(inlayHints(AST, llvm::None), IsEmpty());
97 }
98 
99 // Hack to allow expression-statements operating on parameter packs in C++14.
ignore(T &&...)100 template <typename... T> void ignore(T &&...) {}
101 
102 template <typename... ExpectedHints>
assertParameterHints(llvm::StringRef AnnotatedSource,ExpectedHints...Expected)103 void assertParameterHints(llvm::StringRef AnnotatedSource,
104                           ExpectedHints... Expected) {
105   ignore(Expected.Side = Left...);
106   assertHints(InlayHintKind::Parameter, AnnotatedSource, Expected...);
107 }
108 
109 template <typename... ExpectedHints>
assertTypeHints(llvm::StringRef AnnotatedSource,ExpectedHints...Expected)110 void assertTypeHints(llvm::StringRef AnnotatedSource,
111                      ExpectedHints... Expected) {
112   ignore(Expected.Side = Right...);
113   assertHints(InlayHintKind::Type, AnnotatedSource, Expected...);
114 }
115 
116 template <typename... ExpectedHints>
assertDesignatorHints(llvm::StringRef AnnotatedSource,ExpectedHints...Expected)117 void assertDesignatorHints(llvm::StringRef AnnotatedSource,
118                            ExpectedHints... Expected) {
119   Config Cfg;
120   Cfg.InlayHints.Designators = true;
121   WithContextValue WithCfg(Config::Key, std::move(Cfg));
122   assertHints(InlayHintKind::Designator, AnnotatedSource, Expected...);
123 }
124 
TEST(ParameterHints,Smoke)125 TEST(ParameterHints, Smoke) {
126   assertParameterHints(R"cpp(
127     void foo(int param);
128     void bar() {
129       foo($param[[42]]);
130     }
131   )cpp",
132                        ExpectedHint{"param: ", "param"});
133 }
134 
TEST(ParameterHints,NoName)135 TEST(ParameterHints, NoName) {
136   // No hint for anonymous parameter.
137   assertParameterHints(R"cpp(
138     void foo(int);
139     void bar() {
140       foo(42);
141     }
142   )cpp");
143 }
144 
TEST(ParameterHints,NoNameConstReference)145 TEST(ParameterHints, NoNameConstReference) {
146   // No hint for anonymous const l-value ref parameter.
147   assertParameterHints(R"cpp(
148     void foo(const int&);
149     void bar() {
150       foo(42);
151     }
152   )cpp");
153 }
154 
TEST(ParameterHints,NoNameReference)155 TEST(ParameterHints, NoNameReference) {
156   // Reference hint for anonymous l-value ref parameter.
157   assertParameterHints(R"cpp(
158     void foo(int&);
159     void bar() {
160       int i;
161       foo($param[[i]]);
162     }
163   )cpp",
164                        ExpectedHint{"&: ", "param"});
165 }
166 
TEST(ParameterHints,NoNameRValueReference)167 TEST(ParameterHints, NoNameRValueReference) {
168   // No reference hint for anonymous r-value ref parameter.
169   assertParameterHints(R"cpp(
170     void foo(int&&);
171     void bar() {
172       foo(42);
173     }
174   )cpp");
175 }
176 
TEST(ParameterHints,NoNameVariadicDeclaration)177 TEST(ParameterHints, NoNameVariadicDeclaration) {
178   // No hint for anonymous variadic parameter
179   assertParameterHints(R"cpp(
180     template <typename... Args>
181     void foo(Args&& ...);
182     void bar() {
183       foo(42);
184     }
185   )cpp");
186 }
187 
TEST(ParameterHints,NoNameVariadicForwarded)188 TEST(ParameterHints, NoNameVariadicForwarded) {
189   // No hint for anonymous variadic parameter
190   // This prototype of std::forward is sufficient for clang to recognize it
191   assertParameterHints(R"cpp(
192     namespace std { template <typename T> T&& forward(T&); }
193     void foo(int);
194     template <typename... Args>
195     void bar(Args&&... args) { return foo(std::forward<Args>(args)...); }
196     void baz() {
197       bar(42);
198     }
199   )cpp");
200 }
201 
TEST(ParameterHints,NoNameVariadicPlain)202 TEST(ParameterHints, NoNameVariadicPlain) {
203   // No hint for anonymous variadic parameter
204   assertParameterHints(R"cpp(
205     void foo(int);
206     template <typename... Args>
207     void bar(Args&&... args) { return foo(args...); }
208     void baz() {
209       bar(42);
210     }
211   )cpp");
212 }
213 
TEST(ParameterHints,NameInDefinition)214 TEST(ParameterHints, NameInDefinition) {
215   // Parameter name picked up from definition if necessary.
216   assertParameterHints(R"cpp(
217     void foo(int);
218     void bar() {
219       foo($param[[42]]);
220     }
221     void foo(int param) {};
222   )cpp",
223                        ExpectedHint{"param: ", "param"});
224 }
225 
TEST(ParameterHints,NamePartiallyInDefinition)226 TEST(ParameterHints, NamePartiallyInDefinition) {
227   // Parameter name picked up from definition if necessary.
228   assertParameterHints(R"cpp(
229     void foo(int, int b);
230     void bar() {
231       foo($param1[[42]], $param2[[42]]);
232     }
233     void foo(int a, int) {};
234   )cpp",
235                        ExpectedHint{"a: ", "param1"},
236                        ExpectedHint{"b: ", "param2"});
237 }
238 
TEST(ParameterHints,NameInDefinitionVariadic)239 TEST(ParameterHints, NameInDefinitionVariadic) {
240   // Parameter name picked up from definition in a resolved forwarded parameter.
241   assertParameterHints(R"cpp(
242     void foo(int, int);
243     template <typename... Args>
244     void bar(Args... args) {
245       foo(args...);
246     }
247     void baz() {
248       bar($param1[[42]], $param2[[42]]);
249     }
250     void foo(int a, int b) {};
251   )cpp",
252                        ExpectedHint{"a: ", "param1"},
253                        ExpectedHint{"b: ", "param2"});
254 }
255 
TEST(ParameterHints,NameMismatch)256 TEST(ParameterHints, NameMismatch) {
257   // Prefer name from declaration.
258   assertParameterHints(R"cpp(
259     void foo(int good);
260     void bar() {
261       foo($good[[42]]);
262     }
263     void foo(int bad) {};
264   )cpp",
265                        ExpectedHint{"good: ", "good"});
266 }
267 
TEST(ParameterHints,NameConstReference)268 TEST(ParameterHints, NameConstReference) {
269   // Only name hint for const l-value ref parameter.
270   assertParameterHints(R"cpp(
271     void foo(const int& param);
272     void bar() {
273       foo($param[[42]]);
274     }
275   )cpp",
276                        ExpectedHint{"param: ", "param"});
277 }
278 
TEST(ParameterHints,NameTypeAliasConstReference)279 TEST(ParameterHints, NameTypeAliasConstReference) {
280   // Only name hint for const l-value ref parameter via type alias.
281   assertParameterHints(R"cpp(
282     using alias = const int&;
283     void foo(alias param);
284     void bar() {
285       int i;
286       foo($param[[i]]);
287     }
288   )cpp",
289                        ExpectedHint{"param: ", "param"});
290 }
291 
TEST(ParameterHints,NameReference)292 TEST(ParameterHints, NameReference) {
293   // Reference and name hint for l-value ref parameter.
294   assertParameterHints(R"cpp(
295     void foo(int& param);
296     void bar() {
297       int i;
298       foo($param[[i]]);
299     }
300   )cpp",
301                        ExpectedHint{"&param: ", "param"});
302 }
303 
TEST(ParameterHints,NameTypeAliasReference)304 TEST(ParameterHints, NameTypeAliasReference) {
305   // Reference and name hint for l-value ref parameter via type alias.
306   assertParameterHints(R"cpp(
307     using alias = int&;
308     void foo(alias param);
309     void bar() {
310       int i;
311       foo($param[[i]]);
312     }
313   )cpp",
314                        ExpectedHint{"&param: ", "param"});
315 }
316 
TEST(ParameterHints,NameRValueReference)317 TEST(ParameterHints, NameRValueReference) {
318   // Only name hint for r-value ref parameter.
319   assertParameterHints(R"cpp(
320     void foo(int&& param);
321     void bar() {
322       foo($param[[42]]);
323     }
324   )cpp",
325                        ExpectedHint{"param: ", "param"});
326 }
327 
TEST(ParameterHints,VariadicForwardedConstructor)328 TEST(ParameterHints, VariadicForwardedConstructor) {
329   // Name hint for variadic parameter using std::forward in a constructor call
330   // This prototype of std::forward is sufficient for clang to recognize it
331   assertParameterHints(R"cpp(
332     namespace std { template <typename T> T&& forward(T&); }
333     struct S { S(int a); };
334     template <typename T, typename... Args>
335     T bar(Args&&... args) { return T{std::forward<Args>(args)...}; }
336     void baz() {
337       int b;
338       bar<S>($param[[b]]);
339     }
340   )cpp",
341                        ExpectedHint{"a: ", "param"});
342 }
343 
TEST(ParameterHints,VariadicPlainConstructor)344 TEST(ParameterHints, VariadicPlainConstructor) {
345   // Name hint for variadic parameter in a constructor call
346   assertParameterHints(R"cpp(
347     struct S { S(int a); };
348     template <typename T, typename... Args>
349     T bar(Args&&... args) { return T{args...}; }
350     void baz() {
351       int b;
352       bar<S>($param[[b]]);
353     }
354   )cpp",
355                        ExpectedHint{"a: ", "param"});
356 }
357 
TEST(ParameterHints,VariadicForwardedNewConstructor)358 TEST(ParameterHints, VariadicForwardedNewConstructor) {
359   // Name hint for variadic parameter using std::forward in a new expression
360   // This prototype of std::forward is sufficient for clang to recognize it
361   assertParameterHints(R"cpp(
362     namespace std { template <typename T> T&& forward(T&); }
363     struct S { S(int a); };
364     template <typename T, typename... Args>
365     T* bar(Args&&... args) { return new T{std::forward<Args>(args)...}; }
366     void baz() {
367       int b;
368       bar<S>($param[[b]]);
369     }
370   )cpp",
371                        ExpectedHint{"a: ", "param"});
372 }
373 
TEST(ParameterHints,VariadicPlainNewConstructor)374 TEST(ParameterHints, VariadicPlainNewConstructor) {
375   // Name hint for variadic parameter in a new expression
376   assertParameterHints(R"cpp(
377     struct S { S(int a); };
378     template <typename T, typename... Args>
379     T* bar(Args&&... args) { return new T{args...}; }
380     void baz() {
381       int b;
382       bar<S>($param[[b]]);
383     }
384   )cpp",
385                        ExpectedHint{"a: ", "param"});
386 }
387 
TEST(ParameterHints,VariadicForwarded)388 TEST(ParameterHints, VariadicForwarded) {
389   // Name for variadic parameter using std::forward
390   // This prototype of std::forward is sufficient for clang to recognize it
391   assertParameterHints(R"cpp(
392     namespace std { template <typename T> T&& forward(T&); }
393     void foo(int a);
394     template <typename... Args>
395     void bar(Args&&... args) { return foo(std::forward<Args>(args)...); }
396     void baz() {
397       int b;
398       bar($param[[b]]);
399     }
400   )cpp",
401                        ExpectedHint{"a: ", "param"});
402 }
403 
TEST(ParameterHints,VariadicPlain)404 TEST(ParameterHints, VariadicPlain) {
405   // Name hint for variadic parameter
406   assertParameterHints(R"cpp(
407     void foo(int a);
408     template <typename... Args>
409     void bar(Args&&... args) { return foo(args...); }
410     void baz() {
411       bar($param[[42]]);
412     }
413   )cpp",
414                        ExpectedHint{"a: ", "param"});
415 }
416 
TEST(ParameterHints,VariadicPlainWithPackFirst)417 TEST(ParameterHints, VariadicPlainWithPackFirst) {
418   // Name hint for variadic parameter when the parameter pack is not the last
419   // template parameter
420   assertParameterHints(R"cpp(
421     void foo(int a);
422     template <typename... Args, typename Arg>
423     void bar(Arg, Args&&... args) { return foo(args...); }
424     void baz() {
425       bar(1, $param[[42]]);
426     }
427   )cpp",
428                        ExpectedHint{"a: ", "param"});
429 }
430 
TEST(ParameterHints,VariadicSplitTwolevel)431 TEST(ParameterHints, VariadicSplitTwolevel) {
432   // Name for variadic parameter that involves both head and tail parameters to
433   // deal with.
434   // This prototype of std::forward is sufficient for clang to recognize it
435   assertParameterHints(R"cpp(
436     namespace std { template <typename T> T&& forward(T&); }
437     void baz(int, int b, double);
438     template <typename... Args>
439     void foo(int a, Args&&... args) {
440       return baz(1, std::forward<Args>(args)..., 1.0);
441     }
442     template <typename... Args>
443     void bar(Args&&... args) { return foo(std::forward<Args>(args)...); }
444     void bazz() {
445       bar($param1[[32]], $param2[[42]]);
446     }
447   )cpp",
448                        ExpectedHint{"a: ", "param1"},
449                        ExpectedHint{"b: ", "param2"});
450 }
451 
TEST(ParameterHints,VariadicNameFromSpecialization)452 TEST(ParameterHints, VariadicNameFromSpecialization) {
453   // We don't try to resolve forwarding parameters if the function call uses a
454   // specialization.
455   assertParameterHints(R"cpp(
456     void foo(int a);
457     template <typename... Args>
458     void bar(Args... args) {
459       foo(args...);
460     }
461     template <>
462     void bar<int>(int b);
463     void baz() {
464       bar($param[[42]]);
465     }
466   )cpp",
467                        ExpectedHint{"b: ", "param"});
468 }
469 
TEST(ParameterHints,VariadicNameFromSpecializationRecursive)470 TEST(ParameterHints, VariadicNameFromSpecializationRecursive) {
471   // We don't try to resolve forwarding parameters inside a forwarding function
472   // call if that function call uses a specialization.
473   assertParameterHints(R"cpp(
474     void foo2(int a);
475     template <typename... Args>
476     void foo(Args... args) {
477       foo2(args...);
478     }
479     template <typename... Args>
480     void bar(Args... args) {
481       foo(args...);
482     }
483     template <>
484     void foo<int>(int b);
485     void baz() {
486       bar($param[[42]]);
487     }
488   )cpp",
489                        ExpectedHint{"b: ", "param"});
490 }
491 
TEST(ParameterHints,VariadicOverloaded)492 TEST(ParameterHints, VariadicOverloaded) {
493   // Name for variadic parameter for an overloaded function with unique number
494   // of parameters.
495   // This prototype of std::forward is sufficient for clang to recognize it
496   assertParameterHints(
497       R"cpp(
498     namespace std { template <typename T> T&& forward(T&); }
499     void baz(int b, int c);
500     void baz(int bb, int cc, int dd);
501     template <typename... Args>
502     void foo(int a, Args&&... args) {
503       return baz(std::forward<Args>(args)...);
504     }
505     template <typename... Args>
506     void bar(Args&&... args) { return foo(std::forward<Args>(args)...); }
507     void bazz() {
508       bar($param1[[32]], $param2[[42]], $param3[[52]]);
509       bar($param4[[1]], $param5[[2]], $param6[[3]], $param7[[4]]);
510     }
511   )cpp",
512       ExpectedHint{"a: ", "param1"}, ExpectedHint{"b: ", "param2"},
513       ExpectedHint{"c: ", "param3"}, ExpectedHint{"a: ", "param4"},
514       ExpectedHint{"bb: ", "param5"}, ExpectedHint{"cc: ", "param6"},
515       ExpectedHint{"dd: ", "param7"});
516 }
517 
TEST(ParameterHints,VariadicRecursive)518 TEST(ParameterHints, VariadicRecursive) {
519   // make_tuple-like recursive variadic call
520   assertParameterHints(
521       R"cpp(
522     void foo();
523 
524     template <typename Head, typename... Tail>
525     void foo(Head head, Tail... tail) {
526       foo(tail...);
527     }
528 
529     template <typename... Args>
530     void bar(Args... args) {
531       foo(args...);
532     }
533 
534     int main() {
535       bar(1, 2, 3);
536     }
537   )cpp");
538 }
539 
TEST(ParameterHints,VariadicVarargs)540 TEST(ParameterHints, VariadicVarargs) {
541   // variadic call involving varargs (to make sure we don't crash)
542   assertParameterHints(R"cpp(
543     void foo(int fixed, ...);
544     template <typename... Args>
545     void bar(Args&&... args) {
546       foo(args...);
547     }
548 
549     void baz() {
550       bar($fixed[[41]], 42, 43);
551     }
552   )cpp");
553 }
554 
TEST(ParameterHints,VariadicTwolevelUnresolved)555 TEST(ParameterHints, VariadicTwolevelUnresolved) {
556   // the same setting as VariadicVarargs, only with parameter pack
557   assertParameterHints(R"cpp(
558     template <typename... Args>
559     void foo(int fixed, Args&& ... args);
560     template <typename... Args>
561     void bar(Args&&... args) {
562       foo(args...);
563     }
564 
565     void baz() {
566       bar($fixed[[41]], 42, 43);
567     }
568   )cpp",
569                        ExpectedHint{"fixed: ", "fixed"});
570 }
571 
TEST(ParameterHints,VariadicTwoCalls)572 TEST(ParameterHints, VariadicTwoCalls) {
573   // only the first call using the parameter pack should be picked up
574   assertParameterHints(
575       R"cpp(
576     void f1(int a, int b);
577     void f2(int c, int d);
578 
579     bool cond;
580 
581     template <typename... Args>
582     void foo(Args... args) {
583       if (cond) {
584         f1(args...);
585       } else {
586         f2(args...);
587       }
588     }
589 
590     int main() {
591       foo($param1[[1]], $param2[[2]]);
592     }
593   )cpp",
594       ExpectedHint{"a: ", "param1"}, ExpectedHint{"b: ", "param2"});
595 }
596 
TEST(ParameterHints,VariadicInfinite)597 TEST(ParameterHints, VariadicInfinite) {
598   // infinite recursion should not break clangd
599   assertParameterHints(
600       R"cpp(
601     template <typename... Args>
602     void foo(Args...);
603 
604     template <typename... Args>
605     void bar(Args... args) {
606       foo(args...);
607     }
608 
609     template <typename... Args>
610     void foo(Args... args) {
611       bar(args...);
612     }
613 
614     int main() {
615       foo(1, 2);
616     }
617   )cpp");
618 }
619 
TEST(ParameterHints,VariadicDuplicatePack)620 TEST(ParameterHints, VariadicDuplicatePack) {
621   // edge cases with multiple adjacent packs should work
622   assertParameterHints(
623       R"cpp(
624     void foo(int a, int b, int c, int);
625 
626     template <typename... Args>
627     void bar(int, Args... args, int d) {
628       foo(args..., d);
629     }
630 
631     template <typename... Args>
632     void baz(Args... args, Args... args2) {
633       bar<Args..., int>(1, args..., args2...);
634     }
635 
636     int main() {
637       baz<int, int>($p1[[1]], $p2[[2]], $p3[[3]], $p4[[4]]);
638     }
639   )cpp",
640       ExpectedHint{"a: ", "p1"}, ExpectedHint{"b: ", "p2"},
641       ExpectedHint{"c: ", "p3"}, ExpectedHint{"d: ", "p4"});
642 }
643 
TEST(ParameterHints,VariadicEmplace)644 TEST(ParameterHints, VariadicEmplace) {
645   // emplace-like calls should forward constructor parameters
646   // This prototype of std::forward is sufficient for clang to recognize it
647   assertParameterHints(
648       R"cpp(
649     namespace std { template <typename T> T&& forward(T&); }
650     using size_t = decltype(sizeof(0));
651     void *operator new(size_t, void *);
652     struct S {
653       S(int A);
654       S(int B, int C);
655     };
656     struct alloc {
657       template <typename T>
658       T* allocate();
659       template <typename T, typename... Args>
660       void construct(T* ptr, Args&&... args) {
661         ::new ((void*)ptr) T{std::forward<Args>(args)...};
662       }
663     };
664     template <typename T>
665     struct container {
666       template <typename... Args>
667       void emplace(Args&&... args) {
668         alloc a;
669         auto ptr = a.template allocate<T>();
670         a.construct(ptr, std::forward<Args>(args)...);
671       }
672     };
673     void foo() {
674       container<S> c;
675       c.emplace($param1[[1]]);
676       c.emplace($param2[[2]], $param3[[3]]);
677     }
678   )cpp",
679       ExpectedHint{"A: ", "param1"}, ExpectedHint{"B: ", "param2"},
680       ExpectedHint{"C: ", "param3"});
681 }
682 
TEST(ParameterHints,VariadicReferenceHint)683 TEST(ParameterHints, VariadicReferenceHint) {
684   assertParameterHints(R"cpp(
685     void foo(int&);
686     template <typename... Args>
687     void bar(Args... args) { return foo(args...); }
688     void baz() {
689       int a;
690       bar(a);
691       bar(1);
692     }
693   )cpp");
694 }
695 
TEST(ParameterHints,VariadicReferenceHintForwardingRef)696 TEST(ParameterHints, VariadicReferenceHintForwardingRef) {
697   assertParameterHints(R"cpp(
698     void foo(int&);
699     template <typename... Args>
700     void bar(Args&&... args) { return foo(args...); }
701     void baz() {
702       int a;
703       bar($param[[a]]);
704       bar(1);
705     }
706   )cpp",
707                        ExpectedHint{"&: ", "param"});
708 }
709 
TEST(ParameterHints,VariadicReferenceHintForwardingRefStdForward)710 TEST(ParameterHints, VariadicReferenceHintForwardingRefStdForward) {
711   assertParameterHints(R"cpp(
712     namespace std { template <typename T> T&& forward(T&); }
713     void foo(int&);
714     template <typename... Args>
715     void bar(Args&&... args) { return foo(std::forward<Args>(args)...); }
716     void baz() {
717       int a;
718       bar($param[[a]]);
719     }
720   )cpp",
721                        ExpectedHint{"&: ", "param"});
722 }
723 
TEST(ParameterHints,VariadicNoReferenceHintForwardingRefStdForward)724 TEST(ParameterHints, VariadicNoReferenceHintForwardingRefStdForward) {
725   assertParameterHints(R"cpp(
726     namespace std { template <typename T> T&& forward(T&); }
727     void foo(int);
728     template <typename... Args>
729     void bar(Args&&... args) { return foo(std::forward<Args>(args)...); }
730     void baz() {
731       int a;
732       bar(a);
733       bar(1);
734     }
735   )cpp");
736 }
737 
TEST(ParameterHints,VariadicNoReferenceHintUnresolvedForward)738 TEST(ParameterHints, VariadicNoReferenceHintUnresolvedForward) {
739   assertParameterHints(R"cpp(
740     template <typename... Args>
741     void foo(Args&&... args);
742     void bar() {
743       int a;
744       foo(a);
745     }
746   )cpp");
747 }
748 
TEST(ParameterHints,MatchingNameVariadicForwarded)749 TEST(ParameterHints, MatchingNameVariadicForwarded) {
750   // No name hint for variadic parameter with matching name
751   // This prototype of std::forward is sufficient for clang to recognize it
752   assertParameterHints(R"cpp(
753     namespace std { template <typename T> T&& forward(T&); }
754     void foo(int a);
755     template <typename... Args>
756     void bar(Args&&... args) { return foo(std::forward<Args>(args)...); }
757     void baz() {
758       int a;
759       bar(a);
760     }
761   )cpp");
762 }
763 
TEST(ParameterHints,MatchingNameVariadicPlain)764 TEST(ParameterHints, MatchingNameVariadicPlain) {
765   // No name hint for variadic parameter with matching name
766   assertParameterHints(R"cpp(
767     void foo(int a);
768     template <typename... Args>
769     void bar(Args&&... args) { return foo(args...); }
770     void baz() {
771       int a;
772       bar(a);
773     }
774   )cpp");
775 }
776 
TEST(ParameterHints,Operator)777 TEST(ParameterHints, Operator) {
778   // No hint for operator call with operator syntax.
779   assertParameterHints(R"cpp(
780     struct S {};
781     void operator+(S lhs, S rhs);
782     void bar() {
783       S a, b;
784       a + b;
785     }
786   )cpp");
787 }
788 
TEST(ParameterHints,Macros)789 TEST(ParameterHints, Macros) {
790   // Handling of macros depends on where the call's argument list comes from.
791 
792   // If it comes from a macro definition, there's nothing to hint
793   // at the invocation site.
794   assertParameterHints(R"cpp(
795     void foo(int param);
796     #define ExpandsToCall() foo(42)
797     void bar() {
798       ExpandsToCall();
799     }
800   )cpp");
801 
802   // The argument expression being a macro invocation shouldn't interfere
803   // with hinting.
804   assertParameterHints(R"cpp(
805     #define PI 3.14
806     void foo(double param);
807     void bar() {
808       foo($param[[PI]]);
809     }
810   )cpp",
811                        ExpectedHint{"param: ", "param"});
812 
813   // If the whole argument list comes from a macro parameter, hint it.
814   assertParameterHints(R"cpp(
815     void abort();
816     #define ASSERT(expr) if (!expr) abort()
817     int foo(int param);
818     void bar() {
819       ASSERT(foo($param[[42]]) == 0);
820     }
821   )cpp",
822                        ExpectedHint{"param: ", "param"});
823 
824   // If the macro expands to multiple arguments, don't hint it.
825   assertParameterHints(R"cpp(
826     void foo(double x, double y);
827     #define CONSTANTS 3.14, 2.72
828     void bar() {
829       foo(CONSTANTS);
830     }
831   )cpp");
832 }
833 
TEST(ParameterHints,ConstructorParens)834 TEST(ParameterHints, ConstructorParens) {
835   assertParameterHints(R"cpp(
836     struct S {
837       S(int param);
838     };
839     void bar() {
840       S obj($param[[42]]);
841     }
842   )cpp",
843                        ExpectedHint{"param: ", "param"});
844 }
845 
TEST(ParameterHints,ConstructorBraces)846 TEST(ParameterHints, ConstructorBraces) {
847   assertParameterHints(R"cpp(
848     struct S {
849       S(int param);
850     };
851     void bar() {
852       S obj{$param[[42]]};
853     }
854   )cpp",
855                        ExpectedHint{"param: ", "param"});
856 }
857 
TEST(ParameterHints,ConstructorStdInitList)858 TEST(ParameterHints, ConstructorStdInitList) {
859   // Do not show hints for std::initializer_list constructors.
860   assertParameterHints(R"cpp(
861     namespace std {
862       template <typename> class initializer_list {};
863     }
864     struct S {
865       S(std::initializer_list<int> param);
866     };
867     void bar() {
868       S obj{42, 43};
869     }
870   )cpp");
871 }
872 
TEST(ParameterHints,MemberInit)873 TEST(ParameterHints, MemberInit) {
874   assertParameterHints(R"cpp(
875     struct S {
876       S(int param);
877     };
878     struct T {
879       S member;
880       T() : member($param[[42]]) {}
881     };
882   )cpp",
883                        ExpectedHint{"param: ", "param"});
884 }
885 
TEST(ParameterHints,ImplicitConstructor)886 TEST(ParameterHints, ImplicitConstructor) {
887   assertParameterHints(R"cpp(
888     struct S {
889       S(int param);
890     };
891     void bar(S);
892     S foo() {
893       // Do not show hint for implicit constructor call in argument.
894       bar(42);
895       // Do not show hint for implicit constructor call in return.
896       return 42;
897     }
898   )cpp");
899 }
900 
TEST(ParameterHints,ArgMatchesParam)901 TEST(ParameterHints, ArgMatchesParam) {
902   assertParameterHints(R"cpp(
903     void foo(int param);
904     struct S {
905       static const int param = 42;
906     };
907     void bar() {
908       int param = 42;
909       // Do not show redundant "param: param".
910       foo(param);
911       // But show it if the argument is qualified.
912       foo($param[[S::param]]);
913     }
914     struct A {
915       int param;
916       void bar() {
917         // Do not show "param: param" for member-expr.
918         foo(param);
919       }
920     };
921   )cpp",
922                        ExpectedHint{"param: ", "param"});
923 }
924 
TEST(ParameterHints,ArgMatchesParamReference)925 TEST(ParameterHints, ArgMatchesParamReference) {
926   assertParameterHints(R"cpp(
927     void foo(int& param);
928     void foo2(const int& param);
929     void bar() {
930       int param;
931       // show reference hint on mutable reference
932       foo($param[[param]]);
933       // but not on const reference
934       foo2(param);
935     }
936   )cpp",
937                        ExpectedHint{"&: ", "param"});
938 }
939 
TEST(ParameterHints,LeadingUnderscore)940 TEST(ParameterHints, LeadingUnderscore) {
941   assertParameterHints(R"cpp(
942     void foo(int p1, int _p2, int __p3);
943     void bar() {
944       foo($p1[[41]], $p2[[42]], $p3[[43]]);
945     }
946   )cpp",
947                        ExpectedHint{"p1: ", "p1"}, ExpectedHint{"p2: ", "p2"},
948                        ExpectedHint{"p3: ", "p3"});
949 }
950 
TEST(ParameterHints,DependentCalls)951 TEST(ParameterHints, DependentCalls) {
952   assertParameterHints(R"cpp(
953     template <typename T>
954     void nonmember(T par1);
955 
956     template <typename T>
957     struct A {
958       void member(T par2);
959       static void static_member(T par3);
960     };
961 
962     void overload(int anInt);
963     void overload(double aDouble);
964 
965     template <typename T>
966     struct S {
967       void bar(A<T> a, T t) {
968         nonmember($par1[[t]]);
969         a.member($par2[[t]]);
970         A<T>::static_member($par3[[t]]);
971         // We don't want to arbitrarily pick between
972         // "anInt" or "aDouble", so just show no hint.
973         overload(T{});
974       }
975     };
976   )cpp",
977                        ExpectedHint{"par1: ", "par1"},
978                        ExpectedHint{"par2: ", "par2"},
979                        ExpectedHint{"par3: ", "par3"});
980 }
981 
TEST(ParameterHints,VariadicFunction)982 TEST(ParameterHints, VariadicFunction) {
983   assertParameterHints(R"cpp(
984     template <typename... T>
985     void foo(int fixed, T... variadic);
986 
987     void bar() {
988       foo($fixed[[41]], 42, 43);
989     }
990   )cpp",
991                        ExpectedHint{"fixed: ", "fixed"});
992 }
993 
TEST(ParameterHints,VarargsFunction)994 TEST(ParameterHints, VarargsFunction) {
995   assertParameterHints(R"cpp(
996     void foo(int fixed, ...);
997 
998     void bar() {
999       foo($fixed[[41]], 42, 43);
1000     }
1001   )cpp",
1002                        ExpectedHint{"fixed: ", "fixed"});
1003 }
1004 
TEST(ParameterHints,CopyOrMoveConstructor)1005 TEST(ParameterHints, CopyOrMoveConstructor) {
1006   // Do not show hint for parameter of copy or move constructor.
1007   assertParameterHints(R"cpp(
1008     struct S {
1009       S();
1010       S(const S& other);
1011       S(S&& other);
1012     };
1013     void bar() {
1014       S a;
1015       S b(a);    // copy
1016       S c(S());  // move
1017     }
1018   )cpp");
1019 }
1020 
TEST(ParameterHints,AggregateInit)1021 TEST(ParameterHints, AggregateInit) {
1022   // FIXME: This is not implemented yet, but it would be a natural
1023   // extension to show member names as hints here.
1024   assertParameterHints(R"cpp(
1025     struct Point {
1026       int x;
1027       int y;
1028     };
1029     void bar() {
1030       Point p{41, 42};
1031     }
1032   )cpp");
1033 }
1034 
TEST(ParameterHints,UserDefinedLiteral)1035 TEST(ParameterHints, UserDefinedLiteral) {
1036   // Do not hint call to user-defined literal operator.
1037   assertParameterHints(R"cpp(
1038     long double operator"" _w(long double param);
1039     void bar() {
1040       1.2_w;
1041     }
1042   )cpp");
1043 }
1044 
TEST(ParameterHints,ParamNameComment)1045 TEST(ParameterHints, ParamNameComment) {
1046   // Do not hint an argument which already has a comment
1047   // with the parameter name preceding it.
1048   assertParameterHints(R"cpp(
1049     void foo(int param);
1050     void bar() {
1051       foo(/*param*/42);
1052       foo( /* param = */ 42);
1053       foo(/* the answer */$param[[42]]);
1054     }
1055   )cpp",
1056                        ExpectedHint{"param: ", "param"});
1057 }
1058 
TEST(ParameterHints,SetterFunctions)1059 TEST(ParameterHints, SetterFunctions) {
1060   assertParameterHints(R"cpp(
1061     struct S {
1062       void setParent(S* parent);
1063       void set_parent(S* parent);
1064       void setTimeout(int timeoutMillis);
1065       void setTimeoutMillis(int timeout_millis);
1066     };
1067     void bar() {
1068       S s;
1069       // Parameter name matches setter name - omit hint.
1070       s.setParent(nullptr);
1071       // Support snake_case
1072       s.set_parent(nullptr);
1073       // Parameter name may contain extra info - show hint.
1074       s.setTimeout($timeoutMillis[[120]]);
1075       // FIXME: Ideally we'd want to omit this.
1076       s.setTimeoutMillis($timeout_millis[[120]]);
1077     }
1078   )cpp",
1079                        ExpectedHint{"timeoutMillis: ", "timeoutMillis"},
1080                        ExpectedHint{"timeout_millis: ", "timeout_millis"});
1081 }
1082 
TEST(ParameterHints,BuiltinFunctions)1083 TEST(ParameterHints, BuiltinFunctions) {
1084   // This prototype of std::forward is sufficient for clang to recognize it
1085   assertParameterHints(R"cpp(
1086     namespace std { template <typename T> T&& forward(T&); }
1087     void foo() {
1088       int i;
1089       std::forward(i);
1090     }
1091   )cpp");
1092 }
1093 
TEST(ParameterHints,IncludeAtNonGlobalScope)1094 TEST(ParameterHints, IncludeAtNonGlobalScope) {
1095   Annotations FooInc(R"cpp(
1096     void bar() { foo(42); }
1097   )cpp");
1098   Annotations FooCC(R"cpp(
1099     struct S {
1100       void foo(int param);
1101       #include "foo.inc"
1102     };
1103   )cpp");
1104 
1105   TestWorkspace Workspace;
1106   Workspace.addSource("foo.inc", FooInc.code());
1107   Workspace.addMainFile("foo.cc", FooCC.code());
1108 
1109   auto AST = Workspace.openFile("foo.cc");
1110   ASSERT_TRUE(bool(AST));
1111 
1112   // Ensure the hint for the call in foo.inc is NOT materialized in foo.cc.
1113   EXPECT_EQ(hintsOfKind(*AST, InlayHintKind::Parameter).size(), 0u);
1114 }
1115 
TEST(TypeHints,Smoke)1116 TEST(TypeHints, Smoke) {
1117   assertTypeHints(R"cpp(
1118     auto $waldo[[waldo]] = 42;
1119   )cpp",
1120                   ExpectedHint{": int", "waldo"});
1121 }
1122 
TEST(TypeHints,Decorations)1123 TEST(TypeHints, Decorations) {
1124   assertTypeHints(R"cpp(
1125     int x = 42;
1126     auto* $var1[[var1]] = &x;
1127     auto&& $var2[[var2]] = x;
1128     const auto& $var3[[var3]] = x;
1129   )cpp",
1130                   ExpectedHint{": int *", "var1"},
1131                   ExpectedHint{": int &", "var2"},
1132                   ExpectedHint{": const int &", "var3"});
1133 }
1134 
TEST(TypeHints,DecltypeAuto)1135 TEST(TypeHints, DecltypeAuto) {
1136   assertTypeHints(R"cpp(
1137     int x = 42;
1138     int& y = x;
1139     decltype(auto) $z[[z]] = y;
1140   )cpp",
1141                   ExpectedHint{": int &", "z"});
1142 }
1143 
TEST(TypeHints,NoQualifiers)1144 TEST(TypeHints, NoQualifiers) {
1145   assertTypeHints(R"cpp(
1146     namespace A {
1147       namespace B {
1148         struct S1 {};
1149         S1 foo();
1150         auto $x[[x]] = foo();
1151 
1152         struct S2 {
1153           template <typename T>
1154           struct Inner {};
1155         };
1156         S2::Inner<int> bar();
1157         auto $y[[y]] = bar();
1158       }
1159     }
1160   )cpp",
1161                   ExpectedHint{": S1", "x"},
1162                   // FIXME: We want to suppress scope specifiers
1163                   //        here because we are into the whole
1164                   //        brevity thing, but the ElaboratedType
1165                   //        printer does not honor the SuppressScope
1166                   //        flag by design, so we need to extend the
1167                   //        PrintingPolicy to support this use case.
1168                   ExpectedHint{": S2::Inner<int>", "y"});
1169 }
1170 
TEST(TypeHints,Lambda)1171 TEST(TypeHints, Lambda) {
1172   // Do not print something overly verbose like the lambda's location.
1173   // Show hints for init-captures (but not regular captures).
1174   assertTypeHints(R"cpp(
1175     void f() {
1176       int cap = 42;
1177       auto $L[[L]] = [cap, $init[[init]] = 1 + 1](int a$ret[[)]] {
1178         return a + cap + init;
1179       };
1180     }
1181   )cpp",
1182                   ExpectedHint{": (lambda)", "L"},
1183                   ExpectedHint{": int", "init"}, ExpectedHint{"-> int", "ret"});
1184 
1185   // Lambda return hint shown even if no param list.
1186   // (The digraph :> is just a ] that doesn't conflict with the annotations).
1187   assertTypeHints("auto $L[[x]] = <:$ret[[:>]]{return 42;};",
1188                   ExpectedHint{": (lambda)", "L"},
1189                   ExpectedHint{"-> int", "ret"});
1190 }
1191 
1192 // Structured bindings tests.
1193 // Note, we hint the individual bindings, not the aggregate.
1194 
TEST(TypeHints,StructuredBindings_PublicStruct)1195 TEST(TypeHints, StructuredBindings_PublicStruct) {
1196   assertTypeHints(R"cpp(
1197     // Struct with public fields.
1198     struct Point {
1199       int x;
1200       int y;
1201     };
1202     Point foo();
1203     auto [$x[[x]], $y[[y]]] = foo();
1204   )cpp",
1205                   ExpectedHint{": int", "x"}, ExpectedHint{": int", "y"});
1206 }
1207 
TEST(TypeHints,StructuredBindings_Array)1208 TEST(TypeHints, StructuredBindings_Array) {
1209   assertTypeHints(R"cpp(
1210     int arr[2];
1211     auto [$x[[x]], $y[[y]]] = arr;
1212   )cpp",
1213                   ExpectedHint{": int", "x"}, ExpectedHint{": int", "y"});
1214 }
1215 
TEST(TypeHints,StructuredBindings_TupleLike)1216 TEST(TypeHints, StructuredBindings_TupleLike) {
1217   assertTypeHints(R"cpp(
1218     // Tuple-like type.
1219     struct IntPair {
1220       int a;
1221       int b;
1222     };
1223     namespace std {
1224       template <typename T>
1225       struct tuple_size {};
1226       template <>
1227       struct tuple_size<IntPair> {
1228         constexpr static unsigned value = 2;
1229       };
1230       template <unsigned I, typename T>
1231       struct tuple_element {};
1232       template <unsigned I>
1233       struct tuple_element<I, IntPair> {
1234         using type = int;
1235       };
1236     }
1237     template <unsigned I>
1238     int get(const IntPair& p) {
1239       if constexpr (I == 0) {
1240         return p.a;
1241       } else if constexpr (I == 1) {
1242         return p.b;
1243       }
1244     }
1245     IntPair bar();
1246     auto [$x[[x]], $y[[y]]] = bar();
1247   )cpp",
1248                   ExpectedHint{": int", "x"}, ExpectedHint{": int", "y"});
1249 }
1250 
TEST(TypeHints,StructuredBindings_NoInitializer)1251 TEST(TypeHints, StructuredBindings_NoInitializer) {
1252   assertTypeHints(R"cpp(
1253     // No initializer (ill-formed).
1254     // Do not show useless "NULL TYPE" hint.
1255     auto [x, y];  /*error-ok*/
1256   )cpp");
1257 }
1258 
TEST(TypeHints,ReturnTypeDeduction)1259 TEST(TypeHints, ReturnTypeDeduction) {
1260   assertTypeHints(
1261       R"cpp(
1262     auto f1(int x$ret1a[[)]];  // Hint forward declaration too
1263     auto f1(int x$ret1b[[)]] { return x + 1; }
1264 
1265     // Include pointer operators in hint
1266     int s;
1267     auto& f2($ret2[[)]] { return s; }
1268 
1269     // Do not hint `auto` for trailing return type.
1270     auto f3() -> int;
1271 
1272     // Do not hint when a trailing return type is specified.
1273     auto f4() -> auto* { return "foo"; }
1274 
1275     auto f5($noreturn[[)]] {}
1276 
1277     // `auto` conversion operator
1278     struct A {
1279       operator auto($retConv[[)]] { return 42; }
1280     };
1281 
1282     // FIXME: Dependent types do not work yet.
1283     template <typename T>
1284     struct S {
1285       auto method() { return T(); }
1286     };
1287   )cpp",
1288       ExpectedHint{"-> int", "ret1a"}, ExpectedHint{"-> int", "ret1b"},
1289       ExpectedHint{"-> int &", "ret2"}, ExpectedHint{"-> void", "noreturn"},
1290       ExpectedHint{"-> int", "retConv"});
1291 }
1292 
TEST(TypeHints,DependentType)1293 TEST(TypeHints, DependentType) {
1294   assertTypeHints(R"cpp(
1295     template <typename T>
1296     void foo(T arg) {
1297       // The hint would just be "auto" and we can't do any better.
1298       auto var1 = arg.method();
1299       // FIXME: It would be nice to show "T" as the hint.
1300       auto $var2[[var2]] = arg;
1301     }
1302   )cpp");
1303 }
1304 
TEST(TypeHints,LongTypeName)1305 TEST(TypeHints, LongTypeName) {
1306   assertTypeHints(R"cpp(
1307     template <typename, typename, typename>
1308     struct A {};
1309     struct MultipleWords {};
1310     A<MultipleWords, MultipleWords, MultipleWords> foo();
1311     // Omit type hint past a certain length (currently 32)
1312     auto var = foo();
1313   )cpp");
1314 }
1315 
TEST(TypeHints,DefaultTemplateArgs)1316 TEST(TypeHints, DefaultTemplateArgs) {
1317   assertTypeHints(R"cpp(
1318     template <typename, typename = int>
1319     struct A {};
1320     A<float> foo();
1321     auto $var[[var]] = foo();
1322   )cpp",
1323                   ExpectedHint{": A<float>", "var"});
1324 }
1325 
TEST(TypeHints,Deduplication)1326 TEST(TypeHints, Deduplication) {
1327   assertTypeHints(R"cpp(
1328     template <typename T>
1329     void foo() {
1330       auto $var[[var]] = 42;
1331     }
1332     template void foo<int>();
1333     template void foo<float>();
1334   )cpp",
1335                   ExpectedHint{": int", "var"});
1336 }
1337 
TEST(TypeHints,SinglyInstantiatedTemplate)1338 TEST(TypeHints, SinglyInstantiatedTemplate) {
1339   assertTypeHints(R"cpp(
1340     auto $lambda[[x]] = [](auto *$param[[y]], auto) { return 42; };
1341     int m = x("foo", 3);
1342   )cpp",
1343                   ExpectedHint{": (lambda)", "lambda"},
1344                   ExpectedHint{": const char *", "param"});
1345 
1346   // No hint for packs, or auto params following packs
1347   assertTypeHints(R"cpp(
1348     int x(auto $a[[a]], auto... b, auto c) { return 42; }
1349     int m = x<void*, char, float>(nullptr, 'c', 2.0, 2);
1350   )cpp",
1351                   ExpectedHint{": void *", "a"});
1352 }
1353 
TEST(TypeHints,Aliased)1354 TEST(TypeHints, Aliased) {
1355   // Check that we don't crash for functions without a FunctionTypeLoc.
1356   // https://github.com/clangd/clangd/issues/1140
1357   TestTU TU = TestTU::withCode("void foo(void){} extern typeof(foo) foo;");
1358   TU.ExtraArgs.push_back("-xc");
1359   auto AST = TU.build();
1360 
1361   EXPECT_THAT(hintsOfKind(AST, InlayHintKind::Type), IsEmpty());
1362 }
1363 
TEST(DesignatorHints,Basic)1364 TEST(DesignatorHints, Basic) {
1365   assertDesignatorHints(R"cpp(
1366     struct S { int x, y, z; };
1367     S s {$x[[1]], $y[[2+2]]};
1368 
1369     int x[] = {$0[[0]], $1[[1]]};
1370   )cpp",
1371                         ExpectedHint{".x=", "x"}, ExpectedHint{".y=", "y"},
1372                         ExpectedHint{"[0]=", "0"}, ExpectedHint{"[1]=", "1"});
1373 }
1374 
TEST(DesignatorHints,Nested)1375 TEST(DesignatorHints, Nested) {
1376   assertDesignatorHints(R"cpp(
1377     struct Inner { int x, y; };
1378     struct Outer { Inner a, b; };
1379     Outer o{ $a[[{ $x[[1]], $y[[2]] }]], $bx[[3]] };
1380   )cpp",
1381                         ExpectedHint{".a=", "a"}, ExpectedHint{".x=", "x"},
1382                         ExpectedHint{".y=", "y"}, ExpectedHint{".b.x=", "bx"});
1383 }
1384 
TEST(DesignatorHints,AnonymousRecord)1385 TEST(DesignatorHints, AnonymousRecord) {
1386   assertDesignatorHints(R"cpp(
1387     struct S {
1388       union {
1389         struct {
1390           struct {
1391             int y;
1392           };
1393         } x;
1394       };
1395     };
1396     S s{$xy[[42]]};
1397   )cpp",
1398                         ExpectedHint{".x.y=", "xy"});
1399 }
1400 
TEST(DesignatorHints,Suppression)1401 TEST(DesignatorHints, Suppression) {
1402   assertDesignatorHints(R"cpp(
1403     struct Point { int a, b, c, d, e, f, g, h; };
1404     Point p{/*a=*/1, .c=2, /* .d = */3, $e[[4]]};
1405   )cpp",
1406                         ExpectedHint{".e=", "e"});
1407 }
1408 
TEST(DesignatorHints,StdArray)1409 TEST(DesignatorHints, StdArray) {
1410   // Designators for std::array should be [0] rather than .__elements[0].
1411   // While technically correct, the designator is useless and horrible to read.
1412   assertDesignatorHints(R"cpp(
1413     template <typename T, int N> struct Array { T __elements[N]; };
1414     Array<int, 2> x = {$0[[0]], $1[[1]]};
1415   )cpp",
1416                         ExpectedHint{"[0]=", "0"}, ExpectedHint{"[1]=", "1"});
1417 }
1418 
TEST(DesignatorHints,OnlyAggregateInit)1419 TEST(DesignatorHints, OnlyAggregateInit) {
1420   assertDesignatorHints(R"cpp(
1421     struct Copyable { int x; } c;
1422     Copyable d{c};
1423 
1424     struct Constructible { Constructible(int x); };
1425     Constructible x{42};
1426   )cpp" /*no designator hints expected (but param hints!)*/);
1427 }
1428 
TEST(DesignatorHints,NoCrash)1429 TEST(DesignatorHints, NoCrash) {
1430   assertDesignatorHints(R"cpp(
1431     /*error-ok*/
1432     struct A {};
1433     struct Foo {int a; int b;};
1434     void test() {
1435       Foo f{A(), $b[[1]]};
1436     }
1437   )cpp", ExpectedHint{".b=", "b"});
1438 }
1439 
TEST(InlayHints,RestrictRange)1440 TEST(InlayHints, RestrictRange) {
1441   Annotations Code(R"cpp(
1442     auto a = false;
1443     [[auto b = 1;
1444     auto c = '2';]]
1445     auto d = 3.f;
1446   )cpp");
1447   auto AST = TestTU::withCode(Code.code()).build();
1448   EXPECT_THAT(inlayHints(AST, Code.range()),
1449               ElementsAre(labelIs(": int"), labelIs(": char")));
1450 }
1451 
TEST(ParameterHints,ArgPacksAndConstructors)1452 TEST(ParameterHints, ArgPacksAndConstructors) {
1453   assertParameterHints(
1454       R"cpp(
1455     struct Foo{ Foo(); Foo(int x); };
1456     void foo(Foo a, int b);
1457     template <typename... Args>
1458     void bar(Args... args) {
1459       foo(args...);
1460     }
1461     template <typename... Args>
1462     void baz(Args... args) { foo($param1[[Foo{args...}]], $param2[[1]]); }
1463 
1464     template <typename... Args>
1465     void bax(Args... args) { foo($param3[[{args...}]], args...); }
1466 
1467     void foo() {
1468       bar($param4[[Foo{}]], $param5[[42]]);
1469       bar($param6[[42]], $param7[[42]]);
1470       baz($param8[[42]]);
1471       bax($param9[[42]]);
1472     }
1473   )cpp",
1474       ExpectedHint{"a: ", "param1"}, ExpectedHint{"b: ", "param2"},
1475       ExpectedHint{"a: ", "param3"}, ExpectedHint{"a: ", "param4"},
1476       ExpectedHint{"b: ", "param5"}, ExpectedHint{"a: ", "param6"},
1477       ExpectedHint{"b: ", "param7"}, ExpectedHint{"x: ", "param8"},
1478       ExpectedHint{"b: ", "param9"});
1479 }
1480 
TEST(ParameterHints,DoesntExpandAllArgs)1481 TEST(ParameterHints, DoesntExpandAllArgs) {
1482   assertParameterHints(
1483       R"cpp(
1484     void foo(int x, int y);
1485     int id(int a, int b, int c);
1486     template <typename... Args>
1487     void bar(Args... args) {
1488       foo(id($param1[[args]], $param2[[1]], $param3[[args]])...);
1489     }
1490     void foo() {
1491       bar(1, 2); // FIXME: We could have `bar(a: 1, a: 2)` here.
1492     }
1493   )cpp",
1494       ExpectedHint{"a: ", "param1"}, ExpectedHint{"b: ", "param2"},
1495       ExpectedHint{"c: ", "param3"});
1496 }
1497 // FIXME: Low-hanging fruit where we could omit a type hint:
1498 //  - auto x = TypeName(...);
1499 //  - auto x = (TypeName) (...);
1500 //  - auto x = static_cast<TypeName>(...);  // and other built-in casts
1501 
1502 // Annoyances for which a heuristic is not obvious:
1503 //  - auto x = llvm::dyn_cast<LongTypeName>(y);  // and similar
1504 //  - stdlib algos return unwieldy __normal_iterator<X*, ...> type
1505 //    (For this one, perhaps we should omit type hints that start
1506 //     with a double underscore.)
1507 
1508 } // namespace
1509 } // namespace clangd
1510 } // namespace clang
1511