xref: /llvm-project/clang-tools-extra/clangd/unittests/tweaks/ExtractVariableTests.cpp (revision 8d714db7f9617252401f85537d672c5b92c20557)
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