[TargetVersion] Only enable on RISC-V and AArch64 (#115991)
[llvm-project.git] / clang-tools-extra / clangd / unittests / InlayHintTests.cpp
blob73dd273d6c39d4e878625101dbe31c3904a5256c
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>
26 namespace clang {
27 namespace clangd {
29 llvm::raw_ostream &operator<<(llvm::raw_ostream &Stream,
30 const InlayHint &Hint) {
31 return Stream << Hint.joinLabels() << "@" << Hint.range;
34 namespace {
36 using ::testing::ElementsAre;
37 using ::testing::IsEmpty;
39 std::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);
45 return Result;
48 enum HintSide { Left, Right };
50 struct ExpectedHint {
51 std::string Label;
52 std::string RangeName;
53 HintSide Side = Left;
55 friend llvm::raw_ostream &operator<<(llvm::raw_ostream &Stream,
56 const ExpectedHint &Hint) {
57 return Stream << Hint.Label << "@$" << Hint.RangeName;
61 MATCHER_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;
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;
76 return true;
79 MATCHER_P(labelIs, Label, "") { return arg.joinLabels() == Label; }
81 Config 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;
91 template <typename... ExpectedHints>
92 void 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();
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());
109 template <typename... ExpectedHints>
110 void assertHints(InlayHintKind Kind, llvm::StringRef AnnotatedSource,
111 ExpectedHints... Expected) {
112 return assertHintsWithHeader(Kind, AnnotatedSource, "",
113 std::move(Expected)...);
116 // Hack to allow expression-statements operating on parameter packs in C++14.
117 template <typename... T> void ignore(T &&...) {}
119 template <typename... ExpectedHints>
120 void assertParameterHints(llvm::StringRef AnnotatedSource,
121 ExpectedHints... Expected) {
122 ignore(Expected.Side = Left...);
123 assertHints(InlayHintKind::Parameter, AnnotatedSource, Expected...);
126 template <typename... ExpectedHints>
127 void assertTypeHints(llvm::StringRef AnnotatedSource,
128 ExpectedHints... Expected) {
129 ignore(Expected.Side = Right...);
130 assertHints(InlayHintKind::Type, AnnotatedSource, Expected...);
133 template <typename... ExpectedHints>
134 void 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...);
142 template <typename... ExpectedHints>
143 void 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...);
151 TEST(ParameterHints, Smoke) {
152 assertParameterHints(R"cpp(
153 void foo(int param);
154 void bar() {
155 foo($param[[42]]);
157 )cpp",
158 ExpectedHint{"param: ", "param"});
161 TEST(ParameterHints, NoName) {
162 // No hint for anonymous parameter.
163 assertParameterHints(R"cpp(
164 void foo(int);
165 void bar() {
166 foo(42);
168 )cpp");
171 TEST(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);
178 )cpp");
181 TEST(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]]);
189 )cpp",
190 ExpectedHint{"&: ", "param"});
193 TEST(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);
200 )cpp");
203 TEST(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);
211 )cpp");
214 TEST(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);
225 )cpp");
228 TEST(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);
237 )cpp");
240 TEST(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]]);
247 void foo(int param) {};
248 )cpp",
249 ExpectedHint{"param: ", "param"});
252 TEST(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]]);
259 void foo(int a, int) {};
260 )cpp",
261 ExpectedHint{"a: ", "param1"},
262 ExpectedHint{"b: ", "param2"});
265 TEST(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...);
273 void baz() {
274 bar($param1[[42]], $param2[[42]]);
276 void foo(int a, int b) {};
277 )cpp",
278 ExpectedHint{"a: ", "param1"},
279 ExpectedHint{"b: ", "param2"});
282 TEST(ParameterHints, NameMismatch) {
283 // Prefer name from declaration.
284 assertParameterHints(R"cpp(
285 void foo(int good);
286 void bar() {
287 foo($good[[42]]);
289 void foo(int bad) {};
290 )cpp",
291 ExpectedHint{"good: ", "good"});
294 TEST(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]]);
301 )cpp",
302 ExpectedHint{"param: ", "param"});
305 TEST(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]]);
314 )cpp",
315 ExpectedHint{"param: ", "param"});
318 TEST(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]]);
326 )cpp",
327 ExpectedHint{"&param: ", "param"});
330 TEST(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]]);
339 )cpp",
340 ExpectedHint{"&param: ", "param"});
343 TEST(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]]);
350 )cpp",
351 ExpectedHint{"param: ", "param"});
354 TEST(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]]);
366 )cpp",
367 ExpectedHint{"a: ", "param"});
370 TEST(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]]);
380 )cpp",
381 ExpectedHint{"a: ", "param"});
384 TEST(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]]);
396 )cpp",
397 ExpectedHint{"a: ", "param"});
400 TEST(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]]);
410 )cpp",
411 ExpectedHint{"a: ", "param"});
414 TEST(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]]);
426 )cpp",
427 ExpectedHint{"a: ", "param"});
430 TEST(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]]);
439 )cpp",
440 ExpectedHint{"a: ", "param"});
443 TEST(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]]);
453 )cpp",
454 ExpectedHint{"a: ", "param"});
457 TEST(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);
468 template <typename... Args>
469 void bar(Args&&... args) { return foo(std::forward<Args>(args)...); }
470 void bazz() {
471 bar($param1[[32]], $param2[[42]]);
473 )cpp",
474 ExpectedHint{"a: ", "param1"},
475 ExpectedHint{"b: ", "param2"});
478 TEST(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...);
487 template <>
488 void bar<int>(int b);
489 void baz() {
490 bar($param[[42]]);
492 )cpp",
493 ExpectedHint{"b: ", "param"});
496 TEST(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...);
505 template <typename... Args>
506 void bar(Args... args) {
507 foo(args...);
509 template <>
510 void foo<int>(int b);
511 void baz() {
512 bar($param[[42]]);
514 )cpp",
515 ExpectedHint{"b: ", "param"});
518 TEST(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)...);
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]]);
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"});
544 TEST(ParameterHints, VariadicRecursive) {
545 // make_tuple-like recursive variadic call
546 assertParameterHints(
547 R"cpp(
548 void foo();
550 template <typename Head, typename... Tail>
551 void foo(Head head, Tail... tail) {
552 foo(tail...);
555 template <typename... Args>
556 void bar(Args... args) {
557 foo(args...);
560 int main() {
561 bar(1, 2, 3);
563 )cpp");
566 TEST(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...);
575 void baz() {
576 bar($fixed[[41]], 42, 43);
578 )cpp");
581 TEST(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...);
591 void baz() {
592 bar($fixed[[41]], 42, 43);
594 )cpp",
595 ExpectedHint{"fixed: ", "fixed"});
598 TEST(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);
605 bool cond;
607 template <typename... Args>
608 void foo(Args... args) {
609 if (cond) {
610 f1(args...);
611 } else {
612 f2(args...);
616 int main() {
617 foo($param1[[1]], $param2[[2]]);
619 )cpp",
620 ExpectedHint{"a: ", "param1"}, ExpectedHint{"b: ", "param2"});
623 TEST(ParameterHints, VariadicInfinite) {
624 // infinite recursion should not break clangd
625 assertParameterHints(
626 R"cpp(
627 template <typename... Args>
628 void foo(Args...);
630 template <typename... Args>
631 void bar(Args... args) {
632 foo(args...);
635 template <typename... Args>
636 void foo(Args... args) {
637 bar(args...);
640 int main() {
641 foo(1, 2);
643 )cpp");
646 TEST(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);
652 template <typename... Args>
653 void bar(int, Args... args, int d) {
654 foo(args..., d);
657 template <typename... Args>
658 void baz(Args... args, Args... args2) {
659 bar<Args..., int>(1, args..., args2...);
662 int main() {
663 baz<int, int>($p1[[1]], $p2[[2]], $p3[[3]], $p4[[4]]);
665 )cpp",
666 ExpectedHint{"a: ", "p1"}, ExpectedHint{"b: ", "p2"},
667 ExpectedHint{"c: ", "p3"}, ExpectedHint{"d: ", "p4"});
670 TEST(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);
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)...};
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)...);
699 void foo() {
700 container<S> c;
701 c.emplace($param1[[1]]);
702 c.emplace($param2[[2]], $param3[[3]]);
704 )cpp",
705 ExpectedHint{"A: ", "param1"}, ExpectedHint{"B: ", "param2"},
706 ExpectedHint{"C: ", "param3"});
709 TEST(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);
719 )cpp");
722 TEST(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);
732 )cpp",
733 ExpectedHint{"&: ", "param"});
736 TEST(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]]);
746 )cpp",
747 ExpectedHint{"&: ", "param"});
750 TEST(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);
761 )cpp");
764 TEST(ParameterHints, VariadicNoReferenceHintUnresolvedForward) {
765 assertParameterHints(R"cpp(
766 template <typename... Args>
767 void foo(Args&&... args);
768 void bar() {
769 int a;
770 foo(a);
772 )cpp");
775 TEST(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);
787 )cpp");
790 TEST(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);
800 )cpp");
803 TEST(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;
812 )cpp");
815 TEST(ParameterHints, FunctionCallOperator) {
816 assertParameterHints(R"cpp(
817 struct W {
818 void operator()(int x);
820 struct S : W {
821 using W::operator();
822 static void operator()(int x, int y);
824 void bar() {
825 auto l1 = [](int x) {};
826 auto l2 = [](int x) static {};
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]]);
834 l1($7[[1]]);
835 l1.operator()($8[[1]]);
836 l2($9[[1]]);
837 l2.operator()($10[[1]]);
839 void (*ptr)(int a, int b) = &S::operator();
840 ptr($11[[1]], $12[[2]]);
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"});
851 TEST(ParameterHints, DeducingThis) {
852 assertParameterHints(R"cpp(
853 struct S {
854 template <typename This>
855 auto operator()(this This &&Self, int Param) {
856 return 42;
859 auto function(this auto &Self, int Param) {
860 return Param;
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);
871 lambda($4[['A']]);
873 )cpp",
874 ExpectedHint{"Param: ", "1"},
875 ExpectedHint{"Param: ", "2"},
876 ExpectedHint{"Param: ", "3"}, ExpectedHint{"C: ", "4"});
879 TEST(ParameterHints, Macros) {
880 // Handling of macros depends on where the call's argument list comes from.
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();
890 )cpp");
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]]);
900 )cpp",
901 ExpectedHint{"param: ", "param"});
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);
911 )cpp",
912 ExpectedHint{"param: ", "param"});
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);
921 )cpp");
924 TEST(ParameterHints, ConstructorParens) {
925 assertParameterHints(R"cpp(
926 struct S {
927 S(int param);
929 void bar() {
930 S obj($param[[42]]);
932 )cpp",
933 ExpectedHint{"param: ", "param"});
936 TEST(ParameterHints, ConstructorBraces) {
937 assertParameterHints(R"cpp(
938 struct S {
939 S(int param);
941 void bar() {
942 S obj{$param[[42]]};
944 )cpp",
945 ExpectedHint{"param: ", "param"});
948 TEST(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; };
954 struct S {
955 S(std::initializer_list<int> param);
957 void bar() {
958 S obj{42, 43};
960 )cpp");
963 TEST(ParameterHints, MemberInit) {
964 assertParameterHints(R"cpp(
965 struct S {
966 S(int param);
968 struct T {
969 S member;
970 T() : member($param[[42]]) {}
972 )cpp",
973 ExpectedHint{"param: ", "param"});
976 TEST(ParameterHints, ImplicitConstructor) {
977 assertParameterHints(R"cpp(
978 struct S {
979 S(int param);
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;
988 )cpp");
991 TEST(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]]);
1006 )cpp",
1007 ExpectedHint{"param: ", "f1"}, ExpectedHint{"param: ", "f2"},
1008 ExpectedHint{"param: ", "f3"}, ExpectedHint{"param: ", "f4"});
1011 TEST(ParameterHints, ArgMatchesParam) {
1012 assertParameterHints(R"cpp(
1013 void foo(int param);
1014 struct S {
1015 static const int param = 42;
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]]);
1024 struct A {
1025 int param;
1026 void bar() {
1027 // Do not show "param: param" for member-expr.
1028 foo(param);
1031 )cpp",
1032 ExpectedHint{"param: ", "param"});
1035 TEST(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);
1046 )cpp",
1047 ExpectedHint{"&: ", "param"});
1050 TEST(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]]);
1056 )cpp",
1057 ExpectedHint{"p1: ", "p1"}, ExpectedHint{"p2: ", "p2"},
1058 ExpectedHint{"p3: ", "p3"});
1061 TEST(ParameterHints, DependentCalls) {
1062 assertParameterHints(R"cpp(
1063 template <typename T>
1064 void nonmember(T par1);
1066 template <typename T>
1067 struct A {
1068 void member(T par2);
1069 static void static_member(T par3);
1072 void overload(int anInt);
1073 void overload(double aDouble);
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{});
1086 )cpp",
1087 ExpectedHint{"par1: ", "par1"},
1088 ExpectedHint{"par2: ", "par2"},
1089 ExpectedHint{"par3: ", "par3"});
1092 TEST(ParameterHints, VariadicFunction) {
1093 assertParameterHints(R"cpp(
1094 template <typename... T>
1095 void foo(int fixed, T... variadic);
1097 void bar() {
1098 foo($fixed[[41]], 42, 43);
1100 )cpp",
1101 ExpectedHint{"fixed: ", "fixed"});
1104 TEST(ParameterHints, VarargsFunction) {
1105 assertParameterHints(R"cpp(
1106 void foo(int fixed, ...);
1108 void bar() {
1109 foo($fixed[[41]], 42, 43);
1111 )cpp",
1112 ExpectedHint{"fixed: ", "fixed"});
1115 TEST(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);
1123 void bar() {
1124 S a;
1125 S b(a); // copy
1126 S c(S()); // move
1128 )cpp");
1131 TEST(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;
1139 void bar() {
1140 Point p{41, 42};
1142 )cpp");
1145 TEST(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;
1152 )cpp");
1155 TEST(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]]);
1170 )cpp",
1171 ExpectedHint{"param: ", "macro"},
1172 ExpectedHint{"param: ", "param"});
1175 TEST(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);
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]]);
1194 )cpp",
1195 ExpectedHint{"timeoutMillis: ", "timeoutMillis"},
1196 ExpectedHint{"timeout_millis: ", "timeout_millis"});
1199 TEST(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);
1207 )cpp");
1210 TEST(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"
1219 )cpp");
1221 TestWorkspace Workspace;
1222 Workspace.addSource("foo.inc", FooInc.code());
1223 Workspace.addMainFile("foo.cc", FooCC.code());
1225 auto AST = Workspace.openFile("foo.cc");
1226 ASSERT_TRUE(bool(AST));
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);
1232 TEST(TypeHints, Smoke) {
1233 assertTypeHints(R"cpp(
1234 auto $waldo[[waldo]] = 42;
1235 )cpp",
1236 ExpectedHint{": int", "waldo"});
1239 TEST(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"});
1251 TEST(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"});
1260 TEST(TypeHints, NoQualifiers) {
1261 assertTypeHints(R"cpp(
1262 namespace A {
1263 namespace B {
1264 struct S1 {};
1265 S1 foo();
1266 auto $x[[x]] = foo();
1268 struct S2 {
1269 template <typename T>
1270 struct Inner {};
1272 S2::Inner<int> bar();
1273 auto $y[[y]] = bar();
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"});
1287 TEST(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;
1297 )cpp",
1298 ExpectedHint{": (lambda)", "L"},
1299 ExpectedHint{": int", "init"}, ExpectedHint{"-> int", "ret"});
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"});
1308 // Structured bindings tests.
1309 // Note, we hint the individual bindings, not the aggregate.
1311 TEST(TypeHints, StructuredBindings_PublicStruct) {
1312 assertTypeHints(R"cpp(
1313 // Struct with public fields.
1314 struct Point {
1315 int x;
1316 int y;
1318 Point foo();
1319 auto [$x[[x]], $y[[y]]] = foo();
1320 )cpp",
1321 ExpectedHint{": int", "x"}, ExpectedHint{": int", "y"});
1324 TEST(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"});
1332 TEST(TypeHints, StructuredBindings_TupleLike) {
1333 assertTypeHints(R"cpp(
1334 // Tuple-like type.
1335 struct IntPair {
1336 int a;
1337 int b;
1339 namespace std {
1340 template <typename T>
1341 struct tuple_size {};
1342 template <>
1343 struct tuple_size<IntPair> {
1344 constexpr static unsigned value = 2;
1346 template <unsigned I, typename T>
1347 struct tuple_element {};
1348 template <unsigned I>
1349 struct tuple_element<I, IntPair> {
1350 using type = int;
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;
1361 IntPair bar();
1362 auto [$x[[x]], $y[[y]]] = bar();
1363 )cpp",
1364 ExpectedHint{": int", "x"}, ExpectedHint{": int", "y"});
1367 TEST(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");
1375 TEST(TypeHints, InvalidType) {
1376 assertTypeHints(R"cpp(
1377 auto x = (unknown_type)42; /*error-ok*/
1378 auto *y = (unknown_ptr)nullptr;
1379 )cpp");
1382 TEST(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; }
1388 // Include pointer operators in hint
1389 int s;
1390 auto& f2($ret2[[)]] { return s; }
1392 // Do not hint `auto` for trailing return type.
1393 auto f3() -> int;
1395 // Do not hint when a trailing return type is specified.
1396 auto f4() -> auto* { return "foo"; }
1398 auto f5($noreturn[[)]] {}
1400 // `auto` conversion operator
1401 struct A {
1402 operator auto($retConv[[)]] { return 42; }
1405 // FIXME: Dependent types do not work yet.
1406 template <typename T>
1407 struct S {
1408 auto method() { return T(); }
1410 )cpp",
1411 ExpectedHint{"-> int", "ret1a"}, ExpectedHint{"-> int", "ret1b"},
1412 ExpectedHint{"-> int &", "ret2"}, ExpectedHint{"-> void", "noreturn"},
1413 ExpectedHint{"-> int", "retConv"});
1416 TEST(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;
1426 template <typename T>
1427 void bar(T arg) {
1428 auto [a, b] = arg;
1430 )cpp");
1433 TEST(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");
1443 Config Cfg;
1444 Cfg.InlayHints.TypeNameLimit = 0;
1445 WithContextValue WithCfg(Config::Key, std::move(Cfg));
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"});
1459 TEST(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"});
1472 TEST(DefaultArguments, Smoke) {
1473 Config Cfg;
1474 Cfg.InlayHints.Parameters =
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;
1480 Cfg.InlayHints.DefaultArguments = true;
1481 WithContextValue WithCfg(Config::Key, std::move(Cfg));
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[[)]];
1488 void baz(int = 5) { if (false) baz($unnamed[[)]]; };
1489 )cpp";
1491 assertHints(InlayHintKind::DefaultArgument, Code,
1492 ExpectedHint{"A: 4", "default1", Left},
1493 ExpectedHint{", B: 1, C: foo()", "default2", Left},
1494 ExpectedHint{"5", "unnamed", Left});
1496 assertHints(InlayHintKind::Parameter, Code,
1497 ExpectedHint{"A: ", "explicit", Left});
1500 TEST(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;
1507 Cfg.InlayHints.DefaultArguments = true;
1508 WithContextValue WithCfg(Config::Key, std::move(Cfg));
1510 const auto *Code = R"cpp(
1511 struct Baz {
1512 Baz(float a = 3 //
1513 + 2);
1515 struct Foo {
1516 Foo(int, Baz baz = //
1517 Baz{$abbreviated[[}]]
1520 ) {}
1523 int main() {
1524 Foo foo1(1$paren[[)]];
1525 Foo foo2{2$brace1[[}]];
1526 Foo foo3 = {3$brace2[[}]];
1527 auto foo4 = Foo{4$brace3[[}]];
1529 )cpp";
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});
1538 assertHints(InlayHintKind::Parameter, Code);
1541 TEST(TypeHints, Deduplication) {
1542 assertTypeHints(R"cpp(
1543 template <typename T>
1544 void foo() {
1545 auto $var[[var]] = 42;
1547 template void foo<int>();
1548 template void foo<float>();
1549 )cpp",
1550 ExpectedHint{": int", "var"});
1553 TEST(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"});
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"});
1569 TEST(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();
1576 EXPECT_THAT(hintsOfKind(AST, InlayHintKind::Type), IsEmpty());
1579 TEST(TypeHints, Decltype) {
1580 assertTypeHints(R"cpp(
1581 $a[[decltype(0)]] a;
1582 $b[[decltype(a)]] b;
1583 const $c[[decltype(0)]] &c = b;
1585 // Don't show for dependent type
1586 template <class T>
1587 constexpr decltype(T{}) d;
1589 $e[[decltype(0)]] e();
1590 auto f() -> $f[[decltype(0)]];
1592 template <class, class> struct Foo;
1593 using G = Foo<$g[[decltype(0)]], float>;
1595 auto $h[[h]] = $i[[decltype(0)]]{};
1597 // No crash
1598 /* error-ok */
1599 auto $j[[s]];
1600 )cpp",
1601 ExpectedHint{": int", "a"}, ExpectedHint{": int", "b"},
1602 ExpectedHint{": int", "c"}, ExpectedHint{": int", "e"},
1603 ExpectedHint{": int", "f"}, ExpectedHint{": int", "g"},
1604 ExpectedHint{": int", "h"}, ExpectedHint{": int", "i"});
1607 TEST(TypeHints, SubstTemplateParameterAliases) {
1608 llvm::StringRef Header = R"cpp(
1609 template <class T> struct allocator {};
1611 template <class T, class A>
1612 struct vector_base {
1613 using pointer = T*;
1616 template <class T, class A>
1617 struct internal_iterator_type_template_we_dont_expect {};
1619 struct my_iterator {};
1621 template <class T, class A = allocator<T>>
1622 struct vector : vector_base<T, A> {
1623 using base = vector_base<T, A>;
1624 typedef T value_type;
1625 typedef base::pointer pointer;
1626 using allocator_type = A;
1627 using size_type = int;
1628 using iterator = internal_iterator_type_template_we_dont_expect<T, A>;
1629 using non_template_iterator = my_iterator;
1631 value_type& operator[](int index) { return elements[index]; }
1632 const value_type& at(int index) const { return elements[index]; }
1633 pointer data() { return &elements[0]; }
1634 allocator_type get_allocator() { return A(); }
1635 size_type size() const { return 10; }
1636 iterator begin() { return iterator(); }
1637 non_template_iterator end() { return non_template_iterator(); }
1639 T elements[10];
1641 )cpp";
1643 llvm::StringRef VectorIntPtr = R"cpp(
1644 vector<int *> array;
1645 auto $no_modifier[[x]] = array[3];
1646 auto* $ptr_modifier[[ptr]] = &array[3];
1647 auto& $ref_modifier[[ref]] = array[3];
1648 auto& $at[[immutable]] = array.at(3);
1650 auto $data[[data]] = array.data();
1651 auto $allocator[[alloc]] = array.get_allocator();
1652 auto $size[[size]] = array.size();
1653 auto $begin[[begin]] = array.begin();
1654 auto $end[[end]] = array.end();
1655 )cpp";
1657 assertHintsWithHeader(
1658 InlayHintKind::Type, VectorIntPtr, Header,
1659 ExpectedHint{": int *", "no_modifier"},
1660 ExpectedHint{": int **", "ptr_modifier"},
1661 ExpectedHint{": int *&", "ref_modifier"},
1662 ExpectedHint{": int *const &", "at"}, ExpectedHint{": int **", "data"},
1663 ExpectedHint{": allocator<int *>", "allocator"},
1664 ExpectedHint{": size_type", "size"}, ExpectedHint{": iterator", "begin"},
1665 ExpectedHint{": non_template_iterator", "end"});
1667 llvm::StringRef VectorInt = R"cpp(
1668 vector<int> array;
1669 auto $no_modifier[[by_value]] = array[3];
1670 auto* $ptr_modifier[[ptr]] = &array[3];
1671 auto& $ref_modifier[[ref]] = array[3];
1672 auto& $at[[immutable]] = array.at(3);
1674 auto $data[[data]] = array.data();
1675 auto $allocator[[alloc]] = array.get_allocator();
1676 auto $size[[size]] = array.size();
1677 auto $begin[[begin]] = array.begin();
1678 auto $end[[end]] = array.end();
1679 )cpp";
1681 assertHintsWithHeader(
1682 InlayHintKind::Type, VectorInt, Header,
1683 ExpectedHint{": int", "no_modifier"},
1684 ExpectedHint{": int *", "ptr_modifier"},
1685 ExpectedHint{": int &", "ref_modifier"},
1686 ExpectedHint{": const int &", "at"}, ExpectedHint{": int *", "data"},
1687 ExpectedHint{": allocator<int>", "allocator"},
1688 ExpectedHint{": size_type", "size"}, ExpectedHint{": iterator", "begin"},
1689 ExpectedHint{": non_template_iterator", "end"});
1691 llvm::StringRef TypeAlias = R"cpp(
1692 // If the type alias is not of substituted template parameter type,
1693 // do not show desugared type.
1694 using VeryLongLongTypeName = my_iterator;
1695 using Short = VeryLongLongTypeName;
1697 auto $short_name[[my_value]] = Short();
1699 // Same applies with templates.
1700 template <typename T, typename A>
1701 using basic_static_vector = vector<T, A>;
1702 template <typename T>
1703 using static_vector = basic_static_vector<T, allocator<T>>;
1705 auto $vector_name[[vec]] = static_vector<int>();
1706 )cpp";
1708 assertHintsWithHeader(InlayHintKind::Type, TypeAlias, Header,
1709 ExpectedHint{": Short", "short_name"},
1710 ExpectedHint{": static_vector<int>", "vector_name"});
1713 TEST(DesignatorHints, Basic) {
1714 assertDesignatorHints(R"cpp(
1715 struct S { int x, y, z; };
1716 S s {$x[[1]], $y[[2+2]]};
1718 int x[] = {$0[[0]], $1[[1]]};
1719 )cpp",
1720 ExpectedHint{".x=", "x"}, ExpectedHint{".y=", "y"},
1721 ExpectedHint{"[0]=", "0"}, ExpectedHint{"[1]=", "1"});
1724 TEST(DesignatorHints, Nested) {
1725 assertDesignatorHints(R"cpp(
1726 struct Inner { int x, y; };
1727 struct Outer { Inner a, b; };
1728 Outer o{ $a[[{ $x[[1]], $y[[2]] }]], $bx[[3]] };
1729 )cpp",
1730 ExpectedHint{".a=", "a"}, ExpectedHint{".x=", "x"},
1731 ExpectedHint{".y=", "y"}, ExpectedHint{".b.x=", "bx"});
1734 TEST(DesignatorHints, AnonymousRecord) {
1735 assertDesignatorHints(R"cpp(
1736 struct S {
1737 union {
1738 struct {
1739 struct {
1740 int y;
1742 } x;
1745 S s{$xy[[42]]};
1746 )cpp",
1747 ExpectedHint{".x.y=", "xy"});
1750 TEST(DesignatorHints, Suppression) {
1751 assertDesignatorHints(R"cpp(
1752 struct Point { int a, b, c, d, e, f, g, h; };
1753 Point p{/*a=*/1, .c=2, /* .d = */3, $e[[4]]};
1754 )cpp",
1755 ExpectedHint{".e=", "e"});
1758 TEST(DesignatorHints, StdArray) {
1759 // Designators for std::array should be [0] rather than .__elements[0].
1760 // While technically correct, the designator is useless and horrible to read.
1761 assertDesignatorHints(R"cpp(
1762 template <typename T, int N> struct Array { T __elements[N]; };
1763 Array<int, 2> x = {$0[[0]], $1[[1]]};
1764 )cpp",
1765 ExpectedHint{"[0]=", "0"}, ExpectedHint{"[1]=", "1"});
1768 TEST(DesignatorHints, OnlyAggregateInit) {
1769 assertDesignatorHints(R"cpp(
1770 struct Copyable { int x; } c;
1771 Copyable d{c};
1773 struct Constructible { Constructible(int x); };
1774 Constructible x{42};
1775 )cpp" /*no designator hints expected (but param hints!)*/);
1778 TEST(DesignatorHints, NoCrash) {
1779 assertDesignatorHints(R"cpp(
1780 /*error-ok*/
1781 struct A {};
1782 struct Foo {int a; int b;};
1783 void test() {
1784 Foo f{A(), $b[[1]]};
1786 )cpp",
1787 ExpectedHint{".b=", "b"});
1790 TEST(InlayHints, RestrictRange) {
1791 Annotations Code(R"cpp(
1792 auto a = false;
1793 [[auto b = 1;
1794 auto c = '2';]]
1795 auto d = 3.f;
1796 )cpp");
1797 auto AST = TestTU::withCode(Code.code()).build();
1798 EXPECT_THAT(inlayHints(AST, Code.range()),
1799 ElementsAre(labelIs(": int"), labelIs(": char")));
1802 TEST(ParameterHints, PseudoObjectExpr) {
1803 Annotations Code(R"cpp(
1804 struct S {
1805 __declspec(property(get=GetX, put=PutX)) int x[];
1806 int GetX(int y, int z) { return 42 + y; }
1807 void PutX(int) { }
1809 // This is a PseudoObjectExpression whose syntactic form is a binary
1810 // operator.
1811 void Work(int y) { x = y; } // Not `x = y: y`.
1814 int printf(const char *Format, ...);
1816 int main() {
1817 S s;
1818 __builtin_dump_struct(&s, printf); // Not `Format: __builtin_dump_struct()`
1819 printf($Param[["Hello, %d"]], 42); // Normal calls are not affected.
1820 // This builds a PseudoObjectExpr, but here it's useful for showing the
1821 // arguments from the semantic form.
1822 return s.x[ $one[[1]] ][ $two[[2]] ]; // `x[y: 1][z: 2]`
1824 )cpp");
1825 auto TU = TestTU::withCode(Code.code());
1826 TU.ExtraArgs.push_back("-fms-extensions");
1827 auto AST = TU.build();
1828 EXPECT_THAT(inlayHints(AST, std::nullopt),
1829 ElementsAre(HintMatcher(ExpectedHint{"Format: ", "Param"}, Code),
1830 HintMatcher(ExpectedHint{"y: ", "one"}, Code),
1831 HintMatcher(ExpectedHint{"z: ", "two"}, Code)));
1834 TEST(ParameterHints, ArgPacksAndConstructors) {
1835 assertParameterHints(
1836 R"cpp(
1837 struct Foo{ Foo(); Foo(int x); };
1838 void foo(Foo a, int b);
1839 template <typename... Args>
1840 void bar(Args... args) {
1841 foo(args...);
1843 template <typename... Args>
1844 void baz(Args... args) { foo($param1[[Foo{args...}]], $param2[[1]]); }
1846 template <typename... Args>
1847 void bax(Args... args) { foo($param3[[{args...}]], args...); }
1849 void foo() {
1850 bar($param4[[Foo{}]], $param5[[42]]);
1851 bar($param6[[42]], $param7[[42]]);
1852 baz($param8[[42]]);
1853 bax($param9[[42]]);
1855 )cpp",
1856 ExpectedHint{"a: ", "param1"}, ExpectedHint{"b: ", "param2"},
1857 ExpectedHint{"a: ", "param3"}, ExpectedHint{"a: ", "param4"},
1858 ExpectedHint{"b: ", "param5"}, ExpectedHint{"a: ", "param6"},
1859 ExpectedHint{"b: ", "param7"}, ExpectedHint{"x: ", "param8"},
1860 ExpectedHint{"b: ", "param9"});
1863 TEST(ParameterHints, DoesntExpandAllArgs) {
1864 assertParameterHints(
1865 R"cpp(
1866 void foo(int x, int y);
1867 int id(int a, int b, int c);
1868 template <typename... Args>
1869 void bar(Args... args) {
1870 foo(id($param1[[args]], $param2[[1]], $param3[[args]])...);
1872 void foo() {
1873 bar(1, 2); // FIXME: We could have `bar(a: 1, a: 2)` here.
1875 )cpp",
1876 ExpectedHint{"a: ", "param1"}, ExpectedHint{"b: ", "param2"},
1877 ExpectedHint{"c: ", "param3"});
1880 TEST(BlockEndHints, Functions) {
1881 assertBlockEndHints(R"cpp(
1882 int foo() {
1883 return 41;
1884 $foo[[}]]
1886 template<int X>
1887 int bar() {
1888 // No hint for lambda for now
1889 auto f = []() {
1890 return X;
1892 return f();
1893 $bar[[}]]
1895 // No hint because this isn't a definition
1896 int buz();
1898 struct S{};
1899 bool operator==(S, S) {
1900 return true;
1901 $opEqual[[}]]
1902 )cpp",
1903 ExpectedHint{" // foo", "foo"},
1904 ExpectedHint{" // bar", "bar"},
1905 ExpectedHint{" // operator==", "opEqual"});
1908 TEST(BlockEndHints, Methods) {
1909 assertBlockEndHints(R"cpp(
1910 struct Test {
1911 // No hint because there's no function body
1912 Test() = default;
1914 ~Test() {
1915 $dtor[[}]]
1917 void method1() {
1918 $method1[[}]]
1920 // No hint because this isn't a definition
1921 void method2();
1923 template <typename T>
1924 void method3() {
1925 $method3[[}]]
1927 // No hint because this isn't a definition
1928 template <typename T>
1929 void method4();
1931 Test operator+(int) const {
1932 return *this;
1933 $opIdentity[[}]]
1935 operator bool() const {
1936 return true;
1937 $opBool[[}]]
1939 // No hint because there's no function body
1940 operator int() const = delete;
1941 } x;
1943 void Test::method2() {
1944 $method2[[}]]
1946 template <typename T>
1947 void Test::method4() {
1948 $method4[[}]]
1949 )cpp",
1950 ExpectedHint{" // ~Test", "dtor"},
1951 ExpectedHint{" // method1", "method1"},
1952 ExpectedHint{" // method3", "method3"},
1953 ExpectedHint{" // operator+", "opIdentity"},
1954 ExpectedHint{" // operator bool", "opBool"},
1955 ExpectedHint{" // Test::method2", "method2"},
1956 ExpectedHint{" // Test::method4", "method4"});
1959 TEST(BlockEndHints, Namespaces) {
1960 assertBlockEndHints(
1961 R"cpp(
1962 namespace {
1963 void foo();
1964 $anon[[}]]
1966 namespace ns {
1967 void bar();
1968 $ns[[}]]
1969 )cpp",
1970 ExpectedHint{" // namespace", "anon"},
1971 ExpectedHint{" // namespace ns", "ns"});
1974 TEST(BlockEndHints, Types) {
1975 assertBlockEndHints(
1976 R"cpp(
1977 struct S {
1978 $S[[};]]
1980 class C {
1981 $C[[};]]
1983 union U {
1984 $U[[};]]
1986 enum E1 {
1987 $E1[[};]]
1989 enum class E2 {
1990 $E2[[};]]
1991 )cpp",
1992 ExpectedHint{" // struct S", "S"}, ExpectedHint{" // class C", "C"},
1993 ExpectedHint{" // union U", "U"}, ExpectedHint{" // enum E1", "E1"},
1994 ExpectedHint{" // enum class E2", "E2"});
1997 TEST(BlockEndHints, If) {
1998 assertBlockEndHints(
1999 R"cpp(
2000 void foo(bool cond) {
2001 if (cond)
2004 if (cond) {
2005 $simple[[}]]
2007 if (cond) {
2008 } else {
2009 $ifelse[[}]]
2011 if (cond) {
2012 } else if (!cond) {
2013 $elseif[[}]]
2015 if (cond) {
2016 } else {
2017 if (!cond) {
2018 $inner[[}]]
2019 $outer[[}]]
2021 if (auto X = cond) {
2022 $init[[}]]
2024 if (int i = 0; i > 10) {
2025 $init_cond[[}]]
2026 } // suppress
2027 )cpp",
2028 ExpectedHint{" // if cond", "simple"},
2029 ExpectedHint{" // if cond", "ifelse"}, ExpectedHint{" // if", "elseif"},
2030 ExpectedHint{" // if !cond", "inner"},
2031 ExpectedHint{" // if cond", "outer"}, ExpectedHint{" // if X", "init"},
2032 ExpectedHint{" // if i > 10", "init_cond"});
2035 TEST(BlockEndHints, Loops) {
2036 assertBlockEndHints(
2037 R"cpp(
2038 void foo() {
2039 while (true)
2042 while (true) {
2043 $while[[}]]
2045 do {
2046 } while (true);
2048 for (;true;) {
2049 $forcond[[}]]
2051 for (int I = 0; I < 10; ++I) {
2052 $forvar[[}]]
2054 int Vs[] = {1,2,3};
2055 for (auto V : Vs) {
2056 $foreach[[}]]
2057 } // suppress
2058 )cpp",
2059 ExpectedHint{" // while true", "while"},
2060 ExpectedHint{" // for true", "forcond"},
2061 ExpectedHint{" // for I", "forvar"},
2062 ExpectedHint{" // for V", "foreach"});
2065 TEST(BlockEndHints, Switch) {
2066 assertBlockEndHints(
2067 R"cpp(
2068 void foo(int I) {
2069 switch (I) {
2070 case 0: break;
2071 $switch[[}]]
2072 } // suppress
2073 )cpp",
2074 ExpectedHint{" // switch I", "switch"});
2077 TEST(BlockEndHints, PrintLiterals) {
2078 assertBlockEndHints(
2079 R"cpp(
2080 void foo() {
2081 while ("foo") {
2082 $string[[}]]
2084 while ("foo but this time it is very long") {
2085 $string_long[[}]]
2087 while (true) {
2088 $boolean[[}]]
2090 while (1) {
2091 $integer[[}]]
2093 while (1.5) {
2094 $float[[}]]
2095 } // suppress
2096 )cpp",
2097 ExpectedHint{" // while \"foo\"", "string"},
2098 ExpectedHint{" // while \"foo but...\"", "string_long"},
2099 ExpectedHint{" // while true", "boolean"},
2100 ExpectedHint{" // while 1", "integer"},
2101 ExpectedHint{" // while 1.5", "float"});
2104 TEST(BlockEndHints, PrintRefs) {
2105 assertBlockEndHints(
2106 R"cpp(
2107 namespace ns {
2108 int Var;
2109 int func();
2110 struct S {
2111 int Field;
2112 int method() const;
2113 }; // suppress
2114 } // suppress
2115 void foo() {
2116 while (ns::Var) {
2117 $var[[}]]
2119 while (ns::func()) {
2120 $func[[}]]
2122 while (ns::S{}.Field) {
2123 $field[[}]]
2125 while (ns::S{}.method()) {
2126 $method[[}]]
2127 } // suppress
2128 )cpp",
2129 ExpectedHint{" // while Var", "var"},
2130 ExpectedHint{" // while func", "func"},
2131 ExpectedHint{" // while Field", "field"},
2132 ExpectedHint{" // while method", "method"});
2135 TEST(BlockEndHints, PrintConversions) {
2136 assertBlockEndHints(
2137 R"cpp(
2138 struct S {
2139 S(int);
2140 S(int, int);
2141 explicit operator bool();
2142 }; // suppress
2143 void foo(int I) {
2144 while (float(I)) {
2145 $convert_primitive[[}]]
2147 while (S(I)) {
2148 $convert_class[[}]]
2150 while (S(I, I)) {
2151 $construct_class[[}]]
2152 } // suppress
2153 )cpp",
2154 ExpectedHint{" // while float", "convert_primitive"},
2155 ExpectedHint{" // while S", "convert_class"},
2156 ExpectedHint{" // while S", "construct_class"});
2159 TEST(BlockEndHints, PrintOperators) {
2160 std::string AnnotatedCode = R"cpp(
2161 void foo(Integer I) {
2162 while(++I){
2163 $preinc[[}]]
2165 while(I++){
2166 $postinc[[}]]
2168 while(+(I + I)){
2169 $unary_complex[[}]]
2171 while(I < 0){
2172 $compare[[}]]
2174 while((I + I) < I){
2175 $lhs_complex[[}]]
2177 while(I < (I + I)){
2178 $rhs_complex[[}]]
2180 while((I + I) < (I + I)){
2181 $binary_complex[[}]]
2182 } // suppress
2183 )cpp";
2185 // We can't store shared expectations in a vector, assertHints uses varargs.
2186 auto AssertExpectedHints = [&](llvm::StringRef Code) {
2187 assertBlockEndHints(Code, ExpectedHint{" // while ++I", "preinc"},
2188 ExpectedHint{" // while I++", "postinc"},
2189 ExpectedHint{" // while", "unary_complex"},
2190 ExpectedHint{" // while I < 0", "compare"},
2191 ExpectedHint{" // while ... < I", "lhs_complex"},
2192 ExpectedHint{" // while I < ...", "rhs_complex"},
2193 ExpectedHint{" // while", "binary_complex"});
2196 // First with built-in operators.
2197 AssertExpectedHints("using Integer = int;" + AnnotatedCode);
2198 // And now with overloading!
2199 AssertExpectedHints(R"cpp(
2200 struct Integer {
2201 explicit operator bool();
2202 Integer operator++();
2203 Integer operator++(int);
2204 Integer operator+(Integer);
2205 Integer operator+();
2206 bool operator<(Integer);
2207 bool operator<(int);
2208 }; // suppress
2209 )cpp" + AnnotatedCode);
2212 TEST(BlockEndHints, TrailingSemicolon) {
2213 assertBlockEndHints(R"cpp(
2214 // The hint is placed after the trailing ';'
2215 struct S1 {
2216 $S1[[} ;]]
2218 // The hint is always placed in the same line with the closing '}'.
2219 // So in this case where ';' is missing, it is attached to '}'.
2220 struct S2 {
2221 $S2[[}]]
2225 // No hint because only one trailing ';' is allowed
2226 struct S3 {
2229 // No hint because trailing ';' is only allowed for class/struct/union/enum
2230 void foo() {
2233 // Rare case, but yes we'll have a hint here.
2234 struct {
2235 int x;
2236 $anon[[}]]
2239 )cpp",
2240 ExpectedHint{" // struct S1", "S1"},
2241 ExpectedHint{" // struct S2", "S2"},
2242 ExpectedHint{" // struct", "anon"});
2245 TEST(BlockEndHints, TrailingText) {
2246 assertBlockEndHints(R"cpp(
2247 struct S1 {
2248 $S1[[} ;]]
2250 // No hint for S2 because of the trailing comment
2251 struct S2 {
2252 }; /* Put anything here */
2254 struct S3 {
2255 // No hint for S4 because of the trailing source code
2256 struct S4 {
2257 };$S3[[};]]
2259 // No hint for ns because of the trailing comment
2260 namespace ns {
2261 } // namespace ns
2262 )cpp",
2263 ExpectedHint{" // struct S1", "S1"},
2264 ExpectedHint{" // struct S3", "S3"});
2267 TEST(BlockEndHints, Macro) {
2268 assertBlockEndHints(R"cpp(
2269 #define DECL_STRUCT(NAME) struct NAME {
2270 #define RBRACE }
2272 DECL_STRUCT(S1)
2273 $S1[[};]]
2275 // No hint because we require a '}'
2276 DECL_STRUCT(S2)
2277 RBRACE;
2278 )cpp",
2279 ExpectedHint{" // struct S1", "S1"});
2282 TEST(BlockEndHints, PointerToMemberFunction) {
2283 // Do not crash trying to summarize `a->*p`.
2284 assertBlockEndHints(R"cpp(
2285 class A {};
2286 using Predicate = bool(A::*)();
2287 void foo(A* a, Predicate p) {
2288 if ((a->*p)()) {
2289 $ptrmem[[}]]
2290 } // suppress
2291 )cpp",
2292 ExpectedHint{" // if", "ptrmem"});
2295 // FIXME: Low-hanging fruit where we could omit a type hint:
2296 // - auto x = TypeName(...);
2297 // - auto x = (TypeName) (...);
2298 // - auto x = static_cast<TypeName>(...); // and other built-in casts
2300 // Annoyances for which a heuristic is not obvious:
2301 // - auto x = llvm::dyn_cast<LongTypeName>(y); // and similar
2302 // - stdlib algos return unwieldy __normal_iterator<X*, ...> type
2303 // (For this one, perhaps we should omit type hints that start
2304 // with a double underscore.)
2306 } // namespace
2307 } // namespace clangd
2308 } // namespace clang