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