diff options
Diffstat (limited to 'clang-tools-extra/test')
| -rw-r--r-- | clang-tools-extra/test/clang-tidy/checkers/modernize-avoid-bind-permissive-parameter-list.cpp | 58 | ||||
| -rw-r--r-- | clang-tools-extra/test/clang-tidy/checkers/modernize-avoid-bind.cpp | 304 |
2 files changed, 305 insertions, 57 deletions
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize-avoid-bind-permissive-parameter-list.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize-avoid-bind-permissive-parameter-list.cpp new file mode 100644 index 00000000000..6c81a6e9ab9 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/modernize-avoid-bind-permissive-parameter-list.cpp @@ -0,0 +1,58 @@ +// RUN: %check_clang_tidy -std=c++14-or-later %s modernize-avoid-bind %t -- \ +// RUN: -config="{CheckOptions: [ \ +// RUN: {key: modernize-avoid-bind.PermissiveParameterList, value: 1}]}" -- + +namespace std { +inline namespace impl { +template <class Fp, class... Arguments> +class bind_rt {}; + +template <class Fp, class... Arguments> +bind_rt<Fp, Arguments...> bind(Fp &&, Arguments &&...); +} // namespace impl + +template <typename T> +T ref(T &t); +} // namespace std + +int add(int x, int y) { return x + y; } + +// Let's fake a minimal std::function-like facility. +namespace std { +template <typename _Tp> +_Tp declval(); + +template <typename _Functor, typename... _ArgTypes> +struct __res { + template <typename... _Args> + static decltype(declval<_Functor>()(_Args()...)) _S_test(int); + + template <typename...> + static void _S_test(...); + + using type = decltype(_S_test<_ArgTypes...>(0)); +}; + +template <typename> +struct function; + +template <typename... _ArgTypes> +struct function<void(_ArgTypes...)> { + template <typename _Functor, + typename = typename __res<_Functor, _ArgTypes...>::type> + function(_Functor) {} +}; +} // namespace std + +struct placeholder {}; +placeholder _1; + +void testLiteralParameters() { + auto AAA = std::bind(add, 2, 2); + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind [modernize-avoid-bind] + // CHECK-FIXES: auto AAA = [](auto && ...) { return add(2, 2); }; + + auto BBB = std::bind(add, _1, 2); + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind [modernize-avoid-bind] + // CHECK-FIXES: auto BBB = [](auto && PH1, auto && ...) { return add(PH1, 2); }; +} diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize-avoid-bind.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize-avoid-bind.cpp index fa60cdc2c9d..7e00858c1ac 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/modernize-avoid-bind.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/modernize-avoid-bind.cpp @@ -8,75 +8,62 @@ class bind_rt {}; template <class Fp, class... Arguments> bind_rt<Fp, Arguments...> bind(Fp &&, Arguments &&...); } + +template <typename T> +T ref(T &t); } -int add(int x, int y) { return x + y; } +namespace boost { +template <class Fp, class... Arguments> +class bind_rt {}; -void f() { - auto clj = std::bind(add, 2, 2); - // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind [modernize-avoid-bind] - // CHECK-FIXES: auto clj = [] { return add(2, 2); }; -} +template <class Fp, class... Arguments> +bind_rt<Fp, Arguments...> bind(const Fp &, Arguments...); -void g() { - int x = 2; - int y = 2; - auto clj = std::bind(add, x, y); - // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind - // CHECK-FIXES: auto clj = [=] { return add(x, y); }; +template <class T> +struct reference_wrapper { + explicit reference_wrapper(T &t) {} +}; + +template <class T> +reference_wrapper<T> const ref(T &t) { + return reference_wrapper<T>(t); } -struct placeholder {}; -placeholder _1; -placeholder _2; +} // namespace boost -void h() { - int x = 2; - auto clj = std::bind(add, x, _1); - // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind - // CHECK-FIXES: auto clj = [=](auto && arg1) { return add(x, arg1); }; -} +namespace C { +int add(int x, int y) { return x + y; } +} // namespace C -struct A; -struct B; -bool ABTest(const A &, const B &); +struct Foo { + static int add(int x, int y) { return x + y; } +}; -void i() { - auto BATest = std::bind(ABTest, _2, _1); - // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: prefer a lambda to std::bind - // CHECK-FIXES: auto BATest = [](auto && arg1, auto && arg2) { return ABTest(arg2, arg1); }; -} +struct D { + D() = default; + void operator()(int x, int y) const {} -void j() { - auto clj = std::bind(add, 2, 2, 2); - // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind - // No fix is applied for argument mismatches. - // CHECK-FIXES: auto clj = std::bind(add, 2, 2, 2); -} + void MemberFunction(int x) {} -void k() { - auto clj = std::bind(add, _1, _1); - // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind - // No fix is applied for reused placeholders. - // CHECK-FIXES: auto clj = std::bind(add, _1, _1); -} + static D *create(); +}; -void m() { - auto clj = std::bind(add, 1, add(2, 5)); - // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind - // No fix is applied for nested calls. - // CHECK-FIXES: auto clj = std::bind(add, 1, add(2, 5)); -} +struct F { + F(int x) {} + ~F() {} -namespace C { - int add(int x, int y){ return x + y; } -} + int get() { return 42; } +}; -void n() { - auto clj = std::bind(C::add, 1, 1); - // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind - // CHECK-FIXES: auto clj = [] { return C::add(1, 1); }; -} +void UseF(F); + +struct placeholder {}; +placeholder _1; +placeholder _2; + +int add(int x, int y) { return x + y; } +int addThree(int x, int y, int z) { return x + y + z; } // Let's fake a minimal std::function-like facility. namespace std { @@ -114,10 +101,213 @@ struct Callback { void Reset(std::function<void()>); }; -void test(Thing *t) { +int GlobalVariable = 42; + +struct TestCaptureByValueStruct { + int MemberVariable; + static int StaticMemberVariable; + F MemberStruct; + + void testCaptureByValue(int Param, F f) { + int x = 3; + int y = 4; + auto AAA = std::bind(add, x, y); + // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: prefer a lambda to std::bind [modernize-avoid-bind] + // CHECK-FIXES: auto AAA = [x, y] { return add(x, y); }; + + // When the captured variable is repeated, it should only appear in the capture list once. + auto BBB = std::bind(add, x, x); + // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: prefer a lambda to std::bind [modernize-avoid-bind] + // CHECK-FIXES: auto BBB = [x] { return add(x, x); }; + + int LocalVariable; + // Global variables shouldn't be captured at all, and members should be captured through this. + auto CCC = std::bind(add, MemberVariable, GlobalVariable); + // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: prefer a lambda to std::bind [modernize-avoid-bind] + // CHECK-FIXES: auto CCC = [this] { return add(MemberVariable, GlobalVariable); }; + + // Static member variables shouldn't be captured, but locals should + auto DDD = std::bind(add, TestCaptureByValueStruct::StaticMemberVariable, LocalVariable); + // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: prefer a lambda to std::bind [modernize-avoid-bind] + // CHECK-FIXES: auto DDD = [LocalVariable] { return add(TestCaptureByValueStruct::StaticMemberVariable, LocalVariable); }; + + auto EEE = std::bind(add, Param, Param); + // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: prefer a lambda to std::bind [modernize-avoid-bind] + // CHECK-FIXES: auto EEE = [Param] { return add(Param, Param); }; + + // The signature of boost::bind() is different, and causes + // CXXBindTemporaryExprs to be created in certain cases. So let's test + // those here. + auto FFF = boost::bind(UseF, f); + // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: prefer a lambda to boost::bind [modernize-avoid-bind] + // CHECK-FIXES: auto FFF = [f] { return UseF(f); }; + + auto GGG = boost::bind(UseF, MemberStruct); + // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: prefer a lambda to boost::bind [modernize-avoid-bind] + // CHECK-FIXES: auto GGG = [this] { return UseF(MemberStruct); }; + } +}; + +void testLiteralParameters() { + auto AAA = std::bind(add, 2, 2); + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind [modernize-avoid-bind] + // CHECK-FIXES: auto AAA = [] { return add(2, 2); }; + + auto BBB = std::bind(addThree, 2, 3, 4); + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind [modernize-avoid-bind] + // CHECK-FIXES: auto BBB = [] { return addThree(2, 3, 4); }; +} + +void testCaptureByReference() { + int x = 2; + int y = 2; + auto AAA = std::bind(add, std::ref(x), std::ref(y)); + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind + // CHECK-FIXES: auto AAA = [&x, &y] { return add(x, y); }; + + auto BBB = std::bind(add, std::ref(x), y); + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind + // CHECK-FIXES: auto BBB = [&x, y] { return add(x, y); }; + + auto CCC = std::bind(add, y, std::ref(x)); + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind + // CHECK-FIXES: auto CCC = [y, &x] { return add(y, x); }; + + // Make sure it works with boost::ref() too which has slightly different + // semantics. + auto DDD = boost::bind(add, boost::ref(x), boost::ref(y)); + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to boost::bind + // CHECK-FIXES: auto DDD = [&x, &y] { return add(x, y); }; + + auto EEE = boost::bind(add, boost::ref(x), y); + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to boost::bind + // CHECK-FIXES: auto EEE = [&x, y] { return add(x, y); }; + + auto FFF = boost::bind(add, y, boost::ref(x)); + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to boost::bind + // CHECK-FIXES: auto FFF = [y, &x] { return add(y, x); }; +} + +void testCaptureByInitExpression() { + int x = 42; + auto AAA = std::bind(add, x, F(x).get()); + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind + // CHECK-FIXES: auto AAA = [x, capture0 = F(x).get()] { return add(x, capture0); }; +} + +void testFunctionObjects() { + D d; + D *e = nullptr; + auto AAA = std::bind(d, 1, 2); + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind + // CHECK-FIXES: auto AAA = [d] { return d(1, 2); } + + auto BBB = std::bind(*e, 1, 2); + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind + // CHECK-FIXES: auto BBB = [e] { return (*e)(1, 2); } + + auto CCC = std::bind(D{}, 1, 2); + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind + // CHECK-FIXES: auto CCC = [] { return D{}(1, 2); } + + auto DDD = std::bind(D(), 1, 2); + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind + // CHECK-FIXES: auto DDD = [] { return D()(1, 2); } + + auto EEE = std::bind(*D::create(), 1, 2); + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind + // CHECK-FIXES: auto EEE = [Func = *D::create()] { return Func(1, 2); }; +} + +void testPlaceholders() { + int x = 2; + auto AAA = std::bind(add, x, _1); + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind + // CHECK-FIXES: auto AAA = [x](auto && PH1) { return add(x, PH1); }; + + auto BBB = std::bind(add, _2, _1); + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind + // CHECK-FIXES: auto BBB = [](auto && PH1, auto && PH2) { return add(PH2, PH1); }; + + // No fix is applied for reused placeholders. + auto CCC = std::bind(add, _1, _1); + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind + // CHECK-FIXES: auto CCC = std::bind(add, _1, _1); + + // When a placeholder is skipped, we always add skipped ones to the lambda as + // unnamed parameters. + auto DDD = std::bind(add, _2, 1); + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind + // CHECK-FIXES: auto DDD = [](auto &&, auto && PH2) { return add(PH2, 1); }; +} + +void testGlobalFunctions() { + auto AAA = std::bind(C::add, 1, 1); + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind + // CHECK-FIXES: auto AAA = [] { return C::add(1, 1); }; + + auto BBB = std::bind(Foo::add, 1, 1); + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind + // CHECK-FIXES: auto BBB = [] { return Foo::add(1, 1); }; + + // The & should get removed inside of the lambda body. + auto CCC = std::bind(&C::add, 1, 1); + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind + // CHECK-FIXES: auto CCC = [] { return C::add(1, 1); }; + + auto DDD = std::bind(&Foo::add, 1, 1); + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind + // CHECK-FIXES: auto DDD = [] { return Foo::add(1, 1); }; + + auto EEE = std::bind(&add, 1, 1); + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind + // CHECK-FIXES: auto EEE = [] { return add(1, 1); }; +} + +void testCapturedSubexpressions() { + int x = 3; + int y = 3; + + auto AAA = std::bind(add, 1, add(2, 5)); + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind + // Results of nested calls are captured by value. + // CHECK-FIXES: auto AAA = [capture0 = add(2, 5)] { return add(1, capture0); }; + + auto BBB = std::bind(add, x, add(y, 5)); + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind + // Results of nested calls are captured by value. + // CHECK-FIXES: auto BBB = [x, capture0 = add(y, 5)] { return add(x, capture0); }; +} + +struct E { + void MemberFunction(int x) {} + + void testMemberFunctions() { + D *d; + D dd; + auto AAA = std::bind(&D::MemberFunction, d, 1); + // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: prefer a lambda to std::bind + // CHECK-FIXES: auto AAA = [d] { d->MemberFunction(1); }; + + auto BBB = std::bind(&D::MemberFunction, &dd, 1); + // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: prefer a lambda to std::bind + // CHECK-FIXES: auto BBB = [ObjectPtr = &dd] { ObjectPtr->MemberFunction(1); }; + + auto CCC = std::bind(&E::MemberFunction, this, 1); + // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: prefer a lambda to std::bind + // CHECK-FIXES: auto CCC = [this] { MemberFunction(1); }; + + // Test what happens when the object pointer is itself a placeholder. + auto DDD = std::bind(&D::MemberFunction, _1, 1); + // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: prefer a lambda to std::bind + // CHECK-FIXES: auto DDD = [](auto && PH1) { PH1->MemberFunction(1); }; + } +}; + +void testStdFunction(Thing *t) { Callback cb; if (t) cb.Reset(std::bind(UseThing, t)); // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind - // CHECK-FIXES: cb.Reset([=] { return UseThing(t); }); + // CHECK-FIXES: cb.Reset([t] { return UseThing(t); }); } |

