xref: /freebsd/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/WebKit/RetainPtrCtorAdoptChecker.cpp (revision e64bea71c21eb42e97aa615188ba91f6cce0d36d)
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"
11 #include "clang/AST/RecursiveASTVisitor.h"
12 #include "clang/Analysis/DomainSpecific/CocoaConventions.h"
13 #include "clang/Analysis/RetainSummaryManager.h"
14 #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
15 #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
16 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
17 #include "clang/StaticAnalyzer/Core/Checker.h"
18 #include "llvm/ADT/DenseSet.h"
19 #include <optional>
20 
21 using namespace clang;
22 using namespace ento;
23 
24 namespace {
25 
26 class RetainPtrCtorAdoptChecker
27     : public Checker<check::ASTDecl<TranslationUnitDecl>> {
28 private:
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 
36 public:
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) {
70         if (isRetainPtr(safeGetName(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   }
126 
127   bool isAdoptNS(const std::string &Name) const {
128     return Name == "adoptNS" || Name == "adoptNSArc";
129   }
130 
131   void visitCallExpr(const CallExpr *CE, const Decl *DeclWithIssue) const {
132     assert(BR && "expected nonnull BugReporter");
133     if (BR->getSourceManager().isInSystemHeader(CE->getExprLoc()))
134       return;
135 
136     std::string FnName;
137     if (auto *F = CE->getDirectCallee()) {
138       FnName = safeGetName(F);
139       if (isAdoptFnName(FnName))
140         checkAdoptCall(CE, FnName, DeclWithIssue);
141       else {
142         checkCreateOrCopyFunction(CE, DeclWithIssue);
143         checkBridgingRelease(CE, F, DeclWithIssue);
144       }
145       return;
146     }
147 
148     auto *CalleeExpr = CE->getCallee();
149     if (!CalleeExpr)
150       return;
151     CalleeExpr = CalleeExpr->IgnoreParenCasts();
152     if (auto *UnresolvedExpr = dyn_cast<UnresolvedLookupExpr>(CalleeExpr)) {
153       auto Name = UnresolvedExpr->getName();
154       if (!Name.isIdentifier())
155         return;
156       FnName = Name.getAsString();
157       if (isAdoptFnName(FnName))
158         checkAdoptCall(CE, FnName, DeclWithIssue);
159     }
160     checkCreateOrCopyFunction(CE, DeclWithIssue);
161   }
162 
163   void checkAdoptCall(const CallExpr *CE, const std::string &FnName,
164                       const Decl *DeclWithIssue) const {
165     if (!CE->getNumArgs())
166       return;
167 
168     auto *Arg = CE->getArg(0)->IgnoreParenCasts();
169     auto Result = isOwned(Arg);
170     if (Result == IsOwnedResult::Unknown)
171       Result = IsOwnedResult::NotOwned;
172 
173     const Expr *Inner = nullptr;
174     if (isAllocInit(Arg, &Inner) || isCreateOrCopy(Arg)) {
175       if (Inner)
176         CreateOrCopyFnCall.insert(Inner);
177       CreateOrCopyFnCall.insert(Arg); // Avoid double reporting.
178       return;
179     }
180     if (Result == IsOwnedResult::Owned || Result == IsOwnedResult::Skip) {
181       CreateOrCopyFnCall.insert(Arg);
182       return;
183     }
184 
185     if (auto *DRE = dyn_cast<DeclRefExpr>(Arg)) {
186       if (CreateOrCopyOutArguments.contains(DRE->getDecl()))
187         return;
188     }
189     if (RTC.isARCEnabled() && isAdoptFnName(FnName))
190       reportUseAfterFree(FnName, CE, DeclWithIssue, "when ARC is disabled");
191     else
192       reportUseAfterFree(FnName, CE, DeclWithIssue);
193   }
194 
195   void visitObjCMessageExpr(const ObjCMessageExpr *ObjCMsgExpr,
196                             const Decl *DeclWithIssue) const {
197     if (BR->getSourceManager().isInSystemHeader(ObjCMsgExpr->getExprLoc()))
198       return;
199 
200     auto Selector = ObjCMsgExpr->getSelector();
201     if (Selector.getAsString() == "autorelease") {
202       auto *Receiver = ObjCMsgExpr->getInstanceReceiver()->IgnoreParenCasts();
203       if (!Receiver)
204         return;
205       ObjCMsgExpr = dyn_cast<ObjCMessageExpr>(Receiver);
206       if (!ObjCMsgExpr)
207         return;
208       const Expr *Inner = nullptr;
209       if (!isAllocInit(ObjCMsgExpr, &Inner))
210         return;
211       CreateOrCopyFnCall.insert(ObjCMsgExpr);
212       if (Inner)
213         CreateOrCopyFnCall.insert(Inner);
214       return;
215     }
216 
217     const Expr *Inner = nullptr;
218     if (!isAllocInit(ObjCMsgExpr, &Inner))
219       return;
220     if (RTC.isARCEnabled())
221       return; // ARC never leaks.
222     if (CreateOrCopyFnCall.contains(ObjCMsgExpr))
223       return;
224     if (Inner)
225       CreateOrCopyFnCall.insert(Inner); // Avoid double reporting.
226     reportLeak(ObjCMsgExpr, DeclWithIssue);
227   }
228 
229   void checkCreateOrCopyFunction(const CallExpr *CE,
230                                  const Decl *DeclWithIssue) const {
231     unsigned ArgCount = CE->getNumArgs();
232     auto *CalleeDecl = CE->getCalleeDecl();
233     auto *FnDecl = CalleeDecl ? CalleeDecl->getAsFunction() : nullptr;
234     for (unsigned ArgIndex = 0; ArgIndex < ArgCount; ++ArgIndex) {
235       auto *Arg = CE->getArg(ArgIndex)->IgnoreParenCasts();
236       auto *Unary = dyn_cast<UnaryOperator>(Arg);
237       if (!Unary)
238         continue;
239       if (Unary->getOpcode() != UO_AddrOf)
240         continue;
241       auto *SubExpr = Unary->getSubExpr();
242       if (!SubExpr)
243         continue;
244       auto *DRE = dyn_cast<DeclRefExpr>(SubExpr->IgnoreParenCasts());
245       if (!DRE)
246         continue;
247       auto *Decl = DRE->getDecl();
248       if (!Decl)
249         continue;
250       if (FnDecl && ArgIndex < FnDecl->getNumParams()) {
251         // Manually check attributes on argumenet since RetainSummaryManager
252         // basically ignores CF_RETRUNS_RETAINED on out arguments.
253         auto *ParamDecl = FnDecl->getParamDecl(ArgIndex);
254         if (ParamDecl->hasAttr<CFReturnsRetainedAttr>())
255           CreateOrCopyOutArguments.insert(Decl);
256       } else {
257         // No callee or a variadic argument.
258         // Conservatively assume it's an out argument.
259         if (RTC.isUnretained(Decl->getType()))
260           CreateOrCopyOutArguments.insert(Decl);
261       }
262     }
263     auto Summary = Summaries->getSummary(AnyCall(CE));
264     switch (Summary->getRetEffect().getKind()) {
265     case RetEffect::OwnedSymbol:
266     case RetEffect::OwnedWhenTrackedReceiver:
267       if (!CreateOrCopyFnCall.contains(CE))
268         reportLeak(CE, DeclWithIssue);
269       break;
270     default:
271       break;
272     }
273   }
274 
275   void checkBridgingRelease(const CallExpr *CE, const FunctionDecl *Callee,
276                             const Decl *DeclWithIssue) const {
277     if (safeGetName(Callee) != "CFBridgingRelease" || CE->getNumArgs() != 1)
278       return;
279 
280     auto *Arg = CE->getArg(0)->IgnoreParenCasts();
281     auto *InnerCE = dyn_cast<CallExpr>(Arg);
282     if (!InnerCE)
283       return;
284 
285     auto *InnerF = InnerCE->getDirectCallee();
286     if (!InnerF || !isCreateOrCopyFunction(InnerF))
287       return;
288 
289     CreateOrCopyFnCall.insert(InnerCE);
290   }
291 
292   void visitConstructExpr(const CXXConstructExpr *CE,
293                           const Decl *DeclWithIssue) const {
294     assert(BR && "expected nonnull BugReporter");
295     if (BR->getSourceManager().isInSystemHeader(CE->getExprLoc()))
296       return;
297 
298     auto *Ctor = CE->getConstructor();
299     if (!Ctor)
300       return;
301 
302     auto *Cls = Ctor->getParent();
303     if (!Cls)
304       return;
305 
306     if (!isRetainPtr(safeGetName(Cls)) || !CE->getNumArgs())
307       return;
308 
309     // Ignore RetainPtr construction inside adoptNS, adoptCF, and retainPtr.
310     if (isAdoptFn(DeclWithIssue) || safeGetName(DeclWithIssue) == "retainPtr")
311       return;
312 
313     std::string Name = "RetainPtr constructor";
314     auto *Arg = CE->getArg(0)->IgnoreParenCasts();
315     auto Result = isOwned(Arg);
316 
317     if (isCreateOrCopy(Arg))
318       CreateOrCopyFnCall.insert(Arg); // Avoid double reporting.
319 
320     const Expr *Inner = nullptr;
321     if (isAllocInit(Arg, &Inner)) {
322       CreateOrCopyFnCall.insert(Arg);
323       if (Inner)
324         CreateOrCopyFnCall.insert(Inner);
325     }
326 
327     if (Result == IsOwnedResult::Skip)
328       return;
329 
330     if (Result == IsOwnedResult::Unknown)
331       Result = IsOwnedResult::NotOwned;
332     if (Result == IsOwnedResult::Owned)
333       reportLeak(Name, CE, DeclWithIssue);
334     else if (RTC.isARCEnabled() && isAllocInit(Arg))
335       reportLeak(Name, CE, DeclWithIssue, "when ARC is disabled");
336     else if (isCreateOrCopy(Arg))
337       reportLeak(Name, CE, DeclWithIssue);
338   }
339 
340   void visitVarDecl(const VarDecl *VD) const {
341     auto *Init = VD->getInit();
342     if (!Init || !RTC.isARCEnabled())
343       return;
344     Init = Init->IgnoreParenCasts();
345     const Expr *Inner = nullptr;
346     if (isAllocInit(Init, &Inner)) {
347       CreateOrCopyFnCall.insert(Init);
348       if (Inner)
349         CreateOrCopyFnCall.insert(Inner);
350     }
351   }
352 
353   void visitBinaryOperator(const BinaryOperator *BO) const {
354     if (!BO->isAssignmentOp())
355       return;
356     if (!isa<ObjCIvarRefExpr>(BO->getLHS()))
357       return;
358     auto *RHS = BO->getRHS()->IgnoreParenCasts();
359     const Expr *Inner = nullptr;
360     if (isAllocInit(RHS, &Inner)) {
361       CreateOrCopyFnCall.insert(RHS);
362       if (Inner)
363         CreateOrCopyFnCall.insert(Inner);
364     }
365   }
366 
367   void visitReturnStmt(const ReturnStmt *RS, const Decl *DeclWithIssue) const {
368     if (!DeclWithIssue)
369       return;
370     auto *RetValue = RS->getRetValue();
371     if (!RetValue)
372       return;
373     RetValue = RetValue->IgnoreParenCasts();
374     std::optional<bool> retainsRet;
375     if (auto *FnDecl = dyn_cast<FunctionDecl>(DeclWithIssue))
376       retainsRet = retainsReturnValue(FnDecl);
377     else if (auto *MethodDecl = dyn_cast<ObjCMethodDecl>(DeclWithIssue))
378       retainsRet = retainsReturnValue(MethodDecl);
379     else
380       return;
381     if (!retainsRet || !*retainsRet) {
382       // Under ARC, returning [[X alloc] init] doesn't leak X.
383       if (RTC.isUnretained(RetValue->getType()))
384         return;
385     }
386     if (auto *CE = dyn_cast<CallExpr>(RetValue)) {
387       auto *Callee = CE->getDirectCallee();
388       if (!Callee || !isCreateOrCopyFunction(Callee))
389         return;
390       CreateOrCopyFnCall.insert(CE);
391       return;
392     }
393     const Expr *Inner = nullptr;
394     if (isAllocInit(RetValue, &Inner)) {
395       CreateOrCopyFnCall.insert(RetValue);
396       if (Inner)
397         CreateOrCopyFnCall.insert(Inner);
398     }
399   }
400 
401   template <typename CallableType>
402   std::optional<bool> retainsReturnValue(const CallableType *FnDecl) const {
403     auto Summary = Summaries->getSummary(AnyCall(FnDecl));
404     auto RetEffect = Summary->getRetEffect();
405     switch (RetEffect.getKind()) {
406     case RetEffect::NoRet:
407       return std::nullopt;
408     case RetEffect::OwnedSymbol:
409       return true;
410     case RetEffect::NotOwnedSymbol:
411       return false;
412     case RetEffect::OwnedWhenTrackedReceiver:
413       return std::nullopt;
414     case RetEffect::NoRetHard:
415       return std::nullopt;
416     }
417     return std::nullopt;
418   }
419 
420   bool isAllocInit(const Expr *E, const Expr **InnerExpr = nullptr) const {
421     auto *ObjCMsgExpr = dyn_cast<ObjCMessageExpr>(E);
422     if (auto *POE = dyn_cast<PseudoObjectExpr>(E)) {
423       if (unsigned ExprCount = POE->getNumSemanticExprs()) {
424         auto *Expr = POE->getSemanticExpr(ExprCount - 1)->IgnoreParenCasts();
425         ObjCMsgExpr = dyn_cast<ObjCMessageExpr>(Expr);
426         if (InnerExpr)
427           *InnerExpr = ObjCMsgExpr;
428       }
429     }
430     if (!ObjCMsgExpr)
431       return false;
432     auto Selector = ObjCMsgExpr->getSelector();
433     auto NameForFirstSlot = Selector.getNameForSlot(0);
434     if (NameForFirstSlot == "alloc" || NameForFirstSlot.starts_with("copy") ||
435         NameForFirstSlot.starts_with("mutableCopy"))
436       return true;
437     if (!NameForFirstSlot.starts_with("init") &&
438         !NameForFirstSlot.starts_with("_init"))
439       return false;
440     if (!ObjCMsgExpr->isInstanceMessage())
441       return false;
442     auto *Receiver = ObjCMsgExpr->getInstanceReceiver();
443     if (!Receiver)
444       return false;
445     Receiver = Receiver->IgnoreParenCasts();
446     if (auto *Inner = dyn_cast<ObjCMessageExpr>(Receiver)) {
447       if (InnerExpr)
448         *InnerExpr = Inner;
449       auto InnerSelector = Inner->getSelector();
450       return InnerSelector.getNameForSlot(0) == "alloc";
451     } else if (auto *CE = dyn_cast<CallExpr>(Receiver)) {
452       if (InnerExpr)
453         *InnerExpr = CE;
454       if (auto *Callee = CE->getDirectCallee()) {
455         if (Callee->getDeclName().isIdentifier()) {
456           auto CalleeName = Callee->getName();
457           return CalleeName.starts_with("alloc");
458         }
459       }
460     }
461     return false;
462   }
463 
464   bool isCreateOrCopy(const Expr *E) const {
465     auto *CE = dyn_cast<CallExpr>(E);
466     if (!CE)
467       return false;
468     auto *Callee = CE->getDirectCallee();
469     if (!Callee)
470       return false;
471     return isCreateOrCopyFunction(Callee);
472   }
473 
474   bool isCreateOrCopyFunction(const FunctionDecl *FnDecl) const {
475     auto CalleeName = safeGetName(FnDecl);
476     return CalleeName.find("Create") != std::string::npos ||
477            CalleeName.find("Copy") != std::string::npos;
478   }
479 
480   enum class IsOwnedResult { Unknown, Skip, Owned, NotOwned };
481   IsOwnedResult isOwned(const Expr *E) const {
482     while (1) {
483       if (auto *POE = dyn_cast<PseudoObjectExpr>(E)) {
484         if (unsigned SemanticExprCount = POE->getNumSemanticExprs()) {
485           E = POE->getSemanticExpr(SemanticExprCount - 1);
486           continue;
487         }
488       }
489       if (isa<CXXNullPtrLiteralExpr>(E))
490         return IsOwnedResult::NotOwned;
491       if (auto *DRE = dyn_cast<DeclRefExpr>(E)) {
492         auto QT = DRE->getType();
493         if (isRetainPtrType(QT))
494           return IsOwnedResult::NotOwned;
495         QT = QT.getCanonicalType();
496         if (RTC.isUnretained(QT, true /* ignoreARC */))
497           return IsOwnedResult::NotOwned;
498         auto *PointeeType = QT->getPointeeType().getTypePtrOrNull();
499         if (PointeeType && PointeeType->isVoidType())
500           return IsOwnedResult::NotOwned; // Assume reading void* as +0.
501       }
502       if (auto *TE = dyn_cast<CXXBindTemporaryExpr>(E)) {
503         E = TE->getSubExpr();
504         continue;
505       }
506       if (auto *ObjCMsgExpr = dyn_cast<ObjCMessageExpr>(E)) {
507         auto Summary = Summaries->getSummary(AnyCall(ObjCMsgExpr));
508         auto RetEffect = Summary->getRetEffect();
509         switch (RetEffect.getKind()) {
510         case RetEffect::NoRet:
511           return IsOwnedResult::Unknown;
512         case RetEffect::OwnedSymbol:
513           return IsOwnedResult::Owned;
514         case RetEffect::NotOwnedSymbol:
515           return IsOwnedResult::NotOwned;
516         case RetEffect::OwnedWhenTrackedReceiver:
517           if (auto *Receiver = ObjCMsgExpr->getInstanceReceiver()) {
518             E = Receiver->IgnoreParenCasts();
519             continue;
520           }
521           return IsOwnedResult::Unknown;
522         case RetEffect::NoRetHard:
523           return IsOwnedResult::Unknown;
524         }
525       }
526       if (auto *CXXCE = dyn_cast<CXXMemberCallExpr>(E)) {
527         if (auto *MD = CXXCE->getMethodDecl()) {
528           auto *Cls = MD->getParent();
529           if (auto *CD = dyn_cast<CXXConversionDecl>(MD)) {
530             auto QT = CD->getConversionType().getCanonicalType();
531             auto *ResultType = QT.getTypePtrOrNull();
532             if (isRetainPtr(safeGetName(Cls)) && ResultType &&
533                 (ResultType->isPointerType() || ResultType->isReferenceType() ||
534                  ResultType->isObjCObjectPointerType()))
535               return IsOwnedResult::NotOwned;
536           }
537           if (safeGetName(MD) == "leakRef" && isRetainPtr(safeGetName(Cls)))
538             return IsOwnedResult::Owned;
539         }
540       }
541       if (auto *CE = dyn_cast<CallExpr>(E)) {
542         if (auto *Callee = CE->getDirectCallee()) {
543           if (isAdoptFn(Callee))
544             return IsOwnedResult::NotOwned;
545           auto Name = safeGetName(Callee);
546           if (Name == "__builtin___CFStringMakeConstantString")
547             return IsOwnedResult::NotOwned;
548           if ((Name == "checked_cf_cast" || Name == "dynamic_cf_cast" ||
549                Name == "checked_objc_cast" || Name == "dynamic_objc_cast") &&
550               CE->getNumArgs() == 1) {
551             E = CE->getArg(0)->IgnoreParenCasts();
552             continue;
553           }
554           auto RetType = Callee->getReturnType();
555           if (isRetainPtrType(RetType))
556             return IsOwnedResult::NotOwned;
557           if (isCreateOrCopyFunction(Callee)) {
558             CreateOrCopyFnCall.insert(CE);
559             return IsOwnedResult::Owned;
560           }
561         } else if (auto *CalleeExpr = CE->getCallee()) {
562           if (isa<CXXDependentScopeMemberExpr>(CalleeExpr))
563             return IsOwnedResult::Skip; // Wait for instantiation.
564           if (isa<UnresolvedLookupExpr>(CalleeExpr))
565             return IsOwnedResult::Skip; // Wait for instantiation.
566         }
567         auto Summary = Summaries->getSummary(AnyCall(CE));
568         auto RetEffect = Summary->getRetEffect();
569         switch (RetEffect.getKind()) {
570         case RetEffect::NoRet:
571           return IsOwnedResult::Unknown;
572         case RetEffect::OwnedSymbol:
573           return IsOwnedResult::Owned;
574         case RetEffect::NotOwnedSymbol:
575           return IsOwnedResult::NotOwned;
576         case RetEffect::OwnedWhenTrackedReceiver:
577           return IsOwnedResult::Unknown;
578         case RetEffect::NoRetHard:
579           return IsOwnedResult::Unknown;
580         }
581       }
582       break;
583     }
584     return IsOwnedResult::Unknown;
585   }
586 
587   void reportUseAfterFree(const std::string &Name, const CallExpr *CE,
588                           const Decl *DeclWithIssue,
589                           const char *condition = nullptr) const {
590     SmallString<100> Buf;
591     llvm::raw_svector_ostream Os(Buf);
592 
593     Os << "Incorrect use of " << Name
594        << ". The argument is +0 and results in an use-after-free";
595     if (condition)
596       Os << " " << condition;
597     Os << ".";
598 
599     assert(BR && "expected nonnull BugReporter");
600     PathDiagnosticLocation BSLoc(CE->getSourceRange().getBegin(),
601                                  BR->getSourceManager());
602     auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
603     Report->addRange(CE->getSourceRange());
604     Report->setDeclWithIssue(DeclWithIssue);
605     BR->emitReport(std::move(Report));
606   }
607 
608   void reportLeak(std::string &Name, const CXXConstructExpr *CE,
609                   const Decl *DeclWithIssue,
610                   const char *condition = nullptr) const {
611     SmallString<100> Buf;
612     llvm::raw_svector_ostream Os(Buf);
613 
614     Os << "Incorrect use of " << Name
615        << ". The argument is +1 and results in a memory leak";
616     if (condition)
617       Os << " " << condition;
618     Os << ".";
619 
620     assert(BR && "expected nonnull BugReporter");
621     PathDiagnosticLocation BSLoc(CE->getSourceRange().getBegin(),
622                                  BR->getSourceManager());
623     auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
624     Report->addRange(CE->getSourceRange());
625     Report->setDeclWithIssue(DeclWithIssue);
626     BR->emitReport(std::move(Report));
627   }
628 
629   template <typename ExprType>
630   void reportLeak(const ExprType *E, const Decl *DeclWithIssue) const {
631     SmallString<100> Buf;
632     llvm::raw_svector_ostream Os(Buf);
633 
634     Os << "The return value is +1 and results in a memory leak.";
635 
636     PathDiagnosticLocation BSLoc(E->getSourceRange().getBegin(),
637                                  BR->getSourceManager());
638     auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
639     Report->addRange(E->getSourceRange());
640     Report->setDeclWithIssue(DeclWithIssue);
641     BR->emitReport(std::move(Report));
642   }
643 };
644 } // namespace
645 
646 void ento::registerRetainPtrCtorAdoptChecker(CheckerManager &Mgr) {
647   Mgr.registerChecker<RetainPtrCtorAdoptChecker>();
648 }
649 
650 bool ento::shouldRegisterRetainPtrCtorAdoptChecker(const CheckerManager &mgr) {
651   return true;
652 }
653