clang 23.0.0git
RawPtrRefLambdaCapturesChecker.cpp
Go to the documentation of this file.
1//=======- RawPtrRefLambdaCapturesChecker.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 *typeName() 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 *, SmallVector<const LambdaExpr *>>
56 LambdaOwnerMap;
57
58 QualType ClsType;
59
60 explicit LocalVisitor(const RawPtrRefLambdaCapturesChecker *Checker)
61 : Checker(Checker) {
62 assert(Checker);
63 ShouldVisitTemplateInstantiations = true;
64 ShouldVisitImplicitCode = false;
65 }
66
67 bool TraverseCXXConstructorDecl(CXXConstructorDecl *Ctor) override {
68 llvm::SaveAndRestore SavedDecl(ClsType);
69 ClsType = Ctor->getThisType();
70 return DynamicRecursiveASTVisitor::TraverseCXXConstructorDecl(Ctor);
71 }
72
73 bool TraverseCXXDestructorDecl(CXXDestructorDecl *Dtor) override {
74 llvm::SaveAndRestore SavedDecl(ClsType);
75 ClsType = Dtor->getThisType();
76 return DynamicRecursiveASTVisitor::TraverseCXXDestructorDecl(Dtor);
77 }
78
79 bool TraverseCXXMethodDecl(CXXMethodDecl *CXXMD) override {
80 llvm::SaveAndRestore SavedDecl(ClsType);
81 if (CXXMD->isInstance())
82 ClsType = CXXMD->getThisType();
83 return DynamicRecursiveASTVisitor::TraverseCXXMethodDecl(CXXMD);
84 }
85
86 bool TraverseObjCMethodDecl(ObjCMethodDecl *OCMD) override {
87 llvm::SaveAndRestore SavedDecl(ClsType);
88 if (OCMD && OCMD->isInstanceMethod()) {
89 if (auto *ImplParamDecl = OCMD->getSelfDecl())
90 ClsType = ImplParamDecl->getType();
91 }
92 return DynamicRecursiveASTVisitor::TraverseObjCMethodDecl(OCMD);
93 }
94
95 bool VisitTypedefDecl(TypedefDecl *TD) override {
96 if (Checker->RTC)
97 Checker->RTC->visitTypedef(TD);
98 return true;
99 }
100
101 bool shouldCheckThis() {
102 auto result =
103 !ClsType.isNull() ? Checker->isUnsafePtr(ClsType) : std::nullopt;
104 return result && *result;
105 }
106
107 bool VisitLambdaExpr(LambdaExpr *L) override {
108 if (LambdasToIgnore.contains(L))
109 return true;
110 Checker->visitLambdaExpr(L, shouldCheckThis() && !hasProtectedThis(L),
111 ClsType);
112 return true;
113 }
114
115 bool VisitVarDecl(VarDecl *VD) override {
116 auto *Init = VD->getInit();
117 if (!Init)
118 return true;
119 if (auto *L = dyn_cast_or_null<LambdaExpr>(Init->IgnoreParenCasts())) {
120 LambdasToIgnore.insert(L); // Evaluate lambdas in VisitDeclRefExpr.
121 return true;
122 }
123 if (!VD->hasLocalStorage())
124 return true;
125 if (auto *E = dyn_cast<ExprWithCleanups>(Init))
126 Init = E->getSubExpr();
127 if (auto *E = dyn_cast<CXXBindTemporaryExpr>(Init))
128 Init = E->getSubExpr();
129 if (auto *CE = dyn_cast<CallExpr>(Init)) {
130 if (auto *Callee = CE->getDirectCallee()) {
131 auto FnName = safeGetName(Callee);
132 unsigned ArgCnt = CE->getNumArgs();
133 if (FnName == "makeScopeExit" && ArgCnt == 1) {
134 auto *Arg = CE->getArg(0);
135 if (auto *E = dyn_cast<MaterializeTemporaryExpr>(Arg))
136 Arg = E->getSubExpr();
137 if (auto *L = dyn_cast<LambdaExpr>(Arg))
138 addLambdaOwner(VD, CE, L);
139 } else if (FnName == "makeVisitor") {
140 for (unsigned ArgIndex = 0; ArgIndex < ArgCnt; ++ArgIndex) {
141 auto *Arg = CE->getArg(ArgIndex);
142 if (auto *E = dyn_cast<MaterializeTemporaryExpr>(Arg))
143 Arg = E->getSubExpr();
144 if (auto *L = dyn_cast<LambdaExpr>(Arg))
145 addLambdaOwner(VD, CE, L);
146 }
147 }
148 }
149 } else if (auto *CE = dyn_cast<CXXConstructExpr>(Init)) {
150 if (auto *Ctor = CE->getConstructor()) {
151 if (auto *Cls = Ctor->getParent()) {
152 auto FnName = safeGetName(Cls);
153 unsigned ArgCnt = CE->getNumArgs();
154 if (FnName == "ScopeExit" && ArgCnt == 1) {
155 auto *Arg = CE->getArg(0);
156 if (auto *E = dyn_cast<MaterializeTemporaryExpr>(Arg))
157 Arg = E->getSubExpr();
158 if (auto *L = dyn_cast<LambdaExpr>(Arg))
159 addLambdaOwner(VD, CE, L);
160 }
161 }
162 }
163 }
164 return true;
165 }
166
167 void addLambdaOwner(VarDecl *VD, CallExpr *CE, LambdaExpr *L) {
168 auto result = LambdaOwnerMap.insert(
169 std::make_pair(VD, SmallVector<const LambdaExpr *>{L}));
170 if (!result.second)
171 result.first->second.push_back(L);
172 CallToIgnore.insert(CE);
173 LambdasToIgnore.insert(L);
174 }
175
176 void addLambdaOwner(VarDecl *VD, CXXConstructExpr *CE, LambdaExpr *L) {
177 auto result = LambdaOwnerMap.insert(
178 std::make_pair(VD, SmallVector<const LambdaExpr *>{L}));
179 if (!result.second)
180 result.first->second.push_back(L);
181 ConstructToIgnore.insert(CE);
182 LambdasToIgnore.insert(L);
183 }
184
185 bool VisitDeclRefExpr(DeclRefExpr *DRE) override {
186 if (DeclRefExprsToIgnore.contains(DRE))
187 return true;
188 auto *VD = dyn_cast_or_null<VarDecl>(DRE->getDecl());
189 if (!VD)
190 return true;
191 if (auto It = LambdaOwnerMap.find(VD); It != LambdaOwnerMap.end()) {
192 for (auto *L : It->second) {
193 Checker->visitLambdaExpr(
194 L, shouldCheckThis() && !hasProtectedThis(L), ClsType);
195 }
196 return true;
197 }
198 auto *Init = VD->getInit();
199 if (!Init)
200 return true;
201 auto *L = dyn_cast_or_null<LambdaExpr>(Init->IgnoreParenCasts());
202 if (!L)
203 return true;
204 LambdasToIgnore.insert(L);
205 Checker->visitLambdaExpr(L, shouldCheckThis() && !hasProtectedThis(L),
206 ClsType);
207 return true;
208 }
209
210 bool shouldTreatAllArgAsNoEscape(FunctionDecl *FDecl) {
211 std::string PreviousName = safeGetName(FDecl);
212 for (auto *Decl = FDecl->getParent(); Decl; Decl = Decl->getParent()) {
213 if (!isa<NamespaceDecl>(Decl) && !isa<CXXRecordDecl>(Decl))
214 return false;
215 auto Name = safeGetName(Decl);
216 // WTF::switchOn(T, F... f) is a variadic template function and
217 // couldn't be annotated with NOESCAPE. We hard code it here to
218 // workaround that.
219 if (Name == "WTF" && PreviousName == "switchOn")
220 return true;
221 // Treat every argument of functions in std::ranges as noescape.
222 if (Name == "std" && PreviousName == "ranges")
223 return true;
224 PreviousName = Name;
225 }
226 return false;
227 }
228
229 bool VisitCXXConstructExpr(CXXConstructExpr *CE) override {
230 if (ConstructToIgnore.contains(CE))
231 return true;
232 if (auto *Callee = CE->getConstructor()) {
233 unsigned ArgIndex = 0;
234 for (auto *Param : Callee->parameters()) {
235 if (ArgIndex >= CE->getNumArgs())
236 return true;
237 auto *Arg = CE->getArg(ArgIndex)->IgnoreParenCasts();
238 if (auto *L = findLambdaInArg(Arg)) {
239 LambdasToIgnore.insert(L);
240 if (!Param->hasAttr<NoEscapeAttr>())
241 Checker->visitLambdaExpr(
242 L, shouldCheckThis() && !hasProtectedThis(L), ClsType);
243 }
244 ++ArgIndex;
245 }
246 }
247 return true;
248 }
249
250 bool VisitCallExpr(CallExpr *CE) override {
251 if (CallToIgnore.contains(CE))
252 return true;
253 checkCalleeLambda(CE);
254 if (auto *Callee = CE->getDirectCallee()) {
255 if (isVisitFunction(CE, Callee))
256 return true;
257 checkParameters(CE, Callee);
258 } else if (auto *CalleeE = CE->getCallee()) {
259 if (auto *DRE = dyn_cast<DeclRefExpr>(CalleeE->IgnoreParenCasts())) {
260 if (auto *Callee = dyn_cast_or_null<FunctionDecl>(DRE->getDecl()))
261 checkParameters(CE, Callee);
262 }
263 }
264 return true;
265 }
266
267 bool isVisitFunction(CallExpr *CallExpr, FunctionDecl *FnDecl) {
268 bool IsVisitFn = safeGetName(FnDecl) == "visit";
269 if (!IsVisitFn)
270 return false;
271 bool ArgCnt = CallExpr->getNumArgs();
272 if (!ArgCnt)
273 return false;
274 auto *Ns = FnDecl->getParent();
275 if (!Ns)
276 return false;
277 auto NsName = safeGetName(Ns);
278 if (NsName != "WTF" && NsName != "std")
279 return false;
280 auto *Arg = CallExpr->getArg(0);
281 if (!Arg)
282 return false;
283 auto *DRE = dyn_cast<DeclRefExpr>(Arg->IgnoreParenCasts());
284 if (!DRE)
285 return false;
286 auto *VD = dyn_cast<VarDecl>(DRE->getDecl());
287 if (!VD)
288 return false;
289 if (!LambdaOwnerMap.contains(VD))
290 return false;
291 DeclRefExprsToIgnore.insert(DRE);
292 return true;
293 }
294
295 void checkParameters(CallExpr *CE, FunctionDecl *Callee) {
296 unsigned ArgIndex = isa<CXXOperatorCallExpr>(CE);
297 bool TreatAllArgsAsNoEscape = shouldTreatAllArgAsNoEscape(Callee);
298 for (auto *Param : Callee->parameters()) {
299 if (ArgIndex >= CE->getNumArgs())
300 return;
301 auto *Arg = CE->getArg(ArgIndex)->IgnoreParenCasts();
302 if (auto *L = findLambdaInArg(Arg)) {
303 LambdasToIgnore.insert(L);
304 if (!Param->hasAttr<NoEscapeAttr>() && !TreatAllArgsAsNoEscape)
305 Checker->visitLambdaExpr(
306 L, shouldCheckThis() && !hasProtectedThis(L), ClsType);
307 }
308 ++ArgIndex;
309 }
310 }
311
312 LambdaExpr *findLambdaInArg(Expr *E) {
313 if (auto *Lambda = dyn_cast_or_null<LambdaExpr>(E))
314 return Lambda;
315 auto *TempExpr = dyn_cast_or_null<CXXBindTemporaryExpr>(E);
316 if (!TempExpr)
317 return nullptr;
318 E = TempExpr->getSubExpr()->IgnoreParenCasts();
319 if (!E)
320 return nullptr;
321 if (auto *Lambda = dyn_cast<LambdaExpr>(E))
322 return Lambda;
323 auto *CE = dyn_cast_or_null<CXXConstructExpr>(E);
324 if (!CE || !CE->getNumArgs())
325 return nullptr;
326 auto *CtorArg = CE->getArg(0)->IgnoreParenCasts();
327 if (!CtorArg)
328 return nullptr;
329 auto *InnerCE = dyn_cast_or_null<CXXConstructExpr>(CtorArg);
330 if (InnerCE && InnerCE->getNumArgs())
331 CtorArg = InnerCE->getArg(0)->IgnoreParenCasts();
332 auto updateIgnoreList = [&] {
333 ConstructToIgnore.insert(CE);
334 if (InnerCE)
335 ConstructToIgnore.insert(InnerCE);
336 };
337 if (auto *Lambda = dyn_cast<LambdaExpr>(CtorArg)) {
338 updateIgnoreList();
339 return Lambda;
340 }
341 if (auto *TempExpr = dyn_cast<CXXBindTemporaryExpr>(CtorArg)) {
342 E = TempExpr->getSubExpr()->IgnoreParenCasts();
343 if (auto *Lambda = dyn_cast<LambdaExpr>(E)) {
344 updateIgnoreList();
345 return Lambda;
346 }
347 }
348 auto *DRE = dyn_cast<DeclRefExpr>(CtorArg);
349 if (!DRE)
350 return nullptr;
351 auto *VD = dyn_cast_or_null<VarDecl>(DRE->getDecl());
352 if (!VD)
353 return nullptr;
354 auto *Init = VD->getInit();
355 if (!Init)
356 return nullptr;
357 if (auto *Lambda = dyn_cast<LambdaExpr>(Init)) {
358 DeclRefExprsToIgnore.insert(DRE);
359 updateIgnoreList();
360 return Lambda;
361 }
362 return nullptr;
363 }
364
365 void checkCalleeLambda(CallExpr *CE) {
366 auto *Callee = CE->getCallee();
367 if (!Callee)
368 return;
369 Callee = Callee->IgnoreParenCasts();
370 if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(Callee)) {
371 Callee = MTE->getSubExpr();
372 if (!Callee)
373 return;
374 Callee = Callee->IgnoreParenCasts();
375 }
376 if (auto *L = dyn_cast<LambdaExpr>(Callee)) {
377 LambdasToIgnore.insert(L); // Calling a lambda upon creation is safe.
378 return;
379 }
380 auto *DRE = dyn_cast<DeclRefExpr>(Callee->IgnoreParenCasts());
381 if (!DRE)
382 return;
383 auto *MD = dyn_cast_or_null<CXXMethodDecl>(DRE->getDecl());
384 if (!MD || CE->getNumArgs() < 1)
385 return;
386 auto *Arg = CE->getArg(0)->IgnoreParenCasts();
387 if (auto *L = dyn_cast_or_null<LambdaExpr>(Arg)) {
388 LambdasToIgnore.insert(L); // Calling a lambda upon creation is safe.
389 return;
390 }
391 auto *ArgRef = dyn_cast<DeclRefExpr>(Arg);
392 if (!ArgRef)
393 return;
394 auto *VD = dyn_cast_or_null<VarDecl>(ArgRef->getDecl());
395 if (!VD)
396 return;
397 auto *Init = VD->getInit();
398 if (!Init)
399 return;
400 auto *L = dyn_cast_or_null<LambdaExpr>(Init->IgnoreParenCasts());
401 if (!L)
402 return;
403 DeclRefExprsToIgnore.insert(ArgRef);
404 LambdasToIgnore.insert(L);
405 }
406
407 bool hasProtectedThis(const LambdaExpr *L) {
408 for (const LambdaCapture &OtherCapture : L->captures()) {
409 if (!OtherCapture.capturesVariable())
410 continue;
411 if (auto *ValueDecl = OtherCapture.getCapturedVar()) {
412 if (declProtectsThis(ValueDecl)) {
413 ProtectedThisDecls.insert(ValueDecl);
414 return true;
415 }
416 }
417 }
418 return false;
419 }
420
421 bool declProtectsThis(const ValueDecl *ValueDecl) const {
422 auto *VD = dyn_cast<VarDecl>(ValueDecl);
423 if (!VD)
424 return false;
425 auto *Init = VD->getInit();
426 if (!Init)
427 return false;
428 const Expr *Arg = Init->IgnoreParenCasts();
429 do {
430 if (auto *BTE = dyn_cast<CXXBindTemporaryExpr>(Arg))
431 Arg = BTE->getSubExpr()->IgnoreParenCasts();
432 if (auto *CE = dyn_cast<CXXConstructExpr>(Arg)) {
433 auto *Ctor = CE->getConstructor();
434 if (!Ctor)
435 return false;
436 auto clsName = safeGetName(Ctor->getParent());
437 if (Checker->isPtrType(clsName) && CE->getNumArgs()) {
438 Arg = CE->getArg(0)->IgnoreParenCasts();
439 continue;
440 }
441 if (auto *Type = ClsType.getTypePtrOrNull()) {
442 if (auto *CXXR = Type->getPointeeCXXRecordDecl()) {
443 if (CXXR == Ctor->getParent() && Ctor->isMoveConstructor() &&
444 CE->getNumArgs() == 1) {
445 Arg = CE->getArg(0)->IgnoreParenCasts();
446 continue;
447 }
448 }
449 }
450 return false;
451 }
452 if (auto *CE = dyn_cast<CallExpr>(Arg)) {
453 if (auto *Callee = CE->getDirectCallee()) {
454 if ((isStdOrWTFMove(Callee) || isCtorOfSafePtr(Callee)) &&
455 CE->getNumArgs() == 1) {
456 Arg = CE->getArg(0)->IgnoreParenCasts();
457 continue;
458 }
459 }
460 }
461 if (auto *OpCE = dyn_cast<CXXOperatorCallExpr>(Arg)) {
462 auto OpCode = OpCE->getOperator();
463 if (OpCode == OO_Star || OpCode == OO_Amp) {
464 auto *Callee = OpCE->getDirectCallee();
465 if (!Callee)
466 return false;
467 auto clsName = safeGetName(Callee->getParent());
468 if (!Checker->isPtrType(clsName) || !OpCE->getNumArgs())
469 return false;
470 Arg = OpCE->getArg(0)->IgnoreParenCasts();
471 continue;
472 }
473 }
474 if (auto *UO = dyn_cast<UnaryOperator>(Arg)) {
475 auto OpCode = UO->getOpcode();
476 if (OpCode == UO_Deref || OpCode == UO_AddrOf) {
477 Arg = UO->getSubExpr()->IgnoreParenCasts();
478 continue;
479 }
480 }
481 break;
482 } while (Arg);
483 if (auto *DRE = dyn_cast<DeclRefExpr>(Arg)) {
484 auto *Decl = DRE->getDecl();
485 if (auto *ImplicitParam = dyn_cast<ImplicitParamDecl>(Decl)) {
486 auto kind = ImplicitParam->getParameterKind();
487 return kind == ImplicitParamKind::ObjCSelf ||
488 kind == ImplicitParamKind::CXXThis;
489 }
490 return ProtectedThisDecls.contains(Decl);
491 }
492 return isa<CXXThisExpr>(Arg);
493 }
494 };
495
496 LocalVisitor visitor(this);
497 if (RTC)
498 RTC->visitTranslationUnitDecl(TUD);
499 visitor.TraverseDecl(const_cast<TranslationUnitDecl *>(TUD));
500 }
501
502 void visitLambdaExpr(const LambdaExpr *L, bool shouldCheckThis,
503 const QualType T,
504 bool ignoreParamVarDecl = false) const {
505 if (TFA.isTrivial(L->getBody()))
506 return;
507 for (const LambdaCapture &C : L->captures()) {
508 if (C.capturesVariable()) {
509 ValueDecl *CapturedVar = C.getCapturedVar();
510 if (ignoreParamVarDecl && isa<ParmVarDecl>(CapturedVar))
511 continue;
512 if (auto *ImplicitParam = dyn_cast<ImplicitParamDecl>(CapturedVar)) {
513 auto kind = ImplicitParam->getParameterKind();
514 if ((kind == ImplicitParamKind::ObjCSelf ||
515 kind == ImplicitParamKind::CXXThis) &&
516 !shouldCheckThis)
517 continue;
518 }
519 QualType CapturedVarQualType = CapturedVar->getType();
520 auto IsUncountedPtr = isUnsafePtr(CapturedVar->getType());
521 if (C.getCaptureKind() == LCK_ByCopy &&
522 CapturedVarQualType->isReferenceType())
523 continue;
524 if (IsUncountedPtr && *IsUncountedPtr)
525 reportBug(C, CapturedVar, CapturedVarQualType, L);
526 } else if (C.capturesThis() && shouldCheckThis) {
527 if (ignoreParamVarDecl) // this is always a parameter to this function.
528 continue;
529 reportBugOnThisPtr(C, T);
530 }
531 }
532 }
533
534 void reportBug(const LambdaCapture &Capture, ValueDecl *CapturedVar,
535 const QualType T, const LambdaExpr *L) const {
536 assert(CapturedVar);
537
538 auto Location = Capture.getLocation();
539 if (isa<ImplicitParamDecl>(CapturedVar) && !Location.isValid())
540 Location = L->getBeginLoc();
541
542 SmallString<100> Buf;
543 llvm::raw_svector_ostream Os(Buf);
544
545 if (Capture.isExplicit())
546 Os << "Captured ";
547 else
548 Os << "Implicitly captured ";
549 Os << "variable ";
550 printQuotedQualifiedName(Os, CapturedVar);
551
552 bool IsUnsafePtr = CapturedVar->getType() == T;
553 if (IsUnsafePtr)
554 Os << " is a ";
555 else
556 Os << " contains a ";
557 auto *CapturedType = T.getTypePtrOrNull();
558 printPointer(Os, CapturedType);
559
560 PathDiagnosticLocation BSLoc(Location, BR->getSourceManager());
561 auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
562 BR->emitReport(std::move(Report));
563 }
564
565 void reportBugOnThisPtr(const LambdaCapture &Capture,
566 const QualType T) const {
567 SmallString<100> Buf;
568 llvm::raw_svector_ostream Os(Buf);
569
570 if (Capture.isExplicit()) {
571 Os << "Captured ";
572 } else {
573 Os << "Implicitly captured ";
574 }
575
576 Os << "variable 'this' is a raw pointer to " << typeName();
577 if (auto *RD = T->getPointeeCXXRecordDecl()) {
578 Os << " ";
580 }
581
582 PathDiagnosticLocation BSLoc(Capture.getLocation(), BR->getSourceManager());
583 auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
584 BR->emitReport(std::move(Report));
585 }
586
587 virtual void printPointer(llvm::raw_svector_ostream &Os,
588 const Type *T) const {
590 bool IsPtr = isa<PointerType>(T) || isa<ObjCObjectPointerType>(T);
591 Os << (IsPtr ? "raw pointer" : "raw reference") << " to ";
592 Os << typeName();
593
594 if (auto *RD = T->getPointeeType()->getAsRecordDecl()) {
595 Os << " ";
597 } else if (auto *ObjCDecl = getObjCDeclFromObjCPtr(T)) {
598 Os << " ";
599 printQuotedQualifiedName(Os, ObjCDecl);
600 }
601 }
602};
603
604class UncountedLambdaCapturesChecker : public RawPtrRefLambdaCapturesChecker {
605public:
606 UncountedLambdaCapturesChecker()
607 : RawPtrRefLambdaCapturesChecker("Lambda capture of uncounted variable") {
608 }
609
610 std::optional<bool> isUnsafePtr(QualType QT) const final {
611 return isUncountedPtr(QT.getCanonicalType());
612 }
613
614 virtual bool isPtrType(const std::string &Name) const final {
615 return isRefType(Name);
616 }
617
618 const char *typeName() const final { return "RefPtr-capable type"; }
619};
620
621class UncheckedLambdaCapturesChecker : public RawPtrRefLambdaCapturesChecker {
622public:
623 UncheckedLambdaCapturesChecker()
624 : RawPtrRefLambdaCapturesChecker("Lambda capture of unchecked variable") {
625 }
626
627 std::optional<bool> isUnsafePtr(QualType QT) const final {
628 return isUncheckedPtr(QT.getCanonicalType());
629 }
630
631 virtual bool isPtrType(const std::string &Name) const final {
632 return isCheckedPtr(Name);
633 }
634
635 const char *typeName() const final { return "CheckedPtr-capable type"; }
636};
637
638class UnretainedLambdaCapturesChecker : public RawPtrRefLambdaCapturesChecker {
639public:
640 UnretainedLambdaCapturesChecker()
641 : RawPtrRefLambdaCapturesChecker("Lambda capture of unretained "
642 "variables") {
643 RTC = RetainTypeChecker();
644 }
645
646 std::optional<bool> isUnsafePtr(QualType QT) const final {
647 if (QT.hasStrongOrWeakObjCLifetime())
648 return false;
649 return RTC->isUnretained(QT);
650 }
651
652 virtual bool isPtrType(const std::string &Name) const final {
653 return isRetainPtrOrOSPtr(Name);
654 }
655
656 const char *typeName() const final { return "RetainPtr-capable type"; }
657
658 void printPointer(llvm::raw_svector_ostream &Os, const Type *T) const final {
659 if (auto *ObjCPtr = dyn_cast<ObjCObjectPointerType>(T)) {
660 for (ObjCProtocolDecl *P : ObjCPtr->quals()) {
661 if (const auto *II = P->getIdentifier()) {
662 auto Name = II->getName();
663 if (Name.starts_with("OS_")) {
664 Os << typeName() << " ";
666 return;
667 }
668 }
669 }
670 }
671 if (!isa<ObjCObjectPointerType>(T) && T->getAs<TypedefType>()) {
672 auto Typedef = T->getAs<TypedefType>();
673 assert(Typedef);
674 Os << typeName() << " ";
675 printQuotedQualifiedName(Os, Typedef->getDecl());
676 return;
677 }
678 return RawPtrRefLambdaCapturesChecker::printPointer(Os, T);
679 }
680};
681
682} // namespace
683
684void ento::registerUncountedLambdaCapturesChecker(CheckerManager &Mgr) {
685 Mgr.registerChecker<UncountedLambdaCapturesChecker>();
686}
687
688bool ento::shouldRegisterUncountedLambdaCapturesChecker(
689 const CheckerManager &mgr) {
690 return true;
691}
692
693void ento::registerUncheckedLambdaCapturesChecker(CheckerManager &Mgr) {
694 Mgr.registerChecker<UncheckedLambdaCapturesChecker>();
695}
696
697bool ento::shouldRegisterUncheckedLambdaCapturesChecker(
698 const CheckerManager &mgr) {
699 return true;
700}
701
702void ento::registerUnretainedLambdaCapturesChecker(CheckerManager &Mgr) {
703 Mgr.registerChecker<UnretainedLambdaCapturesChecker>();
704}
705
706bool ento::shouldRegisterUnretainedLambdaCapturesChecker(
707 const CheckerManager &mgr) {
708 return true;
709}
*collection of selector each with an associated kind and an ordered *collection of selectors A selector has a kind
Expr * getArg(unsigned Arg)
Return the specified argument.
Definition ExprCXX.h:1695
CXXConstructorDecl * getConstructor() const
Get the constructor that this expression will (ultimately) call.
Definition ExprCXX.h:1615
unsigned getNumArgs() const
Return the number of arguments to the constructor call.
Definition ExprCXX.h:1692
bool isMoveConstructor(unsigned &TypeQuals) const
Determine whether this constructor is a move constructor (C++11 [class.copy]p3), which can be used to...
Definition DeclCXX.cpp:3096
const CXXRecordDecl * getParent() const
Return the parent of this method declaration, which is the class in which this method is defined.
Definition DeclCXX.h:2284
QualType getThisType() const
Return the type of the this pointer.
Definition DeclCXX.cpp:2892
bool isInstance() const
Definition DeclCXX.h:2172
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
Definition Expr.h:3153
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return null.
Definition Expr.h:3132
Expr * getCallee()
Definition Expr.h:3096
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
Definition Expr.h:3140
DeclContext * getParent()
getParent - Returns the containing DeclContext.
Definition DeclBase.h:2126
ValueDecl * getDecl()
Definition Expr.h:1344
Expr * IgnoreParenCasts() LLVM_READONLY
Skip past any parentheses and casts which might surround this expression until reaching a fixed point...
Definition Expr.cpp:3104
Stmt * getBody() const
Retrieve the body of the lambda.
Definition ExprCXX.cpp:1353
SourceLocation getBeginLoc() const LLVM_READONLY
Definition ExprCXX.h:2186
capture_range captures() const
Retrieve this lambda's captures.
Definition ExprCXX.cpp:1378
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:8451
RecordDecl * getAsRecordDecl() const
Retrieves the RecordDecl this type refers to.
Definition Type.h:41
bool isReferenceType() const
Definition TypeBase.h:8708
const CXXRecordDecl * getPointeeCXXRecordDecl() const
If this is a pointer or reference to a RecordType, return the CXXRecordDecl that the type refers to.
Definition Type.cpp:1958
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Definition Type.cpp:789
const T * getAs() const
Member-template getAs<specific type>'.
Definition TypeBase.h:9277
const Type * getUnqualifiedDesugaredType() const
Return the specified type with any "sugar" removed from the type, removing any typedefs,...
Definition Type.cpp:690
QualType getType() const
Definition Decl.h:723
const Expr * getInit() const
Definition Decl.h:1391
bool hasLocalStorage() const
Returns true if a variable with function scope is a non-static local variable.
Definition Decl.h:1190
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:565
constexpr bool isPtrType(PrimType T)
Definition PrimType.h:55
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)
@ Type
The name was classified as a type.
Definition Sema.h:564
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:98
ObjCInterfaceDecl * getObjCDeclFromObjCPtr(const Type *TypePtr)
Definition ASTUtils.cpp:391
bool isCheckedPtr(const std::string &Name)
DynamicRecursiveASTVisitorBase< false > DynamicRecursiveASTVisitor
bool isStdOrWTFMove(const clang::FunctionDecl *F)
std::optional< bool > isUncheckedPtr(const QualType T)