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{"¶m: ", "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{"¶m: ", "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