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