10 #include "clang/AST/ASTContext.h"
11 #include "clang/ASTMatchers/ASTMatchFinder.h"
12 #include "clang/Basic/LLVM.h"
13 #include "clang/Basic/LangOptions.h"
14 #include "clang/Basic/SourceLocation.h"
15 #include "clang/Lex/Lexer.h"
16 #include "llvm/ADT/ArrayRef.h"
17 #include "llvm/ADT/STLExtras.h"
18 #include "llvm/ADT/SmallSet.h"
19 #include "llvm/ADT/SmallVector.h"
20 #include "llvm/ADT/StringRef.h"
21 #include "llvm/ADT/StringSet.h"
22 #include "llvm/Support/Casting.h"
23 #include "llvm/Support/FormatVariadic.h"
24 #include "llvm/Support/Regex.h"
25 #include "llvm/Support/raw_ostream.h"
59 BindArgumentKind
Kind = BK_Other;
63 CaptureMode
CM = CM_None;
67 CaptureExpr
CE = CE_None;
88 const Expr *
E =
nullptr;
92 CallableType
Type = CT_Other;
94 CaptureMode
CM = CM_None;
95 CaptureExpr
CE = CE_None;
100 const FunctionDecl *
Decl =
nullptr;
103 struct LambdaProperties {
113 BindArgument &B,
const Expr *
E);
116 BindArgument &B,
const Expr *
E);
119 if (
const auto *T = dyn_cast<UnaryOperator>(
E))
122 const Expr *F =
E->IgnoreImplicit();
130 if (
const auto *T = dyn_cast<CXXConstructExpr>(
E))
133 const Expr *F =
E->IgnoreImplicit();
142 return Lexer::getSourceText(
143 CharSourceRange::getTokenRange(
E->getBeginLoc(),
E->getEndLoc()),
144 *Result.SourceManager, Result.Context->getLangOpts());
148 const auto *
CE = dyn_cast<CallExpr>(
E->IgnoreImplicit());
151 const auto *ND = dyn_cast<NamedDecl>(
CE->getCalleeDecl());
154 return ND->getQualifiedNameAsString() ==
Name;
159 BindArgument &B,
const CallExpr *
CE,
160 unsigned &CaptureIndex) {
170 B.CE = CE_InitExpression;
171 B.UsageIdentifier =
"capture" + llvm::utostr(CaptureIndex++);
177 B.Kind = BK_CallExpr;
179 B.CE = CE_InitExpression;
180 B.UsageIdentifier =
"capture" + llvm::utostr(CaptureIndex++);
182 B.CaptureIdentifier = B.UsageIdentifier;
186 if (
const auto *
DeclRef = dyn_cast<DeclRefExpr>(Statement)) {
188 if (
const auto *Var = dyn_cast_or_null<VarDecl>(
Decl)) {
189 if (Var->isLocalVarDeclOrParm())
192 }
else if (isa<CXXThisExpr>(Statement))
199 BindArgument &B,
const Expr *
E) {
200 if (
const auto *BTE = dyn_cast<CXXBindTemporaryExpr>(
E)) {
201 if (
const auto *
CE = dyn_cast<CXXConstructExpr>(BTE->getSubExpr()))
206 const auto *DRE = dyn_cast<DeclRefExpr>(
E->IgnoreImplicit());
210 const auto *VD = dyn_cast<VarDecl>(DRE->getDecl());
211 if (!VD || !VD->isLocalVarDeclOrParm())
216 B.CaptureIdentifier = B.UsageIdentifier;
221 BindArgument &B,
const Expr *
E) {
222 if (
const auto *BTE = dyn_cast<CXXBindTemporaryExpr>(
E)) {
223 if (
const auto *
CE = dyn_cast<CXXConstructExpr>(BTE->getSubExpr()))
228 E =
E->IgnoreImplicit();
229 if (isa<CXXThisExpr>(
E)) {
233 B.CaptureIdentifier =
"this";
237 const auto *ME = dyn_cast<MemberExpr>(
E);
241 if (!ME->isLValue() || !isa<FieldDecl>(ME->getMemberDecl()))
244 if (isa<CXXThisExpr>(ME->getBase())) {
248 B.CaptureIdentifier =
"this";
255 static SmallVector<BindArgument, 4>
259 static llvm::Regex MatchPlaceholder(
"^_([0-9]+)$");
261 const auto *BindCall = Result.Nodes.getNodeAs<CallExpr>(
"bind");
264 unsigned CaptureIndex = 0;
265 for (
size_t I = 1, ArgCount = BindCall->getNumArgs(); I < ArgCount; ++I) {
267 const Expr *
E = BindCall->getArg(I);
270 size_t ArgIndex = I - 1;
271 if (
Callable.Type == CT_MemberFunction)
274 bool IsObjectPtr = (I == 1 &&
Callable.Type == CT_MemberFunction);
278 if (!
Callable.Decl || ArgIndex < Callable.Decl->getNumParams() ||
282 SmallVector<StringRef, 2> Matches;
283 const auto *DRE = dyn_cast<DeclRefExpr>(
E);
284 if (MatchPlaceholder.match(B.SourceTokens, &Matches) ||
286 (DRE && MatchPlaceholder.match(DRE->getDecl()->getName(), &Matches))) {
287 B.Kind = BK_Placeholder;
288 B.PlaceHolderIndex = std::stoi(std::string(Matches[1]));
289 B.UsageIdentifier =
"PH" + llvm::utostr(B.PlaceHolderIndex);
290 B.CaptureIdentifier = B.UsageIdentifier;
308 B.CE = CE_InitExpression;
310 B.UsageIdentifier =
"ObjectPtr";
311 B.CaptureIdentifier = B.UsageIdentifier;
313 B.CE = CE_InitExpression;
315 B.CaptureIdentifier =
"capture" + llvm::utostr(CaptureIndex++);
316 B.UsageIdentifier = B.CaptureIdentifier;
323 size_t PlaceholderIndex) {
324 for (
size_t I = 0; I < Args.size(); ++I)
332 llvm::raw_ostream &Stream,
333 bool PermissiveParameterList) {
335 ArrayRef<BindArgument> Args = LP.BindArguments;
337 auto MaxPlaceholderIt =
338 std::max_element(Args.begin(), Args.end(),
339 [](
const BindArgument &B1,
const BindArgument &B2) {
340 return B1.PlaceHolderIndex < B2.PlaceHolderIndex;
344 if (!PermissiveParameterList && (MaxPlaceholderIt == Args.end() ||
345 MaxPlaceholderIt->PlaceHolderIndex == 0))
348 size_t PlaceholderCount = MaxPlaceholderIt->PlaceHolderIndex;
350 StringRef Delimiter =
"";
351 for (
size_t I = 1; I <= PlaceholderCount; ++I) {
352 Stream << Delimiter <<
"auto &&";
356 if (ArgIndex != -1 && Args[ArgIndex].
IsUsed)
357 Stream <<
" " << Args[ArgIndex].UsageIdentifier;
360 if (PermissiveParameterList)
361 Stream << Delimiter <<
"auto && ...";
366 llvm::raw_ostream &Stream) {
367 StringRef Delimiter =
"";
369 for (
int I = 0, Size = Args.size(); I < Size; ++I) {
370 const BindArgument &B = Args[I];
374 if (B.Kind == BK_Placeholder) {
375 Stream <<
"std::forward<decltype(" << B.UsageIdentifier <<
")>";
376 Stream <<
"(" << B.UsageIdentifier <<
")";
377 }
else if (B.CM != CM_None)
378 Stream << B.UsageIdentifier;
380 Stream << B.SourceTokens;
387 llvm::SmallSet<size_t, 4> PlaceHolderIndices;
388 for (
const BindArgument &B : Args) {
389 if (B.PlaceHolderIndex) {
390 if (!PlaceHolderIndices.insert(B.PlaceHolderIndex).second)
397 static std::vector<const FunctionDecl *>
399 std::vector<const FunctionDecl *> Candidates;
401 for (
const clang::CXXMethodDecl *Method : RecordDecl->methods()) {
402 OverloadedOperatorKind OOK = Method->getOverloadedOperator();
404 if (OOK != OverloadedOperatorKind::OO_Call)
407 if (Method->getNumParams() > NumArgs)
410 Candidates.push_back(Method);
415 const auto *FTD = dyn_cast<FunctionTemplateDecl>(D);
418 const FunctionDecl *FD = FTD->getTemplatedDecl();
420 OverloadedOperatorKind OOK = FD->getOverloadedOperator();
421 if (OOK != OverloadedOperatorKind::OO_Call)
424 if (FD->getNumParams() > NumArgs)
427 Candidates.push_back(FD);
434 ArrayRef<BindArgument> Args) {
439 if (any_of(Args, [](
const BindArgument &B) {
456 if (Callee.Type == CT_Other || Callee.Materialization == CMK_Other)
464 std::vector<const FunctionDecl *> Candidates =
466 if (Candidates.size() != 1)
469 return Candidates.front();
476 const Expr *Callee = Result.Nodes.getNodeAs<Expr>(
"ref");
479 if (
Type == CT_Object) {
480 const auto *BindCall = Result.Nodes.getNodeAs<CallExpr>(
"bind");
481 size_t NumArgs = BindCall->getNumArgs() - 1;
482 return getCallOperator(Callee->getType()->getAsCXXRecordDecl(), NumArgs);
486 if (
const auto *DRE = dyn_cast<DeclRefExpr>(CallExpression))
487 return dyn_cast<FunctionDecl>(DRE->getDecl());
496 const auto *CallableExpr = Result.Nodes.getNodeAs<Expr>(
"ref");
498 QualType QT = CallableExpr->getType();
499 if (QT->isMemberFunctionPointerType())
500 return CT_MemberFunction;
502 if (QT->isFunctionPointerType() || QT->isFunctionReferenceType() ||
503 QT->isFunctionType())
506 if (QT->isRecordType()) {
507 const CXXRecordDecl *
Decl = QT->getAsCXXRecordDecl();
517 static CallableMaterializationKind
519 const auto *CallableExpr = Result.Nodes.getNodeAs<Expr>(
"ref");
523 const auto *
CE = dyn_cast<CXXConstructExpr>(NoTemporaries);
524 const auto *FC = dyn_cast<CXXFunctionalCastExpr>(NoTemporaries);
525 if ((isa<CallExpr>(NoTemporaries)) || (
CE && (
CE->getNumArgs() > 0)) ||
526 (FC && (FC->getCastKind() == CK_ConstructorConversion)))
529 return CMK_CallExpression;
531 if (isa<CXXFunctionalCastExpr>(NoTemporaries) ||
CE)
534 if (
const auto *DRE = dyn_cast<DeclRefExpr>(NoTemporaries)) {
535 if (isa<FunctionDecl>(DRE->getDecl()))
537 if (isa<VarDecl>(DRE->getDecl()))
538 return CMK_VariableRef;
544 static LambdaProperties
546 const auto *CalleeExpr = Result.Nodes.getNodeAs<Expr>(
"ref");
550 const auto *Bind = Result.Nodes.getNodeAs<CallExpr>(
"bind");
551 const auto *
Decl = dyn_cast<FunctionDecl>(Bind->getCalleeDecl());
553 dyn_cast<NamespaceDecl>(
Decl->getEnclosingNamespaceContext());
554 while (NS->isInlineNamespace())
555 NS = dyn_cast<NamespaceDecl>(NS->getDeclContext());
556 LP.BindNamespace = NS->getName();
563 if (LP.Callable.Materialization == CMK_VariableRef) {
564 LP.Callable.CE = CE_Var;
565 LP.Callable.CM = CM_ByValue;
566 LP.Callable.UsageIdentifier =
568 LP.Callable.CaptureIdentifier = std::string(
570 }
else if (LP.Callable.Materialization == CMK_CallExpression) {
571 LP.Callable.CE = CE_InitExpression;
572 LP.Callable.CM = CM_ByValue;
573 LP.Callable.UsageIdentifier =
"Func";
574 LP.Callable.CaptureIdentifier =
"Func";
585 static bool emitCapture(llvm::StringSet<> &CaptureSet, StringRef Delimiter,
586 CaptureMode
CM, CaptureExpr
CE, StringRef Identifier,
587 StringRef InitExpression, raw_ostream &Stream) {
592 if (CaptureSet.count(Identifier) != 0)
599 Stream << Identifier;
600 if (
CE == CE_InitExpression)
601 Stream <<
" = " << InitExpression;
603 CaptureSet.insert(Identifier);
608 const MatchFinder::MatchResult &Result,
609 raw_ostream &Stream) {
610 llvm::StringSet<> CaptureSet;
611 bool AnyCapturesEmitted =
false;
614 CaptureSet,
"", LP.Callable.CM, LP.Callable.CE,
615 LP.Callable.CaptureIdentifier, LP.Callable.CaptureInitializer, Stream);
617 for (
const BindArgument &B : LP.BindArguments) {
618 if (B.CM == CM_None || !B.IsUsed)
621 StringRef Delimiter = AnyCapturesEmitted ?
", " :
"";
623 if (
emitCapture(CaptureSet, Delimiter, B.CM, B.CE, B.CaptureIdentifier,
624 B.SourceTokens, Stream))
625 AnyCapturesEmitted =
true;
629 static ArrayRef<BindArgument>
631 ArrayRef<BindArgument> Args = makeArrayRef(P.BindArguments);
632 if (P.Callable.Type != CT_MemberFunction)
635 return Args.drop_front();
639 PermissiveParameterList(Options.get(
"PermissiveParameterList", false)) {}
642 Options.
store(Opts,
"PermissiveParameterList", PermissiveParameterList);
648 callee(namedDecl(hasAnyName(
"::boost::bind",
"::std::bind"))),
650 0, anyOf(expr(hasType(memberPointerType())).bind(
"ref"),
651 expr(hasParent(materializeTemporaryExpr().bind(
"ref"))),
652 expr().bind(
"ref"))))
658 const auto *MatchedDecl = Result.Nodes.getNodeAs<CallExpr>(
"bind");
662 diag(MatchedDecl->getBeginLoc(),
663 formatv(
"prefer a lambda to {0}::bind", LP.BindNamespace).str());
664 if (!LP.IsFixitSupported)
667 const auto *Ref = Result.Nodes.getNodeAs<Expr>(
"ref");
670 llvm::raw_string_ostream Stream(Buffer);
676 ArrayRef<BindArgument> FunctionCallArgs = makeArrayRef(LP.BindArguments);
680 if (LP.Callable.Type == CT_Function) {
684 }
else if (LP.Callable.Type == CT_MemberFunction) {
685 const auto *MethodDecl = dyn_cast<CXXMethodDecl>(LP.Callable.Decl);
686 const BindArgument &ObjPtr = FunctionCallArgs.front();
690 Stream << ObjPtr.UsageIdentifier;
694 Stream << MethodDecl->getName();
696 Stream <<
" { return ";
697 switch (LP.Callable.CE) {
699 if (LP.Callable.UsageIdentifier != LP.Callable.CaptureIdentifier) {
700 Stream <<
"(" << LP.Callable.UsageIdentifier <<
")";
704 case CE_InitExpression:
705 Stream << LP.Callable.UsageIdentifier;
717 Diag << FixItHint::CreateReplacement(MatchedDecl->getSourceRange(),