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

source code of clang-tools-extra/clangd/unittests/tweaks/ExtractVariableTests.cpp