//=== RetainSummaryManager.h - Summaries for reference counting ---*- C++ -*--//
 
//
 
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 
// See https://llvm.org/LICENSE.txt for license information.
 
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 
//
 
//===----------------------------------------------------------------------===//
 
//
 
//  This file defines summaries implementation for retain counting, which
 
//  implements a reference count checker for Core Foundation and Cocoa
 
//  on (Mac OS X).
 
//
 
//===----------------------------------------------------------------------===//
 
 
 
#ifndef LLVM_CLANG_ANALYSIS_RETAINSUMMARYMANAGER_H
 
#define LLVM_CLANG_ANALYSIS_RETAINSUMMARYMANAGER_H
 
 
 
#include "llvm/ADT/DenseMap.h"
 
#include "llvm/ADT/FoldingSet.h"
 
#include "llvm/ADT/ImmutableMap.h"
 
#include "clang/AST/Attr.h"
 
#include "clang/AST/DeclCXX.h"
 
#include "clang/AST/DeclObjC.h"
 
#include "clang/AST/ParentMap.h"
 
#include "clang/Analysis/AnyCall.h"
 
#include "clang/Analysis/SelectorExtras.h"
 
#include "llvm/ADT/STLExtras.h"
 
#include <optional>
 
 
 
using namespace clang;
 
 
 
namespace clang {
 
namespace ento {
 
 
 
/// Determines the object kind of a tracked object.
 
enum class ObjKind {
 
  /// Indicates that the tracked object is a CF object.
 
  CF,
 
 
 
  /// Indicates that the tracked object is an Objective-C object.
 
  ObjC,
 
 
 
  /// Indicates that the tracked object could be a CF or Objective-C object.
 
  AnyObj,
 
 
 
  /// Indicates that the tracked object is a generalized object.
 
  Generalized,
 
 
 
  /// Indicates that the tracking object is a descendant of a
 
  /// referenced-counted OSObject, used in the Darwin kernel.
 
  OS
 
};
 
 
 
enum ArgEffectKind {
 
  /// There is no effect.
 
  DoNothing,
 
 
 
  /// The argument is treated as if an -autorelease message had been sent to
 
  /// the referenced object.
 
  Autorelease,
 
 
 
  /// The argument is treated as if the referenced object was deallocated.
 
  Dealloc,
 
 
 
  /// The argument has its reference count decreased by 1.
 
  DecRef,
 
 
 
  /// The argument has its reference count decreased by 1 to model
 
  /// a transferred bridge cast under ARC.
 
  DecRefBridgedTransferred,
 
 
 
  /// The argument has its reference count increased by 1.
 
  IncRef,
 
 
 
  /// The argument is a pointer to a retain-counted object; on exit, the new
 
  /// value of the pointer is a +0 value.
 
  UnretainedOutParameter,
 
 
 
  /// The argument is a pointer to a retain-counted object; on exit, the new
 
  /// value of the pointer is a +1 value.
 
  RetainedOutParameter,
 
 
 
  /// The argument is a pointer to a retain-counted object; on exit, the new
 
  /// value of the pointer is a +1 value iff the return code is zero.
 
  RetainedOutParameterOnZero,
 
 
 
  /// The argument is a pointer to a retain-counted object; on exit, the new
 
  /// value of the pointer is a +1 value iff the return code is non-zero.
 
  RetainedOutParameterOnNonZero,
 
 
 
  /// The argument is treated as potentially escaping, meaning that
 
  /// even when its reference count hits 0 it should be treated as still
 
  /// possibly being alive as someone else *may* be holding onto the object.
 
  MayEscape,
 
 
 
  /// All typestate tracking of the object ceases.  This is usually employed
 
  /// when the effect of the call is completely unknown.
 
  StopTracking,
 
 
 
  /// All typestate tracking of the object ceases.  Unlike StopTracking,
 
  /// this is also enforced when the method body is inlined.
 
  ///
 
  /// In some cases, we obtain a better summary for this checker
 
  /// by looking at the call site than by inlining the function.
 
  /// Signifies that we should stop tracking the symbol even if
 
  /// the function is inlined.
 
  StopTrackingHard,
 
 
 
  /// Performs the combined functionality of DecRef and StopTrackingHard.
 
  ///
 
  /// The models the effect that the called function decrements the reference
 
  /// count of the argument and all typestate tracking on that argument
 
  /// should cease.
 
  DecRefAndStopTrackingHard,
 
};
 
 
 
/// An ArgEffect summarizes the retain count behavior on an argument or receiver
 
/// to a function or method.
 
class ArgEffect {
 
  ArgEffectKind K;
 
  ObjKind O;
 
public:
 
  explicit ArgEffect(ArgEffectKind K = DoNothing, ObjKind O = ObjKind::AnyObj)
 
      : K(K), O(O) {}
 
 
 
  ArgEffectKind getKind() const { return K; }
 
  ObjKind getObjKind() const { return O; }
 
 
 
  ArgEffect withKind(ArgEffectKind NewK) {
 
    return ArgEffect(NewK, O);
 
  }
 
 
 
  bool operator==(const ArgEffect &Other) const {
 
    return K == Other.K && O == Other.O;
 
  }
 
};
 
 
 
/// RetEffect summarizes a call's retain/release behavior with respect
 
/// to its return value.
 
class RetEffect {
 
public:
 
  enum Kind {
 
    /// Indicates that no retain count information is tracked for
 
    /// the return value.
 
    NoRet,
 
 
 
    /// Indicates that the returned value is an owned (+1) symbol.
 
    OwnedSymbol,
 
 
 
    /// Indicates that the returned value is an object with retain count
 
    /// semantics but that it is not owned (+0).  This is the default
 
    /// for getters, etc.
 
    NotOwnedSymbol,
 
 
 
    /// Indicates that the return value is an owned object when the
 
    /// receiver is also a tracked object.
 
    OwnedWhenTrackedReceiver,
 
 
 
    // Treat this function as returning a non-tracked symbol even if
 
    // the function has been inlined. This is used where the call
 
    // site summary is more precise than the summary indirectly produced
 
    // by inlining the function
 
    NoRetHard
 
  };
 
 
 
private:
 
  Kind K;
 
  ObjKind O;
 
 
 
  RetEffect(Kind k, ObjKind o = ObjKind::AnyObj) : K(k), O(o) {}
 
 
 
public:
 
  Kind getKind() const { return K; }
 
 
 
  ObjKind getObjKind() const { return O; }
 
 
 
  bool isOwned() const {
 
    return K == OwnedSymbol || K == OwnedWhenTrackedReceiver;
 
  }
 
 
 
  bool notOwned() const {
 
    return K == NotOwnedSymbol;
 
  }
 
 
 
  bool operator==(const RetEffect &Other) const {
 
    return K == Other.K && O == Other.O;
 
  }
 
 
 
  static RetEffect MakeOwnedWhenTrackedReceiver() {
 
    return RetEffect(OwnedWhenTrackedReceiver, ObjKind::ObjC);
 
  }
 
 
 
  static RetEffect MakeOwned(ObjKind o) {
 
    return RetEffect(OwnedSymbol, o);
 
  }
 
  static RetEffect MakeNotOwned(ObjKind o) {
 
    return RetEffect(NotOwnedSymbol, o);
 
  }
 
  static RetEffect MakeNoRet() {
 
    return RetEffect(NoRet);
 
  }
 
  static RetEffect MakeNoRetHard() {
 
    return RetEffect(NoRetHard);
 
  }
 
};
 
 
 
/// A key identifying a summary.
 
class ObjCSummaryKey {
 
  IdentifierInfo* II;
 
  Selector S;
 
public:
 
  ObjCSummaryKey(IdentifierInfo* ii, Selector s)
 
    : II(ii), S(s) {}
 
 
 
  ObjCSummaryKey(const ObjCInterfaceDecl *d, Selector s)
 
    : II(d ? d->getIdentifier() : nullptr), S(s) {}
 
 
 
  ObjCSummaryKey(Selector s)
 
    : II(nullptr), S(s) {}
 
 
 
  IdentifierInfo *getIdentifier() const { return II; }
 
  Selector getSelector() const { return S; }
 
};
 
 
 
} // end namespace ento
 
} // end namespace clang
 
 
 
using namespace ento;
 
 
 
namespace llvm {
 
 
 
//===----------------------------------------------------------------------===//
 
// Adapters for FoldingSet.
 
//===----------------------------------------------------------------------===//
 
template <> struct FoldingSetTrait<ArgEffect> {
 
static inline void Profile(const ArgEffect X, FoldingSetNodeID &ID) {
 
  ID.AddInteger((unsigned) X.getKind());
 
  ID.AddInteger((unsigned) X.getObjKind());
 
}
 
};
 
template <> struct FoldingSetTrait<RetEffect> {
 
  static inline void Profile(const RetEffect &X, FoldingSetNodeID &ID) {
 
    ID.AddInteger((unsigned) X.getKind());
 
    ID.AddInteger((unsigned) X.getObjKind());
 
}
 
};
 
 
 
template <> struct DenseMapInfo<ObjCSummaryKey> {
 
  static inline ObjCSummaryKey getEmptyKey() {
 
    return ObjCSummaryKey(DenseMapInfo<IdentifierInfo*>::getEmptyKey(),
 
                          DenseMapInfo<Selector>::getEmptyKey());
 
  }
 
 
 
  static inline ObjCSummaryKey getTombstoneKey() {
 
    return ObjCSummaryKey(DenseMapInfo<IdentifierInfo*>::getTombstoneKey(),
 
                          DenseMapInfo<Selector>::getTombstoneKey());
 
  }
 
 
 
  static unsigned getHashValue(const ObjCSummaryKey &V) {
 
    typedef std::pair<IdentifierInfo*, Selector> PairTy;
 
    return DenseMapInfo<PairTy>::getHashValue(PairTy(V.getIdentifier(),
 
                                                     V.getSelector()));
 
  }
 
 
 
  static bool isEqual(const ObjCSummaryKey& LHS, const ObjCSummaryKey& RHS) {
 
    return LHS.getIdentifier() == RHS.getIdentifier() &&
 
           LHS.getSelector() == RHS.getSelector();
 
  }
 
 
 
};
 
 
 
} // end llvm namespace
 
 
 
 
 
namespace clang {
 
namespace ento {
 
 
 
/// ArgEffects summarizes the effects of a function/method call on all of
 
/// its arguments.
 
typedef llvm::ImmutableMap<unsigned, ArgEffect> ArgEffects;
 
 
 
/// Summary for a function with respect to ownership changes.
 
class RetainSummary {
 
  /// Args - a map of (index, ArgEffect) pairs, where index
 
  ///  specifies the argument (starting from 0).  This can be sparsely
 
  ///  populated; arguments with no entry in Args use 'DefaultArgEffect'.
 
  ArgEffects Args;
 
 
 
  /// DefaultArgEffect - The default ArgEffect to apply to arguments that
 
  ///  do not have an entry in Args.
 
  ArgEffect DefaultArgEffect;
 
 
 
  /// Receiver - If this summary applies to an Objective-C message expression,
 
  ///  this is the effect applied to the state of the receiver.
 
  ArgEffect Receiver;
 
 
 
  /// Effect on "this" pointer - applicable only to C++ method calls.
 
  ArgEffect This;
 
 
 
  /// Ret - The effect on the return value.  Used to indicate if the
 
  ///  function/method call returns a new tracked symbol.
 
  RetEffect Ret;
 
 
 
public:
 
  RetainSummary(ArgEffects A,
 
                RetEffect R,
 
                ArgEffect defaultEff,
 
                ArgEffect ReceiverEff,
 
                ArgEffect ThisEff)
 
    : Args(A), DefaultArgEffect(defaultEff), Receiver(ReceiverEff),
 
      This(ThisEff), Ret(R) {}
 
 
 
  /// getArg - Return the argument effect on the argument specified by
 
  ///  idx (starting from 0).
 
  ArgEffect getArg(unsigned idx) const {
 
    if (const ArgEffect *AE = Args.lookup(idx))
 
      return *AE;
 
 
 
    return DefaultArgEffect;
 
  }
 
 
 
  void addArg(ArgEffects::Factory &af, unsigned idx, ArgEffect e) {
 
    Args = af.add(Args, idx, e);
 
  }
 
 
 
  /// setDefaultArgEffect - Set the default argument effect.
 
  void setDefaultArgEffect(ArgEffect E) {
 
    DefaultArgEffect = E;
 
  }
 
 
 
  /// getRetEffect - Returns the effect on the return value of the call.
 
  RetEffect getRetEffect() const { return Ret; }
 
 
 
  /// setRetEffect - Set the effect of the return value of the call.
 
  void setRetEffect(RetEffect E) { Ret = E; }
 
 
 
 
 
  /// Sets the effect on the receiver of the message.
 
  void setReceiverEffect(ArgEffect e) { Receiver = e; }
 
 
 
  /// getReceiverEffect - Returns the effect on the receiver of the call.
 
  ///  This is only meaningful if the summary applies to an ObjCMessageExpr*.
 
  ArgEffect getReceiverEffect() const { return Receiver; }
 
 
 
  /// \return the effect on the "this" receiver of the method call.
 
  /// This is only meaningful if the summary applies to CXXMethodDecl*.
 
  ArgEffect getThisEffect() const { return This; }
 
 
 
  ArgEffect getDefaultEffect() const { return DefaultArgEffect; }
 
 
 
  /// Set the effect of the method on "this".
 
  void setThisEffect(ArgEffect e) { This = e; }
 
 
 
  bool isNoop() const {
 
    return Ret == RetEffect::MakeNoRet() && Receiver.getKind() == DoNothing
 
      && DefaultArgEffect.getKind() == MayEscape && This.getKind() == DoNothing
 
      && Args.isEmpty();
 
  }
 
 
 
  /// Test if two retain summaries are identical. Note that merely equivalent
 
  /// summaries are not necessarily identical (for example, if an explicit
 
  /// argument effect matches the default effect).
 
  bool operator==(const RetainSummary &Other) const {
 
    return Args == Other.Args && DefaultArgEffect == Other.DefaultArgEffect &&
 
           Receiver == Other.Receiver && This == Other.This && Ret == Other.Ret;
 
  }
 
 
 
  /// Profile this summary for inclusion in a FoldingSet.
 
  void Profile(llvm::FoldingSetNodeID& ID) const {
 
    ID.Add(Args);
 
    ID.Add(DefaultArgEffect);
 
    ID.Add(Receiver);
 
    ID.Add(This);
 
    ID.Add(Ret);
 
  }
 
 
 
  /// A retain summary is simple if it has no ArgEffects other than the default.
 
  bool isSimple() const {
 
    return Args.isEmpty();
 
  }
 
 
 
  ArgEffects getArgEffects() const { return Args; }
 
 
 
private:
 
  ArgEffect getDefaultArgEffect() const { return DefaultArgEffect; }
 
 
 
  friend class RetainSummaryManager;
 
};
 
 
 
class ObjCSummaryCache {
 
  typedef llvm::DenseMap<ObjCSummaryKey, const RetainSummary *> MapTy;
 
  MapTy M;
 
public:
 
  ObjCSummaryCache() {}
 
 
 
  const RetainSummary * find(const ObjCInterfaceDecl *D, Selector S) {
 
    // Do a lookup with the (D,S) pair.  If we find a match return
 
    // the iterator.
 
    ObjCSummaryKey K(D, S);
 
    MapTy::iterator I = M.find(K);
 
 
 
    if (I != M.end())
 
      return I->second;
 
    if (!D)
 
      return nullptr;
 
 
 
    // Walk the super chain.  If we find a hit with a parent, we'll end
 
    // up returning that summary.  We actually allow that key (null,S), as
 
    // we cache summaries for the null ObjCInterfaceDecl* to allow us to
 
    // generate initial summaries without having to worry about NSObject
 
    // being declared.
 
    // FIXME: We may change this at some point.
 
    for (ObjCInterfaceDecl *C=D->getSuperClass() ;; C=C->getSuperClass()) {
 
      if ((I = M.find(ObjCSummaryKey(C, S))) != M.end())
 
        break;
 
 
 
      if (!C)
 
        return nullptr;
 
    }
 
 
 
    // Cache the summary with original key to make the next lookup faster
 
    // and return the iterator.
 
    const RetainSummary *Summ = I->second;
 
    M[K] = Summ;
 
    return Summ;
 
  }
 
 
 
  const RetainSummary *find(IdentifierInfo* II, Selector S) {
 
    // FIXME: Class method lookup.  Right now we don't have a good way
 
    // of going between IdentifierInfo* and the class hierarchy.
 
    MapTy::iterator I = M.find(ObjCSummaryKey(II, S));
 
 
 
    if (I == M.end())
 
      I = M.find(ObjCSummaryKey(S));
 
 
 
    return I == M.end() ? nullptr : I->second;
 
  }
 
 
 
  const RetainSummary *& operator[](ObjCSummaryKey K) {
 
    return M[K];
 
  }
 
 
 
  const RetainSummary *& operator[](Selector S) {
 
    return M[ ObjCSummaryKey(S) ];
 
  }
 
};
 
 
 
class RetainSummaryTemplate;
 
 
 
class RetainSummaryManager {
 
  typedef llvm::DenseMap<const FunctionDecl*, const RetainSummary *>
 
          FuncSummariesTy;
 
 
 
  typedef ObjCSummaryCache ObjCMethodSummariesTy;
 
 
 
  typedef llvm::FoldingSetNodeWrapper<RetainSummary> CachedSummaryNode;
 
 
 
  /// Ctx - The ASTContext object for the analyzed ASTs.
 
  ASTContext &Ctx;
 
 
 
  /// Records whether or not the analyzed code runs in ARC mode.
 
  const bool ARCEnabled;
 
 
 
  /// Track Objective-C and CoreFoundation objects.
 
  const bool TrackObjCAndCFObjects;
 
 
 
  /// Track sublcasses of OSObject.
 
  const bool TrackOSObjects;
 
 
 
  /// FuncSummaries - A map from FunctionDecls to summaries.
 
  FuncSummariesTy FuncSummaries;
 
 
 
  /// ObjCClassMethodSummaries - A map from selectors (for instance methods)
 
  ///  to summaries.
 
  ObjCMethodSummariesTy ObjCClassMethodSummaries;
 
 
 
  /// ObjCMethodSummaries - A map from selectors to summaries.
 
  ObjCMethodSummariesTy ObjCMethodSummaries;
 
 
 
  /// BPAlloc - A BumpPtrAllocator used for allocating summaries, ArgEffects,
 
  ///  and all other data used by the checker.
 
  llvm::BumpPtrAllocator BPAlloc;
 
 
 
  /// AF - A factory for ArgEffects objects.
 
  ArgEffects::Factory AF;
 
 
 
  /// ObjCAllocRetE - Default return effect for methods returning Objective-C
 
  ///  objects.
 
  RetEffect ObjCAllocRetE;
 
 
 
  /// ObjCInitRetE - Default return effect for init methods returning
 
  ///   Objective-C objects.
 
  RetEffect ObjCInitRetE;
 
 
 
  /// SimpleSummaries - Used for uniquing summaries that don't have special
 
  /// effects.
 
  llvm::FoldingSet<CachedSummaryNode> SimpleSummaries;
 
 
 
  /// Create an OS object at +1.
 
  const RetainSummary *getOSSummaryCreateRule(const FunctionDecl *FD);
 
 
 
  /// Get an OS object at +0.
 
  const RetainSummary *getOSSummaryGetRule(const FunctionDecl *FD);
 
 
 
  /// Increment the reference count on OS object.
 
  const RetainSummary *getOSSummaryRetainRule(const FunctionDecl *FD);
 
 
 
  /// Decrement the reference count on OS object.
 
  const RetainSummary *getOSSummaryReleaseRule(const FunctionDecl *FD);
 
 
 
  /// Free the OS object.
 
  const RetainSummary *getOSSummaryFreeRule(const FunctionDecl *FD);
 
 
 
  const RetainSummary *getUnarySummary(const FunctionType* FT,
 
                                       ArgEffectKind AE);
 
 
 
  const RetainSummary *getCFSummaryCreateRule(const FunctionDecl *FD);
 
  const RetainSummary *getCFSummaryGetRule(const FunctionDecl *FD);
 
  const RetainSummary *getCFCreateGetRuleSummary(const FunctionDecl *FD);
 
 
 
  const RetainSummary *getPersistentSummary(const RetainSummary &OldSumm);
 
 
 
  const RetainSummary *
 
  getPersistentSummary(RetEffect RetEff, ArgEffects ScratchArgs,
 
                       ArgEffect ReceiverEff = ArgEffect(DoNothing),
 
                       ArgEffect DefaultEff = ArgEffect(MayEscape),
 
                       ArgEffect ThisEff = ArgEffect(DoNothing)) {
 
    RetainSummary Summ(ScratchArgs, RetEff, DefaultEff, ReceiverEff, ThisEff);
 
    return getPersistentSummary(Summ);
 
  }
 
 
 
  const RetainSummary *getDoNothingSummary() {
 
    return getPersistentSummary(RetEffect::MakeNoRet(),
 
                                ArgEffects(AF.getEmptyMap()),
 
                                ArgEffect(DoNothing), ArgEffect(DoNothing));
 
  }
 
 
 
  const RetainSummary *getDefaultSummary() {
 
    return getPersistentSummary(RetEffect::MakeNoRet(),
 
                                ArgEffects(AF.getEmptyMap()),
 
                                ArgEffect(DoNothing), ArgEffect(MayEscape));
 
  }
 
 
 
  const RetainSummary *getPersistentStopSummary() {
 
    return getPersistentSummary(
 
        RetEffect::MakeNoRet(), ArgEffects(AF.getEmptyMap()),
 
        ArgEffect(StopTracking), ArgEffect(StopTracking));
 
  }
 
 
 
  void InitializeClassMethodSummaries();
 
  void InitializeMethodSummaries();
 
 
 
  void addNSObjectClsMethSummary(Selector S, const RetainSummary *Summ) {
 
    ObjCClassMethodSummaries[S] = Summ;
 
  }
 
 
 
  void addNSObjectMethSummary(Selector S, const RetainSummary *Summ) {
 
    ObjCMethodSummaries[S] = Summ;
 
  }
 
 
 
  void addClassMethSummary(const char* Cls, const char* name,
 
                           const RetainSummary *Summ, bool isNullary = true) {
 
    IdentifierInfo* ClsII = &Ctx.Idents.get(Cls);
 
    Selector S = isNullary ? GetNullarySelector(name, Ctx)
 
                           : GetUnarySelector(name, Ctx);
 
    ObjCClassMethodSummaries[ObjCSummaryKey(ClsII, S)]  = Summ;
 
  }
 
 
 
  void addInstMethSummary(const char* Cls, const char* nullaryName,
 
                          const RetainSummary *Summ) {
 
    IdentifierInfo* ClsII = &Ctx.Idents.get(Cls);
 
    Selector S = GetNullarySelector(nullaryName, Ctx);
 
    ObjCMethodSummaries[ObjCSummaryKey(ClsII, S)]  = Summ;
 
  }
 
 
 
  template <typename... Keywords>
 
  void addMethodSummary(IdentifierInfo *ClsII, ObjCMethodSummariesTy &Summaries,
 
                        const RetainSummary *Summ, Keywords *... Kws) {
 
    Selector S = getKeywordSelector(Ctx, Kws...);
 
    Summaries[ObjCSummaryKey(ClsII, S)] = Summ;
 
  }
 
 
 
  template <typename... Keywords>
 
  void addInstMethSummary(const char *Cls, const RetainSummary *Summ,
 
                          Keywords *... Kws) {
 
    addMethodSummary(&Ctx.Idents.get(Cls), ObjCMethodSummaries, Summ, Kws...);
 
  }
 
 
 
  template <typename... Keywords>
 
  void addClsMethSummary(const char *Cls, const RetainSummary *Summ,
 
                         Keywords *... Kws) {
 
    addMethodSummary(&Ctx.Idents.get(Cls), ObjCClassMethodSummaries, Summ,
 
                     Kws...);
 
  }
 
 
 
  template <typename... Keywords>
 
  void addClsMethSummary(IdentifierInfo *II, const RetainSummary *Summ,
 
                         Keywords *... Kws) {
 
    addMethodSummary(II, ObjCClassMethodSummaries, Summ, Kws...);
 
  }
 
 
 
  const RetainSummary * generateSummary(const FunctionDecl *FD,
 
                                        bool &AllowAnnotations);
 
 
 
  /// Return a summary for OSObject, or nullptr if not found.
 
  const RetainSummary *getSummaryForOSObject(const FunctionDecl *FD,
 
                                             StringRef FName, QualType RetTy);
 
 
 
  /// Return a summary for Objective-C or CF object, or nullptr if not found.
 
  const RetainSummary *getSummaryForObjCOrCFObject(
 
    const FunctionDecl *FD,
 
    StringRef FName,
 
    QualType RetTy,
 
    const FunctionType *FT,
 
    bool &AllowAnnotations);
 
 
 
  /// Apply the annotation of @c pd in function @c FD
 
  /// to the resulting summary stored in out-parameter @c Template.
 
  /// \return whether an annotation was applied.
 
  bool applyParamAnnotationEffect(const ParmVarDecl *pd, unsigned parm_idx,
 
                                  const NamedDecl *FD,
 
                                  RetainSummaryTemplate &Template);
 
 
 
public:
 
  RetainSummaryManager(ASTContext &ctx, bool trackObjCAndCFObjects,
 
                       bool trackOSObjects)
 
      : Ctx(ctx), ARCEnabled((bool)Ctx.getLangOpts().ObjCAutoRefCount),
 
        TrackObjCAndCFObjects(trackObjCAndCFObjects),
 
        TrackOSObjects(trackOSObjects), AF(BPAlloc),
 
        ObjCAllocRetE(ARCEnabled ? RetEffect::MakeNotOwned(ObjKind::ObjC)
 
                                 : RetEffect::MakeOwned(ObjKind::ObjC)),
 
        ObjCInitRetE(ARCEnabled ? RetEffect::MakeNotOwned(ObjKind::ObjC)
 
                                : RetEffect::MakeOwnedWhenTrackedReceiver()) {
 
    InitializeClassMethodSummaries();
 
    InitializeMethodSummaries();
 
  }
 
 
 
  enum class BehaviorSummary {
 
    // Function does not return.
 
    NoOp,
 
 
 
    // Function returns the first argument.
 
    Identity,
 
 
 
    // Function returns "this" argument.
 
    IdentityThis,
 
 
 
    // Function either returns zero, or the input parameter.
 
    IdentityOrZero
 
  };
 
 
 
  std::optional<BehaviorSummary>
 
  canEval(const CallExpr *CE, const FunctionDecl *FD,
 
          bool &hasTrustedImplementationAnnotation);
 
 
 
  /// \return Whether the type corresponds to a known smart pointer
 
  /// implementation (that is, everything about it is inlineable).
 
  static bool isKnownSmartPointer(QualType QT);
 
 
 
  bool isTrustedReferenceCountImplementation(const Decl *FD);
 
 
 
  const RetainSummary *getSummary(AnyCall C,
 
                                  bool HasNonZeroCallbackArg=false,
 
                                  bool IsReceiverUnconsumedSelf=false,
 
                                  QualType ReceiverType={});
 
 
 
  RetEffect getObjAllocRetEffect() const { return ObjCAllocRetE; }
 
 
 
private:
 
 
 
  /// getMethodSummary - This version of getMethodSummary is used to query
 
  ///  the summary for the current method being analyzed.
 
  const RetainSummary *getMethodSummary(const ObjCMethodDecl *MD);
 
 
 
  const RetainSummary *getFunctionSummary(const FunctionDecl *FD);
 
 
 
  const RetainSummary *getMethodSummary(Selector S, const ObjCInterfaceDecl *ID,
 
                                        const ObjCMethodDecl *MD,
 
                                        QualType RetTy,
 
                                        ObjCMethodSummariesTy &CachedSummaries);
 
 
 
  const RetainSummary *
 
  getInstanceMethodSummary(const ObjCMessageExpr *ME, QualType ReceiverType);
 
 
 
  const RetainSummary *getClassMethodSummary(const ObjCMessageExpr *ME);
 
 
 
  const RetainSummary *getStandardMethodSummary(const ObjCMethodDecl *MD,
 
                                                Selector S, QualType RetTy);
 
 
 
  /// Determine if there is a special return effect for this function or method.
 
  std::optional<RetEffect> getRetEffectFromAnnotations(QualType RetTy,
 
                                                       const Decl *D);
 
 
 
  void updateSummaryFromAnnotations(const RetainSummary *&Summ,
 
                                    const ObjCMethodDecl *MD);
 
 
 
  void updateSummaryFromAnnotations(const RetainSummary *&Summ,
 
                                    const FunctionDecl *FD);
 
 
 
  const RetainSummary *updateSummaryForNonZeroCallbackArg(const RetainSummary *S,
 
                                                          AnyCall &C);
 
 
 
  /// Special case '[super init];' and '[self init];'
 
  ///
 
  /// Even though calling '[super init]' without assigning the result to self
 
  /// and checking if the parent returns 'nil' is a bad pattern, it is common.
 
  /// Additionally, our Self Init checker already warns about it. To avoid
 
  /// overwhelming the user with messages from both checkers, we model the case
 
  /// of '[super init]' in cases when it is not consumed by another expression
 
  /// as if the call preserves the value of 'self'; essentially, assuming it can
 
  /// never fail and return 'nil'.
 
  /// Note, we don't want to just stop tracking the value since we want the
 
  /// RetainCount checker to report leaks and use-after-free if SelfInit checker
 
  /// is turned off.
 
  void updateSummaryForReceiverUnconsumedSelf(const RetainSummary *&S);
 
 
 
  /// Set argument types for arguments which are not doing anything.
 
  void updateSummaryForArgumentTypes(const AnyCall &C, const RetainSummary *&RS);
 
 
 
  /// Determine whether a declaration @c D of correspondent type (return
 
  /// type for functions/methods) @c QT has any of the given attributes,
 
  /// provided they pass necessary validation checks AND tracking the given
 
  /// attribute is enabled.
 
  /// Returns the object kind corresponding to the present attribute, or
 
  /// std::nullopt, if none of the specified attributes are present.
 
  /// Crashes if passed an attribute which is not explicitly handled.
 
  template <class T>
 
  std::optional<ObjKind> hasAnyEnabledAttrOf(const Decl *D, QualType QT);
 
 
 
  template <class T1, class T2, class... Others>
 
  std::optional<ObjKind> hasAnyEnabledAttrOf(const Decl *D, QualType QT);
 
 
 
  friend class RetainSummaryTemplate;
 
};
 
 
 
 
 
// Used to avoid allocating long-term (BPAlloc'd) memory for default retain
 
// summaries. If a function or method looks like it has a default summary, but
 
// it has annotations, the annotations are added to the stack-based template
 
// and then copied into managed memory.
 
class RetainSummaryTemplate {
 
  RetainSummaryManager &Manager;
 
  const RetainSummary *&RealSummary;
 
  RetainSummary ScratchSummary;
 
  bool Accessed;
 
public:
 
  RetainSummaryTemplate(const RetainSummary *&real, RetainSummaryManager &mgr)
 
    : Manager(mgr), RealSummary(real), ScratchSummary(*real), Accessed(false) {}
 
 
 
  ~RetainSummaryTemplate() {
 
    if (Accessed)
 
      RealSummary = Manager.getPersistentSummary(ScratchSummary);
 
  }
 
 
 
  RetainSummary &operator*() {
 
    Accessed = true;
 
    return ScratchSummary;
 
  }
 
 
 
  RetainSummary *operator->() {
 
    Accessed = true;
 
    return &ScratchSummary;
 
  }
 
};
 
 
 
} // end namespace ento
 
} // end namespace clang
 
 
 
#endif