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