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