brintos

brintos / llvm-project-archived public Read only

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