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 Callee = Callee->IgnoreParenCasts();
347 if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(Callee)) {
348 Callee = MTE->getSubExpr();
349 if (!Callee)
350 return;
351 Callee = Callee->IgnoreParenCasts();
352 }
353 if (auto *L = dyn_cast<LambdaExpr>(Callee)) {
354 LambdasToIgnore.insert(L); // Calling a lambda upon creation is safe.
355 return;
356 }
357 auto *DRE = dyn_cast<DeclRefExpr>(Callee->IgnoreParenCasts());
358 if (!DRE)
359 return;
360 auto *MD = dyn_cast_or_null<CXXMethodDecl>(DRE->getDecl());
361 if (!MD || CE->getNumArgs() < 1)
362 return;
363 auto *Arg = CE->getArg(0)->IgnoreParenCasts();
364 if (auto *L = dyn_cast_or_null<LambdaExpr>(Arg)) {
365 LambdasToIgnore.insert(L); // Calling a lambda upon creation is safe.
366 return;
367 }
368 auto *ArgRef = dyn_cast<DeclRefExpr>(Arg);
369 if (!ArgRef)
370 return;
371 auto *VD = dyn_cast_or_null<VarDecl>(ArgRef->getDecl());
372 if (!VD)
373 return;
374 auto *Init = VD->getInit();
375 if (!Init)
376 return;
377 auto *L = dyn_cast_or_null<LambdaExpr>(Init->IgnoreParenCasts());
378 if (!L)
379 return;
380 DeclRefExprsToIgnore.insert(ArgRef);
381 LambdasToIgnore.insert(L);
382 }
383
384 bool hasProtectedThis(const LambdaExpr *L) {
385 for (const LambdaCapture &OtherCapture : L->captures()) {
386 if (!OtherCapture.capturesVariable())
387 continue;
388 if (auto *ValueDecl = OtherCapture.getCapturedVar()) {
389 if (declProtectsThis(ValueDecl)) {
390 ProtectedThisDecls.insert(ValueDecl);
391 return true;
392 }
393 }
394 }
395 return false;
396 }
397
398 bool declProtectsThis(const ValueDecl *ValueDecl) const {
399 auto *VD = dyn_cast<VarDecl>(ValueDecl);
400 if (!VD)
401 return false;
402 auto *Init = VD->getInit();
403 if (!Init)
404 return false;
405 const Expr *Arg = Init->IgnoreParenCasts();
406 do {
407 if (auto *BTE = dyn_cast<CXXBindTemporaryExpr>(Arg))
408 Arg = BTE->getSubExpr()->IgnoreParenCasts();
409 if (auto *CE = dyn_cast<CXXConstructExpr>(Arg)) {
410 auto *Ctor = CE->getConstructor();
411 if (!Ctor)
412 return false;
413 auto clsName = safeGetName(Ctor->getParent());
414 if (Checker->isPtrType(clsName) && CE->getNumArgs()) {
415 Arg = CE->getArg(0)->IgnoreParenCasts();
416 continue;
417 }
418 if (auto *Type = ClsType.getTypePtrOrNull()) {
419 if (auto *CXXR = Type->getPointeeCXXRecordDecl()) {
420 if (CXXR == Ctor->getParent() && Ctor->isMoveConstructor() &&
421 CE->getNumArgs() == 1) {
422 Arg = CE->getArg(0)->IgnoreParenCasts();
423 continue;
424 }
425 }
426 }
427 return false;
428 }
429 if (auto *CE = dyn_cast<CallExpr>(Arg)) {
430 if (auto *Callee = CE->getDirectCallee()) {
431 if ((isStdOrWTFMove(Callee) || isCtorOfSafePtr(Callee)) &&
432 CE->getNumArgs() == 1) {
433 Arg = CE->getArg(0)->IgnoreParenCasts();
434 continue;
435 }
436 }
437 }
438 if (auto *OpCE = dyn_cast<CXXOperatorCallExpr>(Arg)) {
439 auto OpCode = OpCE->getOperator();
440 if (OpCode == OO_Star || OpCode == OO_Amp) {
441 auto *Callee = OpCE->getDirectCallee();
442 if (!Callee)
443 return false;
444 auto clsName = safeGetName(Callee->getParent());
445 if (!Checker->isPtrType(clsName) || !OpCE->getNumArgs())
446 return false;
447 Arg = OpCE->getArg(0)->IgnoreParenCasts();
448 continue;
449 }
450 }
451 if (auto *UO = dyn_cast<UnaryOperator>(Arg)) {
452 auto OpCode = UO->getOpcode();
453 if (OpCode == UO_Deref || OpCode == UO_AddrOf) {
454 Arg = UO->getSubExpr()->IgnoreParenCasts();
455 continue;
456 }
457 }
458 break;
459 } while (Arg);
460 if (auto *DRE = dyn_cast<DeclRefExpr>(Arg)) {
461 auto *Decl = DRE->getDecl();
462 if (auto *ImplicitParam = dyn_cast<ImplicitParamDecl>(Decl)) {
463 auto kind = ImplicitParam->getParameterKind();
464 return kind == ImplicitParamKind::ObjCSelf ||
465 kind == ImplicitParamKind::CXXThis;
466 }
467 return ProtectedThisDecls.contains(Decl);
468 }
469 return isa<CXXThisExpr>(Arg);
470 }
471 };
472
473 LocalVisitor visitor(this);
474 if (RTC)
475 RTC->visitTranslationUnitDecl(TUD);
476 visitor.TraverseDecl(const_cast<TranslationUnitDecl *>(TUD));
477 }
478
479 void visitLambdaExpr(const LambdaExpr *L, bool shouldCheckThis,
480 const QualType T,
481 bool ignoreParamVarDecl = false) const {
482 if (TFA.isTrivial(L->getBody()))
483 return;
484 for (const LambdaCapture &C : L->captures()) {
485 if (C.capturesVariable()) {
486 ValueDecl *CapturedVar = C.getCapturedVar();
487 if (ignoreParamVarDecl && isa<ParmVarDecl>(CapturedVar))
488 continue;
489 if (auto *ImplicitParam = dyn_cast<ImplicitParamDecl>(CapturedVar)) {
490 auto kind = ImplicitParam->getParameterKind();
491 if ((kind == ImplicitParamKind::ObjCSelf ||
492 kind == ImplicitParamKind::CXXThis) &&
493 !shouldCheckThis)
494 continue;
495 }
496 QualType CapturedVarQualType = CapturedVar->getType();
497 auto IsUncountedPtr = isUnsafePtr(CapturedVar->getType());
498 if (C.getCaptureKind() == LCK_ByCopy &&
499 CapturedVarQualType->isReferenceType())
500 continue;
501 if (IsUncountedPtr && *IsUncountedPtr)
502 reportBug(C, CapturedVar, CapturedVarQualType, L);
503 } else if (C.capturesThis() && shouldCheckThis) {
504 if (ignoreParamVarDecl) // this is always a parameter to this function.
505 continue;
506 reportBugOnThisPtr(C, T);
507 }
508 }
509 }
510
511 void reportBug(const LambdaCapture &Capture, ValueDecl *CapturedVar,
512 const QualType T, const LambdaExpr *L) const {
513 assert(CapturedVar);
514
515 auto Location = Capture.getLocation();
516 if (isa<ImplicitParamDecl>(CapturedVar) && !Location.isValid())
517 Location = L->getBeginLoc();
518
519 SmallString<100> Buf;
520 llvm::raw_svector_ostream Os(Buf);
521
522 if (Capture.isExplicit()) {
523 Os << "Captured ";
524 } else {
525 Os << "Implicitly captured ";
526 }
528 Os << "raw-pointer ";
529 } else {
530 Os << "reference ";
531 }
532
533 printQuotedQualifiedName(Os, CapturedVar);
534 Os << " to " << ptrKind(T) << " type is unsafe.";
535
536 PathDiagnosticLocation BSLoc(Location, BR->getSourceManager());
537 auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
538 BR->emitReport(std::move(Report));
539 }
540
541 void reportBugOnThisPtr(const LambdaCapture &Capture,
542 const QualType T) const {
543 SmallString<100> Buf;
544 llvm::raw_svector_ostream Os(Buf);
545
546 if (Capture.isExplicit()) {
547 Os << "Captured ";
548 } else {
549 Os << "Implicitly captured ";
550 }
551
552 Os << "raw-pointer 'this' to " << ptrKind(T) << " type is unsafe.";
553
554 PathDiagnosticLocation BSLoc(Capture.getLocation(), BR->getSourceManager());
555 auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
556 BR->emitReport(std::move(Report));
557 }
558};
559
560class UncountedLambdaCapturesChecker : public RawPtrRefLambdaCapturesChecker {
561public:
562 UncountedLambdaCapturesChecker()
563 : RawPtrRefLambdaCapturesChecker("Lambda capture of uncounted or "
564 "unchecked variable") {}
565
566 std::optional<bool> isUnsafePtr(QualType QT) const final {
567 auto result1 = isUncountedPtr(QT);
568 auto result2 = isUncheckedPtr(QT);
569 if (result1 && *result1)
570 return true;
571 if (result2 && *result2)
572 return true;
573 if (result1)
574 return *result1;
575 return result2;
576 }
577
578 virtual bool isPtrType(const std::string &Name) const final {
579 return isRefType(Name) || isCheckedPtr(Name);
580 }
581
582 const char *ptrKind(QualType QT) const final {
583 if (isUncounted(QT))
584 return "uncounted";
585 return "unchecked";
586 }
587};
588
589class UnretainedLambdaCapturesChecker : public RawPtrRefLambdaCapturesChecker {
590public:
591 UnretainedLambdaCapturesChecker()
592 : RawPtrRefLambdaCapturesChecker("Lambda capture of unretained "
593 "variables") {
594 RTC = RetainTypeChecker();
595 }
596
597 std::optional<bool> isUnsafePtr(QualType QT) const final {
598 if (QT.hasStrongOrWeakObjCLifetime())
599 return false;
600 return RTC->isUnretained(QT);
601 }
602
603 virtual bool isPtrType(const std::string &Name) const final {
604 return isRetainPtrOrOSPtr(Name);
605 }
606
607 const char *ptrKind(QualType QT) const final { return "unretained"; }
608};
609
610} // namespace
611
612void ento::registerUncountedLambdaCapturesChecker(CheckerManager &Mgr) {
613 Mgr.registerChecker<UncountedLambdaCapturesChecker>();
614}
615
616bool ento::shouldRegisterUncountedLambdaCapturesChecker(
617 const CheckerManager &mgr) {
618 return true;
619}
620
621void ento::registerUnretainedLambdaCapturesChecker(CheckerManager &Mgr) {
622 Mgr.registerChecker<UnretainedLambdaCapturesChecker>();
623}
624
625bool ento::shouldRegisterUnretainedLambdaCapturesChecker(
626 const CheckerManager &mgr) {
627 return true;
628}
Expr * getArg(unsigned Arg)
Return the specified argument.
Definition ExprCXX.h:1691
CXXConstructorDecl * getConstructor() const
Get the constructor that this expression will (ultimately) call.
Definition ExprCXX.h:1611
unsigned getNumArgs() const
Return the number of arguments to the constructor call.
Definition ExprCXX.h:1688
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:3147
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return null.
Definition Expr.h:3126
Expr * getCallee()
Definition Expr.h:3090
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
Definition Expr.h:3134
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:3094
Stmt * getBody() const
Retrieve the body of the lambda.
Definition ExprCXX.cpp:1346
SourceLocation getBeginLoc() const LLVM_READONLY
Definition ExprCXX.h:2182
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:8296
bool isReferenceType() const
Definition TypeBase.h:8553
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)
const FunctionProtoType * T
@ Type
The name was classified as a type.
Definition Sema.h:563
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:95
bool isCheckedPtr(const std::string &Name)
DynamicRecursiveASTVisitorBase< false > DynamicRecursiveASTVisitor
bool isStdOrWTFMove(const clang::FunctionDecl *F)
std::optional< bool > isUncounted(const QualType T)
std::optional< bool > isUncheckedPtr(const QualType T)