brintos

brintos / llvm-project-archived public Read only

0
0
Text · 21.8 KiB · 3c65a58 Raw
735 lines · cpp
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-exception6//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 statement27      return [[[[t.b[[a]]r]]([[t.z]])]];28    }29    void f() {30      int a = 5 + [[4 * [[[[xyz]]()]]]];31      // multivariable initialization32      if(1)33        int x = [[1]] + 1, y = a + [[1]], a = [[1]] + 2, z = a + 1;34      // if without else35      if([[1]])36        a = [[1]] + 1;37      // if with else38      if(a < [[3]])39        if(a == [[4]])40          a = [[5]] + 1;41        else42          a = [[5]] + 1;43      else if (a < [[4]])44        a = [[4]] + 1;45      else46        a = [[5]] + 1;47      // for loop48      for(a = [[1]] + 1; a > [[[[3]] + [[4]]]]; a++)49        a = [[2]] + 1;50      // while51      while(a < [[1]])52        a = [[1]] + 1;53      // do while54      do55        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 crash71    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 Foo95    @end96    @implementation Foo97    - (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 crash106    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 argument131    void f(int b = [[1]]) {132      // empty selection133      int a = ^1 ^+ ^2;134      // void expressions135      auto i = new int, j = new int;136      [[[[delete i]], delete j]];137      [[v]]();138      // if139      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 loop145      for(int a = 1, b = 2, c = 3; a > [[b + c]]; [[a++]])146        a = [[a + 1]];147      // lambda148      auto lamb = [&[[a]], &[[b]]](int r = [[1]]) {return 1;};149      // assignment150      xyz([[a = 5]]);151      xyz([[a *= 5]]);152      // Variable DeclRefExpr153      a = [[b]];154      a = [[xyz()]];155      // expression statement of type void156      [[v()]];157      while (a)158        [[++a]];159      // label statement160      goto label;161      label:162        a = [[1]];163 164      // lambdas: captures165      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 scope174      [](int x = [[10]]){};175      [](auto h = [[ [i = [](){}](){} ]]) {};176 177      // lambdas: default args178      // Extracting from capture initializers is usually fine,179      // but not if the capture itself is nested inside a default argument180      [](auto h = [i = [[ [](){} ]]](){}) {};181      [](auto h = [i = [[ 42 ]]](){}) {};182 183      // lambdas: scope184      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 binding194      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 extraction203      //          in trailing return type or in a decltype used204      //          by a parameter205      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 extraction224      //          in requires clause or defaulted explicit template parameters225      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 strings238  std::vector<std::pair<std::string, std::string>> InputOutputs = {239      // extraction from variable declaration/assignment240      {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 case247      /*{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      // Macros270      {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 macro284      {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 testing305      {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      // MemberExpr312      {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 DeclRefExpr323      {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 of331      // DeclStmt don't cover the attribute.332 333      // Binary subexpressions334      {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 support353      {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 associativity367      // 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 expressions385      {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 boundaries608      // FIXME: it'd be nice to do this someday (in a safe way)609      {R"cpp(#define ECHO(X) X610                 void f() {611                   int x = 1 + [[ECHO(2 + 3) + 4]] + 5;612                 })cpp",613       R"cpp(#define ECHO(X) X614                 void f() {615                   auto placeholder = 1 + ECHO(2 + 3) + 4; int x = placeholder + 5;616                 })cpp"},617      {R"cpp(#define ECHO(X) X618                 void f() {619                   int x = 1 + [[ECHO(2) + ECHO(3) + 4]] + 5;620                 })cpp",621       R"cpp(#define ECHO(X) X622                 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 Pointers633      {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 types656      {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 Foo675      - (void)setMethod1:(int)a;676      - (int)method1;677      @property int prop1;678      @end679      @implementation Foo680      - (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 Foo691             @property int prop1;692             @end693             @implementation Foo694             - (void)method {695               int x = [[self.prop1]] + 1;696             }697             @end)cpp",698       R"cpp(__attribute__((objc_root_class))699             @interface Foo700             @property int prop1;701             @end702             @implementation Foo703             - (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 Foo710             - (int)method1;711             @end712             @implementation Foo713             - (void)method {714               int x = [[self.method1]] + 1;715             }716             @end)cpp",717       R"cpp(__attribute__((objc_root_class))718             @interface Foo719             - (int)method1;720             @end721             @implementation Foo722             - (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} // namespace733} // namespace clangd734} // namespace clang735