Skip to content

Commit 9399094

Browse files
authored
[clang-tidy] modernize-avoid-bind only return for non-void function (#69207)
- only return when the return type is non-void - fix missing return on member functions
1 parent e774482 commit 9399094

File tree

3 files changed

+47
-15
lines changed

3 files changed

+47
-15
lines changed

clang-tools-extra/clang-tidy/modernize/AvoidBindCheck.cpp

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ struct CallableInfo {
9696
std::string UsageIdentifier;
9797
StringRef CaptureInitializer;
9898
const FunctionDecl *Decl = nullptr;
99+
bool DoesReturn = false;
99100
};
100101

101102
struct LambdaProperties {
@@ -554,6 +555,10 @@ getLambdaProperties(const MatchFinder::MatchResult &Result) {
554555
LP.Callable.Materialization = getCallableMaterialization(Result);
555556
LP.Callable.Decl =
556557
getCallMethodDecl(Result, LP.Callable.Type, LP.Callable.Materialization);
558+
if (LP.Callable.Decl)
559+
if (const Type *ReturnType =
560+
LP.Callable.Decl->getReturnType().getCanonicalType().getTypePtr())
561+
LP.Callable.DoesReturn = !ReturnType->isVoidType();
557562
LP.Callable.SourceTokens = getSourceTextForExpr(Result, CalleeExpr);
558563
if (LP.Callable.Materialization == CMK_VariableRef) {
559564
LP.Callable.CE = CE_Var;
@@ -672,23 +677,27 @@ void AvoidBindCheck::check(const MatchFinder::MatchResult &Result) {
672677

673678
addPlaceholderArgs(LP, Stream, PermissiveParameterList);
674679

680+
Stream << " { ";
681+
682+
if (LP.Callable.DoesReturn) {
683+
Stream << "return ";
684+
}
685+
675686
if (LP.Callable.Type == CT_Function) {
676687
StringRef SourceTokens = LP.Callable.SourceTokens;
677688
SourceTokens.consume_front("&");
678-
Stream << " { return " << SourceTokens;
689+
Stream << SourceTokens;
679690
} else if (LP.Callable.Type == CT_MemberFunction) {
680691
const auto *MethodDecl = dyn_cast<CXXMethodDecl>(LP.Callable.Decl);
681692
const BindArgument &ObjPtr = FunctionCallArgs.front();
682693

683-
Stream << " { ";
684694
if (!isa<CXXThisExpr>(ignoreTemporariesAndPointers(ObjPtr.E))) {
685695
Stream << ObjPtr.UsageIdentifier;
686696
Stream << "->";
687697
}
688698

689699
Stream << MethodDecl->getName();
690700
} else {
691-
Stream << " { return ";
692701
switch (LP.Callable.CE) {
693702
case CE_Var:
694703
if (LP.Callable.UsageIdentifier != LP.Callable.CaptureIdentifier) {

clang-tools-extra/docs/ReleaseNotes.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,10 @@ Changes in existing checks
286286
<clang-tidy/checks/misc/redundant-expression>` check to ignore
287287
false-positives in unevaluated context (e.g., ``decltype``).
288288

289+
- Improved :doc:`modernize-avoid-bind
290+
<clang-tidy/checks/modernize/avoid-bind>` check to
291+
not emit a ``return`` for fixes when the function returns ``void``.
292+
289293
- Improved :doc:`modernize-loop-convert
290294
<clang-tidy/checks/modernize/loop-convert>` to support for-loops with
291295
iterators initialized by free functions like ``begin``, ``end``, or ``size``

clang-tools-extra/test/clang-tidy/checkers/modernize/avoid-bind.cpp

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ struct D {
4545
void operator()(int x, int y) const {}
4646

4747
void MemberFunction(int x) {}
48+
int MemberFunctionWithReturn(int x) {}
4849

4950
static D *create();
5051
};
@@ -162,11 +163,11 @@ struct TestCaptureByValueStruct {
162163
// those here.
163164
auto FFF = boost::bind(UseF, f);
164165
// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: prefer a lambda to boost::bind [modernize-avoid-bind]
165-
// CHECK-FIXES: auto FFF = [f] { return UseF(f); };
166+
// CHECK-FIXES: auto FFF = [f] { UseF(f); };
166167

167168
auto GGG = boost::bind(UseF, MemberStruct);
168169
// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: prefer a lambda to boost::bind [modernize-avoid-bind]
169-
// CHECK-FIXES: auto GGG = [this] { return UseF(MemberStruct); };
170+
// CHECK-FIXES: auto GGG = [this] { UseF(MemberStruct); };
170171

171172
auto HHH = std::bind(add, MemberStructWithData._member, 1);
172173
// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: prefer a lambda to std::bind
@@ -227,42 +228,42 @@ void testFunctionObjects() {
227228
D *e = nullptr;
228229
auto AAA = std::bind(d, 1, 2);
229230
// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind
230-
// CHECK-FIXES: auto AAA = [d] { return d(1, 2); }
231+
// CHECK-FIXES: auto AAA = [d] { d(1, 2); }
231232

232233
auto BBB = std::bind(*e, 1, 2);
233234
// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind
234-
// CHECK-FIXES: auto BBB = [e] { return (*e)(1, 2); }
235+
// CHECK-FIXES: auto BBB = [e] { (*e)(1, 2); }
235236

236237
auto CCC = std::bind(D{}, 1, 2);
237238
// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind
238-
// CHECK-FIXES: auto CCC = [] { return D{}(1, 2); }
239+
// CHECK-FIXES: auto CCC = [] { D{}(1, 2); }
239240

240241
auto DDD = std::bind(D(), 1, 2);
241242
// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind
242-
// CHECK-FIXES: auto DDD = [] { return D()(1, 2); }
243+
// CHECK-FIXES: auto DDD = [] { D()(1, 2); }
243244

244245
auto EEE = std::bind(*D::create(), 1, 2);
245246
// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind
246-
// CHECK-FIXES: auto EEE = [Func = *D::create()] { return Func(1, 2); };
247+
// CHECK-FIXES: auto EEE = [Func = *D::create()] { Func(1, 2); };
247248

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

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

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

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

341342
struct E {
342343
void MemberFunction(int x) {}
344+
int MemberFunctionWithReturn(int x) {}
343345

344346
void testMemberFunctions() {
345347
D *d;
@@ -360,6 +362,23 @@ struct E {
360362
auto DDD = std::bind(&D::MemberFunction, _1, 1);
361363
// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: prefer a lambda to std::bind
362364
// CHECK-FIXES: auto DDD = [](auto && PH1) { PH1->MemberFunction(1); };
365+
366+
auto EEE = std::bind(&D::MemberFunctionWithReturn, d, 1);
367+
// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: prefer a lambda to std::bind
368+
// CHECK-FIXES: auto EEE = [d] { return d->MemberFunctionWithReturn(1); };
369+
370+
auto FFF = std::bind(&D::MemberFunctionWithReturn, &dd, 1);
371+
// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: prefer a lambda to std::bind
372+
// CHECK-FIXES: auto FFF = [ObjectPtr = &dd] { return ObjectPtr->MemberFunctionWithReturn(1); };
373+
374+
auto GGG = std::bind(&E::MemberFunctionWithReturn, this, 1);
375+
// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: prefer a lambda to std::bind
376+
// CHECK-FIXES: auto GGG = [this] { return MemberFunctionWithReturn(1); };
377+
378+
// Test what happens when the object pointer is itself a placeholder.
379+
auto HHH = std::bind(&D::MemberFunctionWithReturn, _1, 1);
380+
// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: prefer a lambda to std::bind
381+
// CHECK-FIXES: auto HHH = [](auto && PH1) { return PH1->MemberFunctionWithReturn(1); };
363382
}
364383
};
365384

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

0 commit comments

Comments
 (0)