Skip to content

[clang-tidy] modernize-avoid-bind only return for non-void function #69207

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions clang-tools-extra/clang-tidy/modernize/AvoidBindCheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ struct CallableInfo {
std::string UsageIdentifier;
StringRef CaptureInitializer;
const FunctionDecl *Decl = nullptr;
bool DoesReturn = false;
};

struct LambdaProperties {
Expand Down Expand Up @@ -554,6 +555,10 @@ getLambdaProperties(const MatchFinder::MatchResult &Result) {
LP.Callable.Materialization = getCallableMaterialization(Result);
LP.Callable.Decl =
getCallMethodDecl(Result, LP.Callable.Type, LP.Callable.Materialization);
if (LP.Callable.Decl)
if (const Type *ReturnType =
LP.Callable.Decl->getReturnType().getCanonicalType().getTypePtr())
LP.Callable.DoesReturn = !ReturnType->isVoidType();
LP.Callable.SourceTokens = getSourceTextForExpr(Result, CalleeExpr);
if (LP.Callable.Materialization == CMK_VariableRef) {
LP.Callable.CE = CE_Var;
Expand Down Expand Up @@ -672,23 +677,27 @@ void AvoidBindCheck::check(const MatchFinder::MatchResult &Result) {

addPlaceholderArgs(LP, Stream, PermissiveParameterList);

Stream << " { ";

if (LP.Callable.DoesReturn) {
Stream << "return ";
}

if (LP.Callable.Type == CT_Function) {
StringRef SourceTokens = LP.Callable.SourceTokens;
SourceTokens.consume_front("&");
Stream << " { return " << SourceTokens;
Stream << SourceTokens;
} else if (LP.Callable.Type == CT_MemberFunction) {
const auto *MethodDecl = dyn_cast<CXXMethodDecl>(LP.Callable.Decl);
const BindArgument &ObjPtr = FunctionCallArgs.front();

Stream << " { ";
if (!isa<CXXThisExpr>(ignoreTemporariesAndPointers(ObjPtr.E))) {
Stream << ObjPtr.UsageIdentifier;
Stream << "->";
}

Stream << MethodDecl->getName();
} else {
Stream << " { return ";
switch (LP.Callable.CE) {
case CE_Var:
if (LP.Callable.UsageIdentifier != LP.Callable.CaptureIdentifier) {
Expand Down
4 changes: 4 additions & 0 deletions clang-tools-extra/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,10 @@ Changes in existing checks
<clang-tidy/checks/misc/redundant-expression>` check to ignore
false-positives in unevaluated context (e.g., ``decltype``).

- Improved :doc:`modernize-avoid-bind
<clang-tidy/checks/modernize/avoid-bind>` check to
not emit a ``return`` for fixes when the function returns ``void``.

- Improved :doc:`modernize-loop-convert
<clang-tidy/checks/modernize/loop-convert>` to support for-loops with
iterators initialized by free functions like ``begin``, ``end``, or ``size``
Expand Down
43 changes: 31 additions & 12 deletions clang-tools-extra/test/clang-tidy/checkers/modernize/avoid-bind.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ struct D {
void operator()(int x, int y) const {}

void MemberFunction(int x) {}
int MemberFunctionWithReturn(int x) {}

static D *create();
};
Expand Down Expand Up @@ -162,11 +163,11 @@ struct TestCaptureByValueStruct {
// 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); };
// CHECK-FIXES: auto FFF = [f] { 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); };
// CHECK-FIXES: auto GGG = [this] { UseF(MemberStruct); };

auto HHH = std::bind(add, MemberStructWithData._member, 1);
// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: prefer a lambda to std::bind
Expand Down Expand Up @@ -227,42 +228,42 @@ void testFunctionObjects() {
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); }
// CHECK-FIXES: auto AAA = [d] { 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); }
// CHECK-FIXES: auto BBB = [e] { (*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); }
// CHECK-FIXES: auto CCC = [] { 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); }
// CHECK-FIXES: auto DDD = [] { 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); };
// CHECK-FIXES: auto EEE = [Func = *D::create()] { Func(1, 2); };

auto FFF = std::bind(G(), 1);
// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind
// Templated function call operators may be used
// CHECK-FIXES: auto FFF = [] { return G()(1); };
// CHECK-FIXES: auto FFF = [] { G()(1); };

int CTorArg = 42;
auto GGG = std::bind(G(CTorArg), 1);
// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind
// Function objects with constructor arguments should be captured
// CHECK-FIXES: auto GGG = [Func = G(CTorArg)] { return Func(1); };
// CHECK-FIXES: auto GGG = [Func = G(CTorArg)] { Func(1); };
}

template <typename T>
void testMemberFnOfClassTemplate(T) {
auto HHH = std::bind(H<T>(), 42);
// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind
// Ensure function class template arguments are preserved
// CHECK-FIXES: auto HHH = [] { return H<T>()(42); };
// CHECK-FIXES: auto HHH = [] { H<T>()(42); };
}

template void testMemberFnOfClassTemplate(int);
Expand Down Expand Up @@ -335,11 +336,12 @@ void testCapturedSubexpressions() {
auto CCC = std::bind(sub, std::ref(*p), _1);
// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind
// Expressions returning references are captured
// CHECK-FIXES: auto CCC = [&capture0 = *p](auto && PH1) { return sub(capture0, std::forward<decltype(PH1)>(PH1)); };
// CHECK-FIXES: auto CCC = [&capture0 = *p](auto && PH1) { sub(capture0, std::forward<decltype(PH1)>(PH1)); };
}

struct E {
void MemberFunction(int x) {}
int MemberFunctionWithReturn(int x) {}

void testMemberFunctions() {
D *d;
Expand All @@ -360,6 +362,23 @@ struct E {
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); };

auto EEE = std::bind(&D::MemberFunctionWithReturn, d, 1);
// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: prefer a lambda to std::bind
// CHECK-FIXES: auto EEE = [d] { return d->MemberFunctionWithReturn(1); };

auto FFF = std::bind(&D::MemberFunctionWithReturn, &dd, 1);
// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: prefer a lambda to std::bind
// CHECK-FIXES: auto FFF = [ObjectPtr = &dd] { return ObjectPtr->MemberFunctionWithReturn(1); };

auto GGG = std::bind(&E::MemberFunctionWithReturn, this, 1);
// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: prefer a lambda to std::bind
// CHECK-FIXES: auto GGG = [this] { return MemberFunctionWithReturn(1); };

// Test what happens when the object pointer is itself a placeholder.
auto HHH = std::bind(&D::MemberFunctionWithReturn, _1, 1);
// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: prefer a lambda to std::bind
// CHECK-FIXES: auto HHH = [](auto && PH1) { return PH1->MemberFunctionWithReturn(1); };
}
};

Expand All @@ -368,5 +387,5 @@ void testStdFunction(Thing *t) {
if (t)
cb.Reset(std::bind(UseThing, t));
// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind
// CHECK-FIXES: cb.Reset([t] { return UseThing(t); });
// CHECK-FIXES: cb.Reset([t] { UseThing(t); });
}