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 "gmock/gmock.h"
19 #include "gtest/gtest.h"
26 llvm::raw_ostream
&operator<<(llvm::raw_ostream
&Stream
,
27 const InlayHint
&Hint
) {
28 return Stream
<< Hint
.joinLabels() << "@" << Hint
.range
;
33 using ::testing::ElementsAre
;
34 using ::testing::IsEmpty
;
36 std::vector
<InlayHint
> hintsOfKind(ParsedAST
&AST
, InlayHintKind Kind
) {
37 std::vector
<InlayHint
> Result
;
38 for (auto &Hint
: inlayHints(AST
, /*RestrictRange=*/std::nullopt
)) {
39 if (Hint
.kind
== Kind
)
40 Result
.push_back(Hint
);
45 enum HintSide
{ Left
, Right
};
49 std::string RangeName
;
52 friend llvm::raw_ostream
&operator<<(llvm::raw_ostream
&Stream
,
53 const ExpectedHint
&Hint
) {
54 return Stream
<< Hint
.Label
<< "@$" << Hint
.RangeName
;
58 MATCHER_P2(HintMatcher
, Expected
, Code
, llvm::to_string(Expected
)) {
59 llvm::StringRef
ExpectedView(Expected
.Label
);
60 std::string ResultLabel
= arg
.joinLabels();
61 if (ResultLabel
!= ExpectedView
.trim(" ") ||
62 arg
.paddingLeft
!= ExpectedView
.starts_with(" ") ||
63 arg
.paddingRight
!= ExpectedView
.ends_with(" ")) {
64 *result_listener
<< "label is '" << ResultLabel
<< "'";
67 if (arg
.range
!= Code
.range(Expected
.RangeName
)) {
68 *result_listener
<< "range is " << llvm::to_string(arg
.range
) << " but $"
69 << Expected
.RangeName
<< " is "
70 << llvm::to_string(Code
.range(Expected
.RangeName
));
76 MATCHER_P(labelIs
, Label
, "") { return arg
.joinLabels() == Label
; }
78 Config
noHintsConfig() {
80 C
.InlayHints
.Parameters
= false;
81 C
.InlayHints
.DeducedTypes
= false;
82 C
.InlayHints
.Designators
= false;
83 C
.InlayHints
.BlockEnd
= false;
87 template <typename
... ExpectedHints
>
88 void assertHintsWithHeader(InlayHintKind Kind
, llvm::StringRef AnnotatedSource
,
89 llvm::StringRef HeaderContent
,
90 ExpectedHints
... Expected
) {
91 Annotations
Source(AnnotatedSource
);
92 TestTU TU
= TestTU::withCode(Source
.code());
93 TU
.ExtraArgs
.push_back("-std=c++23");
94 TU
.HeaderCode
= HeaderContent
;
95 auto AST
= TU
.build();
97 EXPECT_THAT(hintsOfKind(AST
, Kind
),
98 ElementsAre(HintMatcher(Expected
, Source
)...));
99 // Sneak in a cross-cutting check that hints are disabled by config.
100 // We'll hit an assertion failure if addInlayHint still gets called.
101 WithContextValue
WithCfg(Config::Key
, noHintsConfig());
102 EXPECT_THAT(inlayHints(AST
, std::nullopt
), IsEmpty());
105 template <typename
... ExpectedHints
>
106 void assertHints(InlayHintKind Kind
, llvm::StringRef AnnotatedSource
,
107 ExpectedHints
... Expected
) {
108 return assertHintsWithHeader(Kind
, AnnotatedSource
, "",
109 std::move(Expected
)...);
112 // Hack to allow expression-statements operating on parameter packs in C++14.
113 template <typename
... T
> void ignore(T
&&...) {}
115 template <typename
... ExpectedHints
>
116 void assertParameterHints(llvm::StringRef AnnotatedSource
,
117 ExpectedHints
... Expected
) {
118 ignore(Expected
.Side
= Left
...);
119 assertHints(InlayHintKind::Parameter
, AnnotatedSource
, Expected
...);
122 template <typename
... ExpectedHints
>
123 void assertTypeHints(llvm::StringRef AnnotatedSource
,
124 ExpectedHints
... Expected
) {
125 ignore(Expected
.Side
= Right
...);
126 assertHints(InlayHintKind::Type
, AnnotatedSource
, Expected
...);
129 template <typename
... ExpectedHints
>
130 void assertDesignatorHints(llvm::StringRef AnnotatedSource
,
131 ExpectedHints
... Expected
) {
133 Cfg
.InlayHints
.Designators
= true;
134 WithContextValue
WithCfg(Config::Key
, std::move(Cfg
));
135 assertHints(InlayHintKind::Designator
, AnnotatedSource
, Expected
...);
138 template <typename
... ExpectedHints
>
139 void assertBlockEndHints(llvm::StringRef AnnotatedSource
,
140 ExpectedHints
... Expected
) {
142 Cfg
.InlayHints
.BlockEnd
= true;
143 WithContextValue
WithCfg(Config::Key
, std::move(Cfg
));
144 assertHints(InlayHintKind::BlockEnd
, AnnotatedSource
, Expected
...);
147 TEST(ParameterHints
, Smoke
) {
148 assertParameterHints(R
"cpp(
154 ExpectedHint
{"param: ", "param"});
157 TEST(ParameterHints
, NoName
) {
158 // No hint for anonymous parameter.
159 assertParameterHints(R
"cpp(
167 TEST(ParameterHints
, NoNameConstReference
) {
168 // No hint for anonymous const l-value ref parameter.
169 assertParameterHints(R
"cpp(
170 void foo(const int&);
177 TEST(ParameterHints
, NoNameReference
) {
178 // Reference hint for anonymous l-value ref parameter.
179 assertParameterHints(R
"cpp(
186 ExpectedHint
{"&: ", "param"});
189 TEST(ParameterHints
, NoNameRValueReference
) {
190 // No reference hint for anonymous r-value ref parameter.
191 assertParameterHints(R
"cpp(
199 TEST(ParameterHints
, NoNameVariadicDeclaration
) {
200 // No hint for anonymous variadic parameter
201 assertParameterHints(R
"cpp(
202 template <typename... Args>
203 void foo(Args&& ...);
210 TEST(ParameterHints
, NoNameVariadicForwarded
) {
211 // No hint for anonymous variadic parameter
212 // This prototype of std::forward is sufficient for clang to recognize it
213 assertParameterHints(R
"cpp(
214 namespace std { template <typename T> T&& forward(T&); }
216 template <typename... Args>
217 void bar(Args&&... args) { return foo(std::forward<Args>(args)...); }
224 TEST(ParameterHints
, NoNameVariadicPlain
) {
225 // No hint for anonymous variadic parameter
226 assertParameterHints(R
"cpp(
228 template <typename... Args>
229 void bar(Args&&... args) { return foo(args...); }
236 TEST(ParameterHints
, NameInDefinition
) {
237 // Parameter name picked up from definition if necessary.
238 assertParameterHints(R
"cpp(
243 void foo(int param) {};
245 ExpectedHint
{"param: ", "param"});
248 TEST(ParameterHints
, NamePartiallyInDefinition
) {
249 // Parameter name picked up from definition if necessary.
250 assertParameterHints(R
"cpp(
251 void foo(int, int b);
253 foo($param1[[42]], $param2[[42]]);
255 void foo(int a, int) {};
257 ExpectedHint
{"a: ", "param1"},
258 ExpectedHint
{"b: ", "param2"});
261 TEST(ParameterHints
, NameInDefinitionVariadic
) {
262 // Parameter name picked up from definition in a resolved forwarded parameter.
263 assertParameterHints(R
"cpp(
265 template <typename... Args>
266 void bar(Args... args) {
270 bar($param1[[42]], $param2[[42]]);
272 void foo(int a, int b) {};
274 ExpectedHint
{"a: ", "param1"},
275 ExpectedHint
{"b: ", "param2"});
278 TEST(ParameterHints
, NameMismatch
) {
279 // Prefer name from declaration.
280 assertParameterHints(R
"cpp(
285 void foo(int bad) {};
287 ExpectedHint
{"good: ", "good"});
290 TEST(ParameterHints
, NameConstReference
) {
291 // Only name hint for const l-value ref parameter.
292 assertParameterHints(R
"cpp(
293 void foo(const int& param);
298 ExpectedHint
{"param: ", "param"});
301 TEST(ParameterHints
, NameTypeAliasConstReference
) {
302 // Only name hint for const l-value ref parameter via type alias.
303 assertParameterHints(R
"cpp(
304 using alias = const int&;
305 void foo(alias param);
311 ExpectedHint
{"param: ", "param"});
314 TEST(ParameterHints
, NameReference
) {
315 // Reference and name hint for l-value ref parameter.
316 assertParameterHints(R
"cpp(
317 void foo(int& param);
323 ExpectedHint
{"¶m: ", "param"});
326 TEST(ParameterHints
, NameTypeAliasReference
) {
327 // Reference and name hint for l-value ref parameter via type alias.
328 assertParameterHints(R
"cpp(
330 void foo(alias param);
336 ExpectedHint
{"¶m: ", "param"});
339 TEST(ParameterHints
, NameRValueReference
) {
340 // Only name hint for r-value ref parameter.
341 assertParameterHints(R
"cpp(
342 void foo(int&& param);
347 ExpectedHint
{"param: ", "param"});
350 TEST(ParameterHints
, VariadicForwardedConstructor
) {
351 // Name hint for variadic parameter using std::forward in a constructor call
352 // This prototype of std::forward is sufficient for clang to recognize it
353 assertParameterHints(R
"cpp(
354 namespace std { template <typename T> T&& forward(T&); }
355 struct S { S(int a); };
356 template <typename T, typename... Args>
357 T bar(Args&&... args) { return T{std::forward<Args>(args)...}; }
363 ExpectedHint
{"a: ", "param"});
366 TEST(ParameterHints
, VariadicPlainConstructor
) {
367 // Name hint for variadic parameter in a constructor call
368 assertParameterHints(R
"cpp(
369 struct S { S(int a); };
370 template <typename T, typename... Args>
371 T bar(Args&&... args) { return T{args...}; }
377 ExpectedHint
{"a: ", "param"});
380 TEST(ParameterHints
, VariadicForwardedNewConstructor
) {
381 // Name hint for variadic parameter using std::forward in a new expression
382 // This prototype of std::forward is sufficient for clang to recognize it
383 assertParameterHints(R
"cpp(
384 namespace std { template <typename T> T&& forward(T&); }
385 struct S { S(int a); };
386 template <typename T, typename... Args>
387 T* bar(Args&&... args) { return new T{std::forward<Args>(args)...}; }
393 ExpectedHint
{"a: ", "param"});
396 TEST(ParameterHints
, VariadicPlainNewConstructor
) {
397 // Name hint for variadic parameter in a new expression
398 assertParameterHints(R
"cpp(
399 struct S { S(int a); };
400 template <typename T, typename... Args>
401 T* bar(Args&&... args) { return new T{args...}; }
407 ExpectedHint
{"a: ", "param"});
410 TEST(ParameterHints
, VariadicForwarded
) {
411 // Name for variadic parameter using std::forward
412 // This prototype of std::forward is sufficient for clang to recognize it
413 assertParameterHints(R
"cpp(
414 namespace std { template <typename T> T&& forward(T&); }
416 template <typename... Args>
417 void bar(Args&&... args) { return foo(std::forward<Args>(args)...); }
423 ExpectedHint
{"a: ", "param"});
426 TEST(ParameterHints
, VariadicPlain
) {
427 // Name hint for variadic parameter
428 assertParameterHints(R
"cpp(
430 template <typename... Args>
431 void bar(Args&&... args) { return foo(args...); }
436 ExpectedHint
{"a: ", "param"});
439 TEST(ParameterHints
, VariadicPlainWithPackFirst
) {
440 // Name hint for variadic parameter when the parameter pack is not the last
441 // template parameter
442 assertParameterHints(R
"cpp(
444 template <typename... Args, typename Arg>
445 void bar(Arg, Args&&... args) { return foo(args...); }
447 bar(1, $param[[42]]);
450 ExpectedHint
{"a: ", "param"});
453 TEST(ParameterHints
, VariadicSplitTwolevel
) {
454 // Name for variadic parameter that involves both head and tail parameters to
456 // This prototype of std::forward is sufficient for clang to recognize it
457 assertParameterHints(R
"cpp(
458 namespace std { template <typename T> T&& forward(T&); }
459 void baz(int, int b, double);
460 template <typename... Args>
461 void foo(int a, Args&&... args) {
462 return baz(1, std::forward<Args>(args)..., 1.0);
464 template <typename... Args>
465 void bar(Args&&... args) { return foo(std::forward<Args>(args)...); }
467 bar($param1[[32]], $param2[[42]]);
470 ExpectedHint
{"a: ", "param1"},
471 ExpectedHint
{"b: ", "param2"});
474 TEST(ParameterHints
, VariadicNameFromSpecialization
) {
475 // We don't try to resolve forwarding parameters if the function call uses a
477 assertParameterHints(R
"cpp(
479 template <typename... Args>
480 void bar(Args... args) {
484 void bar<int>(int b);
489 ExpectedHint
{"b: ", "param"});
492 TEST(ParameterHints
, VariadicNameFromSpecializationRecursive
) {
493 // We don't try to resolve forwarding parameters inside a forwarding function
494 // call if that function call uses a specialization.
495 assertParameterHints(R
"cpp(
497 template <typename... Args>
498 void foo(Args... args) {
501 template <typename... Args>
502 void bar(Args... args) {
506 void foo<int>(int b);
511 ExpectedHint
{"b: ", "param"});
514 TEST(ParameterHints
, VariadicOverloaded
) {
515 // Name for variadic parameter for an overloaded function with unique number
517 // This prototype of std::forward is sufficient for clang to recognize it
518 assertParameterHints(
520 namespace std { template <typename T> T&& forward(T&); }
521 void baz(int b, int c);
522 void baz(int bb, int cc, int dd);
523 template <typename... Args>
524 void foo(int a, Args&&... args) {
525 return baz(std::forward<Args>(args)...);
527 template <typename... Args>
528 void bar(Args&&... args) { return foo(std::forward<Args>(args)...); }
530 bar($param1[[32]], $param2[[42]], $param3[[52]]);
531 bar($param4[[1]], $param5[[2]], $param6[[3]], $param7[[4]]);
534 ExpectedHint
{"a: ", "param1"}, ExpectedHint
{"b: ", "param2"},
535 ExpectedHint
{"c: ", "param3"}, ExpectedHint
{"a: ", "param4"},
536 ExpectedHint
{"bb: ", "param5"}, ExpectedHint
{"cc: ", "param6"},
537 ExpectedHint
{"dd: ", "param7"});
540 TEST(ParameterHints
, VariadicRecursive
) {
541 // make_tuple-like recursive variadic call
542 assertParameterHints(
546 template <typename Head, typename... Tail>
547 void foo(Head head, Tail... tail) {
551 template <typename... Args>
552 void bar(Args... args) {
562 TEST(ParameterHints
, VariadicVarargs
) {
563 // variadic call involving varargs (to make sure we don't crash)
564 assertParameterHints(R
"cpp(
565 void foo(int fixed, ...);
566 template <typename... Args>
567 void bar(Args&&... args) {
572 bar($fixed[[41]], 42, 43);
577 TEST(ParameterHints
, VariadicTwolevelUnresolved
) {
578 // the same setting as VariadicVarargs, only with parameter pack
579 assertParameterHints(R
"cpp(
580 template <typename... Args>
581 void foo(int fixed, Args&& ... args);
582 template <typename... Args>
583 void bar(Args&&... args) {
588 bar($fixed[[41]], 42, 43);
591 ExpectedHint
{"fixed: ", "fixed"});
594 TEST(ParameterHints
, VariadicTwoCalls
) {
595 // only the first call using the parameter pack should be picked up
596 assertParameterHints(
598 void f1(int a, int b);
599 void f2(int c, int d);
603 template <typename... Args>
604 void foo(Args... args) {
613 foo($param1[[1]], $param2[[2]]);
616 ExpectedHint
{"a: ", "param1"}, ExpectedHint
{"b: ", "param2"});
619 TEST(ParameterHints
, VariadicInfinite
) {
620 // infinite recursion should not break clangd
621 assertParameterHints(
623 template <typename... Args>
626 template <typename... Args>
627 void bar(Args... args) {
631 template <typename... Args>
632 void foo(Args... args) {
642 TEST(ParameterHints
, VariadicDuplicatePack
) {
643 // edge cases with multiple adjacent packs should work
644 assertParameterHints(
646 void foo(int a, int b, int c, int);
648 template <typename... Args>
649 void bar(int, Args... args, int d) {
653 template <typename... Args>
654 void baz(Args... args, Args... args2) {
655 bar<Args..., int>(1, args..., args2...);
659 baz<int, int>($p1[[1]], $p2[[2]], $p3[[3]], $p4[[4]]);
662 ExpectedHint
{"a: ", "p1"}, ExpectedHint
{"b: ", "p2"},
663 ExpectedHint
{"c: ", "p3"}, ExpectedHint
{"d: ", "p4"});
666 TEST(ParameterHints
, VariadicEmplace
) {
667 // emplace-like calls should forward constructor parameters
668 // This prototype of std::forward is sufficient for clang to recognize it
669 assertParameterHints(
671 namespace std { template <typename T> T&& forward(T&); }
672 using size_t = decltype(sizeof(0));
673 void *operator new(size_t, void *);
679 template <typename T>
681 template <typename T, typename... Args>
682 void construct(T* ptr, Args&&... args) {
683 ::new ((void*)ptr) T{std::forward<Args>(args)...};
686 template <typename T>
688 template <typename... Args>
689 void emplace(Args&&... args) {
691 auto ptr = a.template allocate<T>();
692 a.construct(ptr, std::forward<Args>(args)...);
697 c.emplace($param1[[1]]);
698 c.emplace($param2[[2]], $param3[[3]]);
701 ExpectedHint
{"A: ", "param1"}, ExpectedHint
{"B: ", "param2"},
702 ExpectedHint
{"C: ", "param3"});
705 TEST(ParameterHints
, VariadicReferenceHint
) {
706 assertParameterHints(R
"cpp(
708 template <typename... Args>
709 void bar(Args... args) { return foo(args...); }
718 TEST(ParameterHints
, VariadicReferenceHintForwardingRef
) {
719 assertParameterHints(R
"cpp(
721 template <typename... Args>
722 void bar(Args&&... args) { return foo(args...); }
729 ExpectedHint
{"&: ", "param"});
732 TEST(ParameterHints
, VariadicReferenceHintForwardingRefStdForward
) {
733 assertParameterHints(R
"cpp(
734 namespace std { template <typename T> T&& forward(T&); }
736 template <typename... Args>
737 void bar(Args&&... args) { return foo(std::forward<Args>(args)...); }
743 ExpectedHint
{"&: ", "param"});
746 TEST(ParameterHints
, VariadicNoReferenceHintForwardingRefStdForward
) {
747 assertParameterHints(R
"cpp(
748 namespace std { template <typename T> T&& forward(T&); }
750 template <typename... Args>
751 void bar(Args&&... args) { return foo(std::forward<Args>(args)...); }
760 TEST(ParameterHints
, VariadicNoReferenceHintUnresolvedForward
) {
761 assertParameterHints(R
"cpp(
762 template <typename... Args>
763 void foo(Args&&... args);
771 TEST(ParameterHints
, MatchingNameVariadicForwarded
) {
772 // No name hint for variadic parameter with matching name
773 // This prototype of std::forward is sufficient for clang to recognize it
774 assertParameterHints(R
"cpp(
775 namespace std { template <typename T> T&& forward(T&); }
777 template <typename... Args>
778 void bar(Args&&... args) { return foo(std::forward<Args>(args)...); }
786 TEST(ParameterHints
, MatchingNameVariadicPlain
) {
787 // No name hint for variadic parameter with matching name
788 assertParameterHints(R
"cpp(
790 template <typename... Args>
791 void bar(Args&&... args) { return foo(args...); }
799 TEST(ParameterHints
, Operator
) {
800 // No hint for operator call with operator syntax.
801 assertParameterHints(R
"cpp(
803 void operator+(S lhs, S rhs);
811 TEST(ParameterHints
, FunctionCallOperator
) {
812 assertParameterHints(R
"cpp(
814 void operator()(int x);
818 static void operator()(int x, int y);
821 auto l1 = [](int x) {};
822 auto l2 = [](int x) static {};
826 s.operator()($2[[1]]);
827 s.operator()($3[[1]], $4[[2]]);
828 S::operator()($5[[1]], $6[[2]]);
831 l1.operator()($8[[1]]);
833 l2.operator()($10[[1]]);
835 void (*ptr)(int a, int b) = &S::operator();
836 ptr($11[[1]], $12[[2]]);
839 ExpectedHint
{"x: ", "1"}, ExpectedHint
{"x: ", "2"},
840 ExpectedHint
{"x: ", "3"}, ExpectedHint
{"y: ", "4"},
841 ExpectedHint
{"x: ", "5"}, ExpectedHint
{"y: ", "6"},
842 ExpectedHint
{"x: ", "7"}, ExpectedHint
{"x: ", "8"},
843 ExpectedHint
{"x: ", "9"}, ExpectedHint
{"x: ", "10"},
844 ExpectedHint
{"a: ", "11"}, ExpectedHint
{"b: ", "12"});
847 TEST(ParameterHints
, DeducingThis
) {
848 assertParameterHints(R
"cpp(
850 template <typename This>
851 auto operator()(this This &&Self, int Param) {
855 auto function(this auto &Self, int Param) {
862 s.function($2[[42]]);
864 auto lambda = [](this auto &Self, char C) -> void {
870 ExpectedHint
{"Param: ", "1"},
871 ExpectedHint
{"Param: ", "2"},
872 ExpectedHint
{"Param: ", "3"}, ExpectedHint
{"C: ", "4"});
875 TEST(ParameterHints
, Macros
) {
876 // Handling of macros depends on where the call's argument list comes from.
878 // If it comes from a macro definition, there's nothing to hint
879 // at the invocation site.
880 assertParameterHints(R
"cpp(
882 #define ExpandsToCall() foo(42)
888 // The argument expression being a macro invocation shouldn't interfere
890 assertParameterHints(R
"cpp(
892 void foo(double param);
897 ExpectedHint
{"param: ", "param"});
899 // If the whole argument list comes from a macro parameter, hint it.
900 assertParameterHints(R
"cpp(
902 #define ASSERT(expr) if (!expr) abort()
905 ASSERT(foo($param[[42]]) == 0);
908 ExpectedHint
{"param: ", "param"});
910 // If the macro expands to multiple arguments, don't hint it.
911 assertParameterHints(R
"cpp(
912 void foo(double x, double y);
913 #define CONSTANTS 3.14, 2.72
920 TEST(ParameterHints
, ConstructorParens
) {
921 assertParameterHints(R
"cpp(
929 ExpectedHint
{"param: ", "param"});
932 TEST(ParameterHints
, ConstructorBraces
) {
933 assertParameterHints(R
"cpp(
941 ExpectedHint
{"param: ", "param"});
944 TEST(ParameterHints
, ConstructorStdInitList
) {
945 // Do not show hints for std::initializer_list constructors.
946 assertParameterHints(R
"cpp(
948 template <typename E> class initializer_list { const E *a, *b; };
951 S(std::initializer_list<int> param);
959 TEST(ParameterHints
, MemberInit
) {
960 assertParameterHints(R
"cpp(
966 T() : member($param[[42]]) {}
969 ExpectedHint
{"param: ", "param"});
972 TEST(ParameterHints
, ImplicitConstructor
) {
973 assertParameterHints(R
"cpp(
979 // Do not show hint for implicit constructor call in argument.
981 // Do not show hint for implicit constructor call in return.
987 TEST(ParameterHints
, FunctionPointer
) {
988 assertParameterHints(
990 void (*f1)(int param);
991 void (__stdcall *f2)(int param);
992 using f3_t = void(*)(int param);
994 using f4_t = void(__stdcall *)(int param);
1003 ExpectedHint
{"param: ", "f1"}, ExpectedHint
{"param: ", "f2"},
1004 ExpectedHint
{"param: ", "f3"}, ExpectedHint
{"param: ", "f4"});
1007 TEST(ParameterHints
, ArgMatchesParam
) {
1008 assertParameterHints(R
"cpp(
1009 void foo(int param);
1011 static const int param = 42;
1015 // Do not show redundant "param
: param
".
1017 // But show it if the argument is qualified.
1018 foo($param[[S::param]]);
1023 // Do not show "param
: param
" for member-expr.
1028 ExpectedHint
{"param: ", "param"});
1031 TEST(ParameterHints
, ArgMatchesParamReference
) {
1032 assertParameterHints(R
"cpp(
1033 void foo(int& param);
1034 void foo2(const int& param);
1037 // show reference hint on mutable reference
1038 foo($param[[param]]);
1039 // but not on const reference
1043 ExpectedHint
{"&: ", "param"});
1046 TEST(ParameterHints
, LeadingUnderscore
) {
1047 assertParameterHints(R
"cpp(
1048 void foo(int p1, int _p2, int __p3);
1050 foo($p1[[41]], $p2[[42]], $p3[[43]]);
1053 ExpectedHint
{"p1: ", "p1"}, ExpectedHint
{"p2: ", "p2"},
1054 ExpectedHint
{"p3: ", "p3"});
1057 TEST(ParameterHints
, DependentCalls
) {
1058 assertParameterHints(R
"cpp(
1059 template <typename T>
1060 void nonmember(T par1);
1062 template <typename T>
1064 void member(T par2);
1065 static void static_member(T par3);
1068 void overload(int anInt);
1069 void overload(double aDouble);
1071 template <typename T>
1073 void bar(A<T> a, T t) {
1074 nonmember($par1[[t]]);
1075 a.member($par2[[t]]);
1076 A<T>::static_member($par3[[t]]);
1077 // We don't want to arbitrarily pick between
1078 // "anInt
" or "aDouble
", so just show no hint.
1083 ExpectedHint
{"par1: ", "par1"},
1084 ExpectedHint
{"par2: ", "par2"},
1085 ExpectedHint
{"par3: ", "par3"});
1088 TEST(ParameterHints
, VariadicFunction
) {
1089 assertParameterHints(R
"cpp(
1090 template <typename... T>
1091 void foo(int fixed, T... variadic);
1094 foo($fixed[[41]], 42, 43);
1097 ExpectedHint
{"fixed: ", "fixed"});
1100 TEST(ParameterHints
, VarargsFunction
) {
1101 assertParameterHints(R
"cpp(
1102 void foo(int fixed, ...);
1105 foo($fixed[[41]], 42, 43);
1108 ExpectedHint
{"fixed: ", "fixed"});
1111 TEST(ParameterHints
, CopyOrMoveConstructor
) {
1112 // Do not show hint for parameter of copy or move constructor.
1113 assertParameterHints(R
"cpp(
1127 TEST(ParameterHints
, AggregateInit
) {
1128 // FIXME: This is not implemented yet, but it would be a natural
1129 // extension to show member names as hints here.
1130 assertParameterHints(R
"cpp(
1141 TEST(ParameterHints
, UserDefinedLiteral
) {
1142 // Do not hint call to user-defined literal operator.
1143 assertParameterHints(R
"cpp(
1144 long double operator"" _w(long double param);
1151 TEST(ParameterHints
, ParamNameComment
) {
1152 // Do not hint an argument which already has a comment
1153 // with the parameter name preceding it.
1154 assertParameterHints(R
"cpp(
1155 void foo(int param);
1158 foo( /* param = */ 42);
1162 foo(/*param=*/Z(a));
1163 foo($macro[[Z(a)]]);
1164 foo(/* the answer */$param[[42]]);
1167 ExpectedHint
{"param: ", "macro"},
1168 ExpectedHint
{"param: ", "param"});
1171 TEST(ParameterHints
, SetterFunctions
) {
1172 assertParameterHints(R
"cpp(
1174 void setParent(S* parent);
1175 void set_parent(S* parent);
1176 void setTimeout(int timeoutMillis);
1177 void setTimeoutMillis(int timeout_millis);
1181 // Parameter name matches setter name - omit hint.
1182 s.setParent(nullptr);
1183 // Support snake_case
1184 s.set_parent(nullptr);
1185 // Parameter name may contain extra info - show hint.
1186 s.setTimeout($timeoutMillis[[120]]);
1187 // FIXME: Ideally we'd want to omit this.
1188 s.setTimeoutMillis($timeout_millis[[120]]);
1191 ExpectedHint
{"timeoutMillis: ", "timeoutMillis"},
1192 ExpectedHint
{"timeout_millis: ", "timeout_millis"});
1195 TEST(ParameterHints
, BuiltinFunctions
) {
1196 // This prototype of std::forward is sufficient for clang to recognize it
1197 assertParameterHints(R
"cpp(
1198 namespace std { template <typename T> T&& forward(T&); }
1206 TEST(ParameterHints
, IncludeAtNonGlobalScope
) {
1207 Annotations
FooInc(R
"cpp(
1208 void bar() { foo(42); }
1210 Annotations
FooCC(R
"cpp(
1212 void foo(int param);
1217 TestWorkspace Workspace
;
1218 Workspace
.addSource("foo.inc", FooInc
.code());
1219 Workspace
.addMainFile("foo.cc", FooCC
.code());
1221 auto AST
= Workspace
.openFile("foo.cc");
1222 ASSERT_TRUE(bool(AST
));
1224 // Ensure the hint for the call in foo.inc is NOT materialized in foo.cc.
1225 EXPECT_EQ(hintsOfKind(*AST
, InlayHintKind::Parameter
).size(), 0u);
1228 TEST(TypeHints
, Smoke
) {
1229 assertTypeHints(R
"cpp(
1230 auto $waldo[[waldo]] = 42;
1232 ExpectedHint
{": int", "waldo"});
1235 TEST(TypeHints
, Decorations
) {
1236 assertTypeHints(R
"cpp(
1238 auto* $var1[[var1]] = &x;
1239 auto&& $var2[[var2]] = x;
1240 const auto& $var3[[var3]] = x;
1242 ExpectedHint
{": int *", "var1"},
1243 ExpectedHint
{": int &", "var2"},
1244 ExpectedHint
{": const int &", "var3"});
1247 TEST(TypeHints
, DecltypeAuto
) {
1248 assertTypeHints(R
"cpp(
1251 decltype(auto) $z[[z]] = y;
1253 ExpectedHint
{": int &", "z"});
1256 TEST(TypeHints
, NoQualifiers
) {
1257 assertTypeHints(R
"cpp(
1262 auto $x[[x]] = foo();
1265 template <typename T>
1268 S2::Inner<int> bar();
1269 auto $y[[y]] = bar();
1273 ExpectedHint
{": S1", "x"},
1274 // FIXME: We want to suppress scope specifiers
1275 // here because we are into the whole
1276 // brevity thing, but the ElaboratedType
1277 // printer does not honor the SuppressScope
1278 // flag by design, so we need to extend the
1279 // PrintingPolicy to support this use case.
1280 ExpectedHint
{": S2::Inner<int>", "y"});
1283 TEST(TypeHints
, Lambda
) {
1284 // Do not print something overly verbose like the lambda's location.
1285 // Show hints for init-captures (but not regular captures).
1286 assertTypeHints(R
"cpp(
1289 auto $L[[L]] = [cap, $init[[init]] = 1 + 1](int a$ret[[)]] {
1290 return a + cap + init;
1294 ExpectedHint
{": (lambda)", "L"},
1295 ExpectedHint
{": int", "init"}, ExpectedHint
{"-> int", "ret"});
1297 // Lambda return hint shown even if no param list.
1298 // (The digraph :> is just a ] that doesn't conflict with the annotations).
1299 assertTypeHints("auto $L[[x]] = <:$ret[[:>]]{return 42;};",
1300 ExpectedHint
{": (lambda)", "L"},
1301 ExpectedHint
{"-> int", "ret"});
1304 // Structured bindings tests.
1305 // Note, we hint the individual bindings, not the aggregate.
1307 TEST(TypeHints
, StructuredBindings_PublicStruct
) {
1308 assertTypeHints(R
"cpp(
1309 // Struct with public fields.
1315 auto [$x[[x]], $y[[y]]] = foo();
1317 ExpectedHint
{": int", "x"}, ExpectedHint
{": int", "y"});
1320 TEST(TypeHints
, StructuredBindings_Array
) {
1321 assertTypeHints(R
"cpp(
1323 auto [$x[[x]], $y[[y]]] = arr;
1325 ExpectedHint
{": int", "x"}, ExpectedHint
{": int", "y"});
1328 TEST(TypeHints
, StructuredBindings_TupleLike
) {
1329 assertTypeHints(R
"cpp(
1336 template <typename T>
1337 struct tuple_size {};
1339 struct tuple_size<IntPair> {
1340 constexpr static unsigned value = 2;
1342 template <unsigned I, typename T>
1343 struct tuple_element {};
1344 template <unsigned I>
1345 struct tuple_element<I, IntPair> {
1349 template <unsigned I>
1350 int get(const IntPair& p) {
1351 if constexpr (I == 0) {
1353 } else if constexpr (I == 1) {
1358 auto [$x[[x]], $y[[y]]] = bar();
1360 ExpectedHint
{": int", "x"}, ExpectedHint
{": int", "y"});
1363 TEST(TypeHints
, StructuredBindings_NoInitializer
) {
1364 assertTypeHints(R
"cpp(
1365 // No initializer (ill-formed).
1366 // Do not show useless "NULL TYPE
" hint.
1367 auto [x, y]; /*error-ok*/
1371 TEST(TypeHints
, InvalidType
) {
1372 assertTypeHints(R
"cpp(
1373 auto x = (unknown_type)42; /*error-ok*/
1374 auto *y = (unknown_ptr)nullptr;
1378 TEST(TypeHints
, ReturnTypeDeduction
) {
1381 auto f1(int x$ret1a[[)]]; // Hint forward declaration too
1382 auto f1(int x$ret1b[[)]] { return x + 1; }
1384 // Include pointer operators in hint
1386 auto& f2($ret2[[)]] { return s; }
1388 // Do not hint `auto` for trailing return type.
1391 // Do not hint when a trailing return type is specified.
1392 auto f4() -> auto* { return "foo
"; }
1394 auto f5($noreturn[[)]] {}
1396 // `auto` conversion operator
1398 operator auto($retConv[[)]] { return 42; }
1401 // FIXME: Dependent types do not work yet.
1402 template <typename T>
1404 auto method() { return T(); }
1407 ExpectedHint
{"-> int", "ret1a"}, ExpectedHint
{"-> int", "ret1b"},
1408 ExpectedHint
{"-> int &", "ret2"}, ExpectedHint
{"-> void", "noreturn"},
1409 ExpectedHint
{"-> int", "retConv"});
1412 TEST(TypeHints
, DependentType
) {
1413 assertTypeHints(R
"cpp(
1414 template <typename T>
1416 // The hint would just be "auto" and we can't do any better.
1417 auto var1 = arg.method();
1418 // FIXME: It would be nice to show "T
" as the hint.
1419 auto $var2[[var2]] = arg;
1422 template <typename T>
1429 TEST(TypeHints
, LongTypeName
) {
1430 assertTypeHints(R
"cpp(
1431 template <typename, typename, typename>
1433 struct MultipleWords {};
1434 A<MultipleWords, MultipleWords, MultipleWords> foo();
1435 // Omit type hint past a certain length (currently 32)
1440 Cfg
.InlayHints
.TypeNameLimit
= 0;
1441 WithContextValue
WithCfg(Config::Key
, std::move(Cfg
));
1445 template <typename, typename, typename>
1447 struct MultipleWords {};
1448 A<MultipleWords, MultipleWords, MultipleWords> foo();
1449 // Should have type hint with TypeNameLimit = 0
1450 auto $var[[var]] = foo();
1452 ExpectedHint
{": A<MultipleWords, MultipleWords, MultipleWords>", "var"});
1455 TEST(TypeHints
, DefaultTemplateArgs
) {
1456 assertTypeHints(R
"cpp(
1457 template <typename, typename = int>
1460 auto $var[[var]] = foo();
1462 auto [$binding[[value]]] = bar;
1464 ExpectedHint
{": A<float>", "var"},
1465 ExpectedHint
{": A<float>", "binding"});
1468 TEST(TypeHints
, Deduplication
) {
1469 assertTypeHints(R
"cpp(
1470 template <typename T>
1472 auto $var[[var]] = 42;
1474 template void foo<int>();
1475 template void foo<float>();
1477 ExpectedHint
{": int", "var"});
1480 TEST(TypeHints
, SinglyInstantiatedTemplate
) {
1481 assertTypeHints(R
"cpp(
1482 auto $lambda[[x]] = [](auto *$param[[y]], auto) { return 42; };
1483 int m = x("foo
", 3);
1485 ExpectedHint
{": (lambda)", "lambda"},
1486 ExpectedHint
{": const char *", "param"});
1488 // No hint for packs, or auto params following packs
1489 assertTypeHints(R
"cpp(
1490 int x(auto $a[[a]], auto... b, auto c) { return 42; }
1491 int m = x<void*, char, float>(nullptr, 'c', 2.0, 2);
1493 ExpectedHint
{": void *", "a"});
1496 TEST(TypeHints
, Aliased
) {
1497 // Check that we don't crash for functions without a FunctionTypeLoc.
1498 // https://github.com/clangd/clangd/issues/1140
1499 TestTU TU
= TestTU::withCode("void foo(void){} extern typeof(foo) foo;");
1500 TU
.ExtraArgs
.push_back("-xc");
1501 auto AST
= TU
.build();
1503 EXPECT_THAT(hintsOfKind(AST
, InlayHintKind::Type
), IsEmpty());
1506 TEST(TypeHints
, Decltype
) {
1507 assertTypeHints(R
"cpp(
1508 $a[[decltype(0)]] a;
1509 $b[[decltype(a)]] b;
1510 const $c[[decltype(0)]] &c = b;
1512 // Don't show for dependent type
1514 constexpr decltype(T{}) d;
1516 $e[[decltype(0)]] e();
1517 auto f() -> $f[[decltype(0)]];
1519 template <class, class> struct Foo;
1520 using G = Foo<$g[[decltype(0)]], float>;
1522 auto $h[[h]] = $i[[decltype(0)]]{};
1528 ExpectedHint
{": int", "a"}, ExpectedHint
{": int", "b"},
1529 ExpectedHint
{": int", "c"}, ExpectedHint
{": int", "e"},
1530 ExpectedHint
{": int", "f"}, ExpectedHint
{": int", "g"},
1531 ExpectedHint
{": int", "h"}, ExpectedHint
{": int", "i"});
1534 TEST(TypeHints
, SubstTemplateParameterAliases
) {
1535 llvm::StringRef Header
= R
"cpp(
1536 template <class T> struct allocator {};
1538 template <class T, class A>
1539 struct vector_base {
1543 template <class T, class A>
1544 struct internal_iterator_type_template_we_dont_expect {};
1546 struct my_iterator {};
1548 template <class T, class A = allocator<T>>
1549 struct vector : vector_base<T, A> {
1550 using base = vector_base<T, A>;
1551 typedef T value_type;
1552 typedef base::pointer pointer;
1553 using allocator_type = A;
1554 using size_type = int;
1555 using iterator = internal_iterator_type_template_we_dont_expect<T, A>;
1556 using non_template_iterator = my_iterator;
1558 value_type& operator[](int index) { return elements[index]; }
1559 const value_type& at(int index) const { return elements[index]; }
1560 pointer data() { return &elements[0]; }
1561 allocator_type get_allocator() { return A(); }
1562 size_type size() const { return 10; }
1563 iterator begin() { return iterator(); }
1564 non_template_iterator end() { return non_template_iterator(); }
1570 llvm::StringRef VectorIntPtr
= R
"cpp(
1571 vector<int *> array;
1572 auto $no_modifier[[x]] = array[3];
1573 auto* $ptr_modifier[[ptr]] = &array[3];
1574 auto& $ref_modifier[[ref]] = array[3];
1575 auto& $at[[immutable]] = array.at(3);
1577 auto $data[[data]] = array.data();
1578 auto $allocator[[alloc]] = array.get_allocator();
1579 auto $size[[size]] = array.size();
1580 auto $begin[[begin]] = array.begin();
1581 auto $end[[end]] = array.end();
1584 assertHintsWithHeader(
1585 InlayHintKind::Type
, VectorIntPtr
, Header
,
1586 ExpectedHint
{": int *", "no_modifier"},
1587 ExpectedHint
{": int **", "ptr_modifier"},
1588 ExpectedHint
{": int *&", "ref_modifier"},
1589 ExpectedHint
{": int *const &", "at"}, ExpectedHint
{": int **", "data"},
1590 ExpectedHint
{": allocator<int *>", "allocator"},
1591 ExpectedHint
{": size_type", "size"}, ExpectedHint
{": iterator", "begin"},
1592 ExpectedHint
{": non_template_iterator", "end"});
1594 llvm::StringRef VectorInt
= R
"cpp(
1596 auto $no_modifier[[by_value]] = array[3];
1597 auto* $ptr_modifier[[ptr]] = &array[3];
1598 auto& $ref_modifier[[ref]] = array[3];
1599 auto& $at[[immutable]] = array.at(3);
1601 auto $data[[data]] = array.data();
1602 auto $allocator[[alloc]] = array.get_allocator();
1603 auto $size[[size]] = array.size();
1604 auto $begin[[begin]] = array.begin();
1605 auto $end[[end]] = array.end();
1608 assertHintsWithHeader(
1609 InlayHintKind::Type
, VectorInt
, Header
,
1610 ExpectedHint
{": int", "no_modifier"},
1611 ExpectedHint
{": int *", "ptr_modifier"},
1612 ExpectedHint
{": int &", "ref_modifier"},
1613 ExpectedHint
{": const int &", "at"}, ExpectedHint
{": int *", "data"},
1614 ExpectedHint
{": allocator<int>", "allocator"},
1615 ExpectedHint
{": size_type", "size"}, ExpectedHint
{": iterator", "begin"},
1616 ExpectedHint
{": non_template_iterator", "end"});
1618 llvm::StringRef TypeAlias
= R
"cpp(
1619 // If the type alias is not of substituted template parameter type,
1620 // do not show desugared type.
1621 using VeryLongLongTypeName = my_iterator;
1622 using Short = VeryLongLongTypeName;
1624 auto $short_name[[my_value]] = Short();
1626 // Same applies with templates.
1627 template <typename T, typename A>
1628 using basic_static_vector = vector<T, A>;
1629 template <typename T>
1630 using static_vector = basic_static_vector<T, allocator<T>>;
1632 auto $vector_name[[vec]] = static_vector<int>();
1635 assertHintsWithHeader(InlayHintKind::Type
, TypeAlias
, Header
,
1636 ExpectedHint
{": Short", "short_name"},
1637 ExpectedHint
{": static_vector<int>", "vector_name"});
1640 TEST(DesignatorHints
, Basic
) {
1641 assertDesignatorHints(R
"cpp(
1642 struct S { int x, y, z; };
1643 S s {$x[[1]], $y[[2+2]]};
1645 int x[] = {$0[[0]], $1[[1]]};
1647 ExpectedHint
{".x=", "x"}, ExpectedHint
{".y=", "y"},
1648 ExpectedHint
{"[0]=", "0"}, ExpectedHint
{"[1]=", "1"});
1651 TEST(DesignatorHints
, Nested
) {
1652 assertDesignatorHints(R
"cpp(
1653 struct Inner { int x, y; };
1654 struct Outer { Inner a, b; };
1655 Outer o{ $a[[{ $x[[1]], $y[[2]] }]], $bx[[3]] };
1657 ExpectedHint
{".a=", "a"}, ExpectedHint
{".x=", "x"},
1658 ExpectedHint
{".y=", "y"}, ExpectedHint
{".b.x=", "bx"});
1661 TEST(DesignatorHints
, AnonymousRecord
) {
1662 assertDesignatorHints(R
"cpp(
1674 ExpectedHint
{".x.y=", "xy"});
1677 TEST(DesignatorHints
, Suppression
) {
1678 assertDesignatorHints(R
"cpp(
1679 struct Point { int a, b, c, d, e, f, g, h; };
1680 Point p{/*a=*/1, .c=2, /* .d = */3, $e[[4]]};
1682 ExpectedHint
{".e=", "e"});
1685 TEST(DesignatorHints
, StdArray
) {
1686 // Designators for std::array should be [0] rather than .__elements[0].
1687 // While technically correct, the designator is useless and horrible to read.
1688 assertDesignatorHints(R
"cpp(
1689 template <typename T, int N> struct Array { T __elements[N]; };
1690 Array<int, 2> x = {$0[[0]], $1[[1]]};
1692 ExpectedHint
{"[0]=", "0"}, ExpectedHint
{"[1]=", "1"});
1695 TEST(DesignatorHints
, OnlyAggregateInit
) {
1696 assertDesignatorHints(R
"cpp(
1697 struct Copyable { int x; } c;
1700 struct Constructible { Constructible(int x); };
1701 Constructible x{42};
1702 )cpp" /*no designator hints expected (but param hints!)*/);
1705 TEST(DesignatorHints
, NoCrash
) {
1706 assertDesignatorHints(R
"cpp(
1709 struct Foo {int a; int b;};
1711 Foo f{A(), $b[[1]]};
1714 ExpectedHint
{".b=", "b"});
1717 TEST(InlayHints
, RestrictRange
) {
1718 Annotations
Code(R
"cpp(
1724 auto AST
= TestTU::withCode(Code
.code()).build();
1725 EXPECT_THAT(inlayHints(AST
, Code
.range()),
1726 ElementsAre(labelIs(": int"), labelIs(": char")));
1729 TEST(ParameterHints
, PseudoObjectExpr
) {
1730 Annotations
Code(R
"cpp(
1732 __declspec(property(get=GetX, put=PutX)) int x[];
1733 int GetX(int y, int z) { return 42 + y; }
1736 // This is a PseudoObjectExpression whose syntactic form is a binary
1738 void Work(int y) { x = y; } // Not `x = y: y`.
1741 int printf(const char *Format, ...);
1745 __builtin_dump_struct(&s, printf); // Not `Format: __builtin_dump_struct()`
1746 printf($Param[["Hello
, %d
"]], 42); // Normal calls are not affected.
1747 // This builds a PseudoObjectExpr, but here it's useful for showing the
1748 // arguments from the semantic form.
1749 return s.x[ $one[[1]] ][ $two[[2]] ]; // `x[y: 1][z: 2]`
1752 auto TU
= TestTU::withCode(Code
.code());
1753 TU
.ExtraArgs
.push_back("-fms-extensions");
1754 auto AST
= TU
.build();
1755 EXPECT_THAT(inlayHints(AST
, std::nullopt
),
1756 ElementsAre(HintMatcher(ExpectedHint
{"Format: ", "Param"}, Code
),
1757 HintMatcher(ExpectedHint
{"y: ", "one"}, Code
),
1758 HintMatcher(ExpectedHint
{"z: ", "two"}, Code
)));
1761 TEST(ParameterHints
, ArgPacksAndConstructors
) {
1762 assertParameterHints(
1764 struct Foo{ Foo(); Foo(int x); };
1765 void foo(Foo a, int b);
1766 template <typename... Args>
1767 void bar(Args... args) {
1770 template <typename... Args>
1771 void baz(Args... args) { foo($param1[[Foo{args...}]], $param2[[1]]); }
1773 template <typename... Args>
1774 void bax(Args... args) { foo($param3[[{args...}]], args...); }
1777 bar($param4[[Foo{}]], $param5[[42]]);
1778 bar($param6[[42]], $param7[[42]]);
1783 ExpectedHint
{"a: ", "param1"}, ExpectedHint
{"b: ", "param2"},
1784 ExpectedHint
{"a: ", "param3"}, ExpectedHint
{"a: ", "param4"},
1785 ExpectedHint
{"b: ", "param5"}, ExpectedHint
{"a: ", "param6"},
1786 ExpectedHint
{"b: ", "param7"}, ExpectedHint
{"x: ", "param8"},
1787 ExpectedHint
{"b: ", "param9"});
1790 TEST(ParameterHints
, DoesntExpandAllArgs
) {
1791 assertParameterHints(
1793 void foo(int x, int y);
1794 int id(int a, int b, int c);
1795 template <typename... Args>
1796 void bar(Args... args) {
1797 foo(id($param1[[args]], $param2[[1]], $param3[[args]])...);
1800 bar(1, 2); // FIXME: We could have `bar(a: 1, a: 2)` here.
1803 ExpectedHint
{"a: ", "param1"}, ExpectedHint
{"b: ", "param2"},
1804 ExpectedHint
{"c: ", "param3"});
1807 TEST(BlockEndHints
, Functions
) {
1808 assertBlockEndHints(R
"cpp(
1815 // No hint for lambda for now
1822 // No hint because this isn't a definition
1826 bool operator==(S, S) {
1830 ExpectedHint
{" // foo", "foo"},
1831 ExpectedHint
{" // bar", "bar"},
1832 ExpectedHint
{" // operator==", "opEqual"});
1835 TEST(BlockEndHints
, Methods
) {
1836 assertBlockEndHints(R
"cpp(
1838 // No hint because there's no function body
1847 // No hint because this isn't a definition
1850 template <typename T>
1854 // No hint because this isn't a definition
1855 template <typename T>
1858 Test operator+(int) const {
1862 operator bool() const {
1866 // No hint because there's no function body
1867 operator int() const = delete;
1870 void Test::method2() {
1873 template <typename T>
1874 void Test::method4() {
1877 ExpectedHint
{" // ~Test", "dtor"},
1878 ExpectedHint
{" // method1", "method1"},
1879 ExpectedHint
{" // method3", "method3"},
1880 ExpectedHint
{" // operator+", "opIdentity"},
1881 ExpectedHint
{" // operator bool", "opBool"},
1882 ExpectedHint
{" // Test::method2", "method2"},
1883 ExpectedHint
{" // Test::method4", "method4"});
1886 TEST(BlockEndHints
, Namespaces
) {
1887 assertBlockEndHints(
1897 ExpectedHint
{" // namespace", "anon"},
1898 ExpectedHint
{" // namespace ns", "ns"});
1901 TEST(BlockEndHints
, Types
) {
1902 assertBlockEndHints(
1919 ExpectedHint
{" // struct S", "S"}, ExpectedHint
{" // class C", "C"},
1920 ExpectedHint
{" // union U", "U"}, ExpectedHint
{" // enum E1", "E1"},
1921 ExpectedHint
{" // enum class E2", "E2"});
1924 TEST(BlockEndHints
, If
) {
1925 assertBlockEndHints(
1927 void foo(bool cond) {
1948 if (auto X = cond) {
1951 if (int i = 0; i > 10) {
1955 ExpectedHint
{" // if cond", "simple"},
1956 ExpectedHint
{" // if cond", "ifelse"}, ExpectedHint
{" // if", "elseif"},
1957 ExpectedHint
{" // if !cond", "inner"},
1958 ExpectedHint
{" // if cond", "outer"}, ExpectedHint
{" // if X", "init"},
1959 ExpectedHint
{" // if i > 10", "init_cond"});
1962 TEST(BlockEndHints
, Loops
) {
1963 assertBlockEndHints(
1978 for (int I = 0; I < 10; ++I) {
1986 ExpectedHint
{" // while true", "while"},
1987 ExpectedHint
{" // for true", "forcond"},
1988 ExpectedHint
{" // for I", "forvar"},
1989 ExpectedHint
{" // for V", "foreach"});
1992 TEST(BlockEndHints
, Switch
) {
1993 assertBlockEndHints(
2001 ExpectedHint
{" // switch I", "switch"});
2004 TEST(BlockEndHints
, PrintLiterals
) {
2005 assertBlockEndHints(
2011 while ("foo but
this time it is very
long") {
2024 ExpectedHint
{" // while \"foo\"", "string"},
2025 ExpectedHint
{" // while \"foo but...\"", "string_long"},
2026 ExpectedHint
{" // while true", "boolean"},
2027 ExpectedHint
{" // while 1", "integer"},
2028 ExpectedHint
{" // while 1.5", "float"});
2031 TEST(BlockEndHints
, PrintRefs
) {
2032 assertBlockEndHints(
2046 while (ns::func()) {
2049 while (ns::S{}.Field) {
2052 while (ns::S{}.method()) {
2056 ExpectedHint
{" // while Var", "var"},
2057 ExpectedHint
{" // while func", "func"},
2058 ExpectedHint
{" // while Field", "field"},
2059 ExpectedHint
{" // while method", "method"});
2062 TEST(BlockEndHints
, PrintConversions
) {
2063 assertBlockEndHints(
2068 explicit operator bool();
2072 $convert_primitive[[}]]
2078 $construct_class[[}]]
2081 ExpectedHint
{" // while float", "convert_primitive"},
2082 ExpectedHint
{" // while S", "convert_class"},
2083 ExpectedHint
{" // while S", "construct_class"});
2086 TEST(BlockEndHints
, PrintOperators
) {
2087 std::string AnnotatedCode
= R
"cpp(
2088 void foo(Integer I) {
2107 while((I + I) < (I + I)){
2108 $binary_complex[[}]]
2112 // We can't store shared expectations in a vector, assertHints uses varargs.
2113 auto AssertExpectedHints
= [&](llvm::StringRef Code
) {
2114 assertBlockEndHints(Code
, ExpectedHint
{" // while ++I", "preinc"},
2115 ExpectedHint
{" // while I++", "postinc"},
2116 ExpectedHint
{" // while", "unary_complex"},
2117 ExpectedHint
{" // while I < 0", "compare"},
2118 ExpectedHint
{" // while ... < I", "lhs_complex"},
2119 ExpectedHint
{" // while I < ...", "rhs_complex"},
2120 ExpectedHint
{" // while", "binary_complex"});
2123 // First with built-in operators.
2124 AssertExpectedHints("using Integer = int;" + AnnotatedCode
);
2125 // And now with overloading!
2126 AssertExpectedHints(R
"cpp(
2128 explicit operator bool();
2129 Integer operator++();
2130 Integer operator++(int);
2131 Integer operator+(Integer);
2132 Integer operator+();
2133 bool operator<(Integer);
2134 bool operator<(int);
2136 )cpp" + AnnotatedCode
);
2139 TEST(BlockEndHints
, TrailingSemicolon
) {
2140 assertBlockEndHints(R
"cpp(
2141 // The hint is placed after the trailing ';'
2145 // The hint is always placed in the same line with the closing '}'.
2146 // So in this case where ';' is missing, it is attached to '}'.
2152 // No hint because only one trailing ';' is allowed
2156 // No hint because trailing ';' is only allowed for class/struct/union/enum
2160 // Rare case, but yes we'll have a hint here.
2167 ExpectedHint
{" // struct S1", "S1"},
2168 ExpectedHint
{" // struct S2", "S2"},
2169 ExpectedHint
{" // struct", "anon"});
2172 TEST(BlockEndHints
, TrailingText
) {
2173 assertBlockEndHints(R
"cpp(
2177 // No hint for S2 because of the trailing comment
2179 }; /* Put anything here */
2182 // No hint for S4 because of the trailing source code
2186 // No hint for ns because of the trailing comment
2190 ExpectedHint
{" // struct S1", "S1"},
2191 ExpectedHint
{" // struct S3", "S3"});
2194 TEST(BlockEndHints
, Macro
) {
2195 assertBlockEndHints(R
"cpp(
2196 #define DECL_STRUCT(NAME) struct NAME {
2202 // No hint because we require a '}'
2206 ExpectedHint
{" // struct S1", "S1"});
2209 TEST(BlockEndHints
, PointerToMemberFunction
) {
2210 // Do not crash trying to summarize `a->*p`.
2211 assertBlockEndHints(R
"cpp(
2213 using Predicate = bool(A::*)();
2214 void foo(A* a, Predicate p) {
2219 ExpectedHint
{" // if", "ptrmem"});
2222 // FIXME: Low-hanging fruit where we could omit a type hint:
2223 // - auto x = TypeName(...);
2224 // - auto x = (TypeName) (...);
2225 // - auto x = static_cast<TypeName>(...); // and other built-in casts
2227 // Annoyances for which a heuristic is not obvious:
2228 // - auto x = llvm::dyn_cast<LongTypeName>(y); // and similar
2229 // - stdlib algos return unwieldy __normal_iterator<X*, ...> type
2230 // (For this one, perhaps we should omit type hints that start
2231 // with a double underscore.)
2234 } // namespace clangd
2235 } // namespace clang