1 //===-- ExtractVariableTests.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 9 #include "TweakTesting.h" 10 #include "gmock/gmock.h" 11 #include "gtest/gtest.h" 12 13 namespace clang { 14 namespace clangd { 15 namespace { 16 17 TWEAK_TEST(ExtractVariable); 18 19 TEST_F(ExtractVariableTest, Test) { 20 const char *AvailableCases = R"cpp( 21 int xyz(int a = 1) { 22 struct T { 23 int bar(int a = 1); 24 int z; 25 } t; 26 // return statement 27 return [[[[t.b[[a]]r]]([[t.z]])]]; 28 } 29 void f() { 30 int a = 5 + [[4 * [[[[xyz]]()]]]]; 31 // multivariable initialization 32 if(1) 33 int x = [[1]] + 1, y = a + [[1]], a = [[1]] + 2, z = a + 1; 34 // if without else 35 if([[1]]) 36 a = [[1]] + 1; 37 // if with else 38 if(a < [[3]]) 39 if(a == [[4]]) 40 a = [[5]] + 1; 41 else 42 a = [[5]] + 1; 43 else if (a < [[4]]) 44 a = [[4]] + 1; 45 else 46 a = [[5]] + 1; 47 // for loop 48 for(a = [[1]] + 1; a > [[[[3]] + [[4]]]]; a++) 49 a = [[2]] + 1; 50 // while 51 while(a < [[1]]) 52 a = [[1]] + 1; 53 // do while 54 do 55 a = [[1]] + 1; 56 while(a < [[3]]); 57 } 58 )cpp"; 59 EXPECT_AVAILABLE(AvailableCases); 60 61 ExtraArgs = {"-xc"}; 62 const char *AvailableC = R"cpp( 63 void foo() { 64 int x = [[1]] + 1; 65 })cpp"; 66 EXPECT_AVAILABLE(AvailableC); 67 68 ExtraArgs = {"-xc"}; 69 const char *NoCrashCasesC = R"cpp( 70 // error-ok: broken code, but shouldn't crash 71 int x = [[foo()]]; 72 )cpp"; 73 EXPECT_UNAVAILABLE(NoCrashCasesC); 74 75 ExtraArgs = {"-xc"}; 76 const char *NoCrashDesignator = R"cpp( 77 struct A { 78 struct { 79 int x; 80 }; 81 }; 82 struct B { 83 int y; 84 }; 85 void foo(struct B *b) { 86 struct A a = {.x=b[[->]]y}; 87 } 88 )cpp"; 89 EXPECT_AVAILABLE(NoCrashDesignator); 90 91 ExtraArgs = {"-xobjective-c"}; 92 const char *AvailableObjC = R"cpp( 93 __attribute__((objc_root_class)) 94 @interface Foo 95 @end 96 @implementation Foo 97 - (void)method { 98 int x = [[1]] + 2; 99 } 100 @end)cpp"; 101 EXPECT_AVAILABLE(AvailableObjC); 102 ExtraArgs = {}; 103 104 const char *NoCrashCases = R"cpp( 105 // error-ok: broken code, but shouldn't crash 106 template<typename T, typename ...Args> 107 struct Test<T, Args...> { 108 Test(const T &v) :val[[(^]]) {} 109 T val; 110 }; 111 )cpp"; 112 EXPECT_UNAVAILABLE(NoCrashCases); 113 114 const char *UnavailableCases = R"cpp( 115 int xyz(int a = [[1]]) { 116 struct T { 117 int bar(int a = [[1]]) { 118 int b = [[z]]; 119 } 120 int z = [[1]]; 121 } t; 122 int x = [[1 + 2]]; 123 int y; 124 y = [[1 + 2]]; 125 return [[t]].bar([[t]].z); 126 } 127 void v() { return; } 128 129 // function default argument 130 void f(int b = [[1]]) { 131 // empty selection 132 int a = ^1 ^+ ^2; 133 // void expressions 134 auto i = new int, j = new int; 135 [[[[delete i]], delete j]]; 136 [[v]](); 137 // if 138 if(1) 139 int x = 1, y = a + 1, a = 1, z = [[a + 1]]; 140 if(int a = 1) 141 if([[a + 1]] == 4) 142 a = [[[[a]] +]] 1; 143 // for loop 144 for(int a = 1, b = 2, c = 3; a > [[b + c]]; [[a++]]) 145 a = [[a + 1]]; 146 // lambda 147 auto lamb = [&[[a]], &[[b]]](int r = [[1]]) {return 1;}; 148 // assignment 149 xyz([[a = 5]]); 150 xyz([[a *= 5]]); 151 // Variable DeclRefExpr 152 a = [[b]]; 153 a = [[xyz()]]; 154 // expression statement of type void 155 [[v()]]; 156 while (a) 157 [[++a]]; 158 // label statement 159 goto label; 160 label: 161 a = [[1]]; 162 163 // lambdas: captures 164 int x = 0; 165 [ [[=]] ](){}; 166 [ [[&]] ](){}; 167 [ [[x]] ](){}; 168 [ [[&x]] ](){}; 169 [y = [[x]] ](){}; 170 [ [[y = x]] ](){}; 171 172 // lambdas: default args, cannot extract into function-local scope 173 [](int x = [[10]]){}; 174 [](auto h = [[ [i = [](){}](){} ]]) {}; 175 176 // lambdas: default args 177 // Extracting from capture initializers is usually fine, 178 // but not if the capture itself is nested inside a default argument 179 [](auto h = [i = [[ [](){} ]]](){}) {}; 180 [](auto h = [i = [[ 42 ]]](){}) {}; 181 182 // lambdas: scope 183 if (int a = 1) 184 if ([[ [&](){ return a + 1; } ]]() == 4) 185 a = a + 1; 186 187 for (int c = 0; [[ [&]() { return c < b; } ]](); ++c) { 188 } 189 for (int c = 0; [[ [&]() { return c < b; } () ]]; ++c) { 190 } 191 192 // lambdas: scope with structured binding 193 struct Coordinates { 194 int x{}; 195 int y{}; 196 }; 197 Coordinates c{}; 198 if (const auto [x, y] = c; x > y) 199 auto f = [[ [&]() { return x + y; } ]]; 200 201 // lambdas: referencing outside variables that block extraction 202 // in trailing return type or in a decltype used 203 // by a parameter 204 if (int a = 1) 205 if ([[ []() -> decltype(a) { return 1; } ]] () == 4) 206 a = a + 1; 207 if (int a = 1) 208 if ([[ [](int x = decltype(a){}) { return 1; } ]] () == 4) 209 a = a + 1; 210 if (int a = 1) 211 if ([[ [](decltype(a) x) { return 1; } ]] (42) == 4) 212 a = a + 1; 213 } 214 )cpp"; 215 EXPECT_UNAVAILABLE(UnavailableCases); 216 217 ExtraArgs = {"-std=c++20"}; 218 const char *UnavailableCasesCXX20 = R"cpp( 219 template <typename T> 220 concept Constraint = requires (T t) { true; }; 221 void foo() { 222 // lambdas: referencing outside variables that block extraction 223 // in requires clause or defaulted explicit template parameters 224 if (int a = 1) 225 if ([[ [](auto b) requires (Constraint<decltype(a)> && Constraint<decltype(b)>) { return true; } ]] (a)) 226 a = a + 1; 227 228 if (int a = 1) 229 if ([[ []<typename T = decltype(a)>(T b) { return true; } ]] (a)) 230 a = a + 1; 231 } 232 )cpp"; 233 EXPECT_UNAVAILABLE(UnavailableCasesCXX20); 234 ExtraArgs.clear(); 235 236 // vector of pairs of input and output strings 237 std::vector<std::pair<std::string, std::string>> InputOutputs = { 238 // extraction from variable declaration/assignment 239 {R"cpp(void varDecl() { 240 int a = 5 * (4 + (3 [[- 1)]]); 241 })cpp", 242 R"cpp(void varDecl() { 243 auto placeholder = (3 - 1); int a = 5 * (4 + placeholder); 244 })cpp"}, 245 // FIXME: extraction from switch case 246 /*{R"cpp(void f(int a) { 247 if(1) 248 while(a < 1) 249 switch (1) { 250 case 1: 251 a = [[1 + 2]]; 252 break; 253 default: 254 break; 255 } 256 })cpp", 257 R"cpp(void f(int a) { 258 auto placeholder = 1 + 2; if(1) 259 while(a < 1) 260 switch (1) { 261 case 1: 262 a = placeholder; 263 break; 264 default: 265 break; 266 } 267 })cpp"},*/ 268 // Macros 269 {R"cpp(#define PLUS(x) x++ 270 void f(int a) { 271 int y = PLUS([[1+a]]); 272 })cpp", 273 /*FIXME: It should be extracted like this. 274 R"cpp(#define PLUS(x) x++ 275 void f(int a) { 276 auto placeholder = 1+a; int y = PLUS(placeholder); 277 })cpp"},*/ 278 R"cpp(#define PLUS(x) x++ 279 void f(int a) { 280 auto placeholder = PLUS(1+a); int y = placeholder; 281 })cpp"}, 282 // ensure InsertionPoint isn't inside a macro 283 {R"cpp(#define LOOP(x) while (1) {a = x;} 284 void f(int a) { 285 if(1) 286 LOOP(5 + [[3]]) 287 })cpp", 288 R"cpp(#define LOOP(x) while (1) {a = x;} 289 void f(int a) { 290 auto placeholder = 3; if(1) 291 LOOP(5 + placeholder) 292 })cpp"}, 293 {R"cpp(#define LOOP(x) do {x;} while(1); 294 void f(int a) { 295 if(1) 296 LOOP(5 + [[3]]) 297 })cpp", 298 R"cpp(#define LOOP(x) do {x;} while(1); 299 void f(int a) { 300 auto placeholder = 3; if(1) 301 LOOP(5 + placeholder) 302 })cpp"}, 303 // attribute testing 304 {R"cpp(void f(int a) { 305 [ [gsl::suppress("type")] ] for (;;) a = [[1]] + 1; 306 })cpp", 307 R"cpp(void f(int a) { 308 auto placeholder = 1; [ [gsl::suppress("type")] ] for (;;) a = placeholder + 1; 309 })cpp"}, 310 // MemberExpr 311 {R"cpp(class T { 312 T f() { 313 return [[T().f()]].f(); 314 } 315 };)cpp", 316 R"cpp(class T { 317 T f() { 318 auto placeholder = T().f(); return placeholder.f(); 319 } 320 };)cpp"}, 321 // Function DeclRefExpr 322 {R"cpp(int f() { 323 return [[f]](); 324 })cpp", 325 R"cpp(int f() { 326 auto placeholder = f(); return placeholder; 327 })cpp"}, 328 // FIXME: Wrong result for \[\[clang::uninitialized\]\] int b = [[1]]; 329 // since the attr is inside the DeclStmt and the bounds of 330 // DeclStmt don't cover the attribute. 331 332 // Binary subexpressions 333 {R"cpp(void f() { 334 int x = 1 + [[2 + 3 + 4]] + 5; 335 })cpp", 336 R"cpp(void f() { 337 auto placeholder = 2 + 3 + 4; int x = 1 + placeholder + 5; 338 })cpp"}, 339 {R"cpp(void f() { 340 int x = [[1 + 2 + 3]] + 4 + 5; 341 })cpp", 342 R"cpp(void f() { 343 auto placeholder = 1 + 2 + 3; int x = placeholder + 4 + 5; 344 })cpp"}, 345 {R"cpp(void f() { 346 int x = 1 + 2 + [[3 + 4 + 5]]; 347 })cpp", 348 R"cpp(void f() { 349 auto placeholder = 3 + 4 + 5; int x = 1 + 2 + placeholder; 350 })cpp"}, 351 // Non-associative operations have no special support 352 {R"cpp(void f() { 353 int x = 1 - [[2 - 3 - 4]] - 5; 354 })cpp", 355 R"cpp(void f() { 356 auto placeholder = 1 - 2 - 3 - 4; int x = placeholder - 5; 357 })cpp"}, 358 // A mix of associative operators isn't associative. 359 {R"cpp(void f() { 360 int x = 0 + 1 * [[2 + 3]] * 4 + 5; 361 })cpp", 362 R"cpp(void f() { 363 auto placeholder = 1 * 2 + 3 * 4; int x = 0 + placeholder + 5; 364 })cpp"}, 365 // Overloaded operators are supported, we assume associativity 366 // as if they were built-in. 367 {R"cpp(struct S { 368 S(int); 369 }; 370 S operator+(S, S); 371 372 void f() { 373 S x = S(1) + [[S(2) + S(3) + S(4)]] + S(5); 374 })cpp", 375 R"cpp(struct S { 376 S(int); 377 }; 378 S operator+(S, S); 379 380 void f() { 381 auto placeholder = S(2) + S(3) + S(4); S x = S(1) + placeholder + S(5); 382 })cpp"}, 383 // lambda expressions 384 {R"cpp(template <typename T> void f(T) {} 385 void f2() { 386 f([[ [](){ return 42; }]]); 387 } 388 )cpp", 389 R"cpp(template <typename T> void f(T) {} 390 void f2() { 391 auto placeholder = [](){ return 42; }; f( placeholder); 392 } 393 )cpp"}, 394 {R"cpp(template <typename T> void f(T) {} 395 void f2() { 396 f([x = [[40 + 2]] ](){ return 42; }); 397 } 398 )cpp", 399 R"cpp(template <typename T> void f(T) {} 400 void f2() { 401 auto placeholder = 40 + 2; f([x = placeholder ](){ return 42; }); 402 } 403 )cpp"}, 404 {R"cpp(auto foo(int VarA) { 405 return [VarA]() { 406 return [[ [VarA, VarC = 42 + VarA](int VarB) { return VarA + VarB + VarC; }]]; 407 }; 408 } 409 )cpp", 410 R"cpp(auto foo(int VarA) { 411 return [VarA]() { 412 auto placeholder = [VarA, VarC = 42 + VarA](int VarB) { return VarA + VarB + VarC; }; return placeholder; 413 }; 414 } 415 )cpp"}, 416 {R"cpp(template <typename T> void f(T) {} 417 void f2(int var) { 418 f([[ [&var](){ auto internal_val = 42; return var + internal_val; }]]); 419 } 420 )cpp", 421 R"cpp(template <typename T> void f(T) {} 422 void f2(int var) { 423 auto placeholder = [&var](){ auto internal_val = 42; return var + internal_val; }; f( placeholder); 424 } 425 )cpp"}, 426 {R"cpp(template <typename T> void f(T) { } 427 struct A { 428 void f2(int& var) { 429 auto local_var = 42; 430 f([[ [&var, &local_var, this]() { 431 auto internal_val = 42; 432 return var + local_var + internal_val + member; 433 }]]); 434 } 435 436 int member = 42; 437 }; 438 )cpp", 439 R"cpp(template <typename T> void f(T) { } 440 struct A { 441 void f2(int& var) { 442 auto local_var = 42; 443 auto placeholder = [&var, &local_var, this]() { 444 auto internal_val = 42; 445 return var + local_var + internal_val + member; 446 }; f( placeholder); 447 } 448 449 int member = 42; 450 }; 451 )cpp"}, 452 {R"cpp(void f() { auto x = +[[ [](){ return 42; }]]; })cpp", 453 R"cpp(void f() { auto placeholder = [](){ return 42; }; auto x = + placeholder; })cpp"}, 454 {R"cpp( 455 template <typename T> 456 auto sink(T f) { return f(); } 457 int bar() { 458 return sink([[ []() { return 42; }]]); 459 } 460 )cpp", 461 R"cpp( 462 template <typename T> 463 auto sink(T f) { return f(); } 464 int bar() { 465 auto placeholder = []() { return 42; }; return sink( placeholder); 466 } 467 )cpp"}, 468 {R"cpp( 469 int main() { 470 if (int a = 1) { 471 if ([[ [&](){ return a + 1; } ]]() == 4) 472 a = a + 1; 473 } 474 })cpp", 475 R"cpp( 476 int main() { 477 if (int a = 1) { 478 auto placeholder = [&](){ return a + 1; }; if ( placeholder () == 4) 479 a = a + 1; 480 } 481 })cpp"}, 482 {R"cpp( 483 int main() { 484 if (int a = 1) { 485 if ([[ [&](){ return a + 1; }() ]] == 4) 486 a = a + 1; 487 } 488 })cpp", 489 R"cpp( 490 int main() { 491 if (int a = 1) { 492 auto placeholder = [&](){ return a + 1; }(); if ( placeholder == 4) 493 a = a + 1; 494 } 495 })cpp"}, 496 {R"cpp( 497 int func() { return 0; } 498 int main() { 499 [[func()]]; 500 })cpp", 501 R"cpp( 502 int func() { return 0; } 503 int main() { 504 auto placeholder = func(); 505 })cpp"}, 506 {R"cpp( 507 template <typename T> 508 auto call(T t) { return t(); } 509 510 int main() { 511 return [[ call([](){ int a = 1; return a + 1; }) ]] + 5; 512 })cpp", 513 R"cpp( 514 template <typename T> 515 auto call(T t) { return t(); } 516 517 int main() { 518 auto placeholder = call([](){ int a = 1; return a + 1; }); return placeholder + 5; 519 })cpp"}, 520 {R"cpp( 521 class Foo { 522 int bar() { 523 return [f = [[ [this](int g) { return g + x; } ]] ]() { return 42; }(); 524 } 525 int x; 526 }; 527 )cpp", 528 R"cpp( 529 class Foo { 530 int bar() { 531 auto placeholder = [this](int g) { return g + x; }; return [f = placeholder ]() { return 42; }(); 532 } 533 int x; 534 }; 535 )cpp"}, 536 {R"cpp( 537 int main() { 538 return [[ []() { return 42; }() ]]; 539 })cpp", 540 R"cpp( 541 int main() { 542 auto placeholder = []() { return 42; }(); return placeholder ; 543 })cpp"}, 544 {R"cpp( 545 template <typename ...Ts> 546 void foo(Ts ...args) { 547 auto x = +[[ [&args...]() {} ]]; 548 } 549 )cpp", 550 R"cpp( 551 template <typename ...Ts> 552 void foo(Ts ...args) { 553 auto placeholder = [&args...]() {}; auto x = + placeholder ; 554 } 555 )cpp"}, 556 {R"cpp( 557 struct Coordinates { 558 int x{}; 559 int y{}; 560 }; 561 562 int main() { 563 Coordinates c = {}; 564 const auto [x, y] = c; 565 auto f = [[ [&]() { return x + y; } ]](); 566 } 567 )cpp", 568 R"cpp( 569 struct Coordinates { 570 int x{}; 571 int y{}; 572 }; 573 574 int main() { 575 Coordinates c = {}; 576 const auto [x, y] = c; 577 auto placeholder = [&]() { return x + y; }; auto f = placeholder (); 578 } 579 )cpp"}, 580 {R"cpp( 581 struct Coordinates { 582 int x{}; 583 int y{}; 584 }; 585 586 int main() { 587 Coordinates c = {}; 588 if (const auto [x, y] = c; x > y) { 589 auto f = [[ [&]() { return x + y; } ]](); 590 } 591 } 592 )cpp", 593 R"cpp( 594 struct Coordinates { 595 int x{}; 596 int y{}; 597 }; 598 599 int main() { 600 Coordinates c = {}; 601 if (const auto [x, y] = c; x > y) { 602 auto placeholder = [&]() { return x + y; }; auto f = placeholder (); 603 } 604 } 605 )cpp"}, 606 // Don't try to analyze across macro boundaries 607 // FIXME: it'd be nice to do this someday (in a safe way) 608 {R"cpp(#define ECHO(X) X 609 void f() { 610 int x = 1 + [[ECHO(2 + 3) + 4]] + 5; 611 })cpp", 612 R"cpp(#define ECHO(X) X 613 void f() { 614 auto placeholder = 1 + ECHO(2 + 3) + 4; int x = placeholder + 5; 615 })cpp"}, 616 {R"cpp(#define ECHO(X) X 617 void f() { 618 int x = 1 + [[ECHO(2) + ECHO(3) + 4]] + 5; 619 })cpp", 620 R"cpp(#define ECHO(X) X 621 void f() { 622 auto placeholder = 1 + ECHO(2) + ECHO(3) + 4; int x = placeholder + 5; 623 })cpp"}, 624 }; 625 for (const auto &IO : InputOutputs) { 626 EXPECT_EQ(IO.second, apply(IO.first)) << IO.first; 627 } 628 629 ExtraArgs = {"-xc"}; 630 InputOutputs = { 631 // Function Pointers 632 {R"cpp(struct Handlers { 633 void (*handlerFunc)(int); 634 }; 635 void runFunction(void (*func)(int)) {} 636 void f(struct Handlers *handler) { 637 runFunction([[handler->handlerFunc]]); 638 })cpp", 639 R"cpp(struct Handlers { 640 void (*handlerFunc)(int); 641 }; 642 void runFunction(void (*func)(int)) {} 643 void f(struct Handlers *handler) { 644 void (*placeholder)(int) = handler->handlerFunc; runFunction(placeholder); 645 })cpp"}, 646 {R"cpp(int (*foo(char))(int); 647 void bar() { 648 (void)[[foo('c')]]; 649 })cpp", 650 R"cpp(int (*foo(char))(int); 651 void bar() { 652 int (*placeholder)(int) = foo('c'); (void)placeholder; 653 })cpp"}, 654 // Arithmetic on typedef types preserves typedef types 655 {R"cpp(typedef long NSInteger; 656 void varDecl() { 657 NSInteger a = 2 * 5; 658 NSInteger b = [[a * 7]] + 3; 659 })cpp", 660 R"cpp(typedef long NSInteger; 661 void varDecl() { 662 NSInteger a = 2 * 5; 663 NSInteger placeholder = a * 7; NSInteger b = placeholder + 3; 664 })cpp"}, 665 }; 666 for (const auto &IO : InputOutputs) { 667 EXPECT_EQ(IO.second, apply(IO.first)) << IO.first; 668 } 669 670 ExtraArgs = {"-xobjective-c"}; 671 EXPECT_UNAVAILABLE(R"cpp( 672 __attribute__((objc_root_class)) 673 @interface Foo 674 - (void)setMethod1:(int)a; 675 - (int)method1; 676 @property int prop1; 677 @end 678 @implementation Foo 679 - (void)method { 680 [[self.method1]] = 1; 681 [[self.method1]] += 1; 682 [[self.prop1]] = 1; 683 [[self.prop1]] += 1; 684 } 685 @end)cpp"); 686 InputOutputs = { 687 // Support ObjC property references (explicit property getter). 688 {R"cpp(__attribute__((objc_root_class)) 689 @interface Foo 690 @property int prop1; 691 @end 692 @implementation Foo 693 - (void)method { 694 int x = [[self.prop1]] + 1; 695 } 696 @end)cpp", 697 R"cpp(__attribute__((objc_root_class)) 698 @interface Foo 699 @property int prop1; 700 @end 701 @implementation Foo 702 - (void)method { 703 int placeholder = self.prop1; int x = placeholder + 1; 704 } 705 @end)cpp"}, 706 // Support ObjC property references (implicit property getter). 707 {R"cpp(__attribute__((objc_root_class)) 708 @interface Foo 709 - (int)method1; 710 @end 711 @implementation Foo 712 - (void)method { 713 int x = [[self.method1]] + 1; 714 } 715 @end)cpp", 716 R"cpp(__attribute__((objc_root_class)) 717 @interface Foo 718 - (int)method1; 719 @end 720 @implementation Foo 721 - (void)method { 722 int placeholder = self.method1; int x = placeholder + 1; 723 } 724 @end)cpp"}, 725 }; 726 for (const auto &IO : InputOutputs) { 727 EXPECT_EQ(IO.second, apply(IO.first)) << IO.first; 728 } 729 } 730 731 } // namespace 732 } // namespace clangd 733 } // namespace clang 734