diff options
author | thegeorg <thegeorg@yandex-team.com> | 2024-03-13 13:58:24 +0300 |
---|---|---|
committer | thegeorg <thegeorg@yandex-team.com> | 2024-03-13 14:11:53 +0300 |
commit | 11a895b7e15d1c5a1f52706396b82e3f9db953cb (patch) | |
tree | fabc6d883b0f946151f61ae7865cee9f529a1fdd /contrib/libs/clang16/include/clang/Analysis/RetainSummaryManager.h | |
parent | 9685917341315774aad5733b1793b1e533a88bbb (diff) | |
download | ydb-11a895b7e15d1c5a1f52706396b82e3f9db953cb.tar.gz |
Export clang-format16 via ydblib project
6e6be3a95868fde888d801b7590af4044049563f
Diffstat (limited to 'contrib/libs/clang16/include/clang/Analysis/RetainSummaryManager.h')
-rw-r--r-- | contrib/libs/clang16/include/clang/Analysis/RetainSummaryManager.h | 780 |
1 files changed, 780 insertions, 0 deletions
diff --git a/contrib/libs/clang16/include/clang/Analysis/RetainSummaryManager.h b/contrib/libs/clang16/include/clang/Analysis/RetainSummaryManager.h new file mode 100644 index 0000000000..74a134584d --- /dev/null +++ b/contrib/libs/clang16/include/clang/Analysis/RetainSummaryManager.h @@ -0,0 +1,780 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//=== 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 + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif |