summaryrefslogtreecommitdiffstats
path: root/clang-tools-extra/test
diff options
context:
space:
mode:
Diffstat (limited to 'clang-tools-extra/test')
-rw-r--r--clang-tools-extra/test/clang-tidy/checkers/modernize-avoid-bind-permissive-parameter-list.cpp58
-rw-r--r--clang-tools-extra/test/clang-tidy/checkers/modernize-avoid-bind.cpp304
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); });
}
OpenPOWER on IntegriCloud