1 //===-- InlayHintTests.cpp -------------------------------*- C++ -*-------===//
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
7 //===----------------------------------------------------------------------===//
8 #include "Annotations.h"
10 #include "InlayHints.h"
13 #include "TestWorkspace.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"
29 llvm::raw_ostream
&operator<<(llvm::raw_ostream
&Stream
,
30 const InlayHint
&Hint
) {
31 return Stream
<< Hint
.joinLabels() << "@" << Hint
.range
;
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
);
48 enum HintSide
{ Left
, Right
};
52 std::string RangeName
;
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
<< "'";
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
));
79 MATCHER_P(labelIs
, Label
, "") { return arg
.joinLabels() == Label
; }
81 Config
noHintsConfig() {
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;
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
) {
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
) {
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(
158 ExpectedHint
{"param: ", "param"});
161 TEST(ParameterHints
, NoName
) {
162 // No hint for anonymous parameter.
163 assertParameterHints(R
"cpp(
171 TEST(ParameterHints
, NoNameConstReference
) {
172 // No hint for anonymous const l-value ref parameter.
173 assertParameterHints(R
"cpp(
174 void foo(const int&);
181 TEST(ParameterHints
, NoNameReference
) {
182 // Reference hint for anonymous l-value ref parameter.
183 assertParameterHints(R
"cpp(
190 ExpectedHint
{"&: ", "param"});
193 TEST(ParameterHints
, NoNameRValueReference
) {
194 // No reference hint for anonymous r-value ref parameter.
195 assertParameterHints(R
"cpp(
203 TEST(ParameterHints
, NoNameVariadicDeclaration
) {
204 // No hint for anonymous variadic parameter
205 assertParameterHints(R
"cpp(
206 template <typename... Args>
207 void foo(Args&& ...);
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&); }
220 template <typename... Args>
221 void bar(Args&&... args) { return foo(std::forward<Args>(args)...); }
228 TEST(ParameterHints
, NoNameVariadicPlain
) {
229 // No hint for anonymous variadic parameter
230 assertParameterHints(R
"cpp(
232 template <typename... Args>
233 void bar(Args&&... args) { return foo(args...); }
240 TEST(ParameterHints
, NameInDefinition
) {
241 // Parameter name picked up from definition if necessary.
242 assertParameterHints(R
"cpp(
247 void foo(int param) {};
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);
257 foo($param1[[42]], $param2[[42]]);
259 void foo(int a, int) {};
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(
269 template <typename... Args>
270 void bar(Args... args) {
274 bar($param1[[42]], $param2[[42]]);
276 void foo(int a, int b) {};
278 ExpectedHint
{"a: ", "param1"},
279 ExpectedHint
{"b: ", "param2"});
282 TEST(ParameterHints
, NameMismatch
) {
283 // Prefer name from declaration.
284 assertParameterHints(R
"cpp(
289 void foo(int bad) {};
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);
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);
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);
327 ExpectedHint
{"¶m: ", "param"});
330 TEST(ParameterHints
, NameTypeAliasReference
) {
331 // Reference and name hint for l-value ref parameter via type alias.
332 assertParameterHints(R
"cpp(
334 void foo(alias param);
340 ExpectedHint
{"¶m: ", "param"});
343 TEST(ParameterHints
, NameRValueReference
) {
344 // Only name hint for r-value ref parameter.
345 assertParameterHints(R
"cpp(
346 void foo(int&& param);
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)...}; }
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...}; }
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)...}; }
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...}; }
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&); }
420 template <typename... Args>
421 void bar(Args&&... args) { return foo(std::forward<Args>(args)...); }
427 ExpectedHint
{"a: ", "param"});
430 TEST(ParameterHints
, VariadicPlain
) {
431 // Name hint for variadic parameter
432 assertParameterHints(R
"cpp(
434 template <typename... Args>
435 void bar(Args&&... args) { return foo(args...); }
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(
448 template <typename... Args, typename Arg>
449 void bar(Arg, Args&&... args) { return foo(args...); }
451 bar(1, $param[[42]]);
454 ExpectedHint
{"a: ", "param"});
457 TEST(ParameterHints
, VariadicSplitTwolevel
) {
458 // Name for variadic parameter that involves both head and tail parameters to
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)...); }
471 bar($param1[[32]], $param2[[42]]);
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
481 assertParameterHints(R
"cpp(
483 template <typename... Args>
484 void bar(Args... args) {
488 void bar<int>(int b);
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(
501 template <typename... Args>
502 void foo(Args... args) {
505 template <typename... Args>
506 void bar(Args... args) {
510 void foo<int>(int b);
515 ExpectedHint
{"b: ", "param"});
518 TEST(ParameterHints
, VariadicOverloaded
) {
519 // Name for variadic parameter for an overloaded function with unique number
521 // This prototype of std::forward is sufficient for clang to recognize it
522 assertParameterHints(
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)...); }
534 bar($param1[[32]], $param2[[42]], $param3[[52]]);
535 bar($param4[[1]], $param5[[2]], $param6[[3]], $param7[[4]]);
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(
550 template <typename Head, typename... Tail>
551 void foo(Head head, Tail... tail) {
555 template <typename... Args>
556 void bar(Args... args) {
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) {
576 bar($fixed[[41]], 42, 43);
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) {
592 bar($fixed[[41]], 42, 43);
595 ExpectedHint
{"fixed: ", "fixed"});
598 TEST(ParameterHints
, VariadicTwoCalls
) {
599 // only the first call using the parameter pack should be picked up
600 assertParameterHints(
602 void f1(int a, int b);
603 void f2(int c, int d);
607 template <typename... Args>
608 void foo(Args... args) {
617 foo($param1[[1]], $param2[[2]]);
620 ExpectedHint
{"a: ", "param1"}, ExpectedHint
{"b: ", "param2"});
623 TEST(ParameterHints
, VariadicInfinite
) {
624 // infinite recursion should not break clangd
625 assertParameterHints(
627 template <typename... Args>
630 template <typename... Args>
631 void bar(Args... args) {
635 template <typename... Args>
636 void foo(Args... args) {
646 TEST(ParameterHints
, VariadicDuplicatePack
) {
647 // edge cases with multiple adjacent packs should work
648 assertParameterHints(
650 void foo(int a, int b, int c, int);
652 template <typename... Args>
653 void bar(int, Args... args, int d) {
657 template <typename... Args>
658 void baz(Args... args, Args... args2) {
659 bar<Args..., int>(1, args..., args2...);
663 baz<int, int>($p1[[1]], $p2[[2]], $p3[[3]], $p4[[4]]);
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(
675 namespace std { template <typename T> T&& forward(T&); }
676 using size_t = decltype(sizeof(0));
677 void *operator new(size_t, void *);
683 template <typename T>
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>
692 template <typename... Args>
693 void emplace(Args&&... args) {
695 auto ptr = a.template allocate<T>();
696 a.construct(ptr, std::forward<Args>(args)...);
701 c.emplace($param1[[1]]);
702 c.emplace($param2[[2]], $param3[[3]]);
705 ExpectedHint
{"A: ", "param1"}, ExpectedHint
{"B: ", "param2"},
706 ExpectedHint
{"C: ", "param3"});
709 TEST(ParameterHints
, VariadicReferenceHint
) {
710 assertParameterHints(R
"cpp(
712 template <typename... Args>
713 void bar(Args... args) { return foo(args...); }
722 TEST(ParameterHints
, VariadicReferenceHintForwardingRef
) {
723 assertParameterHints(R
"cpp(
725 template <typename... Args>
726 void bar(Args&&... args) { return foo(args...); }
733 ExpectedHint
{"&: ", "param"});
736 TEST(ParameterHints
, VariadicReferenceHintForwardingRefStdForward
) {
737 assertParameterHints(R
"cpp(
738 namespace std { template <typename T> T&& forward(T&); }
740 template <typename... Args>
741 void bar(Args&&... args) { return foo(std::forward<Args>(args)...); }
747 ExpectedHint
{"&: ", "param"});
750 TEST(ParameterHints
, VariadicNoReferenceHintForwardingRefStdForward
) {
751 assertParameterHints(R
"cpp(
752 namespace std { template <typename T> T&& forward(T&); }
754 template <typename... Args>
755 void bar(Args&&... args) { return foo(std::forward<Args>(args)...); }
764 TEST(ParameterHints
, VariadicNoReferenceHintUnresolvedForward
) {
765 assertParameterHints(R
"cpp(
766 template <typename... Args>
767 void foo(Args&&... args);
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&); }
781 template <typename... Args>
782 void bar(Args&&... args) { return foo(std::forward<Args>(args)...); }
790 TEST(ParameterHints
, MatchingNameVariadicPlain
) {
791 // No name hint for variadic parameter with matching name
792 assertParameterHints(R
"cpp(
794 template <typename... Args>
795 void bar(Args&&... args) { return foo(args...); }
803 TEST(ParameterHints
, Operator
) {
804 // No hint for operator call with operator syntax.
805 assertParameterHints(R
"cpp(
807 void operator+(S lhs, S rhs);
815 TEST(ParameterHints
, FunctionCallOperator
) {
816 assertParameterHints(R
"cpp(
818 void operator()(int x);
822 static void operator()(int x, int y);
825 auto l1 = [](int x) {};
826 auto l2 = [](int x) static {};
830 s.operator()($2[[1]]);
831 s.operator()($3[[1]], $4[[2]]);
832 S::operator()($5[[1]], $6[[2]]);
835 l1.operator()($8[[1]]);
837 l2.operator()($10[[1]]);
839 void (*ptr)(int a, int b) = &S::operator();
840 ptr($11[[1]], $12[[2]]);
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(
854 template <typename This>
855 auto operator()(this This &&Self, int Param) {
859 auto function(this auto &Self, int Param) {
866 s.function($2[[42]]);
868 auto lambda = [](this auto &Self, char C) -> void {
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(
886 #define ExpandsToCall() foo(42)
892 // The argument expression being a macro invocation shouldn't interfere
894 assertParameterHints(R
"cpp(
896 void foo(double param);
901 ExpectedHint
{"param: ", "param"});
903 // If the whole argument list comes from a macro parameter, hint it.
904 assertParameterHints(R
"cpp(
906 #define ASSERT(expr) if (!expr) abort()
909 ASSERT(foo($param[[42]]) == 0);
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
924 TEST(ParameterHints
, ConstructorParens
) {
925 assertParameterHints(R
"cpp(
933 ExpectedHint
{"param: ", "param"});
936 TEST(ParameterHints
, ConstructorBraces
) {
937 assertParameterHints(R
"cpp(
945 ExpectedHint
{"param: ", "param"});
948 TEST(ParameterHints
, ConstructorStdInitList
) {
949 // Do not show hints for std::initializer_list constructors.
950 assertParameterHints(R
"cpp(
952 template <typename E> class initializer_list { const E *a, *b; };
955 S(std::initializer_list<int> param);
963 TEST(ParameterHints
, MemberInit
) {
964 assertParameterHints(R
"cpp(
970 T() : member($param[[42]]) {}
973 ExpectedHint
{"param: ", "param"});
976 TEST(ParameterHints
, ImplicitConstructor
) {
977 assertParameterHints(R
"cpp(
983 // Do not show hint for implicit constructor call in argument.
985 // Do not show hint for implicit constructor call in return.
991 TEST(ParameterHints
, FunctionPointer
) {
992 assertParameterHints(
994 void (*f1)(int param);
995 void (__stdcall *f2)(int param);
996 using f3_t = void(*)(int param);
998 using f4_t = void(__stdcall *)(int param);
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);
1015 static const int param = 42;
1019 // Do not show redundant "param
: param
".
1021 // But show it if the argument is qualified.
1022 foo($param[[S::param]]);
1027 // Do not show "param
: param
" for member-expr.
1032 ExpectedHint
{"param: ", "param"});
1035 TEST(ParameterHints
, ArgMatchesParamReference
) {
1036 assertParameterHints(R
"cpp(
1037 void foo(int& param);
1038 void foo2(const int& param);
1041 // show reference hint on mutable reference
1042 foo($param[[param]]);
1043 // but not on const reference
1047 ExpectedHint
{"&: ", "param"});
1050 TEST(ParameterHints
, LeadingUnderscore
) {
1051 assertParameterHints(R
"cpp(
1052 void foo(int p1, int _p2, int __p3);
1054 foo($p1[[41]], $p2[[42]], $p3[[43]]);
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>
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>
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.
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);
1098 foo($fixed[[41]], 42, 43);
1101 ExpectedHint
{"fixed: ", "fixed"});
1104 TEST(ParameterHints
, VarargsFunction
) {
1105 assertParameterHints(R
"cpp(
1106 void foo(int fixed, ...);
1109 foo($fixed[[41]], 42, 43);
1112 ExpectedHint
{"fixed: ", "fixed"});
1115 TEST(ParameterHints
, CopyOrMoveConstructor
) {
1116 // Do not show hint for parameter of copy or move constructor.
1117 assertParameterHints(R
"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(
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);
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);
1162 foo( /* param = */ 42);
1166 foo(/*param=*/Z(a));
1167 foo($macro[[Z(a)]]);
1168 foo(/* the answer */$param[[42]]);
1171 ExpectedHint
{"param: ", "macro"},
1172 ExpectedHint
{"param: ", "param"});
1175 TEST(ParameterHints
, SetterFunctions
) {
1176 assertParameterHints(R
"cpp(
1178 void setParent(S* parent);
1179 void set_parent(S* parent);
1180 void setTimeout(int timeoutMillis);
1181 void setTimeoutMillis(int timeout_millis);
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]]);
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&); }
1210 TEST(ParameterHints
, IncludeAtNonGlobalScope
) {
1211 Annotations
FooInc(R
"cpp(
1212 void bar() { foo(42); }
1214 Annotations
FooCC(R
"cpp(
1216 void foo(int param);
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;
1236 ExpectedHint
{": int", "waldo"});
1239 TEST(TypeHints
, Decorations
) {
1240 assertTypeHints(R
"cpp(
1242 auto* $var1[[var1]] = &x;
1243 auto&& $var2[[var2]] = x;
1244 const auto& $var3[[var3]] = x;
1246 ExpectedHint
{": int *", "var1"},
1247 ExpectedHint
{": int &", "var2"},
1248 ExpectedHint
{": const int &", "var3"});
1251 TEST(TypeHints
, DecltypeAuto
) {
1252 assertTypeHints(R
"cpp(
1255 decltype(auto) $z[[z]] = y;
1257 ExpectedHint
{": int &", "z"});
1260 TEST(TypeHints
, NoQualifiers
) {
1261 assertTypeHints(R
"cpp(
1266 auto $x[[x]] = foo();
1269 template <typename T>
1272 S2::Inner<int> bar();
1273 auto $y[[y]] = bar();
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(
1293 auto $L[[L]] = [cap, $init[[init]] = 1 + 1](int a$ret[[)]] {
1294 return a + cap + init;
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.
1319 auto [$x[[x]], $y[[y]]] = foo();
1321 ExpectedHint
{": int", "x"}, ExpectedHint
{": int", "y"});
1324 TEST(TypeHints
, StructuredBindings_Array
) {
1325 assertTypeHints(R
"cpp(
1327 auto [$x[[x]], $y[[y]]] = arr;
1329 ExpectedHint
{": int", "x"}, ExpectedHint
{": int", "y"});
1332 TEST(TypeHints
, StructuredBindings_TupleLike
) {
1333 assertTypeHints(R
"cpp(
1340 template <typename T>
1341 struct tuple_size {};
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> {
1353 template <unsigned I>
1354 int get(const IntPair& p) {
1355 if constexpr (I == 0) {
1357 } else if constexpr (I == 1) {
1362 auto [$x[[x]], $y[[y]]] = bar();
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*/
1375 TEST(TypeHints
, InvalidType
) {
1376 assertTypeHints(R
"cpp(
1377 auto x = (unknown_type)42; /*error-ok*/
1378 auto *y = (unknown_ptr)nullptr;
1382 TEST(TypeHints
, ReturnTypeDeduction
) {
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
1390 auto& f2($ret2[[)]] { return s; }
1392 // Do not hint `auto` for trailing return type.
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
1402 operator auto($retConv[[)]] { return 42; }
1405 // FIXME: Dependent types do not work yet.
1406 template <typename T>
1408 auto method() { return T(); }
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>
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>
1433 TEST(TypeHints
, LongTypeName
) {
1434 assertTypeHints(R
"cpp(
1435 template <typename, typename, typename>
1437 struct MultipleWords {};
1438 A<MultipleWords, MultipleWords, MultipleWords> foo();
1439 // Omit type hint past a certain length (currently 32)
1444 Cfg
.InlayHints
.TypeNameLimit
= 0;
1445 WithContextValue
WithCfg(Config::Key
, std::move(Cfg
));
1449 template <typename, typename, typename>
1451 struct MultipleWords {};
1452 A<MultipleWords, MultipleWords, MultipleWords> foo();
1453 // Should have type hint with TypeNameLimit = 0
1454 auto $var[[var]] = foo();
1456 ExpectedHint
{": A<MultipleWords, MultipleWords, MultipleWords>", "var"});
1459 TEST(TypeHints
, DefaultTemplateArgs
) {
1460 assertTypeHints(R
"cpp(
1461 template <typename, typename = int>
1464 auto $var[[var]] = foo();
1466 auto [$binding[[value]]] = bar;
1468 ExpectedHint
{": A<float>", "var"},
1469 ExpectedHint
{": A<float>", "binding"});
1472 TEST(DefaultArguments
, Smoke
) {
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[[)]]; };
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
) {
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(
1516 Foo(int, Baz baz = //
1517 Baz{$abbreviated[[}]]
1524 Foo foo1(1$paren[[)]];
1525 Foo foo2{2$brace1[[}]];
1526 Foo foo3 = {3$brace2[[}]];
1527 auto foo4 = Foo{4$brace3[[}]];
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>
1545 auto $var[[var]] = 42;
1547 template void foo<int>();
1548 template void foo<float>();
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);
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);
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
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)]]{};
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 {
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(); }
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();
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(
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();
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>();
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]]};
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]] };
1730 ExpectedHint
{".a=", "a"}, ExpectedHint
{".x=", "x"},
1731 ExpectedHint
{".y=", "y"}, ExpectedHint
{".b.x=", "bx"});
1734 TEST(DesignatorHints
, AnonymousRecord
) {
1735 assertDesignatorHints(R
"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]]};
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]]};
1765 ExpectedHint
{"[0]=", "0"}, ExpectedHint
{"[1]=", "1"});
1768 TEST(DesignatorHints
, OnlyAggregateInit
) {
1769 assertDesignatorHints(R
"cpp(
1770 struct Copyable { int x; } 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(
1782 struct Foo {int a; int b;};
1784 Foo f{A(), $b[[1]]};
1787 ExpectedHint
{".b=", "b"});
1790 TEST(InlayHints
, RestrictRange
) {
1791 Annotations
Code(R
"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(
1805 __declspec(property(get=GetX, put=PutX)) int x[];
1806 int GetX(int y, int z) { return 42 + y; }
1809 // This is a PseudoObjectExpression whose syntactic form is a binary
1811 void Work(int y) { x = y; } // Not `x = y: y`.
1814 int printf(const char *Format, ...);
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]`
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(
1837 struct Foo{ Foo(); Foo(int x); };
1838 void foo(Foo a, int b);
1839 template <typename... Args>
1840 void bar(Args... 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...); }
1850 bar($param4[[Foo{}]], $param5[[42]]);
1851 bar($param6[[42]], $param7[[42]]);
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(
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]])...);
1873 bar(1, 2); // FIXME: We could have `bar(a: 1, a: 2)` here.
1876 ExpectedHint
{"a: ", "param1"}, ExpectedHint
{"b: ", "param2"},
1877 ExpectedHint
{"c: ", "param3"});
1880 TEST(BlockEndHints
, Functions
) {
1881 assertBlockEndHints(R
"cpp(
1888 // No hint for lambda for now
1895 // No hint because this isn't a definition
1899 bool operator==(S, S) {
1903 ExpectedHint
{" // foo", "foo"},
1904 ExpectedHint
{" // bar", "bar"},
1905 ExpectedHint
{" // operator==", "opEqual"});
1908 TEST(BlockEndHints
, Methods
) {
1909 assertBlockEndHints(R
"cpp(
1911 // No hint because there's no function body
1920 // No hint because this isn't a definition
1923 template <typename T>
1927 // No hint because this isn't a definition
1928 template <typename T>
1931 Test operator+(int) const {
1935 operator bool() const {
1939 // No hint because there's no function body
1940 operator int() const = delete;
1943 void Test::method2() {
1946 template <typename T>
1947 void Test::method4() {
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(
1970 ExpectedHint
{" // namespace", "anon"},
1971 ExpectedHint
{" // namespace ns", "ns"});
1974 TEST(BlockEndHints
, Types
) {
1975 assertBlockEndHints(
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(
2000 void foo(bool cond) {
2021 if (auto X = cond) {
2024 if (int i = 0; i > 10) {
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(
2051 for (int I = 0; I < 10; ++I) {
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(
2074 ExpectedHint
{" // switch I", "switch"});
2077 TEST(BlockEndHints
, PrintLiterals
) {
2078 assertBlockEndHints(
2084 while ("foo but
this time it is very
long") {
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(
2119 while (ns::func()) {
2122 while (ns::S{}.Field) {
2125 while (ns::S{}.method()) {
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(
2141 explicit operator bool();
2145 $convert_primitive[[}]]
2151 $construct_class[[}]]
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) {
2180 while((I + I) < (I + I)){
2181 $binary_complex[[}]]
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(
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);
2209 )cpp" + AnnotatedCode
);
2212 TEST(BlockEndHints
, TrailingSemicolon
) {
2213 assertBlockEndHints(R
"cpp(
2214 // The hint is placed after the trailing ';'
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 '}'.
2225 // No hint because only one trailing ';' is allowed
2229 // No hint because trailing ';' is only allowed for class/struct/union/enum
2233 // Rare case, but yes we'll have a hint here.
2240 ExpectedHint
{" // struct S1", "S1"},
2241 ExpectedHint
{" // struct S2", "S2"},
2242 ExpectedHint
{" // struct", "anon"});
2245 TEST(BlockEndHints
, TrailingText
) {
2246 assertBlockEndHints(R
"cpp(
2250 // No hint for S2 because of the trailing comment
2252 }; /* Put anything here */
2255 // No hint for S4 because of the trailing source code
2259 // No hint for ns because of the trailing comment
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 {
2275 // No hint because we require a '}'
2279 ExpectedHint
{" // struct S1", "S1"});
2282 TEST(BlockEndHints
, PointerToMemberFunction
) {
2283 // Do not crash trying to summarize `a->*p`.
2284 assertBlockEndHints(R
"cpp(
2286 using Predicate = bool(A::*)();
2287 void foo(A* a, Predicate p) {
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.)
2307 } // namespace clangd
2308 } // namespace clang