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