clang 22.0.0git
RawPtrRefLambdaCapturesChecker.cpp
Go to the documentation of this file.
1//=======- UncountedLambdaCapturesChecker.cpp --------------------*- C++ -*-==//
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 "ASTUtils.h"
10#include "DiagOutputUtils.h"
11#include "PtrTypesSemantics.h"
17#include <optional>
18
19using namespace clang;
20using namespace ento;
21
22namespace {
23class RawPtrRefLambdaCapturesChecker
24 : public Checker<check::ASTDecl<TranslationUnitDecl>> {
25private:
26 BugType Bug;
27 mutable BugReporter *BR = nullptr;
28 TrivialFunctionAnalysis TFA;
29
30protected:
31 mutable std::optional<RetainTypeChecker> RTC;
32
33public:
34 RawPtrRefLambdaCapturesChecker(const char *description)
35 : Bug(this, description, "WebKit coding guidelines") {}
36
37 virtual std::optional<bool> isUnsafePtr(QualType) const = 0;
38 virtual bool isPtrType(const std::string &) const = 0;
39 virtual const char *ptrKind(QualType QT) const = 0;
40
41 void checkASTDecl(const TranslationUnitDecl *TUD, AnalysisManager &MGR,
42 BugReporter &BRArg) const {
43 BR = &BRArg;
44
45 // The calls to checkAST* from AnalysisConsumer don't
46 // visit template instantiations or lambda classes. We
47 // want to visit those, so we make our own RecursiveASTVisitor.
48 struct LocalVisitor : DynamicRecursiveASTVisitor {
49 const RawPtrRefLambdaCapturesChecker *Checker;
50 llvm::DenseSet<const DeclRefExpr *> DeclRefExprsToIgnore;
51 llvm::DenseSet<const LambdaExpr *> LambdasToIgnore;
52 llvm::DenseSet<const ValueDecl *> ProtectedThisDecls;
53 llvm::DenseSet<const CallExpr *> CallToIgnore;
54 llvm::DenseSet<const CXXConstructExpr *> ConstructToIgnore;
55 llvm::DenseMap<const VarDecl *, const LambdaExpr *> LambdaOwnerMap;
56
57 QualType ClsType;
58
59 explicit LocalVisitor(const RawPtrRefLambdaCapturesChecker *Checker)
60 : Checker(Checker) {
61 assert(Checker);
62 ShouldVisitTemplateInstantiations = true;
63 ShouldVisitImplicitCode = false;
64 }
65
66 bool TraverseCXXMethodDecl(CXXMethodDecl *CXXMD) override {
67 llvm::SaveAndRestore SavedDecl(ClsType);
68 if (CXXMD->isInstance())
69 ClsType = CXXMD->getThisType();
70 return DynamicRecursiveASTVisitor::TraverseCXXMethodDecl(CXXMD);
71 }
72
73 bool TraverseObjCMethodDecl(ObjCMethodDecl *OCMD) override {
74 llvm::SaveAndRestore SavedDecl(ClsType);
75 if (OCMD && OCMD->isInstanceMethod()) {
76 if (auto *ImplParamDecl = OCMD->getSelfDecl())
77 ClsType = ImplParamDecl->getType();
78 }
79 return DynamicRecursiveASTVisitor::TraverseObjCMethodDecl(OCMD);
80 }
81
82 bool VisitTypedefDecl(TypedefDecl *TD) override {
83 if (Checker->RTC)
84 Checker->RTC->visitTypedef(TD);
85 return true;
86 }
87
88 bool shouldCheckThis() {
89 auto result =
90 !ClsType.isNull() ? Checker->isUnsafePtr(ClsType) : std::nullopt;
91 return result && *result;
92 }
93
94 bool VisitLambdaExpr(LambdaExpr *L) override {
95 if (LambdasToIgnore.contains(L))
96 return true;
97 Checker->visitLambdaExpr(L, shouldCheckThis() && !hasProtectedThis(L),
98 ClsType);
99 return true;
100 }
101
102 bool VisitVarDecl(VarDecl *VD) override {
103 auto *Init = VD->getInit();
104 if (!Init)
105 return true;
106 if (auto *L = dyn_cast_or_null<LambdaExpr>(Init->IgnoreParenCasts())) {
107 LambdasToIgnore.insert(L); // Evaluate lambdas in VisitDeclRefExpr.
108 return true;
109 }
110 if (!VD->hasLocalStorage())
111 return true;
112 if (auto *E = dyn_cast<ExprWithCleanups>(Init))
113 Init = E->getSubExpr();
114 if (auto *E = dyn_cast<CXXBindTemporaryExpr>(Init))
115 Init = E->getSubExpr();
116 if (auto *CE = dyn_cast<CallExpr>(Init)) {
117 if (auto *Callee = CE->getDirectCallee()) {
118 auto FnName = safeGetName(Callee);
119 unsigned ArgCnt = CE->getNumArgs();
120 if (FnName == "makeScopeExit" && ArgCnt == 1) {
121 auto *Arg = CE->getArg(0);
122 if (auto *E = dyn_cast<MaterializeTemporaryExpr>(Arg))
123 Arg = E->getSubExpr();
124 if (auto *L = dyn_cast<LambdaExpr>(Arg)) {
125 LambdaOwnerMap.insert(std::make_pair(VD, L));
126 CallToIgnore.insert(CE);
127 LambdasToIgnore.insert(L);
128 }
129 } else if (FnName == "makeVisitor") {
130 for (unsigned ArgIndex = 0; ArgIndex < ArgCnt; ++ArgIndex) {
131 auto *Arg = CE->getArg(ArgIndex);
132 if (auto *E = dyn_cast<MaterializeTemporaryExpr>(Arg))
133 Arg = E->getSubExpr();
134 if (auto *L = dyn_cast<LambdaExpr>(Arg)) {
135 LambdaOwnerMap.insert(std::make_pair(VD, L));
136 CallToIgnore.insert(CE);
137 LambdasToIgnore.insert(L);
138 }
139 }
140 }
141 }
142 } else if (auto *CE = dyn_cast<CXXConstructExpr>(Init)) {
143 if (auto *Ctor = CE->getConstructor()) {
144 if (auto *Cls = Ctor->getParent()) {
145 auto FnName = safeGetName(Cls);
146 unsigned ArgCnt = CE->getNumArgs();
147 if (FnName == "ScopeExit" && ArgCnt == 1) {
148 auto *Arg = CE->getArg(0);
149 if (auto *E = dyn_cast<MaterializeTemporaryExpr>(Arg))
150 Arg = E->getSubExpr();
151 if (auto *L = dyn_cast<LambdaExpr>(Arg)) {
152 LambdaOwnerMap.insert(std::make_pair(VD, L));
153 ConstructToIgnore.insert(CE);
154 LambdasToIgnore.insert(L);
155 }
156 }
157 }
158 }
159 }
160 return true;
161 }
162
163 bool VisitDeclRefExpr(DeclRefExpr *DRE) override {
164 if (DeclRefExprsToIgnore.contains(DRE))
165 return true;
166 auto *VD = dyn_cast_or_null<VarDecl>(DRE->getDecl());
167 if (!VD)
168 return true;
169 if (auto It = LambdaOwnerMap.find(VD); It != LambdaOwnerMap.end()) {
170 auto *L = It->second;
171 Checker->visitLambdaExpr(L, shouldCheckThis() && !hasProtectedThis(L),
172 ClsType);
173 return true;
174 }
175 auto *Init = VD->getInit();
176 if (!Init)
177 return true;
178 auto *L = dyn_cast_or_null<LambdaExpr>(Init->IgnoreParenCasts());
179 if (!L)
180 return true;
181 LambdasToIgnore.insert(L);
182 Checker->visitLambdaExpr(L, shouldCheckThis() && !hasProtectedThis(L),
183 ClsType);
184 return true;
185 }
186
187 bool shouldTreatAllArgAsNoEscape(FunctionDecl *FDecl) {
188 std::string PreviousName = safeGetName(FDecl);
189 for (auto *Decl = FDecl->getParent(); Decl; Decl = Decl->getParent()) {
190 if (!isa<NamespaceDecl>(Decl) && !isa<CXXRecordDecl>(Decl))
191 return false;
192 auto Name = safeGetName(Decl);
193 // WTF::switchOn(T, F... f) is a variadic template function and
194 // couldn't be annotated with NOESCAPE. We hard code it here to
195 // workaround that.
196 if (Name == "WTF" && PreviousName == "switchOn")
197 return true;
198 // Treat every argument of functions in std::ranges as noescape.
199 if (Name == "std" && PreviousName == "ranges")
200 return true;
201 PreviousName = Name;
202 }
203 return false;
204 }
205
206 bool VisitCXXConstructExpr(CXXConstructExpr *CE) override {
207 if (ConstructToIgnore.contains(CE))
208 return true;
209 if (auto *Callee = CE->getConstructor()) {
210 unsigned ArgIndex = 0;
211 for (auto *Param : Callee->parameters()) {
212 if (ArgIndex >= CE->getNumArgs())
213 return true;
214 auto *Arg = CE->getArg(ArgIndex)->IgnoreParenCasts();
215 if (auto *L = findLambdaInArg(Arg)) {
216 LambdasToIgnore.insert(L);
217 if (!Param->hasAttr<NoEscapeAttr>())
218 Checker->visitLambdaExpr(
219 L, shouldCheckThis() && !hasProtectedThis(L), ClsType);
220 }
221 ++ArgIndex;
222 }
223 }
224 return true;
225 }
226
227 bool VisitCallExpr(CallExpr *CE) override {
228 if (CallToIgnore.contains(CE))
229 return true;
230 checkCalleeLambda(CE);
231 if (auto *Callee = CE->getDirectCallee()) {
232 if (isVisitFunction(CE, Callee))
233 return true;
234 checkParameters(CE, Callee);
235 } else if (auto *CalleeE = CE->getCallee()) {
236 if (auto *DRE = dyn_cast<DeclRefExpr>(CalleeE->IgnoreParenCasts())) {
237 if (auto *Callee = dyn_cast_or_null<FunctionDecl>(DRE->getDecl()))
238 checkParameters(CE, Callee);
239 }
240 }
241 return true;
242 }
243
244 bool isVisitFunction(CallExpr *CallExpr, FunctionDecl *FnDecl) {
245 bool IsVisitFn = safeGetName(FnDecl) == "visit";
246 if (!IsVisitFn)
247 return false;
248 bool ArgCnt = CallExpr->getNumArgs();
249 if (!ArgCnt)
250 return false;
251 auto *Ns = FnDecl->getParent();
252 if (!Ns)
253 return false;
254 auto NsName = safeGetName(Ns);
255 if (NsName != "WTF" && NsName != "std")
256 return false;
257 auto *Arg = CallExpr->getArg(0);
258 if (!Arg)
259 return false;
260 auto *DRE = dyn_cast<DeclRefExpr>(Arg->IgnoreParenCasts());
261 if (!DRE)
262 return false;
263 auto *VD = dyn_cast<VarDecl>(DRE->getDecl());
264 if (!VD)
265 return false;
266 if (!LambdaOwnerMap.contains(VD))
267 return false;
268 DeclRefExprsToIgnore.insert(DRE);
269 return true;
270 }
271
272 void checkParameters(CallExpr *CE, FunctionDecl *Callee) {
273 unsigned ArgIndex = isa<CXXOperatorCallExpr>(CE);
274 bool TreatAllArgsAsNoEscape = shouldTreatAllArgAsNoEscape(Callee);
275 for (auto *Param : Callee->parameters()) {
276 if (ArgIndex >= CE->getNumArgs())
277 return;
278 auto *Arg = CE->getArg(ArgIndex)->IgnoreParenCasts();
279 if (auto *L = findLambdaInArg(Arg)) {
280 LambdasToIgnore.insert(L);
281 if (!Param->hasAttr<NoEscapeAttr>() && !TreatAllArgsAsNoEscape)
282 Checker->visitLambdaExpr(
283 L, shouldCheckThis() && !hasProtectedThis(L), ClsType);
284 }
285 ++ArgIndex;
286 }
287 }
288
289 LambdaExpr *findLambdaInArg(Expr *E) {
290 if (auto *Lambda = dyn_cast_or_null<LambdaExpr>(E))
291 return Lambda;
292 auto *TempExpr = dyn_cast_or_null<CXXBindTemporaryExpr>(E);
293 if (!TempExpr)
294 return nullptr;
295 E = TempExpr->getSubExpr()->IgnoreParenCasts();
296 if (!E)
297 return nullptr;
298 if (auto *Lambda = dyn_cast<LambdaExpr>(E))
299 return Lambda;
300 auto *CE = dyn_cast_or_null<CXXConstructExpr>(E);
301 if (!CE || !CE->getNumArgs())
302 return nullptr;
303 auto *CtorArg = CE->getArg(0)->IgnoreParenCasts();
304 if (!CtorArg)
305 return nullptr;
306 auto *InnerCE = dyn_cast_or_null<CXXConstructExpr>(CtorArg);
307 if (InnerCE && InnerCE->getNumArgs())
308 CtorArg = InnerCE->getArg(0)->IgnoreParenCasts();
309 auto updateIgnoreList = [&] {
310 ConstructToIgnore.insert(CE);
311 if (InnerCE)
312 ConstructToIgnore.insert(InnerCE);
313 };
314 if (auto *Lambda = dyn_cast<LambdaExpr>(CtorArg)) {
315 updateIgnoreList();
316 return Lambda;
317 }
318 if (auto *TempExpr = dyn_cast<CXXBindTemporaryExpr>(CtorArg)) {
319 E = TempExpr->getSubExpr()->IgnoreParenCasts();
320 if (auto *Lambda = dyn_cast<LambdaExpr>(E)) {
321 updateIgnoreList();
322 return Lambda;
323 }
324 }
325 auto *DRE = dyn_cast<DeclRefExpr>(CtorArg);
326 if (!DRE)
327 return nullptr;
328 auto *VD = dyn_cast_or_null<VarDecl>(DRE->getDecl());
329 if (!VD)
330 return nullptr;
331 auto *Init = VD->getInit();
332 if (!Init)
333 return nullptr;
334 if (auto *Lambda = dyn_cast<LambdaExpr>(Init)) {
335 DeclRefExprsToIgnore.insert(DRE);
336 updateIgnoreList();
337 return Lambda;
338 }
339 return nullptr;
340 }
341
342 void checkCalleeLambda(CallExpr *CE) {
343 auto *Callee = CE->getCallee();
344 if (!Callee)
345 return;
346 auto *DRE = dyn_cast<DeclRefExpr>(Callee->IgnoreParenCasts());
347 if (!DRE)
348 return;
349 auto *MD = dyn_cast_or_null<CXXMethodDecl>(DRE->getDecl());
350 if (!MD || CE->getNumArgs() < 1)
351 return;
352 auto *Arg = CE->getArg(0)->IgnoreParenCasts();
353 if (auto *L = dyn_cast_or_null<LambdaExpr>(Arg)) {
354 LambdasToIgnore.insert(L); // Calling a lambda upon creation is safe.
355 return;
356 }
357 auto *ArgRef = dyn_cast<DeclRefExpr>(Arg);
358 if (!ArgRef)
359 return;
360 auto *VD = dyn_cast_or_null<VarDecl>(ArgRef->getDecl());
361 if (!VD)
362 return;
363 auto *Init = VD->getInit();
364 if (!Init)
365 return;
366 auto *L = dyn_cast_or_null<LambdaExpr>(Init->IgnoreParenCasts());
367 if (!L)
368 return;
369 DeclRefExprsToIgnore.insert(ArgRef);
370 LambdasToIgnore.insert(L);
371 }
372
373 bool hasProtectedThis(const LambdaExpr *L) {
374 for (const LambdaCapture &OtherCapture : L->captures()) {
375 if (!OtherCapture.capturesVariable())
376 continue;
377 if (auto *ValueDecl = OtherCapture.getCapturedVar()) {
378 if (declProtectsThis(ValueDecl)) {
379 ProtectedThisDecls.insert(ValueDecl);
380 return true;
381 }
382 }
383 }
384 return false;
385 }
386
387 bool declProtectsThis(const ValueDecl *ValueDecl) const {
388 auto *VD = dyn_cast<VarDecl>(ValueDecl);
389 if (!VD)
390 return false;
391 auto *Init = VD->getInit();
392 if (!Init)
393 return false;
394 const Expr *Arg = Init->IgnoreParenCasts();
395 do {
396 if (auto *BTE = dyn_cast<CXXBindTemporaryExpr>(Arg))
397 Arg = BTE->getSubExpr()->IgnoreParenCasts();
398 if (auto *CE = dyn_cast<CXXConstructExpr>(Arg)) {
399 auto *Ctor = CE->getConstructor();
400 if (!Ctor)
401 return false;
402 auto clsName = safeGetName(Ctor->getParent());
403 if (Checker->isPtrType(clsName) && CE->getNumArgs()) {
404 Arg = CE->getArg(0)->IgnoreParenCasts();
405 continue;
406 }
407 if (auto *Type = ClsType.getTypePtrOrNull()) {
408 if (auto *CXXR = Type->getPointeeCXXRecordDecl()) {
409 if (CXXR == Ctor->getParent() && Ctor->isMoveConstructor() &&
410 CE->getNumArgs() == 1) {
411 Arg = CE->getArg(0)->IgnoreParenCasts();
412 continue;
413 }
414 }
415 }
416 return false;
417 }
418 if (auto *CE = dyn_cast<CallExpr>(Arg)) {
419 if (CE->isCallToStdMove() && CE->getNumArgs() == 1) {
420 Arg = CE->getArg(0)->IgnoreParenCasts();
421 continue;
422 }
423 if (auto *Callee = CE->getDirectCallee()) {
424 if (isCtorOfSafePtr(Callee) && CE->getNumArgs() == 1) {
425 Arg = CE->getArg(0)->IgnoreParenCasts();
426 continue;
427 }
428 }
429 }
430 if (auto *OpCE = dyn_cast<CXXOperatorCallExpr>(Arg)) {
431 auto OpCode = OpCE->getOperator();
432 if (OpCode == OO_Star || OpCode == OO_Amp) {
433 auto *Callee = OpCE->getDirectCallee();
434 if (!Callee)
435 return false;
436 auto clsName = safeGetName(Callee->getParent());
437 if (!Checker->isPtrType(clsName) || !OpCE->getNumArgs())
438 return false;
439 Arg = OpCE->getArg(0)->IgnoreParenCasts();
440 continue;
441 }
442 }
443 if (auto *UO = dyn_cast<UnaryOperator>(Arg)) {
444 auto OpCode = UO->getOpcode();
445 if (OpCode == UO_Deref || OpCode == UO_AddrOf) {
446 Arg = UO->getSubExpr()->IgnoreParenCasts();
447 continue;
448 }
449 }
450 break;
451 } while (Arg);
452 if (auto *DRE = dyn_cast<DeclRefExpr>(Arg)) {
453 auto *Decl = DRE->getDecl();
454 if (auto *ImplicitParam = dyn_cast<ImplicitParamDecl>(Decl)) {
455 auto kind = ImplicitParam->getParameterKind();
456 return kind == ImplicitParamKind::ObjCSelf ||
457 kind == ImplicitParamKind::CXXThis;
458 }
459 return ProtectedThisDecls.contains(Decl);
460 }
461 return isa<CXXThisExpr>(Arg);
462 }
463 };
464
465 LocalVisitor visitor(this);
466 if (RTC)
467 RTC->visitTranslationUnitDecl(TUD);
468 visitor.TraverseDecl(const_cast<TranslationUnitDecl *>(TUD));
469 }
470
471 void visitLambdaExpr(const LambdaExpr *L, bool shouldCheckThis,
472 const QualType T,
473 bool ignoreParamVarDecl = false) const {
474 if (TFA.isTrivial(L->getBody()))
475 return;
476 for (const LambdaCapture &C : L->captures()) {
477 if (C.capturesVariable()) {
478 ValueDecl *CapturedVar = C.getCapturedVar();
479 if (ignoreParamVarDecl && isa<ParmVarDecl>(CapturedVar))
480 continue;
481 if (auto *ImplicitParam = dyn_cast<ImplicitParamDecl>(CapturedVar)) {
482 auto kind = ImplicitParam->getParameterKind();
483 if ((kind == ImplicitParamKind::ObjCSelf ||
484 kind == ImplicitParamKind::CXXThis) &&
485 !shouldCheckThis)
486 continue;
487 }
488 QualType CapturedVarQualType = CapturedVar->getType();
489 auto IsUncountedPtr = isUnsafePtr(CapturedVar->getType());
490 if (C.getCaptureKind() == LCK_ByCopy &&
491 CapturedVarQualType->isReferenceType())
492 continue;
493 if (IsUncountedPtr && *IsUncountedPtr)
494 reportBug(C, CapturedVar, CapturedVarQualType, L);
495 } else if (C.capturesThis() && shouldCheckThis) {
496 if (ignoreParamVarDecl) // this is always a parameter to this function.
497 continue;
498 reportBugOnThisPtr(C, T);
499 }
500 }
501 }
502
503 void reportBug(const LambdaCapture &Capture, ValueDecl *CapturedVar,
504 const QualType T, const LambdaExpr *L) const {
505 assert(CapturedVar);
506
507 auto Location = Capture.getLocation();
508 if (isa<ImplicitParamDecl>(CapturedVar) && !Location.isValid())
509 Location = L->getBeginLoc();
510
511 SmallString<100> Buf;
512 llvm::raw_svector_ostream Os(Buf);
513
514 if (Capture.isExplicit()) {
515 Os << "Captured ";
516 } else {
517 Os << "Implicitly captured ";
518 }
520 Os << "raw-pointer ";
521 } else {
522 Os << "reference ";
523 }
524
525 printQuotedQualifiedName(Os, CapturedVar);
526 Os << " to " << ptrKind(T) << " type is unsafe.";
527
528 PathDiagnosticLocation BSLoc(Location, BR->getSourceManager());
529 auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
530 BR->emitReport(std::move(Report));
531 }
532
533 void reportBugOnThisPtr(const LambdaCapture &Capture,
534 const QualType T) const {
535 SmallString<100> Buf;
536 llvm::raw_svector_ostream Os(Buf);
537
538 if (Capture.isExplicit()) {
539 Os << "Captured ";
540 } else {
541 Os << "Implicitly captured ";
542 }
543
544 Os << "raw-pointer 'this' to " << ptrKind(T) << " type is unsafe.";
545
546 PathDiagnosticLocation BSLoc(Capture.getLocation(), BR->getSourceManager());
547 auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
548 BR->emitReport(std::move(Report));
549 }
550};
551
552class UncountedLambdaCapturesChecker : public RawPtrRefLambdaCapturesChecker {
553public:
554 UncountedLambdaCapturesChecker()
555 : RawPtrRefLambdaCapturesChecker("Lambda capture of uncounted or "
556 "unchecked variable") {}
557
558 std::optional<bool> isUnsafePtr(QualType QT) const final {
559 auto result1 = isUncountedPtr(QT);
560 auto result2 = isUncheckedPtr(QT);
561 if (result1 && *result1)
562 return true;
563 if (result2 && *result2)
564 return true;
565 if (result1)
566 return *result1;
567 return result2;
568 }
569
570 virtual bool isPtrType(const std::string &Name) const final {
571 return isRefType(Name) || isCheckedPtr(Name);
572 }
573
574 const char *ptrKind(QualType QT) const final {
575 if (isUncounted(QT))
576 return "uncounted";
577 return "unchecked";
578 }
579};
580
581class UnretainedLambdaCapturesChecker : public RawPtrRefLambdaCapturesChecker {
582public:
583 UnretainedLambdaCapturesChecker()
584 : RawPtrRefLambdaCapturesChecker("Lambda capture of unretained "
585 "variables") {
586 RTC = RetainTypeChecker();
587 }
588
589 std::optional<bool> isUnsafePtr(QualType QT) const final {
590 return RTC->isUnretained(QT);
591 }
592
593 virtual bool isPtrType(const std::string &Name) const final {
594 return isRetainPtrOrOSPtr(Name);
595 }
596
597 const char *ptrKind(QualType QT) const final { return "unretained"; }
598};
599
600} // namespace
601
602void ento::registerUncountedLambdaCapturesChecker(CheckerManager &Mgr) {
603 Mgr.registerChecker<UncountedLambdaCapturesChecker>();
604}
605
606bool ento::shouldRegisterUncountedLambdaCapturesChecker(
607 const CheckerManager &mgr) {
608 return true;
609}
610
611void ento::registerUnretainedLambdaCapturesChecker(CheckerManager &Mgr) {
612 Mgr.registerChecker<UnretainedLambdaCapturesChecker>();
613}
614
615bool ento::shouldRegisterUnretainedLambdaCapturesChecker(
616 const CheckerManager &mgr) {
617 return true;
618}
Expr * getArg(unsigned Arg)
Return the specified argument.
Definition ExprCXX.h:1692
CXXConstructorDecl * getConstructor() const
Get the constructor that this expression will (ultimately) call.
Definition ExprCXX.h:1612
unsigned getNumArgs() const
Return the number of arguments to the constructor call.
Definition ExprCXX.h:1689
QualType getThisType() const
Return the type of the this pointer.
Definition DeclCXX.cpp:2809
bool isInstance() const
Definition DeclCXX.h:2156
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
Definition Expr.h:3081
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return null.
Definition Expr.h:3060
bool isCallToStdMove() const
Definition Expr.cpp:3619
Expr * getCallee()
Definition Expr.h:3024
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
Definition Expr.h:3068
DeclContext * getParent()
getParent - Returns the containing DeclContext.
Definition DeclBase.h:2109
ValueDecl * getDecl()
Definition Expr.h:1338
Expr * IgnoreParenCasts() LLVM_READONLY
Skip past any parentheses and casts which might surround this expression until reaching a fixed point...
Definition Expr.cpp:3090
Stmt * getBody() const
Retrieve the body of the lambda.
Definition ExprCXX.cpp:1346
SourceLocation getBeginLoc() const LLVM_READONLY
Definition ExprCXX.h:2184
capture_range captures() const
Retrieve this lambda's captures.
Definition ExprCXX.cpp:1371
ImplicitParamDecl * getSelfDecl() const
Definition DeclObjC.h:418
bool isInstanceMethod() const
Definition DeclObjC.h:426
bool isNull() const
Return true if this QualType doesn't point to a type yet.
Definition TypeBase.h:1004
const Type * getTypePtrOrNull() const
Definition TypeBase.h:8282
bool isReferenceType() const
Definition TypeBase.h:8539
QualType getType() const
Definition Decl.h:723
const Expr * getInit() const
Definition Decl.h:1368
bool hasLocalStorage() const
Returns true if a variable with function scope is a non-static local variable.
Definition Decl.h:1184
CHECKER * registerChecker(AT &&...Args)
Register a single-part checker (derived from Checker): construct its singleton instance,...
Simple checker classes that implement one frontend (i.e.
Definition Checker.h:553
unsigned kind
All of the diagnostics that can be emitted by the frontend.
constexpr bool isPtrType(PrimType T)
Definition PrimType.h:85
std::variant< struct RequiresDecl, struct HeaderDecl, struct UmbrellaDirDecl, struct ModuleDecl, struct ExcludeDecl, struct ExportDecl, struct ExportAsDecl, struct ExternModuleDecl, struct UseDecl, struct LinkDecl, struct ConfigMacrosDecl, struct ConflictDecl > Decl
All declarations that can appear in a module declaration.
The JSON file list parser is used to communicate input to InstallAPI.
bool isCtorOfSafePtr(const clang::FunctionDecl *F)
bool isa(CodeGen::Address addr)
Definition Address.h:330
@ LCK_ByCopy
Capturing by copy (a.k.a., by value)
Definition Lambda.h:36
void printQuotedQualifiedName(llvm::raw_ostream &Os, const NamedDeclDerivedT &D)
std::optional< bool > isUnsafePtr(const QualType T, bool IsArcEnabled)
const FunctionProtoType * T
@ Type
The name was classified as a type.
Definition Sema.h:562
bool isRetainPtrOrOSPtr(const std::string &Name)
bool isRefType(const std::string &Name)
std::optional< bool > isUncountedPtr(const QualType T)
std::string safeGetName(const T *ASTNode)
Definition ASTUtils.h:91
bool isCheckedPtr(const std::string &Name)
DynamicRecursiveASTVisitorBase< false > DynamicRecursiveASTVisitor
std::optional< bool > isUncounted(const QualType T)
std::optional< bool > isUncheckedPtr(const QualType T)