clang 24.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"
18#include <optional>
19
20using namespace clang;
21using namespace ento;
22
23namespace {
24class RawPtrRefLambdaCapturesChecker
25 : public Checker<check::ASTDecl<TranslationUnitDecl>> {
26private:
27 BugType Bug;
28 mutable BugReporter *BR = nullptr;
29 TrivialFunctionAnalysis TFA;
30
31protected:
32 const std::unique_ptr<PtrRefSafetyModel> Model;
33
34public:
35 RawPtrRefLambdaCapturesChecker(const char *description,
36 std::unique_ptr<PtrRefSafetyModel> Model)
37 : Bug(this, description, "WebKit coding guidelines"),
38 Model(std::move(Model)) {}
39
40 std::optional<bool> isUnsafePtr(QualType QT) const {
41 return isUnsafePtrForStorage(*Model, QT);
42 }
43 bool isPtrType(const std::string &Name) const {
44 return Model->isPtrType(Name);
45 }
46
47 void checkASTDecl(const TranslationUnitDecl *TUD, AnalysisManager &MGR,
48 BugReporter &BRArg) const {
49 BR = &BRArg;
50
51 // The calls to checkAST* from AnalysisConsumer don't
52 // visit template instantiations or lambda classes. We
53 // want to visit those, so we make our own RecursiveASTVisitor.
54 struct LocalVisitor : DynamicRecursiveASTVisitor {
55 const RawPtrRefLambdaCapturesChecker *Checker;
56 llvm::DenseSet<const DeclRefExpr *> DeclRefExprsToIgnore;
57 llvm::DenseSet<const LambdaExpr *> LambdasToIgnore;
58 llvm::DenseSet<const ValueDecl *> ProtectedThisDecls;
59 llvm::DenseSet<const CallExpr *> CallToIgnore;
60 llvm::DenseSet<const CXXConstructExpr *> ConstructToIgnore;
61 llvm::DenseMap<const VarDecl *, SmallVector<const LambdaExpr *>>
62 LambdaOwnerMap;
63
64 QualType ClsType;
65
66 explicit LocalVisitor(const RawPtrRefLambdaCapturesChecker *Checker)
67 : Checker(Checker) {
68 assert(Checker);
69 ShouldVisitTemplateInstantiations = true;
70 ShouldVisitImplicitCode = false;
71 }
72
73 bool TraverseCXXConstructorDecl(CXXConstructorDecl *Ctor) override {
74 llvm::SaveAndRestore SavedDecl(ClsType);
75 ClsType = Ctor->getThisType();
76 return DynamicRecursiveASTVisitor::TraverseCXXConstructorDecl(Ctor);
77 }
78
79 bool TraverseCXXDestructorDecl(CXXDestructorDecl *Dtor) override {
80 llvm::SaveAndRestore SavedDecl(ClsType);
81 ClsType = Dtor->getThisType();
82 return DynamicRecursiveASTVisitor::TraverseCXXDestructorDecl(Dtor);
83 }
84
85 bool TraverseCXXMethodDecl(CXXMethodDecl *CXXMD) override {
86 llvm::SaveAndRestore SavedDecl(ClsType);
87 if (CXXMD->isInstance())
88 ClsType = CXXMD->getThisType();
89 return DynamicRecursiveASTVisitor::TraverseCXXMethodDecl(CXXMD);
90 }
91
92 bool TraverseObjCMethodDecl(ObjCMethodDecl *OCMD) override {
93 llvm::SaveAndRestore SavedDecl(ClsType);
94 if (OCMD && OCMD->isInstanceMethod()) {
95 if (auto *ImplParamDecl = OCMD->getSelfDecl())
96 ClsType = ImplParamDecl->getType();
97 }
98 return DynamicRecursiveASTVisitor::TraverseObjCMethodDecl(OCMD);
99 }
100
101 bool VisitTypedefDecl(TypedefDecl *TD) override {
102 if (auto *RTC = Checker->Model->retainTypeChecker())
103 RTC->visitTypedef(TD);
104 return true;
105 }
106
107 bool shouldCheckThis() {
108 auto result =
109 !ClsType.isNull() ? Checker->isUnsafePtr(ClsType) : std::nullopt;
110 return result && *result;
111 }
112
113 bool VisitLambdaExpr(LambdaExpr *L) override {
114 if (LambdasToIgnore.contains(L))
115 return true;
116 Checker->visitLambdaExpr(L, shouldCheckThis() && !hasProtectedThis(L),
117 ClsType);
118 return true;
119 }
120
121 bool VisitVarDecl(VarDecl *VD) override {
122 auto *Init = VD->getInit();
123 if (!Init)
124 return true;
125 if (auto *L = dyn_cast_or_null<LambdaExpr>(Init->IgnoreParenCasts())) {
126 LambdasToIgnore.insert(L); // Evaluate lambdas in VisitDeclRefExpr.
127 return true;
128 }
129 if (!VD->hasLocalStorage())
130 return true;
131 if (auto *E = dyn_cast<ExprWithCleanups>(Init))
132 Init = E->getSubExpr();
133 if (auto *E = dyn_cast<CXXBindTemporaryExpr>(Init))
134 Init = E->getSubExpr();
135 if (auto *CE = dyn_cast<CallExpr>(Init)) {
136 if (auto *Callee = CE->getDirectCallee()) {
137 auto FnName = safeGetName(Callee);
138 unsigned ArgCnt = CE->getNumArgs();
139 if (FnName == "makeScopeExit" && ArgCnt == 1) {
140 auto *Arg = CE->getArg(0);
141 if (auto *E = dyn_cast<MaterializeTemporaryExpr>(Arg))
142 Arg = E->getSubExpr();
143 if (auto *L = dyn_cast<LambdaExpr>(Arg))
144 addLambdaOwner(VD, CE, L);
145 } else if (FnName == "makeVisitor") {
146 for (unsigned ArgIndex = 0; ArgIndex < ArgCnt; ++ArgIndex) {
147 auto *Arg = CE->getArg(ArgIndex);
148 if (auto *E = dyn_cast<MaterializeTemporaryExpr>(Arg))
149 Arg = E->getSubExpr();
150 if (auto *L = dyn_cast<LambdaExpr>(Arg))
151 addLambdaOwner(VD, CE, L);
152 }
153 }
154 }
155 } else if (auto *CE = dyn_cast<CXXConstructExpr>(Init)) {
156 if (auto *Ctor = CE->getConstructor()) {
157 if (auto *Cls = Ctor->getParent()) {
158 auto FnName = safeGetName(Cls);
159 unsigned ArgCnt = CE->getNumArgs();
160 if (FnName == "ScopeExit" && ArgCnt == 1) {
161 auto *Arg = CE->getArg(0);
162 if (auto *E = dyn_cast<MaterializeTemporaryExpr>(Arg))
163 Arg = E->getSubExpr();
164 if (auto *L = dyn_cast<LambdaExpr>(Arg))
165 addLambdaOwner(VD, CE, L);
166 }
167 }
168 }
169 }
170 return true;
171 }
172
173 void addLambdaOwner(VarDecl *VD, CallExpr *CE, LambdaExpr *L) {
174 auto result = LambdaOwnerMap.insert(
175 std::make_pair(VD, SmallVector<const LambdaExpr *>{L}));
176 if (!result.second)
177 result.first->second.push_back(L);
178 CallToIgnore.insert(CE);
179 LambdasToIgnore.insert(L);
180 }
181
182 void addLambdaOwner(VarDecl *VD, CXXConstructExpr *CE, LambdaExpr *L) {
183 auto result = LambdaOwnerMap.insert(
184 std::make_pair(VD, SmallVector<const LambdaExpr *>{L}));
185 if (!result.second)
186 result.first->second.push_back(L);
187 ConstructToIgnore.insert(CE);
188 LambdasToIgnore.insert(L);
189 }
190
191 bool VisitDeclRefExpr(DeclRefExpr *DRE) override {
192 if (DeclRefExprsToIgnore.contains(DRE))
193 return true;
194 auto *VD = dyn_cast_or_null<VarDecl>(DRE->getDecl());
195 if (!VD)
196 return true;
197 if (auto It = LambdaOwnerMap.find(VD); It != LambdaOwnerMap.end()) {
198 for (auto *L : It->second) {
199 Checker->visitLambdaExpr(
200 L, shouldCheckThis() && !hasProtectedThis(L), ClsType);
201 }
202 return true;
203 }
204 auto *Init = VD->getInit();
205 if (!Init)
206 return true;
207 auto *L = dyn_cast_or_null<LambdaExpr>(Init->IgnoreParenCasts());
208 if (!L)
209 return true;
210 LambdasToIgnore.insert(L);
211 Checker->visitLambdaExpr(L, shouldCheckThis() && !hasProtectedThis(L),
212 ClsType);
213 return true;
214 }
215
216 bool shouldTreatAllArgAsNoEscape(FunctionDecl *FDecl) {
217 std::string PreviousName = safeGetName(FDecl);
218 for (auto *Decl = FDecl->getParent(); Decl; Decl = Decl->getParent()) {
219 if (!isa<NamespaceDecl>(Decl) && !isa<CXXRecordDecl>(Decl))
220 return false;
221 auto Name = safeGetName(Decl);
222 // WTF::switchOn(T, F... f) is a variadic template function and
223 // couldn't be annotated with NOESCAPE. We hard code it here to
224 // workaround that.
225 if (Name == "WTF" && PreviousName == "switchOn")
226 return true;
227 // Treat every argument of functions in std::ranges as noescape.
228 if (Name == "std" && PreviousName == "ranges")
229 return true;
230 PreviousName = Name;
231 }
232 return false;
233 }
234
235 bool VisitCXXConstructExpr(CXXConstructExpr *CE) override {
236 if (ConstructToIgnore.contains(CE))
237 return true;
238 if (auto *Callee = CE->getConstructor()) {
239 unsigned ArgIndex = 0;
240 for (auto *Param : Callee->parameters()) {
241 if (ArgIndex >= CE->getNumArgs())
242 return true;
243 auto *Arg = CE->getArg(ArgIndex)->IgnoreParenCasts();
244 if (auto *L = findLambdaInArg(Arg)) {
245 LambdasToIgnore.insert(L);
246 if (!Param->hasAttr<NoEscapeAttr>())
247 Checker->visitLambdaExpr(
248 L, shouldCheckThis() && !hasProtectedThis(L), ClsType);
249 }
250 ++ArgIndex;
251 }
252 }
253 return true;
254 }
255
256 bool VisitCallExpr(CallExpr *CE) override {
257 if (CallToIgnore.contains(CE))
258 return true;
259 checkCalleeLambda(CE);
260 if (auto *Callee = CE->getDirectCallee()) {
261 if (isVisitFunction(CE, Callee))
262 return true;
263 checkParameters(CE, Callee);
264 } else if (auto *CalleeE = CE->getCallee()) {
265 if (auto *DRE = dyn_cast<DeclRefExpr>(CalleeE->IgnoreParenCasts())) {
266 if (auto *Callee = dyn_cast_or_null<FunctionDecl>(DRE->getDecl()))
267 checkParameters(CE, Callee);
268 }
269 }
270 return true;
271 }
272
273 bool isVisitFunction(CallExpr *CallExpr, FunctionDecl *FnDecl) {
274 bool IsVisitFn = safeGetName(FnDecl) == "visit";
275 if (!IsVisitFn)
276 return false;
277 bool ArgCnt = CallExpr->getNumArgs();
278 if (!ArgCnt)
279 return false;
280 auto *Ns = FnDecl->getParent();
281 if (!Ns)
282 return false;
283 auto NsName = safeGetName(Ns);
284 if (NsName != "WTF" && NsName != "std")
285 return false;
286 auto *Arg = CallExpr->getArg(0);
287 if (!Arg)
288 return false;
289 auto *DRE = dyn_cast<DeclRefExpr>(Arg->IgnoreParenCasts());
290 if (!DRE)
291 return false;
292 auto *VD = dyn_cast<VarDecl>(DRE->getDecl());
293 if (!VD)
294 return false;
295 if (!LambdaOwnerMap.contains(VD))
296 return false;
297 DeclRefExprsToIgnore.insert(DRE);
298 return true;
299 }
300
301 void checkParameters(CallExpr *CE, FunctionDecl *Callee) {
302 unsigned ArgIndex = isa<CXXOperatorCallExpr>(CE);
303 bool TreatAllArgsAsNoEscape = shouldTreatAllArgAsNoEscape(Callee);
304 for (auto *Param : Callee->parameters()) {
305 if (ArgIndex >= CE->getNumArgs())
306 return;
307 auto *Arg = CE->getArg(ArgIndex)->IgnoreParenCasts();
308 if (auto *L = findLambdaInArg(Arg)) {
309 LambdasToIgnore.insert(L);
310 if (!Param->hasAttr<NoEscapeAttr>() && !TreatAllArgsAsNoEscape)
311 Checker->visitLambdaExpr(
312 L, shouldCheckThis() && !hasProtectedThis(L), ClsType);
313 }
314 ++ArgIndex;
315 }
316 }
317
318 LambdaExpr *findLambdaInArg(Expr *E) {
319 if (auto *Lambda = dyn_cast_or_null<LambdaExpr>(E))
320 return Lambda;
321 auto *TempExpr = dyn_cast_or_null<CXXBindTemporaryExpr>(E);
322 if (!TempExpr)
323 return nullptr;
324 E = TempExpr->getSubExpr()->IgnoreParenCasts();
325 if (!E)
326 return nullptr;
327 if (auto *Lambda = dyn_cast<LambdaExpr>(E))
328 return Lambda;
329 auto *CE = dyn_cast_or_null<CXXConstructExpr>(E);
330 if (!CE || !CE->getNumArgs())
331 return nullptr;
332 auto *CtorArg = CE->getArg(0)->IgnoreParenCasts();
333 if (!CtorArg)
334 return nullptr;
335 auto *InnerCE = dyn_cast_or_null<CXXConstructExpr>(CtorArg);
336 if (InnerCE && InnerCE->getNumArgs())
337 CtorArg = InnerCE->getArg(0)->IgnoreParenCasts();
338 auto updateIgnoreList = [&] {
339 ConstructToIgnore.insert(CE);
340 if (InnerCE)
341 ConstructToIgnore.insert(InnerCE);
342 };
343 if (auto *Lambda = dyn_cast<LambdaExpr>(CtorArg)) {
344 updateIgnoreList();
345 return Lambda;
346 }
347 if (auto *TempExpr = dyn_cast<CXXBindTemporaryExpr>(CtorArg)) {
348 E = TempExpr->getSubExpr()->IgnoreParenCasts();
349 if (auto *Lambda = dyn_cast<LambdaExpr>(E)) {
350 updateIgnoreList();
351 return Lambda;
352 }
353 }
354 auto *DRE = dyn_cast<DeclRefExpr>(CtorArg);
355 if (!DRE)
356 return nullptr;
357 auto *VD = dyn_cast_or_null<VarDecl>(DRE->getDecl());
358 if (!VD)
359 return nullptr;
360 auto *Init = VD->getInit();
361 if (!Init)
362 return nullptr;
363 if (auto *Lambda = dyn_cast<LambdaExpr>(Init)) {
364 DeclRefExprsToIgnore.insert(DRE);
365 updateIgnoreList();
366 return Lambda;
367 }
368 return nullptr;
369 }
370
371 void checkCalleeLambda(CallExpr *CE) {
372 auto *Callee = CE->getCallee();
373 if (!Callee)
374 return;
375 Callee = Callee->IgnoreParenCasts();
376 if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(Callee)) {
377 Callee = MTE->getSubExpr();
378 if (!Callee)
379 return;
380 Callee = Callee->IgnoreParenCasts();
381 }
382 if (auto *L = dyn_cast<LambdaExpr>(Callee)) {
383 LambdasToIgnore.insert(L); // Calling a lambda upon creation is safe.
384 return;
385 }
386 auto *DRE = dyn_cast<DeclRefExpr>(Callee->IgnoreParenCasts());
387 if (!DRE)
388 return;
389 auto *MD = dyn_cast_or_null<CXXMethodDecl>(DRE->getDecl());
390 if (!MD || CE->getNumArgs() < 1)
391 return;
392 auto *Arg = CE->getArg(0)->IgnoreParenCasts();
393 if (auto *L = dyn_cast_or_null<LambdaExpr>(Arg)) {
394 LambdasToIgnore.insert(L); // Calling a lambda upon creation is safe.
395 return;
396 }
397 auto *ArgRef = dyn_cast<DeclRefExpr>(Arg);
398 if (!ArgRef)
399 return;
400 auto *VD = dyn_cast_or_null<VarDecl>(ArgRef->getDecl());
401 if (!VD)
402 return;
403 auto *Init = VD->getInit();
404 if (!Init)
405 return;
406 auto *L = dyn_cast_or_null<LambdaExpr>(Init->IgnoreParenCasts());
407 if (!L)
408 return;
409 DeclRefExprsToIgnore.insert(ArgRef);
410 LambdasToIgnore.insert(L);
411 }
412
413 bool hasProtectedThis(const LambdaExpr *L) {
414 for (const LambdaCapture &OtherCapture : L->captures()) {
415 if (!OtherCapture.capturesVariable())
416 continue;
417 if (auto *ValueDecl = OtherCapture.getCapturedVar()) {
418 if (declProtectsThis(ValueDecl)) {
419 ProtectedThisDecls.insert(ValueDecl);
420 return true;
421 }
422 }
423 }
424 return false;
425 }
426
427 bool declProtectsThis(const ValueDecl *ValueDecl) const {
428 auto *VD = dyn_cast<VarDecl>(ValueDecl);
429 if (!VD)
430 return false;
431 auto *Init = VD->getInit();
432 if (!Init)
433 return false;
434 const Expr *Arg = Init->IgnoreParenCasts();
435 do {
436 if (auto *BTE = dyn_cast<CXXBindTemporaryExpr>(Arg))
437 Arg = BTE->getSubExpr()->IgnoreParenCasts();
438 if (auto *CE = dyn_cast<CXXConstructExpr>(Arg)) {
439 auto *Ctor = CE->getConstructor();
440 if (!Ctor)
441 return false;
442 auto clsName = safeGetName(Ctor->getParent());
443 if (Checker->isPtrType(clsName) && CE->getNumArgs()) {
444 Arg = CE->getArg(0)->IgnoreParenCasts();
445 continue;
446 }
447 if (auto *Type = ClsType.getTypePtrOrNull()) {
448 if (auto *CXXR = Type->getPointeeCXXRecordDecl()) {
449 if (CXXR == Ctor->getParent() && Ctor->isMoveConstructor() &&
450 CE->getNumArgs() == 1) {
451 Arg = CE->getArg(0)->IgnoreParenCasts();
452 continue;
453 }
454 }
455 }
456 return false;
457 }
458 if (auto *CE = dyn_cast<CallExpr>(Arg)) {
459 if (auto *Callee = CE->getDirectCallee()) {
460 if ((isStdOrWTFMove(Callee) || isCtorOfSafePtr(Callee)) &&
461 CE->getNumArgs() == 1) {
462 Arg = CE->getArg(0)->IgnoreParenCasts();
463 continue;
464 }
465 }
466 }
467 if (auto *OpCE = dyn_cast<CXXOperatorCallExpr>(Arg)) {
468 auto OpCode = OpCE->getOperator();
469 if (OpCode == OO_Star || OpCode == OO_Amp) {
470 auto *Callee = OpCE->getDirectCallee();
471 if (!Callee)
472 return false;
473 auto clsName = safeGetName(Callee->getParent());
474 if (!Checker->isPtrType(clsName) || !OpCE->getNumArgs())
475 return false;
476 Arg = OpCE->getArg(0)->IgnoreParenCasts();
477 continue;
478 }
479 }
480 if (auto *UO = dyn_cast<UnaryOperator>(Arg)) {
481 auto OpCode = UO->getOpcode();
482 if (OpCode == UO_Deref || OpCode == UO_AddrOf) {
483 Arg = UO->getSubExpr()->IgnoreParenCasts();
484 continue;
485 }
486 }
487 break;
488 } while (Arg);
489 if (auto *DRE = dyn_cast<DeclRefExpr>(Arg)) {
490 auto *Decl = DRE->getDecl();
491 if (auto *ImplicitParam = dyn_cast<ImplicitParamDecl>(Decl)) {
492 auto kind = ImplicitParam->getParameterKind();
493 return kind == ImplicitParamKind::ObjCSelf ||
494 kind == ImplicitParamKind::CXXThis;
495 }
496 return ProtectedThisDecls.contains(Decl);
497 }
498 return isa<CXXThisExpr>(Arg);
499 }
500 };
501
502 LocalVisitor visitor(this);
503 if (auto *RTC = Model->retainTypeChecker())
504 RTC->visitTranslationUnitDecl(TUD);
505 visitor.TraverseDecl(const_cast<TranslationUnitDecl *>(TUD));
506 }
507
508 void visitLambdaExpr(const LambdaExpr *L, bool shouldCheckThis,
509 const QualType T,
510 bool ignoreParamVarDecl = false) const {
511 if (TFA.isTrivial(L->getBody()))
512 return;
513 for (const LambdaCapture &C : L->captures()) {
514 if (C.capturesVariable()) {
515 ValueDecl *CapturedVar = C.getCapturedVar();
516 if (ignoreParamVarDecl && isa<ParmVarDecl>(CapturedVar))
517 continue;
518 if (auto *ImplicitParam = dyn_cast<ImplicitParamDecl>(CapturedVar)) {
519 auto kind = ImplicitParam->getParameterKind();
520 if ((kind == ImplicitParamKind::ObjCSelf ||
521 kind == ImplicitParamKind::CXXThis) &&
522 !shouldCheckThis)
523 continue;
524 }
525 QualType CapturedVarQualType = CapturedVar->getType();
526 auto IsUncountedPtr = isUnsafePtr(CapturedVar->getType());
527 if (C.getCaptureKind() == LCK_ByCopy &&
528 CapturedVarQualType->isReferenceType())
529 continue;
530 if (IsUncountedPtr && *IsUncountedPtr)
531 reportBug(C, CapturedVar, CapturedVarQualType, L);
532 } else if (C.capturesThis() && shouldCheckThis) {
533 if (ignoreParamVarDecl) // this is always a parameter to this function.
534 continue;
535 reportBugOnThisPtr(C, T);
536 }
537 }
538 }
539
540 void reportBug(const LambdaCapture &Capture, ValueDecl *CapturedVar,
541 const QualType T, const LambdaExpr *L) const {
542 assert(CapturedVar);
543
544 auto Location = Capture.getLocation();
545 if (isa<ImplicitParamDecl>(CapturedVar) && !Location.isValid())
546 Location = L->getBeginLoc();
547
548 SmallString<100> Buf;
549 llvm::raw_svector_ostream Os(Buf);
550
551 if (Capture.isExplicit())
552 Os << "Captured ";
553 else
554 Os << "Implicitly captured ";
555 Os << "variable ";
556 printQuotedQualifiedName(Os, CapturedVar);
557
558 bool IsUnsafePtr = CapturedVar->getType() == T;
559 if (IsUnsafePtr)
560 Os << " is a ";
561 else
562 Os << " contains a ";
563 auto *CapturedType = T.getTypePtrOrNull();
564 printPointer(Os, CapturedType);
565
566 PathDiagnosticLocation BSLoc(Location, BR->getSourceManager());
567 auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
568 BR->emitReport(std::move(Report));
569 }
570
571 void reportBugOnThisPtr(const LambdaCapture &Capture,
572 const QualType T) const {
573 SmallString<100> Buf;
574 llvm::raw_svector_ostream Os(Buf);
575
576 if (Capture.isExplicit()) {
577 Os << "Captured ";
578 } else {
579 Os << "Implicitly captured ";
580 }
581
582 Os << "variable 'this' is a raw pointer to " << Model->typeName();
583 if (auto *RD = T->getPointeeCXXRecordDecl()) {
584 Os << " ";
586 }
587
588 PathDiagnosticLocation BSLoc(Capture.getLocation(), BR->getSourceManager());
589 auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
590 BR->emitReport(std::move(Report));
591 }
592
593 void printPointer(llvm::raw_svector_ostream &Os, const Type *T) const {
594 if (Model->retainTypeChecker()) {
595 // An OS object may be spelled as an id qualified by an OS_-prefixed
596 // protocol; print that protocol name.
597 if (auto *ObjCPtr = dyn_cast<ObjCObjectPointerType>(T)) {
598 for (ObjCProtocolDecl *P : ObjCPtr->quals()) {
599 if (const auto *II = P->getIdentifier()) {
600 auto Name = II->getName();
601 if (Name.starts_with("OS_")) {
602 Os << Model->typeName() << " ";
604 return;
605 }
606 }
607 }
608 }
609 // Retain/OS types are frequently spelled through a typedef (e.g.
610 // CFXXXRef); print the typedef name rather than desugaring.
611 if (!isa<ObjCObjectPointerType>(T) && T->getAs<TypedefType>()) {
612 auto Typedef = T->getAs<TypedefType>();
613 assert(Typedef);
614 Os << Model->typeName() << " ";
615 printQuotedQualifiedName(Os, Typedef->getDecl());
616 return;
617 }
618 }
621 Os << (IsPtr ? "raw pointer" : "raw reference") << " to ";
622 Os << Model->typeName();
623
624 if (auto *RD = T->getPointeeType()->getAsRecordDecl()) {
625 Os << " ";
627 } else if (auto *ObjCDecl = getObjCDeclFromObjCPtr(T)) {
628 Os << " ";
629 printQuotedQualifiedName(Os, ObjCDecl);
630 }
631 }
632};
633
634class UncountedLambdaCapturesChecker : public RawPtrRefLambdaCapturesChecker {
635public:
636 UncountedLambdaCapturesChecker()
637 : RawPtrRefLambdaCapturesChecker("Lambda capture of uncounted variable",
639};
640
641class UncheckedLambdaCapturesChecker : public RawPtrRefLambdaCapturesChecker {
642public:
643 UncheckedLambdaCapturesChecker()
644 : RawPtrRefLambdaCapturesChecker("Lambda capture of unchecked variable",
646};
647
648class UnretainedLambdaCapturesChecker : public RawPtrRefLambdaCapturesChecker {
649public:
650 UnretainedLambdaCapturesChecker()
651 : RawPtrRefLambdaCapturesChecker("Lambda capture of unretained "
652 "variables",
654};
655
656} // namespace
657
658void ento::registerUncountedLambdaCapturesChecker(CheckerManager &Mgr) {
659 Mgr.registerChecker<UncountedLambdaCapturesChecker>();
660}
661
662bool ento::shouldRegisterUncountedLambdaCapturesChecker(
663 const CheckerManager &mgr) {
664 return true;
665}
666
667void ento::registerUncheckedLambdaCapturesChecker(CheckerManager &Mgr) {
668 Mgr.registerChecker<UncheckedLambdaCapturesChecker>();
669}
670
671bool ento::shouldRegisterUncheckedLambdaCapturesChecker(
672 const CheckerManager &mgr) {
673 return true;
674}
675
676void ento::registerUnretainedLambdaCapturesChecker(CheckerManager &Mgr) {
677 Mgr.registerChecker<UnretainedLambdaCapturesChecker>();
678}
679
680bool ento::shouldRegisterUnretainedLambdaCapturesChecker(
681 const CheckerManager &mgr) {
682 return true;
683}
*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:1694
CXXConstructorDecl * getConstructor() const
Get the constructor that this expression will (ultimately) call.
Definition ExprCXX.h:1614
unsigned getNumArgs() const
Return the number of arguments to the constructor call.
Definition ExprCXX.h:1691
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:3063
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:2859
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:3106
Stmt * getBody() const
Retrieve the body of the lambda.
Definition ExprCXX.cpp:1353
SourceLocation getBeginLoc() const LLVM_READONLY
Definition ExprCXX.h:2185
capture_range captures() const
Retrieve this lambda's captures.
Definition ExprCXX.cpp:1378
ImplicitParamDecl * getSelfDecl() const
Definition DeclObjC.h:421
bool isInstanceMethod() const
Definition DeclObjC.h:429
bool isNull() const
Return true if this QualType doesn't point to a type yet.
Definition TypeBase.h:1005
const Type * getTypePtrOrNull() const
Definition TypeBase.h:8499
RecordDecl * getAsRecordDecl() const
Retrieves the RecordDecl this type refers to.
Definition Type.h:41
bool isReferenceType() const
Definition TypeBase.h:8756
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:9325
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
std::unique_ptr< PtrRefSafetyModel > makeCheckedPtrSafetyModel()
@ 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 > isUnsafePtrForStorage(const PtrRefSafetyModel &Model, QualType T, bool IgnoreARC=false)
Applies the memory-management exemptions that hold for a variable, member, or lambda capture (but not...
const FunctionProtoType * T
@ Type
The name was classified as a type.
Definition Sema.h:564
std::string safeGetName(const T *ASTNode)
Definition ASTUtils.h:98
ObjCInterfaceDecl * getObjCDeclFromObjCPtr(const Type *TypePtr)
Definition ASTUtils.cpp:391
DynamicRecursiveASTVisitorBase< false > DynamicRecursiveASTVisitor
bool isStdOrWTFMove(const clang::FunctionDecl *F)
std::unique_ptr< PtrRefSafetyModel > makeRefPtrSafetyModel()
std::unique_ptr< PtrRefSafetyModel > makeRetainPtrSafetyModel()