clang-tools 10.0.0

AvoidBindCheck.cpp
Go to the documentation of this file.
1 //===--- AvoidBindCheck.cpp - clang-tidy-----------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "AvoidBindCheck.h"
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/Support/Casting.h"
22 #include "llvm/Support/FormatVariadic.h"
23 #include "llvm/Support/Regex.h"
24 #include "llvm/Support/raw_ostream.h"
25 #include <algorithm>
26 #include <cstddef>
27 #include <string>
28
29 using namespace clang::ast_matchers;
30
31 namespace clang {
32 namespace tidy {
33 namespace modernize {
34
35 namespace {
36
37 enum BindArgumentKind { BK_Temporary, BK_Placeholder, BK_CallExpr, BK_Other };
38 enum CaptureMode { CM_None, CM_ByRef, CM_ByValue, CM_InitExpression };
39
40 enum CallableType {
41 CT_Other, // unknown
42 CT_Function, // global or static function
43 CT_MemberFunction, // member function with implicit this
44 CT_Object, // object with operator()
45 };
46
47 enum CallableMaterializationKind {
48 CMK_Other, // unknown
49 CMK_Function, // callable is the name of a member or non-member function.
50 CMK_VariableRef, // callable is a simple expression involving a global or
51 // local variable.
52 CMK_CallExpression, // callable is obtained as the result of a call expression
53 };
54
55 struct BindArgument {
56 // A rough classification of the type of expression this argument was.
57 BindArgumentKind Kind = BK_Other;
58
59 // If this argument required a capture, a value indicating how it was
60 // captured.
61 CaptureMode CM = CM_None;
62
63 // The exact spelling of this argument in the source code.
64 StringRef SourceTokens;
65
66 // The identifier of the variable within the capture list. This may be
67 // different from UsageIdentifier for example in the expression *d, where the
68 // variable is captured as d, but referred to as *d.
69 std::string CaptureIdentifier;
70
71 // If this is a placeholder or capture init expression, contains the tokens
72 // used to refer to this parameter from within the body of the lambda.
73 std::string UsageIdentifier;
74
75 // If Kind == BK_Placeholder, the index of the placeholder.
76 size_t PlaceHolderIndex = 0;
77
78 // True if the argument is used inside the lambda, false otherwise.
79 bool IsUsed = false;
80
81 // The actual Expr object representing this expression.
82 const Expr *E = nullptr;
83 };
84
85 struct CallableInfo {
86 CallableType Type = CT_Other;
87 CallableMaterializationKind Materialization = CMK_Other;
88 CaptureMode CM = CM_None;
89 StringRef SourceTokens;
90 std::string CaptureIdentifier;
91 std::string UsageIdentifier;
92 StringRef CaptureInitializer;
93 const FunctionDecl *Decl = nullptr;
94 };
95
96 struct LambdaProperties {
97 CallableInfo Callable;
98 SmallVector<BindArgument, 4> BindArguments;
99 StringRef BindNamespace;
100 bool IsFixitSupported = false;
101 };
102
103 } // end namespace
104
105 static const Expr *ignoreTemporariesAndPointers(const Expr *E) {
106 if (const auto *T = dyn_cast<UnaryOperator>(E))
107 return ignoreTemporariesAndPointers(T->getSubExpr());
108
109 const Expr *F = E->IgnoreImplicit();
110 if (E != F)
111 return ignoreTemporariesAndPointers(F);
112
113 return E;
114 }
115
116 static const Expr *ignoreTemporariesAndConstructors(const Expr *E) {
117 if (const auto *T = dyn_cast<CXXConstructExpr>(E))
118 return ignoreTemporariesAndConstructors(T->getArg(0));
119
120 const Expr *F = E->IgnoreImplicit();
121 if (E != F)
122 return ignoreTemporariesAndPointers(F);
123
124 return E;
125 }
126
127 static StringRef getSourceTextForExpr(const MatchFinder::MatchResult &Result,
128 const Expr *E) {
129 return Lexer::getSourceText(
130 CharSourceRange::getTokenRange(E->getBeginLoc(), E->getEndLoc()),
131 *Result.SourceManager, Result.Context->getLangOpts());
132 }
133
134 static bool isCallExprNamed(const Expr *E, StringRef Name) {
135 const auto *CE = dyn_cast<CallExpr>(E->IgnoreImplicit());
136 if (!CE)
137 return false;
138 const auto *ND = dyn_cast<NamedDecl>(CE->getCalleeDecl());
139 if (!ND)
140 return false;
141 return ND->getQualifiedNameAsString() == Name;
142 }
143
144 static void
145 initializeBindArgumentForCallExpr(const MatchFinder::MatchResult &Result,
146 BindArgument &B, const CallExpr *CE,
147 unsigned &CaptureIndex) {
148 // std::ref(x) means to capture x by reference.
149 if (isCallExprNamed(CE, "boost::ref") || isCallExprNamed(CE, "std::ref")) {
150 B.Kind = BK_Other;
151 B.CM = CM_ByRef;
152 B.UsageIdentifier = getSourceTextForExpr(Result, CE->getArg(0));
153 } else {
154 B.Kind = BK_CallExpr;
155 B.CM = CM_InitExpression;
156 B.UsageIdentifier = "capture" + llvm::utostr(CaptureIndex++);
157 }
158 B.CaptureIdentifier = B.UsageIdentifier;
159 }
160
161 static bool anyDescendantIsLocal(const Stmt *Statement) {
162 if (const auto *DeclRef = dyn_cast<DeclRefExpr>(Statement)) {
163 const ValueDecl *Decl = DeclRef->getDecl();
164 if (const auto *Var = dyn_cast_or_null<VarDecl>(Decl)) {
165 if (Var->isLocalVarDeclOrParm())
166 return true;
167 }
168 } else if (isa<CXXThisExpr>(Statement))
169 return true;
170
171 return any_of(Statement->children(), anyDescendantIsLocal);
172 }
173
174 static bool tryCaptureAsLocalVariable(const MatchFinder::MatchResult &Result,
175 BindArgument &B, const Expr *E) {
176 if (const auto *BTE = dyn_cast<CXXBindTemporaryExpr>(E)) {
177 if (const auto *CE = dyn_cast<CXXConstructExpr>(BTE->getSubExpr()))
178 return tryCaptureAsLocalVariable(Result, B, CE->getArg(0));
179 return false;
180 }
181
182 const auto *DRE = dyn_cast<DeclRefExpr>(E->IgnoreImplicit());
183 if (!DRE)
184 return false;
185
186 const auto *VD = dyn_cast<VarDecl>(DRE->getDecl());
187 if (!VD || !VD->isLocalVarDeclOrParm())
188 return false;
189
190 B.CM = CM_ByValue;
191 B.UsageIdentifier = getSourceTextForExpr(Result, E);
192 B.CaptureIdentifier = B.UsageIdentifier;
193 return true;
194 }
195
196 static bool tryCaptureAsMemberVariable(const MatchFinder::MatchResult &Result,
197 BindArgument &B, const Expr *E) {
198 if (const auto *BTE = dyn_cast<CXXBindTemporaryExpr>(E)) {
199 if (const auto *CE = dyn_cast<CXXConstructExpr>(BTE->getSubExpr()))
200 return tryCaptureAsMemberVariable(Result, B, CE->getArg(0));
201 return false;
202 }
203
204 E = E->IgnoreImplicit();
205 if (isa<CXXThisExpr>(E)) {
206 B.CM = CM_ByValue;
207 B.UsageIdentifier = getSourceTextForExpr(Result, E);
208 B.CaptureIdentifier = "this";
209 return true;
210 }
211
212 const auto *ME = dyn_cast<MemberExpr>(E);
213 if (!ME)
214 return false;
215
216 if (!ME->isLValue() || !isa<FieldDecl>(ME->getMemberDecl()))
217 return false;
218
219 B.CM = CM_ByValue;
220 B.UsageIdentifier = getSourceTextForExpr(Result, E);
221 B.CaptureIdentifier = "this";
222 return true;
223 }
224
225 static SmallVector<BindArgument, 4>
226 buildBindArguments(const MatchFinder::MatchResult &Result,
227 const CallableInfo &Callable) {
228 SmallVector<BindArgument, 4> BindArguments;
229 llvm::Regex MatchPlaceholder("^_([0-9]+)$");
230
231 const auto *BindCall = Result.Nodes.getNodeAs<CallExpr>("bind");
232
233 // Start at index 1 as first argument to bind is the function name.
234 unsigned CaptureIndex = 0;
235 for (size_t I = 1, ArgCount = BindCall->getNumArgs(); I < ArgCount; ++I) {
236
237 const Expr *E = BindCall->getArg(I);
238 BindArgument &B = BindArguments.emplace_back();
239
240 size_t ArgIndex = I - 1;
241 if (Callable.Type == CT_MemberFunction)
242 --ArgIndex;
243
244 bool IsObjectPtr = (I == 1 && Callable.Type == CT_MemberFunction);
245 B.E = E;
246 B.SourceTokens = getSourceTextForExpr(Result, E);
247
248 if (!Callable.Decl || ArgIndex < Callable.Decl->getNumParams() ||
249 IsObjectPtr)
250 B.IsUsed = true;
251
252 SmallVector<StringRef, 2> Matches;
253 if (MatchPlaceholder.match(B.SourceTokens, &Matches)) {
254 B.Kind = BK_Placeholder;
255 B.PlaceHolderIndex = std::stoi(Matches[1]);
256 B.UsageIdentifier = "PH" + llvm::utostr(B.PlaceHolderIndex);
257 B.CaptureIdentifier = B.UsageIdentifier;
258 continue;
259 }
260
261 if (const auto *CE =
262 dyn_cast<CallExpr>(ignoreTemporariesAndConstructors(E))) {
263 initializeBindArgumentForCallExpr(Result, B, CE, CaptureIndex);
264 continue;
265 }
266
267 if (tryCaptureAsLocalVariable(Result, B, B.E) ||
268 tryCaptureAsMemberVariable(Result, B, B.E))
269 continue;
270
271 // If it's not something we recognize, capture it by init expression to be
272 // safe.
273 B.Kind = BK_Other;
274 if (IsObjectPtr) {
275 B.CM = CM_InitExpression;
276 B.UsageIdentifier = "ObjectPtr";
277 B.CaptureIdentifier = B.UsageIdentifier;
278 } else if (anyDescendantIsLocal(B.E)) {
279 B.CM = CM_InitExpression;
280 B.CaptureIdentifier = "capture" + llvm::utostr(CaptureIndex++);
281 B.UsageIdentifier = B.CaptureIdentifier;
282 }
283 }
284 return BindArguments;
285 }
286
287 static int findPositionOfPlaceholderUse(ArrayRef<BindArgument> Args,
288 size_t PlaceholderIndex) {
289 for (size_t I = 0; I < Args.size(); ++I)
290 if (Args[I].PlaceHolderIndex == PlaceholderIndex)
291 return I;
292
293 return -1;
294 }
295
296 static void addPlaceholderArgs(const LambdaProperties &LP,
297 llvm::raw_ostream &Stream,
298 bool PermissiveParameterList) {
299
300 ArrayRef<BindArgument> Args = LP.BindArguments;
301
302 auto MaxPlaceholderIt =
303 std::max_element(Args.begin(), Args.end(),
304 [](const BindArgument &B1, const BindArgument &B2) {
305 return B1.PlaceHolderIndex < B2.PlaceHolderIndex;
306 });
307
308 // Placeholders (if present) have index 1 or greater.
309 if (!PermissiveParameterList && (MaxPlaceholderIt == Args.end() ||
310 MaxPlaceholderIt->PlaceHolderIndex == 0))
311 return;
312
313 size_t PlaceholderCount = MaxPlaceholderIt->PlaceHolderIndex;
314 Stream << "(";
315 StringRef Delimiter = "";
316 for (size_t I = 1; I <= PlaceholderCount; ++I) {
317 Stream << Delimiter << "auto &&";
318
319 int ArgIndex = findPositionOfPlaceholderUse(Args, I);
320
321 if (ArgIndex != -1 && Args[ArgIndex].IsUsed)
322 Stream << " " << Args[ArgIndex].UsageIdentifier;
323 Delimiter = ", ";
324 }
325 if (PermissiveParameterList)
326 Stream << Delimiter << "auto && ...";
327 Stream << ")";
328 }
329
330 static void addFunctionCallArgs(ArrayRef<BindArgument> Args,
331 llvm::raw_ostream &Stream) {
332 StringRef Delimiter = "";
333
334 for (int I = 0, Size = Args.size(); I < Size; ++I) {
335 const BindArgument &B = Args[I];
336
337 Stream << Delimiter;
338
339 if (B.Kind == BK_Placeholder || B.CM != CM_None)
340 Stream << B.UsageIdentifier;
341 else if (B.CM == CM_None)
342 Stream << B.SourceTokens;
343
344 Delimiter = ", ";
345 }
346 }
347
348 static bool isPlaceHolderIndexRepeated(const ArrayRef<BindArgument> Args) {
349 llvm::SmallSet<size_t, 4> PlaceHolderIndices;
350 for (const BindArgument &B : Args) {
351 if (B.PlaceHolderIndex) {
352 if (!PlaceHolderIndices.insert(B.PlaceHolderIndex).second)
353 return true;
354 }
355 }
356 return false;
357 }
358
359 static std::vector<const CXXMethodDecl *>
360 findCandidateCallOperators(const CXXRecordDecl *RecordDecl, size_t NumArgs) {
361 std::vector<const CXXMethodDecl *> Candidates;
362
363 for (const clang::CXXMethodDecl *Method : RecordDecl->methods()) {
364 OverloadedOperatorKind OOK = Method->getOverloadedOperator();
365
366 if (OOK != OverloadedOperatorKind::OO_Call)
367 continue;
368
369 if (Method->getNumParams() > NumArgs)
370 continue;
371
372 Candidates.push_back(Method);
373 }
374
375 return Candidates;
376 }
377
378 static bool isFixitSupported(const CallableInfo &Callee,
379 ArrayRef<BindArgument> Args) {
380 // Do not attempt to create fixits for nested std::bind or std::ref.
381 // Supporting nested std::bind will be more difficult due to placeholder
382 // sharing between outer and inner std::bind invocations, and std::ref
383 // requires us to capture some parameters by reference instead of by value.
384 if (any_of(Args, [](const BindArgument &B) {
385 return isCallExprNamed(B.E, "boost::bind") ||
386 isCallExprNamed(B.E, "std::bind");
387 })) {
388 return false;
389 }
390
391 // Do not attempt to create fixits when placeholders are reused.
392 // Unused placeholders are supported by requiring C++14 generic lambdas.
393 // FIXME: Support this case by deducing the common type.
394 if (isPlaceHolderIndexRepeated(Args))
395 return false;
396
397 // If we can't determine the Decl being used, don't offer a fixit.
398 if (!Callee.Decl)
399 return false;
400
401 if (Callee.Type == CT_Other || Callee.Materialization == CMK_Other)
402 return false;
403
404 return true;
405 }
406
407 const FunctionDecl *getCallOperator(const CXXRecordDecl *Callable,
408 size_t NumArgs) {
409 std::vector<const CXXMethodDecl *> Candidates =
410 findCandidateCallOperators(Callable, NumArgs);
411 if (Candidates.size() != 1)
412 return nullptr;
413
414 return Candidates.front();
415 }
416
417 const FunctionDecl *
418 getCallMethodDecl(const MatchFinder::MatchResult &Result, CallableType Type,
419 CallableMaterializationKind Materialization) {
420
421 const Expr *Callee = Result.Nodes.getNodeAs<Expr>("ref");
422 const Expr *CallExpression = ignoreTemporariesAndPointers(Callee);
423
424 if (Type == CT_Object) {
425 const auto *BindCall = Result.Nodes.getNodeAs<CallExpr>("bind");
426 size_t NumArgs = BindCall->getNumArgs() - 1;
427 return getCallOperator(Callee->getType()->getAsCXXRecordDecl(), NumArgs);
428 }
429
430 if (Materialization == CMK_Function) {
431 if (const auto *DRE = dyn_cast<DeclRefExpr>(CallExpression))
432 return dyn_cast<FunctionDecl>(DRE->getDecl());
433 }
434
435 // Maybe this is an indirect call through a function pointer or something
436 // where we can't determine the exact decl.
437 return nullptr;
438 }
439
440 static CallableType getCallableType(const MatchFinder::MatchResult &Result) {
441 const auto *CallableExpr = Result.Nodes.getNodeAs<Expr>("ref");
442
443 QualType QT = CallableExpr->getType();
444 if (QT->isMemberFunctionPointerType())
445 return CT_MemberFunction;
446
447 if (QT->isFunctionPointerType() || QT->isFunctionReferenceType() ||
448 QT->isFunctionType())
449 return CT_Function;
450
451 if (QT->isRecordType()) {
452 const CXXRecordDecl *Decl = QT->getAsCXXRecordDecl();
453 if (!Decl)
454 return CT_Other;
455
456 return CT_Object;
457 }
458
459 return CT_Other;
460 }
461
462 static CallableMaterializationKind
463 getCallableMaterialization(const MatchFinder::MatchResult &Result) {
464 const auto *CallableExpr = Result.Nodes.getNodeAs<Expr>("ref");
465
466 const auto *NoTemporaries = ignoreTemporariesAndPointers(CallableExpr);
467
468 if (isa<CallExpr>(NoTemporaries))
469 return CMK_CallExpression;
470
471 if (isa<CXXFunctionalCastExpr>(NoTemporaries) ||
472 isa<CXXConstructExpr>(NoTemporaries))
473 return CMK_Function;
474
475 if (const auto *DRE = dyn_cast<DeclRefExpr>(NoTemporaries)) {
476 if (isa<FunctionDecl>(DRE->getDecl()))
477 return CMK_Function;
478 if (isa<VarDecl>(DRE->getDecl()))
479 return CMK_VariableRef;
480 }
481
482 return CMK_Other;
483 }
484
485 static LambdaProperties
486 getLambdaProperties(const MatchFinder::MatchResult &Result) {
487 const auto *CalleeExpr = Result.Nodes.getNodeAs<Expr>("ref");
488
489 LambdaProperties LP;
490
491 const auto *Bind = Result.Nodes.getNodeAs<CallExpr>("bind");
492 const auto *Decl = dyn_cast<FunctionDecl>(Bind->getCalleeDecl());
493 const auto *NS =
494 dyn_cast<NamespaceDecl>(Decl->getEnclosingNamespaceContext());
495 while (NS->isInlineNamespace())
496 NS = dyn_cast<NamespaceDecl>(NS->getDeclContext());
497 LP.BindNamespace = NS->getName();
498
499 LP.Callable.Type = getCallableType(Result);
500 LP.Callable.Materialization = getCallableMaterialization(Result);
501 LP.Callable.Decl =
502 getCallMethodDecl(Result, LP.Callable.Type, LP.Callable.Materialization);
503 LP.Callable.SourceTokens = getSourceTextForExpr(Result, CalleeExpr);
504 if (LP.Callable.Materialization == CMK_VariableRef) {
505 LP.Callable.CM = CM_ByValue;
506 LP.Callable.UsageIdentifier = getSourceTextForExpr(Result, CalleeExpr);
507 LP.Callable.CaptureIdentifier =
508 getSourceTextForExpr(Result, ignoreTemporariesAndPointers(CalleeExpr));
509 } else if (LP.Callable.Materialization == CMK_CallExpression) {
510 LP.Callable.CM = CM_InitExpression;
511 LP.Callable.UsageIdentifier = "Func";
512 LP.Callable.CaptureIdentifier = "Func";
513 LP.Callable.CaptureInitializer = getSourceTextForExpr(Result, CalleeExpr);
514 }
515
516 LP.BindArguments = buildBindArguments(Result, LP.Callable);
517
518 LP.IsFixitSupported = isFixitSupported(LP.Callable, LP.BindArguments);
519
520 return LP;
521 }
522
523 static bool emitCapture(llvm::StringSet<> &CaptureSet, StringRef Delimiter,
524 CaptureMode CM, StringRef Identifier,
525 StringRef InitExpression, raw_ostream &Stream) {
526 if (CM == CM_None)
527 return false;
528
529 // This capture has already been emitted.
530 if (CaptureSet.count(Identifier) != 0)
531 return false;
532
533 Stream << Delimiter;
534
535 if (CM == CM_ByRef)
536 Stream << "&";
537 Stream << Identifier;
538 if (CM == CM_InitExpression)
539 Stream << " = " << InitExpression;
540
541 CaptureSet.insert(Identifier);
542 return true;
543 }
544
545 static void emitCaptureList(const LambdaProperties &LP,
546 const MatchFinder::MatchResult &Result,
547 raw_ostream &Stream) {
548 llvm::StringSet<> CaptureSet;
549 bool AnyCapturesEmitted = false;
550
551 AnyCapturesEmitted = emitCapture(CaptureSet, "", LP.Callable.CM,
552 LP.Callable.CaptureIdentifier,
553 LP.Callable.CaptureInitializer, Stream);
554
555 for (const BindArgument &B : LP.BindArguments) {
556 if (B.CM == CM_None || !B.IsUsed)
557 continue;
558
559 StringRef Delimiter = AnyCapturesEmitted ? ", " : "";
560
561 if (emitCapture(CaptureSet, Delimiter, B.CM, B.CaptureIdentifier,
562 B.SourceTokens, Stream))
563 AnyCapturesEmitted = true;
564 }
565 }
566
567 static ArrayRef<BindArgument>
568 getForwardedArgumentList(const LambdaProperties &P) {
569 ArrayRef<BindArgument> Args = makeArrayRef(P.BindArguments);
570 if (P.Callable.Type != CT_MemberFunction)
571 return Args;
572
573 return Args.drop_front();
574 }
575 AvoidBindCheck::AvoidBindCheck(StringRef Name, ClangTidyContext *Context)
576 : ClangTidyCheck(Name, Context),
577 PermissiveParameterList(Options.get("PermissiveParameterList", 0) != 0) {}
578
579 void AvoidBindCheck::registerMatchers(MatchFinder *Finder) {
580 if (!getLangOpts().CPlusPlus14) // Need C++14 for generic lambdas.
581 return;
582
583 Finder->addMatcher(
584 callExpr(
585 callee(namedDecl(
586 anyOf(hasName("::boost::bind"), hasName("::std::bind")))),
587 hasArgument(
588 0, anyOf(expr(hasType(memberPointerType())).bind("ref"),
589 expr(hasParent(materializeTemporaryExpr().bind("ref"))),
590 expr().bind("ref"))))
591 .bind("bind"),
592 this);
593 }
594
595 void AvoidBindCheck::check(const MatchFinder::MatchResult &Result) {
596 const auto *MatchedDecl = Result.Nodes.getNodeAs<CallExpr>("bind");
597
598 LambdaProperties LP = getLambdaProperties(Result);
599 auto Diag =
600 diag(MatchedDecl->getBeginLoc(),
601 formatv("prefer a lambda to {0}::bind", LP.BindNamespace).str());
602 if (!LP.IsFixitSupported)
603 return;
604
605 const auto *Ref = Result.Nodes.getNodeAs<Expr>("ref");
606
607 std::string Buffer;
608 llvm::raw_string_ostream Stream(Buffer);
609
610 Stream << "[";
611 emitCaptureList(LP, Result, Stream);
612 Stream << "]";
613
614 ArrayRef<BindArgument> FunctionCallArgs = makeArrayRef(LP.BindArguments);
615
616 addPlaceholderArgs(LP, Stream, PermissiveParameterList);
617
618 if (LP.Callable.Type == CT_Function) {
619 StringRef SourceTokens = LP.Callable.SourceTokens;
620 SourceTokens.consume_front("&");
621 Stream << " { return " << SourceTokens;
622 } else if (LP.Callable.Type == CT_MemberFunction) {
623 const auto *MethodDecl = dyn_cast<CXXMethodDecl>(LP.Callable.Decl);
624 const BindArgument &ObjPtr = FunctionCallArgs.front();
625
626 Stream << " { ";
627 if (!isa<CXXThisExpr>(ignoreTemporariesAndPointers(ObjPtr.E))) {
628 Stream << ObjPtr.UsageIdentifier;
629 Stream << "->";
630 }
631
632 Stream << MethodDecl->getName();
633 } else {
634 Stream << " { return ";
635 switch (LP.Callable.CM) {
636 case CM_ByValue:
637 case CM_ByRef:
638 if (LP.Callable.UsageIdentifier != LP.Callable.CaptureIdentifier) {
639 Stream << "(" << LP.Callable.UsageIdentifier << ")";
640 break;
641 }
642 LLVM_FALLTHROUGH;
643 case CM_InitExpression:
644 Stream << LP.Callable.UsageIdentifier;
645 break;
646 default:
647 Ref->printPretty(Stream, nullptr, Result.Context->getPrintingPolicy());
648 }
649 }
650
651 Stream << "(";
652
653 addFunctionCallArgs(getForwardedArgumentList(LP), Stream);
654 Stream << "); }";
655
656 Diag << FixItHint::CreateReplacement(MatchedDecl->getSourceRange(),
657 Stream.str());
658 }
659
660 } // namespace modernize
661 } // namespace tidy
662 } // namespace clang
clang::ast_matchers
Definition: AbseilMatcher.h:14
clang::tidy::modernize::getCallOperator
const FunctionDecl * getCallOperator(const CXXRecordDecl *Callable, size_t NumArgs)
Definition: AvoidBindCheck.cpp:407
clang::tidy::modernize::getCallableType
static CallableType getCallableType(const MatchFinder::MatchResult &Result)
Definition: AvoidBindCheck.cpp:440
Decl
const FunctionDecl * Decl
Definition: AvoidBindCheck.cpp:93
clang::tidy::modernize::AvoidBindCheck::check
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
ClangTidyChecks that register ASTMatchers should do the actual work in here.
Definition: AvoidBindCheck.cpp:595
clang::tidy::modernize::addFunctionCallArgs
static void addFunctionCallArgs(ArrayRef< BindArgument > Args, llvm::raw_ostream &Stream)
Definition: AvoidBindCheck.cpp:330
clang::tidy::modernize::@397::CallableMaterializationKind
CallableMaterializationKind
Definition: AvoidBindCheck.cpp:47
clang::tidy::modernize::@397::CaptureMode
CaptureMode
Definition: AvoidBindCheck.cpp:38
clang::tidy::modernize::@397::BindArgumentKind
BindArgumentKind
Definition: AvoidBindCheck.cpp:37
CaptureInitializer
StringRef CaptureInitializer
Definition: AvoidBindCheck.cpp:92
Callable
CallableInfo Callable
Definition: AvoidBindCheck.cpp:97
BindArguments
SmallVector< BindArgument, 4 > BindArguments
Definition: AvoidBindCheck.cpp:98
clang::tidy::modernize::initializeBindArgumentForCallExpr
static void initializeBindArgumentForCallExpr(const MatchFinder::MatchResult &Result, BindArgument &B, const CallExpr *CE, unsigned &CaptureIndex)
Definition: AvoidBindCheck.cpp:145
clang::tidy::modernize::tryCaptureAsLocalVariable
static bool tryCaptureAsLocalVariable(const MatchFinder::MatchResult &Result, BindArgument &B, const Expr *E)
Definition: AvoidBindCheck.cpp:174
clang::tidy::modernize::buildBindArguments
static SmallVector< BindArgument, 4 > buildBindArguments(const MatchFinder::MatchResult &Result, const CallableInfo &Callable)
Definition: AvoidBindCheck.cpp:226
clang::tidy::modernize::ignoreTemporariesAndConstructors
static const Expr * ignoreTemporariesAndConstructors(const Expr *E)
Definition: AvoidBindCheck.cpp:116
IsFixitSupported
bool IsFixitSupported
Definition: AvoidBindCheck.cpp:100
Materialization
CallableMaterializationKind Materialization
Definition: AvoidBindCheck.cpp:87
AvoidBindCheck.h
clang::tidy::ClangTidyCheck
Base class for all clang-tidy checks.
Definition: ClangTidyCheck.h:47
clang::tidy::ClangTidyCheck::getLangOpts
const LangOptions & getLangOpts() const
Returns the language options from the context.
Definition: ClangTidyCheck.h:188
clang::tidy::modernize::anyDescendantIsLocal
static bool anyDescendantIsLocal(const Stmt *Statement)
Definition: AvoidBindCheck.cpp:161
clang::tidy::modernize::isPlaceHolderIndexRepeated
static bool isPlaceHolderIndexRepeated(const ArrayRef< BindArgument > Args)
Definition: AvoidBindCheck.cpp:348
clang::tidy::modernize::addPlaceholderArgs
static void addPlaceholderArgs(const LambdaProperties &LP, llvm::raw_ostream &Stream, bool PermissiveParameterList)
Definition: AvoidBindCheck.cpp:296
Kind
BindArgumentKind Kind
Definition: AvoidBindCheck.cpp:57
clang::tidy::modernize::tryCaptureAsMemberVariable
static bool tryCaptureAsMemberVariable(const MatchFinder::MatchResult &Result, BindArgument &B, const Expr *E)
Definition: AvoidBindCheck.cpp:196
UsageIdentifier
std::string UsageIdentifier
Definition: AvoidBindCheck.cpp:73
clang::tidy::modernize::getForwardedArgumentList
static ArrayRef< BindArgument > getForwardedArgumentList(const LambdaProperties &P)
Definition: AvoidBindCheck.cpp:568
BindNamespace
StringRef BindNamespace
Definition: AvoidBindCheck.cpp:99
clang::tidy::modernize::getCallMethodDecl
const FunctionDecl * getCallMethodDecl(const MatchFinder::MatchResult &Result, CallableType Type, CallableMaterializationKind Materialization)
Definition: AvoidBindCheck.cpp:418
SourceTokens
StringRef SourceTokens
Definition: AvoidBindCheck.cpp:64
clang::tidy::modernize::findPositionOfPlaceholderUse
static int findPositionOfPlaceholderUse(ArrayRef< BindArgument > Args, size_t PlaceholderIndex)
Definition: AvoidBindCheck.cpp:287
Name
static constexpr llvm::StringLiteral Name
Definition: UppercaseLiteralSuffixCheck.cpp:27
clang::clangd::getTokenRange
llvm::Optional< Range > getTokenRange(const SourceManager &SM, const LangOptions &LangOpts, SourceLocation TokLoc)
Returns the taken range at TokLoc.
Definition: SourceCode.cpp:227
clang::tidy::modernize::getLambdaProperties
static LambdaProperties getLambdaProperties(const MatchFinder::MatchResult &Result)
Definition: AvoidBindCheck.cpp:486
clang::tidy::modernize::isFixitSupported
static bool isFixitSupported(const CallableInfo &Callee, ArrayRef< BindArgument > Args)
Definition: AvoidBindCheck.cpp:378
clang::tidy::modernize::AvoidBindCheck::registerMatchers
void registerMatchers(ast_matchers::MatchFinder *Finder) override
Override this to register AST matchers with Finder.
Definition: AvoidBindCheck.cpp:579
clang::tidy::modernize::getCallableMaterialization
static CallableMaterializationKind getCallableMaterialization(const MatchFinder::MatchResult &Result)
Definition: AvoidBindCheck.cpp:463
clang
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Definition: ApplyReplacements.h:27
CaptureIdentifier
std::string CaptureIdentifier
Definition: AvoidBindCheck.cpp:69
Type
CallableType Type
Definition: AvoidBindCheck.cpp:86
clang::tidy::modernize::getSourceTextForExpr
static StringRef getSourceTextForExpr(const MatchFinder::MatchResult &Result, const Expr *E)
Definition: AvoidBindCheck.cpp:127
clang::tidy::ClangTidyContext
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
Definition: ClangTidyDiagnosticConsumer.h:77
E
const Expr * E
Definition: AvoidBindCheck.cpp:82
CM
CaptureMode CM
Definition: AvoidBindCheck.cpp:61
clang::tidy::modernize::@397::CallableType
CallableType
Definition: AvoidBindCheck.cpp:40
clang::tidy::modernize::isCallExprNamed
static bool isCallExprNamed(const Expr *E, StringRef Name)
Definition: AvoidBindCheck.cpp:134
IsUsed
bool IsUsed
Definition: AvoidBindCheck.cpp:79
clang::tidy::modernize::emitCapture
static bool emitCapture(llvm::StringSet<> &CaptureSet, StringRef Delimiter, CaptureMode CM, StringRef Identifier, StringRef InitExpression, raw_ostream &Stream)
Definition: AvoidBindCheck.cpp:523
DeclRef
const DeclRefExpr * DeclRef
Definition: UseAfterMoveCheck.cpp:29
clang::tidy::ClangTidyCheck::diag
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check&#39;s name.
Definition: ClangTidyCheck.cpp:21
clang::tidy::modernize::ignoreTemporariesAndPointers
static const Expr * ignoreTemporariesAndPointers(const Expr *E)
Definition: AvoidBindCheck.cpp:105
clang::tidy::modernize::emitCaptureList
static void emitCaptureList(const LambdaProperties &LP, const MatchFinder::MatchResult &Result, raw_ostream &Stream)
Definition: AvoidBindCheck.cpp:545
clang::tidy::modernize::findCandidateCallOperators
static std::vector< const CXXMethodDecl * > findCandidateCallOperators(const CXXRecordDecl *RecordDecl, size_t NumArgs)
Definition: AvoidBindCheck.cpp:360
PlaceHolderIndex
size_t PlaceHolderIndex
Definition: AvoidBindCheck.cpp:76