clang 23.0.0git
RetainPtrCtorAdoptChecker.cpp
Go to the documentation of this file.
1//=======- RetainPtrCtorAdoptChecker.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 "PtrTypesSemantics.h"
18#include "llvm/ADT/DenseSet.h"
19#include <optional>
20
21using namespace clang;
22using namespace ento;
23
24namespace {
25
26class RetainPtrCtorAdoptChecker
27 : public Checker<check::ASTDecl<TranslationUnitDecl>> {
28private:
29 BugType Bug;
30 mutable BugReporter *BR = nullptr;
31 mutable std::unique_ptr<RetainSummaryManager> Summaries;
32 mutable llvm::DenseSet<const ValueDecl *> CreateOrCopyOutArguments;
33 mutable llvm::DenseSet<const Expr *> CreateOrCopyFnCall;
34 mutable RetainTypeChecker RTC;
35
36public:
37 RetainPtrCtorAdoptChecker()
38 : Bug(this, "Correct use of RetainPtr, adoptNS, and adoptCF",
39 "WebKit coding guidelines") {}
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 : public RecursiveASTVisitor<LocalVisitor> {
49 const RetainPtrCtorAdoptChecker *Checker;
50 Decl *DeclWithIssue{nullptr};
51
52 using Base = RecursiveASTVisitor<LocalVisitor>;
53
54 explicit LocalVisitor(const RetainPtrCtorAdoptChecker *Checker)
55 : Checker(Checker) {
56 assert(Checker);
57 }
58
59 bool shouldVisitTemplateInstantiations() const { return true; }
60 bool shouldVisitImplicitCode() const { return false; }
61
62 bool TraverseDecl(Decl *D) {
63 llvm::SaveAndRestore SavedDecl(DeclWithIssue);
64 if (D && (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)))
65 DeclWithIssue = D;
66 return Base::TraverseDecl(D);
67 }
68
69 bool TraverseClassTemplateDecl(ClassTemplateDecl *CTD) {
71 return true; // Skip the contents of RetainPtr.
72 return Base::TraverseClassTemplateDecl(CTD);
73 }
74
75 bool VisitTypedefDecl(TypedefDecl *TD) {
76 Checker->RTC.visitTypedef(TD);
77 return true;
78 }
79
80 bool VisitCallExpr(const CallExpr *CE) {
81 Checker->visitCallExpr(CE, DeclWithIssue);
82 return true;
83 }
84
85 bool VisitCXXConstructExpr(const CXXConstructExpr *CE) {
86 Checker->visitConstructExpr(CE, DeclWithIssue);
87 return true;
88 }
89
90 bool VisitObjCMessageExpr(const ObjCMessageExpr *ObjCMsgExpr) {
91 Checker->visitObjCMessageExpr(ObjCMsgExpr, DeclWithIssue);
92 return true;
93 }
94
95 bool VisitReturnStmt(const ReturnStmt *RS) {
96 Checker->visitReturnStmt(RS, DeclWithIssue);
97 return true;
98 }
99
100 bool VisitVarDecl(const VarDecl *VD) {
101 Checker->visitVarDecl(VD);
102 return true;
103 }
104
105 bool VisitBinaryOperator(const BinaryOperator *BO) {
106 Checker->visitBinaryOperator(BO);
107 return true;
108 }
109 };
110
111 LocalVisitor visitor(this);
112 Summaries = std::make_unique<RetainSummaryManager>(
113 TUD->getASTContext(), true /* trackObjCAndCFObjects */,
114 false /* trackOSObjects */);
115 RTC.visitTranslationUnitDecl(TUD);
116 visitor.TraverseDecl(const_cast<TranslationUnitDecl *>(TUD));
117 }
118
119 bool isAdoptFn(const Decl *FnDecl) const {
120 return isAdoptFnName(safeGetName(FnDecl));
121 }
122
123 bool isAdoptFnName(const std::string &Name) const {
124 return isAdoptNS(Name) || Name == "adoptCF" || Name == "adoptCFArc" ||
125 Name == "adoptCFNullable" || Name == "adoptCFNullableArc" ||
126 Name == "adoptOSObject" || Name == "adoptOSObjectArc";
127 }
128
129 bool isAdoptNS(const std::string &Name) const {
130 return Name == "adoptNS" || Name == "adoptNSArc" ||
131 Name == "adoptNSNullable" || Name == "adoptNSNullableArc";
132 }
133
134 void visitCallExpr(const CallExpr *CE, const Decl *DeclWithIssue) const {
135 assert(BR && "expected nonnull BugReporter");
136 if (BR->getSourceManager().isInSystemHeader(CE->getExprLoc()))
137 return;
138
139 std::string FnName;
140 if (auto *F = CE->getDirectCallee()) {
141 FnName = safeGetName(F);
142 if (isAdoptFnName(FnName))
143 checkAdoptCall(CE, FnName, DeclWithIssue);
144 else {
145 checkCreateOrCopyFunction(CE, DeclWithIssue);
146 checkBridgingRelease(CE, F, DeclWithIssue);
147 }
148 return;
149 }
150
151 auto *CalleeExpr = CE->getCallee();
152 if (!CalleeExpr)
153 return;
154 CalleeExpr = CalleeExpr->IgnoreParenCasts();
155 if (auto *UnresolvedExpr = dyn_cast<UnresolvedLookupExpr>(CalleeExpr)) {
156 auto Name = UnresolvedExpr->getName();
157 if (!Name.isIdentifier())
158 return;
159 FnName = Name.getAsString();
160 if (isAdoptFnName(FnName))
161 checkAdoptCall(CE, FnName, DeclWithIssue);
162 }
163 checkCreateOrCopyFunction(CE, DeclWithIssue);
164 }
165
166 void checkAdoptCall(const CallExpr *CE, const std::string &FnName,
167 const Decl *DeclWithIssue) const {
168 if (!CE->getNumArgs())
169 return;
170
171 auto *Arg = CE->getArg(0)->IgnoreParenCasts();
172 auto Result = isOwned(Arg);
173 if (Result == IsOwnedResult::Unknown)
174 Result = IsOwnedResult::NotOwned;
175
176 const Expr *Inner = nullptr;
177 if (isAllocInit(Arg, &Inner) || isCreateOrCopy(Arg)) {
178 if (Inner)
179 CreateOrCopyFnCall.insert(Inner);
180 CreateOrCopyFnCall.insert(Arg); // Avoid double reporting.
181 return;
182 }
183 if (Result == IsOwnedResult::Owned || Result == IsOwnedResult::Skip ||
184 isNullPtr(Arg)) {
185 CreateOrCopyFnCall.insert(Arg);
186 return;
187 }
188
189 if (auto *DRE = dyn_cast<DeclRefExpr>(Arg)) {
190 if (CreateOrCopyOutArguments.contains(DRE->getDecl()))
191 return;
192 }
193 if (RTC.isARCEnabled() && isAdoptFnName(FnName))
194 reportUseAfterFree(FnName, CE, DeclWithIssue, "when ARC is disabled");
195 else
196 reportUseAfterFree(FnName, CE, DeclWithIssue);
197 }
198
199 void visitObjCMessageExpr(const ObjCMessageExpr *ObjCMsgExpr,
200 const Decl *DeclWithIssue) const {
201 if (BR->getSourceManager().isInSystemHeader(ObjCMsgExpr->getExprLoc()))
202 return;
203
204 auto Selector = ObjCMsgExpr->getSelector();
205 if (Selector.getAsString() == "autorelease") {
206 auto *Receiver = ObjCMsgExpr->getInstanceReceiver()->IgnoreParenCasts();
207 if (!Receiver)
208 return;
209 ObjCMsgExpr = dyn_cast<ObjCMessageExpr>(Receiver);
210 if (!ObjCMsgExpr)
211 return;
212 const Expr *Inner = nullptr;
213 if (!isAllocInit(ObjCMsgExpr, &Inner))
214 return;
215 CreateOrCopyFnCall.insert(ObjCMsgExpr);
216 if (Inner)
217 CreateOrCopyFnCall.insert(Inner);
218 return;
219 }
220
221 const Expr *Inner = nullptr;
222 if (!isAllocInit(ObjCMsgExpr, &Inner))
223 return;
224 if (RTC.isARCEnabled())
225 return; // ARC never leaks.
226 if (CreateOrCopyFnCall.contains(ObjCMsgExpr))
227 return;
228 if (Inner)
229 CreateOrCopyFnCall.insert(Inner); // Avoid double reporting.
230 reportLeak(ObjCMsgExpr, DeclWithIssue);
231 }
232
233 void checkCreateOrCopyFunction(const CallExpr *CE,
234 const Decl *DeclWithIssue) const {
235 unsigned ArgCount = CE->getNumArgs();
236 auto *CalleeDecl = CE->getCalleeDecl();
237 auto *FnDecl = CalleeDecl ? CalleeDecl->getAsFunction() : nullptr;
238 for (unsigned ArgIndex = 0; ArgIndex < ArgCount; ++ArgIndex) {
239 auto *Arg = CE->getArg(ArgIndex)->IgnoreParenCasts();
240 auto *Unary = dyn_cast<UnaryOperator>(Arg);
241 if (!Unary)
242 continue;
243 if (Unary->getOpcode() != UO_AddrOf)
244 continue;
245 auto *SubExpr = Unary->getSubExpr();
246 if (!SubExpr)
247 continue;
248 auto *DRE = dyn_cast<DeclRefExpr>(SubExpr->IgnoreParenCasts());
249 if (!DRE)
250 continue;
251 auto *Decl = DRE->getDecl();
252 if (!Decl)
253 continue;
254 if (FnDecl && ArgIndex < FnDecl->getNumParams()) {
255 // Manually check attributes on argumenet since RetainSummaryManager
256 // basically ignores CF_RETRUNS_RETAINED on out arguments.
257 auto *ParamDecl = FnDecl->getParamDecl(ArgIndex);
258 if (ParamDecl->hasAttr<CFReturnsRetainedAttr>())
259 CreateOrCopyOutArguments.insert(Decl);
260 } else {
261 // No callee or a variadic argument.
262 // Conservatively assume it's an out argument.
263 if (RTC.isUnretained(Decl->getType()))
264 CreateOrCopyOutArguments.insert(Decl);
265 }
266 }
267 auto Summary = Summaries->getSummary(AnyCall(CE));
268 switch (Summary->getRetEffect().getKind()) {
271 if (!CreateOrCopyFnCall.contains(CE))
272 reportLeak(CE, DeclWithIssue);
273 break;
274 default:
275 break;
276 }
277 }
278
279 void checkBridgingRelease(const CallExpr *CE, const FunctionDecl *Callee,
280 const Decl *DeclWithIssue) const {
281 if (safeGetName(Callee) != "CFBridgingRelease" || CE->getNumArgs() != 1)
282 return;
283
284 auto *Arg = CE->getArg(0)->IgnoreParenCasts();
285 auto *InnerCE = dyn_cast<CallExpr>(Arg);
286 if (!InnerCE)
287 return;
288
289 auto *InnerF = InnerCE->getDirectCallee();
290 if (!InnerF || !isCreateOrCopyFunction(InnerF))
291 return;
292
293 CreateOrCopyFnCall.insert(InnerCE);
294 }
295
296 void visitConstructExpr(const CXXConstructExpr *CE,
297 const Decl *DeclWithIssue) const {
298 assert(BR && "expected nonnull BugReporter");
299 if (BR->getSourceManager().isInSystemHeader(CE->getExprLoc()))
300 return;
301
302 auto *Ctor = CE->getConstructor();
303 if (!Ctor)
304 return;
305
306 auto *Cls = Ctor->getParent();
307 if (!Cls)
308 return;
309
310 if (!isRetainPtrOrOSPtr(safeGetName(Cls)) || !CE->getNumArgs())
311 return;
312
313 // Ignore RetainPtr construction inside adoptNS, adoptCF, and retainPtr.
314 if (isAdoptFn(DeclWithIssue) || safeGetName(DeclWithIssue) == "retainPtr")
315 return;
316
317 std::string Name = "RetainPtr constructor";
318 auto *Arg = CE->getArg(0)->IgnoreParenCasts();
319 auto Result = isOwned(Arg);
320
321 if (isCreateOrCopy(Arg))
322 CreateOrCopyFnCall.insert(Arg); // Avoid double reporting.
323
324 const Expr *Inner = nullptr;
325 if (isAllocInit(Arg, &Inner)) {
326 CreateOrCopyFnCall.insert(Arg);
327 if (Inner)
328 CreateOrCopyFnCall.insert(Inner);
329 }
330
331 if (Result == IsOwnedResult::Skip)
332 return;
333
334 if (Result == IsOwnedResult::Unknown)
335 Result = IsOwnedResult::NotOwned;
336 if (Result == IsOwnedResult::Owned)
337 reportLeak(Name, CE, DeclWithIssue);
338 else if (RTC.isARCEnabled() && isAllocInit(Arg))
339 reportLeak(Name, CE, DeclWithIssue, "when ARC is disabled");
340 else if (isCreateOrCopy(Arg))
341 reportLeak(Name, CE, DeclWithIssue);
342 }
343
344 void visitVarDecl(const VarDecl *VD) const {
345 auto *Init = VD->getInit();
346 if (!Init || !RTC.isARCEnabled())
347 return;
349 const Expr *Inner = nullptr;
350 if (isAllocInit(Init, &Inner)) {
351 CreateOrCopyFnCall.insert(Init);
352 if (Inner)
353 CreateOrCopyFnCall.insert(Inner);
354 }
355 }
356
357 void visitBinaryOperator(const BinaryOperator *BO) const {
358 if (!BO->isAssignmentOp())
359 return;
360 auto *LHS = BO->getLHS();
361 auto *RHS = BO->getRHS()->IgnoreParenCasts();
362 if (isa<ObjCIvarRefExpr>(LHS)) {
363 const Expr *Inner = nullptr;
364 if (isAllocInit(RHS, &Inner)) {
365 CreateOrCopyFnCall.insert(RHS);
366 if (Inner)
367 CreateOrCopyFnCall.insert(Inner);
368 }
369 return;
370 }
371 auto *UO = dyn_cast<UnaryOperator>(LHS);
372 if (!UO)
373 return;
374 auto OpCode = UO->getOpcode();
375 if (OpCode != UO_Deref)
376 return;
377 auto *DerefTarget = UO->getSubExpr();
378 if (!DerefTarget)
379 return;
380 DerefTarget = DerefTarget->IgnoreParenCasts();
381 auto *DRE = dyn_cast<DeclRefExpr>(DerefTarget);
382 if (!DRE)
383 return;
384 auto *Decl = DRE->getDecl();
385 if (!Decl)
386 return;
387 if (!isa<ParmVarDecl>(Decl) || !isCreateOrCopy(RHS))
388 return;
389 if (Decl->hasAttr<CFReturnsRetainedAttr>())
390 CreateOrCopyFnCall.insert(RHS);
391 }
392
393 void visitReturnStmt(const ReturnStmt *RS, const Decl *DeclWithIssue) const {
394 if (!DeclWithIssue)
395 return;
396 auto *RetValue = RS->getRetValue();
397 if (!RetValue)
398 return;
399 RetValue = RetValue->IgnoreParenCasts();
400 std::optional<bool> retainsRet;
401 if (auto *FnDecl = dyn_cast<FunctionDecl>(DeclWithIssue))
402 retainsRet = retainsReturnValue(FnDecl);
403 else if (auto *MethodDecl = dyn_cast<ObjCMethodDecl>(DeclWithIssue))
404 retainsRet = retainsReturnValue(MethodDecl);
405 else
406 return;
407 if (!retainsRet || !*retainsRet) {
408 // Under ARC, returning [[X alloc] init] doesn't leak X.
409 if (RTC.isUnretained(RetValue->getType()))
410 return;
411 }
412 if (retainsRet && *retainsRet) {
413 CreateOrCopyFnCall.insert(RetValue);
414 return;
415 }
416 if (auto *CE = dyn_cast<CallExpr>(RetValue)) {
417 auto *Callee = CE->getDirectCallee();
418 if (!Callee || !isCreateOrCopyFunction(Callee))
419 return;
420 CreateOrCopyFnCall.insert(CE);
421 return;
422 }
423 const Expr *Inner = nullptr;
424 if (isAllocInit(RetValue, &Inner)) {
425 CreateOrCopyFnCall.insert(RetValue);
426 if (Inner)
427 CreateOrCopyFnCall.insert(Inner);
428 }
429 }
430
431 template <typename CallableType>
432 std::optional<bool> retainsReturnValue(const CallableType *FnDecl) const {
433 auto Summary = Summaries->getSummary(AnyCall(FnDecl));
434 auto RetEffect = Summary->getRetEffect();
435 switch (RetEffect.getKind()) {
436 case RetEffect::NoRet:
437 return std::nullopt;
439 return true;
441 return false;
443 return std::nullopt;
445 return std::nullopt;
446 }
447 return std::nullopt;
448 }
449
450 bool isCreateOrCopy(const Expr *E) const {
451 auto *CE = dyn_cast<CallExpr>(E);
452 if (!CE)
453 return false;
454 auto *Callee = CE->getDirectCallee();
455 if (!Callee)
456 return false;
457 return isCreateOrCopyFunction(Callee);
458 }
459
460 bool isCreateOrCopyFunction(const FunctionDecl *FnDecl) const {
461 auto CalleeName = safeGetName(FnDecl);
462 return CalleeName.find("Create") != std::string::npos ||
463 CalleeName.find("Copy") != std::string::npos;
464 }
465
466 enum class IsOwnedResult { Unknown, Skip, Owned, NotOwned };
467 IsOwnedResult isOwned(const Expr *E) const {
468 while (1) {
469 if (auto *POE = dyn_cast<PseudoObjectExpr>(E)) {
470 if (unsigned SemanticExprCount = POE->getNumSemanticExprs()) {
471 E = POE->getSemanticExpr(SemanticExprCount - 1);
472 continue;
473 }
474 }
475 if (isNullPtr(E))
476 return IsOwnedResult::NotOwned;
477 if (auto *DRE = dyn_cast<DeclRefExpr>(E)) {
478 auto QT = DRE->getType();
480 return IsOwnedResult::NotOwned;
481 QT = QT.getCanonicalType();
482 if (RTC.isUnretained(QT, true /* ignoreARC */))
483 return IsOwnedResult::NotOwned;
484 auto *PointeeType = QT->getPointeeType().getTypePtrOrNull();
485 if (PointeeType && PointeeType->isVoidType())
486 return IsOwnedResult::NotOwned; // Assume reading void* as +0.
487 }
488 if (auto *TE = dyn_cast<CXXBindTemporaryExpr>(E)) {
489 E = TE->getSubExpr();
490 continue;
491 }
492 if (auto *ObjCMsgExpr = dyn_cast<ObjCMessageExpr>(E)) {
493 auto Summary = Summaries->getSummary(AnyCall(ObjCMsgExpr));
494 auto RetEffect = Summary->getRetEffect();
495 switch (RetEffect.getKind()) {
496 case RetEffect::NoRet:
497 return IsOwnedResult::Unknown;
499 return IsOwnedResult::Owned;
501 return IsOwnedResult::NotOwned;
503 if (auto *Receiver = ObjCMsgExpr->getInstanceReceiver()) {
504 E = Receiver->IgnoreParenCasts();
505 continue;
506 }
507 return IsOwnedResult::Unknown;
509 return IsOwnedResult::Unknown;
510 }
511 }
512 if (auto *CXXCE = dyn_cast<CXXMemberCallExpr>(E)) {
513 if (auto *MD = CXXCE->getMethodDecl()) {
514 auto *Cls = MD->getParent();
515 if (auto *CD = dyn_cast<CXXConversionDecl>(MD)) {
516 auto QT = CD->getConversionType().getCanonicalType();
517 auto *ResultType = QT.getTypePtrOrNull();
518 if (isRetainPtrOrOSPtr(safeGetName(Cls)) && ResultType &&
519 (ResultType->isPointerType() || ResultType->isReferenceType() ||
520 ResultType->isObjCObjectPointerType()))
521 return IsOwnedResult::NotOwned;
522 }
523 if (safeGetName(MD) == "leakRef" &&
525 return IsOwnedResult::Owned;
526 }
527 }
528 if (auto *CE = dyn_cast<CallExpr>(E)) {
529 if (auto *Callee = CE->getDirectCallee()) {
530 if (isAdoptFn(Callee))
531 return IsOwnedResult::NotOwned;
532 auto Name = safeGetName(Callee);
533 if (Name == "__builtin___CFStringMakeConstantString")
534 return IsOwnedResult::NotOwned;
535 if ((Name == "checked_cf_cast" || Name == "dynamic_cf_cast" ||
536 Name == "checked_objc_cast" || Name == "dynamic_objc_cast") &&
537 CE->getNumArgs() == 1) {
538 E = CE->getArg(0)->IgnoreParenCasts();
539 continue;
540 }
541 auto RetType = Callee->getReturnType();
542 if (isRetainPtrOrOSPtrType(RetType))
543 return IsOwnedResult::NotOwned;
544 if (isCreateOrCopyFunction(Callee)) {
545 CreateOrCopyFnCall.insert(CE);
546 return IsOwnedResult::Owned;
547 }
548 } else if (auto *CalleeExpr = CE->getCallee()) {
549 if (isa<CXXDependentScopeMemberExpr>(CalleeExpr))
550 return IsOwnedResult::Skip; // Wait for instantiation.
551 if (isa<UnresolvedLookupExpr>(CalleeExpr))
552 return IsOwnedResult::Skip; // Wait for instantiation.
553 }
554 auto Summary = Summaries->getSummary(AnyCall(CE));
555 auto RetEffect = Summary->getRetEffect();
556 switch (RetEffect.getKind()) {
557 case RetEffect::NoRet:
558 return IsOwnedResult::Unknown;
560 return IsOwnedResult::Owned;
562 return IsOwnedResult::NotOwned;
564 return IsOwnedResult::Unknown;
566 return IsOwnedResult::Unknown;
567 }
568 }
569 break;
570 }
571 return IsOwnedResult::Unknown;
572 }
573
574 void reportUseAfterFree(const std::string &Name, const CallExpr *CE,
575 const Decl *DeclWithIssue,
576 const char *condition = nullptr) const {
577 SmallString<100> Buf;
578 llvm::raw_svector_ostream Os(Buf);
579
580 Os << "Incorrect use of " << Name
581 << ". The argument is +0 and results in an use-after-free";
582 if (condition)
583 Os << " " << condition;
584 Os << ".";
585
586 assert(BR && "expected nonnull BugReporter");
587 PathDiagnosticLocation BSLoc(CE->getSourceRange().getBegin(),
588 BR->getSourceManager());
589 auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
590 Report->addRange(CE->getSourceRange());
591 Report->setDeclWithIssue(DeclWithIssue);
592 BR->emitReport(std::move(Report));
593 }
594
595 void reportLeak(std::string &Name, const CXXConstructExpr *CE,
596 const Decl *DeclWithIssue,
597 const char *condition = nullptr) const {
598 SmallString<100> Buf;
599 llvm::raw_svector_ostream Os(Buf);
600
601 Os << "Incorrect use of " << Name
602 << ". The argument is +1 and results in a memory leak";
603 if (condition)
604 Os << " " << condition;
605 Os << ".";
606
607 assert(BR && "expected nonnull BugReporter");
608 PathDiagnosticLocation BSLoc(CE->getSourceRange().getBegin(),
609 BR->getSourceManager());
610 auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
611 Report->addRange(CE->getSourceRange());
612 Report->setDeclWithIssue(DeclWithIssue);
613 BR->emitReport(std::move(Report));
614 }
615
616 template <typename ExprType>
617 void reportLeak(const ExprType *E, const Decl *DeclWithIssue) const {
618 SmallString<100> Buf;
619 llvm::raw_svector_ostream Os(Buf);
620
621 Os << "The return value is +1 and results in a memory leak.";
622
623 PathDiagnosticLocation BSLoc(E->getSourceRange().getBegin(),
624 BR->getSourceManager());
625 auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
626 Report->addRange(E->getSourceRange());
627 Report->setDeclWithIssue(DeclWithIssue);
628 BR->emitReport(std::move(Report));
629 }
630};
631} // namespace
632
633void ento::registerRetainPtrCtorAdoptChecker(CheckerManager &Mgr) {
634 Mgr.registerChecker<RetainPtrCtorAdoptChecker>();
635}
636
637bool ento::shouldRegisterRetainPtrCtorAdoptChecker(const CheckerManager &mgr) {
638 return true;
639}
static PRESERVE_NONE bool RetValue(InterpState &S, CodePtr &Ptr)
Definition Interp.cpp:52
*collection of selector each with an associated kind and an ordered *collection of selectors A selector has a an optional score condition
Expr * getLHS() const
Definition Expr.h:4091
Expr * getRHS() const
Definition Expr.h:4093
static bool isAssignmentOp(Opcode Opc)
Definition Expr.h:4177
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
const CXXRecordDecl * getParent() const
Return the parent of this method declaration, which is the class in which this method is defined.
Definition DeclCXX.h:2271
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
Definition Expr.h:3150
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return null.
Definition Expr.h:3129
Expr * getCallee()
Definition Expr.h:3093
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
Definition Expr.h:3137
Decl * getCalleeDecl()
Definition Expr.h:3123
FunctionDecl * getAsFunction() LLVM_READONLY
Returns the function itself, or the templated function if this is a function template.
Definition DeclBase.cpp:273
Expr * IgnoreParenCasts() LLVM_READONLY
Skip past any parentheses and casts which might surround this expression until reaching a fixed point...
Definition Expr.cpp:3100
SourceLocation getExprLoc() const LLVM_READONLY
getExprLoc - Return the preferred location for the arrow when diagnosing a problem with a generic exp...
Definition Expr.cpp:282
Expr * getInstanceReceiver()
Returns the object expression (receiver) for an instance message, or null for a message that is not a...
Definition ExprObjC.h:1299
Selector getSelector() const
Definition ExprObjC.cpp:301
void visitTypedef(const TypedefDecl *)
Expr * getRetValue()
Definition Stmt.h:3193
SourceLocation getBegin() const
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition Stmt.cpp:343
ASTContext & getASTContext() const
Definition Decl.h:141
const Expr * getInit() const
Definition Decl.h:1381
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
@ OwnedSymbol
Indicates that the returned value is an owned (+1) symbol.
@ OwnedWhenTrackedReceiver
Indicates that the return value is an owned object when the receiver is also a tracked object.
@ NoRet
Indicates that no retain count information is tracked for the return value.
@ NotOwnedSymbol
Indicates that the returned value is an object with retain count semantics but that it is not owned (...
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 isa(CodeGen::Address addr)
Definition Address.h:330
bool isRetainPtrOrOSPtrType(const clang::QualType T)
@ Result
The result type of a method or function.
Definition TypeBase.h:905
bool isRetainPtrOrOSPtr(const std::string &Name)
std::string safeGetName(const T *ASTNode)
Definition ASTUtils.h:95
bool isNullPtr(const clang::Expr *E)
Definition ASTUtils.cpp:270
bool isAllocInit(const Expr *E, const Expr **InnerExpr)
Definition ASTUtils.cpp:324