brintos

brintos / llvm-project-archived public Read only

0
0
Text · 14.8 KiB · 6aa7d48 Raw
414 lines · cpp
1// RUN: %check_clang_tidy -std=c++14-or-later %s modernize-avoid-bind %t2 3namespace std {4inline namespace impl {5template <class Fp, class... Arguments>6class bind_rt {};7 8template <class Fp, class... Arguments>9bind_rt<Fp, Arguments...> bind(Fp &&, Arguments &&...);10} // namespace impl11 12template <typename T>13T ref(T &t);14} // namespace std15 16namespace boost {17template <class Fp, class... Arguments>18class bind_rt {};19 20template <class Fp, class... Arguments>21bind_rt<Fp, Arguments...> bind(const Fp &, Arguments...);22 23template <class T>24struct reference_wrapper {25  explicit reference_wrapper(T &t) {}26};27 28template <class T>29reference_wrapper<T> const ref(T &t) {30  return reference_wrapper<T>(t);31}32 33} // namespace boost34 35namespace C {36int add(int x, int y) { return x + y; }37} // namespace C38 39struct Foo {40  static int add(int x, int y) { return x + y; }41};42 43struct D {44  D() = default;45  void operator()(int x, int y) const {}46  operator bool() const { return true; }47 48  void MemberFunction(int x) {}49  int MemberFunctionWithReturn(int x) { return 0; }50 51  static D *create();52};53 54struct F {55  F(int x) {}56  ~F() {}57 58  int get() { return 42; }59};60 61void UseF(F);62 63struct G {64  G() : _member(0) {}65  G(int m) : _member(m) {}66 67  template <typename T>68  void operator()(T) const {}69 70  int _member;71};72 73template <typename T>74struct H {75  void operator()(T) const {};76};77 78struct placeholder {};79placeholder _1;80placeholder _2;81 82namespace placeholders {83using ::_1;84using ::_2;85} // namespace placeholders86 87int add(int x, int y) { return x + y; }88int addThree(int x, int y, int z) { return x + y + z; }89void sub(int &x, int y) { x += y; }90 91// Let's fake a minimal std::function-like facility.92namespace std {93template <typename _Tp>94_Tp declval();95 96template <typename _Functor, typename... _ArgTypes>97struct __res {98  template <typename... _Args>99  static decltype(declval<_Functor>()(_Args()...)) _S_test(int);100 101  template <typename...>102  static void _S_test(...);103 104  using type = decltype(_S_test<_ArgTypes...>(0));105};106 107template <typename>108struct function;109 110template <typename... _ArgTypes>111struct function<void(_ArgTypes...)> {112  template <typename _Functor,113            typename = typename __res<_Functor, _ArgTypes...>::type>114  function(_Functor) {}115};116} // namespace std117 118struct Thing {};119void UseThing(Thing *);120 121struct Callback {122  Callback();123  Callback(std::function<void()>);124  void Reset(std::function<void()>);125};126 127int GlobalVariable = 42;128 129struct TestCaptureByValueStruct {130  int MemberVariable;131  static int StaticMemberVariable;132  F MemberStruct;133  G MemberStructWithData;134 135  void testCaptureByValue(int Param, F f) {136    int x = 3;137    int y = 4;138    auto AAA = std::bind(add, x, y);139    // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: prefer a lambda to std::bind [modernize-avoid-bind]140    // CHECK-FIXES: auto AAA = [x, y] { return add(x, y); };141 142    // When the captured variable is repeated, it should only appear in the capture list once.143    auto BBB = std::bind(add, x, x);144    // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: prefer a lambda to std::bind [modernize-avoid-bind]145    // CHECK-FIXES: auto BBB = [x] { return add(x, x); };146 147    int LocalVariable;148    // Global variables shouldn't be captured at all, and members should be captured through this.149    auto CCC = std::bind(add, MemberVariable, GlobalVariable);150    // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: prefer a lambda to std::bind [modernize-avoid-bind]151    // CHECK-FIXES: auto CCC = [this] { return add(MemberVariable, GlobalVariable); };152 153    // Static member variables shouldn't be captured, but locals should154    auto DDD = std::bind(add, TestCaptureByValueStruct::StaticMemberVariable, LocalVariable);155    // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: prefer a lambda to std::bind [modernize-avoid-bind]156    // CHECK-FIXES: auto DDD = [LocalVariable] { return add(TestCaptureByValueStruct::StaticMemberVariable, LocalVariable); };157 158    auto EEE = std::bind(add, Param, Param);159    // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: prefer a lambda to std::bind [modernize-avoid-bind]160    // CHECK-FIXES: auto EEE = [Param] { return add(Param, Param); };161 162    // The signature of boost::bind() is different, and causes163    // CXXBindTemporaryExprs to be created in certain cases.  So let's test164    // those here.165    auto FFF = boost::bind(UseF, f);166    // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: prefer a lambda to boost::bind [modernize-avoid-bind]167    // CHECK-FIXES: auto FFF = [f] { UseF(f); };168 169    auto GGG = boost::bind(UseF, MemberStruct);170    // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: prefer a lambda to boost::bind [modernize-avoid-bind]171    // CHECK-FIXES: auto GGG = [this] { UseF(MemberStruct); };172 173    auto HHH = std::bind(add, MemberStructWithData._member, 1);174    // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: prefer a lambda to std::bind175    // Correctly distinguish data members of other classes176    // CHECK-FIXES: auto HHH = [capture0 = MemberStructWithData._member] { return add(capture0, 1); };177  }178};179 180void testLiteralParameters() {181  auto AAA = std::bind(add, 2, 2);182  // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind [modernize-avoid-bind]183  // CHECK-FIXES: auto AAA = [] { return add(2, 2); };184 185  auto BBB = std::bind(addThree, 2, 3, 4);186  // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind [modernize-avoid-bind]187  // CHECK-FIXES: auto BBB = [] { return addThree(2, 3, 4); };188}189 190void testCaptureByReference() {191  int x = 2;192  int y = 2;193  auto AAA = std::bind(add, std::ref(x), std::ref(y));194  // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind195  // CHECK-FIXES: auto AAA = [&x, &y] { return add(x, y); };196 197  auto BBB = std::bind(add, std::ref(x), y);198  // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind199  // CHECK-FIXES: auto BBB = [&x, y] { return add(x, y); };200 201  auto CCC = std::bind(add, y, std::ref(x));202  // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind203  // CHECK-FIXES: auto CCC = [y, &x] { return add(y, x); };204 205  // Make sure it works with boost::ref() too which has slightly different206  // semantics.207  auto DDD = boost::bind(add, boost::ref(x), boost::ref(y));208  // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to boost::bind209  // CHECK-FIXES: auto DDD = [&x, &y] { return add(x, y); };210 211  auto EEE = boost::bind(add, boost::ref(x), y);212  // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to boost::bind213  // CHECK-FIXES: auto EEE = [&x, y] { return add(x, y); };214 215  auto FFF = boost::bind(add, y, boost::ref(x));216  // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to boost::bind217  // CHECK-FIXES: auto FFF = [y, &x] { return add(y, x); };218}219 220void testCaptureByInitExpression() {221  int x = 42;222  auto AAA = std::bind(add, x, F(x).get());223  // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind224  // CHECK-FIXES: auto AAA = [x, capture0 = F(x).get()] { return add(x, capture0); };225}226 227void testFunctionObjects() {228  D d;229  D *e = nullptr;230  auto AAA = std::bind(d, 1, 2);231  // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind232  // CHECK-FIXES: auto AAA = [d] { d(1, 2); };233 234  auto BBB = std::bind(*e, 1, 2);235  // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind236  // CHECK-FIXES: auto BBB = [e] { (*e)(1, 2); };237 238  auto CCC = std::bind(D{}, 1, 2);239  // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind240  // CHECK-FIXES: auto CCC = [] { D{}(1, 2); };241 242  auto DDD = std::bind(D(), 1, 2);243  // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind244  // CHECK-FIXES: auto DDD = [] { D()(1, 2); };245 246  auto EEE = std::bind(*D::create(), 1, 2);247  // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind248  // CHECK-FIXES: auto EEE = [Func = *D::create()] { Func(1, 2); };249 250  auto FFF = std::bind(G(), 1);251  // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind252  // Templated function call operators may be used253  // CHECK-FIXES: auto FFF = [] { G()(1); };254 255  int CTorArg = 42;256  auto GGG = std::bind(G(CTorArg), 1);257  // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind258  // Function objects with constructor arguments should be captured259  // CHECK-FIXES: auto GGG = [Func = G(CTorArg)] { Func(1); };260}261 262template <typename T>263void testMemberFnOfClassTemplate(T) {264  auto HHH = std::bind(H<T>(), 42);265  // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind266  // Ensure function class template arguments are preserved267  // CHECK-FIXES: auto HHH = [] { H<T>()(42); };268}269 270template void testMemberFnOfClassTemplate(int);271 272void testPlaceholders() {273  int x = 2;274  auto AAA = std::bind(add, x, _1);275  // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind276  // CHECK-FIXES: auto AAA = [x](auto && PH1) { return add(x, std::forward<decltype(PH1)>(PH1)); };277 278  auto BBB = std::bind(add, _2, _1);279  // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind280  // CHECK-FIXES: auto BBB = [](auto && PH1, auto && PH2) { return add(std::forward<decltype(PH2)>(PH2), std::forward<decltype(PH1)>(PH1)); };281 282  // No fix is applied for reused placeholders.283  auto CCC = std::bind(add, _1, _1);284  // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind285  // CHECK-FIXES: auto CCC = std::bind(add, _1, _1);286 287  // When a placeholder is skipped, we always add skipped ones to the lambda as288  // unnamed parameters.289  auto DDD = std::bind(add, _2, 1);290  // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind291  // CHECK-FIXES: auto DDD = [](auto &&, auto && PH2) { return add(std::forward<decltype(PH2)>(PH2), 1); };292 293  // Namespace-qualified placeholders are valid too294  auto EEE = std::bind(add, placeholders::_2, 1);295  // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind296  // CHECK-FIXES: auto EEE = [](auto &&, auto && PH2) { return add(std::forward<decltype(PH2)>(PH2), 1); };297}298 299void testGlobalFunctions() {300  auto AAA = std::bind(C::add, 1, 1);301  // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind302  // CHECK-FIXES: auto AAA = [] { return C::add(1, 1); };303 304  auto BBB = std::bind(Foo::add, 1, 1);305  // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind306  // CHECK-FIXES: auto BBB = [] { return Foo::add(1, 1); };307 308  // The & should get removed inside of the lambda body.309  auto CCC = std::bind(&C::add, 1, 1);310  // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind311  // CHECK-FIXES: auto CCC = [] { return C::add(1, 1); };312 313  auto DDD = std::bind(&Foo::add, 1, 1);314  // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind315  // CHECK-FIXES: auto DDD = [] { return Foo::add(1, 1); };316 317  auto EEE = std::bind(&add, 1, 1);318  // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind319  // CHECK-FIXES: auto EEE = [] { return add(1, 1); };320}321 322void testCapturedSubexpressions() {323  int x = 3;324  int y = 3;325  int *p = &x;326 327  auto AAA = std::bind(add, 1, add(2, 5));328  // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind329  // Results of nested calls are captured by value.330  // CHECK-FIXES: auto AAA = [capture0 = add(2, 5)] { return add(1, capture0); };331 332  auto BBB = std::bind(add, x, add(y, 5));333  // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind334  // Results of nested calls are captured by value.335  // CHECK-FIXES: auto BBB = [x, capture0 = add(y, 5)] { return add(x, capture0); };336 337  auto CCC = std::bind(sub, std::ref(*p), _1);338  // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind339  // Expressions returning references are captured340  // CHECK-FIXES: auto CCC = [&capture0 = *p](auto && PH1) { sub(capture0, std::forward<decltype(PH1)>(PH1)); };341}342 343struct E {344  void MemberFunction(int x) {}345  int MemberFunctionWithReturn(int x) { return 0; }346  int operator()(int x, int y) const { return x + y; }347 348  void testMemberFunctions() {349    D *d;350    D dd;351    auto AAA = std::bind(&D::MemberFunction, d, 1);352    // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: prefer a lambda to std::bind353    // CHECK-FIXES: auto AAA = [d] { d->MemberFunction(1); };354 355    auto BBB = std::bind(&D::MemberFunction, &dd, 1);356    // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: prefer a lambda to std::bind357    // CHECK-FIXES: auto BBB = [ObjectPtr = &dd] { ObjectPtr->MemberFunction(1); };358 359    auto CCC = std::bind(&E::MemberFunction, this, 1);360    // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: prefer a lambda to std::bind361    // CHECK-FIXES: auto CCC = [this] { MemberFunction(1); };362 363    // Test what happens when the object pointer is itself a placeholder.364    auto DDD = std::bind(&D::MemberFunction, _1, 1);365    // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: prefer a lambda to std::bind366    // CHECK-FIXES: auto DDD = [](auto && PH1) { PH1->MemberFunction(1); };367 368    auto EEE = std::bind(&D::MemberFunctionWithReturn, d, 1);369    // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: prefer a lambda to std::bind370    // CHECK-FIXES: auto EEE = [d] { return d->MemberFunctionWithReturn(1); };371 372    auto FFF = std::bind(&D::MemberFunctionWithReturn, &dd, 1);373    // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: prefer a lambda to std::bind374    // CHECK-FIXES: auto FFF = [ObjectPtr = &dd] { return ObjectPtr->MemberFunctionWithReturn(1); };375 376    auto GGG = std::bind(&E::MemberFunctionWithReturn, this, 1);377    // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: prefer a lambda to std::bind378    // CHECK-FIXES: auto GGG = [this] { return MemberFunctionWithReturn(1); };379 380    // Test what happens when the object pointer is itself a placeholder.381    auto HHH = std::bind(&D::MemberFunctionWithReturn, _1, 1);382    // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: prefer a lambda to std::bind383    // CHECK-FIXES: auto HHH = [](auto && PH1) { return PH1->MemberFunctionWithReturn(1); };384 385    auto III = std::bind(&D::operator(), d, 1, 2);386    // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: prefer a lambda to std::bind387    // CHECK-FIXES: auto III = [d] { (*d)(1, 2); };388 389    auto JJJ = std::bind(&D::operator(), &dd, 1, 2);390    // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: prefer a lambda to std::bind391    // CHECK-FIXES: auto JJJ = [ObjectPtr = &dd] { (*ObjectPtr)(1, 2); };392 393    auto KKK = std::bind(&D::operator(), _1, 1, 2);394    // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: prefer a lambda to std::bind395    // CHECK-FIXES: auto KKK = [](auto && PH1) { (*PH1)(1, 2); };396 397    auto LLL = std::bind(&D::operator bool, d);398    // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: prefer a lambda to std::bind399    // CHECK-FIXES: auto LLL = [d] { return d->operator bool(); };400 401    auto MMM = std::bind(&E::operator(), this, 1, 2);402    // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: prefer a lambda to std::bind403    // CHECK-FIXES: auto MMM = [this] { return (*this)(1, 2); };404  }405};406 407void testStdFunction(Thing *t) {408  Callback cb;409  if (t)410    cb.Reset(std::bind(UseThing, t));411  // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind412  // CHECK-FIXES: cb.Reset([t] { UseThing(t); });413}414