Index: clang-tools-extra/clang-tidy/modernize/AvoidBindCheck.cpp =================================================================== --- clang-tools-extra/clang-tidy/modernize/AvoidBindCheck.cpp +++ clang-tools-extra/clang-tidy/modernize/AvoidBindCheck.cpp @@ -120,12 +120,10 @@ if (!getLangOpts().CPlusPlus14) // Need C++14 for generic lambdas. return; - Finder->addMatcher( - callExpr( - callee(namedDecl(hasName("::std::bind"))), - hasArgument(0, declRefExpr(to(functionDecl().bind("f"))).bind("ref"))) - .bind("bind"), - this); + Finder->addMatcher(callExpr(callee(namedDecl(hasName("::std::bind"))), + hasArgument(0, expr().bind("ref"))) + .bind("bind"), + this); } void AvoidBindCheck::check(const MatchFinder::MatchResult &Result) { @@ -148,21 +146,27 @@ if (isPlaceHolderIndexRepeated(Args)) return; - const auto *F = Result.Nodes.getNodeAs("f"); - - // std::bind can support argument count mismatch between its arguments and the - // bound function's arguments. Do not attempt to generate a fixit for such - // cases. - // FIXME: Support this case by creating unused lambda capture variables. - if (F->getNumParams() != Args.size()) + const auto *Ref = Result.Nodes.getNodeAs("ref"); + if (Ref) { + const auto *FD = llvm::dyn_cast_or_null(Ref->getFoundDecl()); + + // std::bind can support argument count mismatch between its arguments and + // the bound function's arguments. Do not attempt to generate a fixit for + // such cases. + // FIXME: Support this case by creating unused lambda capture variables. + if (!FD || (FD->getNumParams() != Args.size())) + return; + } else { + // Don't support fixits for generalized call expressions. + // FIXME: Support fixits for member function pointers as well as call objects. return; + } std::string Buffer; llvm::raw_string_ostream Stream(Buffer); bool HasCapturedArgument = llvm::any_of( Args, [](const BindArgument &B) { return B.Kind == BK_Other; }); - const auto *Ref = Result.Nodes.getNodeAs("ref"); Stream << "[" << (HasCapturedArgument ? "=" : "") << "]"; addPlaceholderArgs(Args, Stream); Stream << " { return "; Index: clang-tools-extra/test/clang-tidy/checkers/modernize-avoid-bind.cpp =================================================================== --- clang-tools-extra/test/clang-tidy/checkers/modernize-avoid-bind.cpp +++ clang-tools-extra/test/clang-tidy/checkers/modernize-avoid-bind.cpp @@ -78,6 +78,39 @@ // CHECK-FIXES: auto clj = [] { return C::add(1, 1); }; } +struct D { + void operator()(int x, int y) {} + + void MemberFunction(int x) {} +}; + +void o() { + D d; + auto clj = std::bind(d, 1, 2); + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind + // CHECK-FIXES: auto clj = std::bind(d, 1, 2); +} + +void p() { + auto clj = std::bind(D{}, 1, 2); + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind + // CHECK-FIXES: auto clj = std::bind(D{}, 1, 2); +} + +void q() { + D *d; + auto clj = std::bind(*d, 1, 2); + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind + // CHECK-FIXES: auto clj = std::bind(*d, 1, 2); +} + +void r() { + D *d; + auto clj = std::bind(&D::MemberFunction, d, 1); + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind + // CHECK-FIXES: auto clj = std::bind(&D::MemberFunction, d, 1); +} + // Let's fake a minimal std::function-like facility. namespace std { template