r340114 - [analyzer] [NFC] Split up RetainSummaryManager from RetainCountChecker
Bruno Cardoso Lopes via cfe-commits
cfe-commits at lists.llvm.org
Fri Aug 17 20:24:20 PDT 2018
Hi George,
This broke the modules build, reverted in r340117 for now. I can help
you figure out any module map change if necessary next week.
Thanks,
On Fri, Aug 17, 2018 at 6:46 PM George Karpenkov via cfe-commits
<cfe-commits at lists.llvm.org> wrote:
>
> Author: george.karpenkov
> Date: Fri Aug 17 18:45:50 2018
> New Revision: 340114
>
> URL: http://llvm.org/viewvc/llvm-project?rev=340114&view=rev
> Log:
> [analyzer] [NFC] Split up RetainSummaryManager from RetainCountChecker
>
> ARCMigrator is using code from RetainCountChecker, which is a layering
> violation (and it also does it badly, by using a different header, and
> then relying on implementation being present in a header file).
>
> This change splits up RetainSummaryManager into a separate library in
> lib/Analysis, which can be used independently of a checker.
>
> Differential Revision: https://reviews.llvm.org/D50934
>
> Added:
> cfe/trunk/include/clang/Analysis/RetainSummaryManager.h
> cfe/trunk/include/clang/StaticAnalyzer/Checkers/SelectorExtras.h
> cfe/trunk/lib/Analysis/RetainSummaryManager.cpp
> Removed:
> cfe/trunk/include/clang/Analysis/ObjCRetainCount.h
> cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountSummaries.cpp
> cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountSummaries.h
> cfe/trunk/lib/StaticAnalyzer/Checkers/SelectorExtras.h
> Modified:
> cfe/trunk/lib/ARCMigrate/CMakeLists.txt
> cfe/trunk/lib/ARCMigrate/ObjCMT.cpp
> cfe/trunk/lib/Analysis/CMakeLists.txt
> cfe/trunk/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
> cfe/trunk/lib/StaticAnalyzer/Checkers/CMakeLists.txt
> cfe/trunk/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp
> cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp
> cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.h
> cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.h
> cfe/trunk/lib/StaticAnalyzer/Checkers/TrustNonnullChecker.cpp
>
> Removed: cfe/trunk/include/clang/Analysis/ObjCRetainCount.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/ObjCRetainCount.h?rev=340113&view=auto
> ==============================================================================
> --- cfe/trunk/include/clang/Analysis/ObjCRetainCount.h (original)
> +++ cfe/trunk/include/clang/Analysis/ObjCRetainCount.h (removed)
> @@ -1,231 +0,0 @@
> -//==-- ObjCRetainCount.h - Retain count summaries for Cocoa -------*- C++ -*--//
> -//
> -// The LLVM Compiler Infrastructure
> -//
> -// This file is distributed under the University of Illinois Open Source
> -// License. See LICENSE.TXT for details.
> -//
> -//===----------------------------------------------------------------------===//
> -//
> -// This file defines the core data structures for retain count "summaries"
> -// for Objective-C and Core Foundation APIs. These summaries are used
> -// by the static analyzer to summarize the retain/release effects of
> -// function and method calls. This drives a path-sensitive typestate
> -// analysis in the static analyzer, but can also potentially be used by
> -// other clients.
> -//
> -//===----------------------------------------------------------------------===//
> -
> -#ifndef LLVM_CLANG_STATICANALYZER_CHECKERS_OBJCRETAINCOUNT_H
> -#define LLVM_CLANG_STATICANALYZER_CHECKERS_OBJCRETAINCOUNT_H
> -
> -#include "clang/Basic/LLVM.h"
> -#include "llvm/ADT/ArrayRef.h"
> -#include "llvm/ADT/SmallVector.h"
> -
> -namespace clang {
> -class FunctionDecl;
> -class ObjCMethodDecl;
> -
> -namespace ento { namespace objc_retain {
> -
> -/// An ArgEffect summarizes the retain count behavior on an argument or receiver
> -/// to a function or method.
> -enum ArgEffect {
> - /// 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 an -dealloc message had been sent to
> - /// the referenced object.
> - Dealloc,
> -
> - /// The argument has its reference count decreased by 1. This is as
> - /// if CFRelease has been called on the argument.
> - DecRef,
> -
> - /// The argument has its reference count decreased by 1. This is as
> - /// if a -release message has been sent to the argument. This differs
> - /// in behavior from DecRef when GC is enabled.
> - DecRefMsg,
> -
> - /// 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. This is as
> - /// if a -retain message has been sent to the argument. This differs
> - /// in behavior from IncRef when GC is enabled.
> - IncRefMsg,
> -
> - /// The argument has its reference count increased by 1. This is as
> - /// if CFRetain has been called on the argument.
> - IncRef,
> -
> - /// Used to mark an argument as collectible in GC mode, currently a noop.
> - MakeCollectable,
> -
> - /// The argument is a pointer to a retain-counted object; on exit, the new
> - /// value of the pointer is a +0 value or NULL.
> - UnretainedOutParameter,
> -
> - /// The argument is a pointer to a retain-counted object; on exit, the new
> - /// value of the pointer is a +1 value or NULL.
> - RetainedOutParameter,
> -
> - /// 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,
> -
> - /// Performs the combined functionality of DecRefMsg 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.
> - DecRefMsgAndStopTrackingHard
> -};
> -
> -/// 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 object is not owned and controlled by the
> - /// Garbage collector.
> - GCNotOwnedSymbol,
> - /// 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 presise than the summary indirectly produced
> - // by inlining the function
> - NoRetHard
> - };
> -
> - /// Determines the object kind of a tracked object.
> - enum ObjKind {
> - /// Indicates that the tracked object is a CF object. This is
> - /// important between GC and non-GC code.
> - 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
> - };
> -
> -private:
> - Kind K;
> - ObjKind O;
> -
> - RetEffect(Kind k, ObjKind o = 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, ObjC);
> - }
> -
> - static RetEffect MakeOwned(ObjKind o) {
> - return RetEffect(OwnedSymbol, o);
> - }
> - static RetEffect MakeNotOwned(ObjKind o) {
> - return RetEffect(NotOwnedSymbol, o);
> - }
> - static RetEffect MakeGCNotOwned() {
> - return RetEffect(GCNotOwnedSymbol, ObjC);
> - }
> - static RetEffect MakeNoRet() {
> - return RetEffect(NoRet);
> - }
> - static RetEffect MakeNoRetHard() {
> - return RetEffect(NoRetHard);
> - }
> -};
> -
> -/// Encapsulates the retain count semantics on the arguments, return value,
> -/// and receiver (if any) of a function/method call.
> -///
> -/// Note that construction of these objects is not highly efficient. That
> -/// is okay for clients where creating these objects isn't really a bottleneck.
> -/// The purpose of the API is to provide something simple. The actual
> -/// static analyzer checker that implements retain/release typestate
> -/// tracking uses something more efficient.
> -class CallEffects {
> - llvm::SmallVector<ArgEffect, 10> Args;
> - RetEffect Ret;
> - ArgEffect Receiver;
> -
> - CallEffects(const RetEffect &R) : Ret(R) {}
> -
> -public:
> - /// Returns the argument effects for a call.
> - ArrayRef<ArgEffect> getArgs() const { return Args; }
> -
> - /// Returns the effects on the receiver.
> - ArgEffect getReceiver() const { return Receiver; }
> -
> - /// Returns the effect on the return value.
> - RetEffect getReturnValue() const { return Ret; }
> -
> - /// Return the CallEfect for a given Objective-C method.
> - static CallEffects getEffect(const ObjCMethodDecl *MD);
> -
> - /// Return the CallEfect for a given C/C++ function.
> - static CallEffects getEffect(const FunctionDecl *FD);
> -};
> -
> -}}}
> -
> -#endif
> -
>
> Added: cfe/trunk/include/clang/Analysis/RetainSummaryManager.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/RetainSummaryManager.h?rev=340114&view=auto
> ==============================================================================
> --- cfe/trunk/include/clang/Analysis/RetainSummaryManager.h (added)
> +++ cfe/trunk/include/clang/Analysis/RetainSummaryManager.h Fri Aug 17 18:45:50 2018
> @@ -0,0 +1,706 @@
> +//=== RetainSummaryManager.h - Summaries for reference counting ---*- C++ -*--//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
> +//
> +// 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_LIB_ANALYSIS_RETAINSUMMARYMANAGER
> +#define LLVM_CLANG_LIB_ANALYSIS_RETAINSUMMARYMANAGER
> +
> +#include "llvm/ADT/DenseMap.h"
> +#include "llvm/ADT/FoldingSet.h"
> +#include "clang/AST/Attr.h"
> +#include "clang/AST/DeclCXX.h"
> +#include "clang/AST/DeclObjC.h"
> +#include "clang/AST/ParentMap.h"
> +#include "clang/StaticAnalyzer/Checkers/SelectorExtras.h"
> +#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
> +#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
> +#include "clang/StaticAnalyzer/Core/Checker.h"
> +#include "clang/StaticAnalyzer/Core/CheckerManager.h"
> +#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
> +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
> +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
> +#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
> +#include "llvm/ADT/ImmutableList.h"
> +#include "llvm/ADT/ImmutableMap.h"
> +#include "llvm/ADT/STLExtras.h"
> +
> +//===----------------------------------------------------------------------===//
> +// Adapters for FoldingSet.
> +//===----------------------------------------------------------------------===//
> +
> +using namespace clang;
> +using namespace ento;
> +
> +namespace clang {
> +namespace ento {
> +
> +/// An ArgEffect summarizes the retain count behavior on an argument or receiver
> +/// to a function or method.
> +enum ArgEffect {
> + /// 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 an -dealloc message had been sent to
> + /// the referenced object.
> + Dealloc,
> +
> + /// The argument has its reference count decreased by 1. This is as
> + /// if CFRelease has been called on the argument.
> + DecRef,
> +
> + /// The argument has its reference count decreased by 1. This is as
> + /// if a -release message has been sent to the argument. This differs
> + /// in behavior from DecRef when GC is enabled.
> + DecRefMsg,
> +
> + /// 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. This is as
> + /// if a -retain message has been sent to the argument. This differs
> + /// in behavior from IncRef when GC is enabled.
> + IncRefMsg,
> +
> + /// The argument has its reference count increased by 1. This is as
> + /// if CFRetain has been called on the argument.
> + IncRef,
> +
> + /// The argument acts as if has been passed to CFMakeCollectable, which
> + /// transfers the object to the Garbage Collector under GC.
> + MakeCollectable,
> +
> + /// The argument is a pointer to a retain-counted object; on exit, the new
> + /// value of the pointer is a +0 value or NULL.
> + UnretainedOutParameter,
> +
> + /// The argument is a pointer to a retain-counted object; on exit, the new
> + /// value of the pointer is a +1 value or NULL.
> + RetainedOutParameter,
> +
> + /// 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,
> +
> + /// Performs the combined functionality of DecRefMsg 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.
> + DecRefMsgAndStopTrackingHard
> +};
> +
> +/// 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 object is not owned and controlled by the
> + /// Garbage collector.
> + GCNotOwnedSymbol,
> + /// 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 presise than the summary indirectly produced
> + // by inlining the function
> + NoRetHard
> + };
> +
> + /// Determines the object kind of a tracked object.
> + enum ObjKind {
> + /// Indicates that the tracked object is a CF object. This is
> + /// important between GC and non-GC code.
> + 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
> + };
> +
> +private:
> + Kind K;
> + ObjKind O;
> +
> + RetEffect(Kind k, ObjKind o = 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, ObjC);
> + }
> +
> + static RetEffect MakeOwned(ObjKind o) {
> + return RetEffect(OwnedSymbol, o);
> + }
> + static RetEffect MakeNotOwned(ObjKind o) {
> + return RetEffect(NotOwnedSymbol, o);
> + }
> + static RetEffect MakeGCNotOwned() {
> + return RetEffect(GCNotOwnedSymbol, ObjC);
> + }
> + static RetEffect MakeNoRet() {
> + return RetEffect(NoRet);
> + }
> + static RetEffect MakeNoRetHard() {
> + return RetEffect(NoRetHard);
> + }
> +};
> +
> +/// Encapsulates the retain count semantics on the arguments, return value,
> +/// and receiver (if any) of a function/method call.
> +///
> +/// Note that construction of these objects is not highly efficient. That
> +/// is okay for clients where creating these objects isn't really a bottleneck.
> +/// The purpose of the API is to provide something simple. The actual
> +/// static analyzer checker that implements retain/release typestate
> +/// tracking uses something more efficient.
> +class CallEffects {
> + llvm::SmallVector<ArgEffect, 10> Args;
> + RetEffect Ret;
> + ArgEffect Receiver;
> +
> + CallEffects(const RetEffect &R) : Ret(R) {}
> +
> +public:
> + /// Returns the argument effects for a call.
> + ArrayRef<ArgEffect> getArgs() const { return Args; }
> +
> + /// Returns the effects on the receiver.
> + ArgEffect getReceiver() const { return Receiver; }
> +
> + /// Returns the effect on the return value.
> + RetEffect getReturnValue() const { return Ret; }
> +
> + /// Return the CallEfect for a given Objective-C method.
> + static CallEffects getEffect(const ObjCMethodDecl *MD);
> +
> + /// Return the CallEfect for a given C/C++ function.
> + static CallEffects getEffect(const FunctionDecl *FD);
> +};
> +
> +/// 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
> +
> +namespace llvm {
> +
> +template <> struct FoldingSetTrait<ArgEffect> {
> +static inline void Profile(const ArgEffect X, FoldingSetNodeID &ID) {
> + ID.AddInteger((unsigned) X);
> +}
> +};
> +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;
> +
> + /// 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)
> + : Args(A), DefaultArgEffect(defaultEff), Receiver(ReceiverEff), 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; }
> +
> + /// 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 && 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(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 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;
> +
> + /// 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;
> +
> + /// ScratchArgs - A holding buffer for construct ArgEffects.
> + ArgEffects ScratchArgs;
> +
> + /// 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;
> +
> + /// getArgEffects - Returns a persistent ArgEffects object based on the
> + /// data in ScratchArgs.
> + ArgEffects getArgEffects();
> +
> + enum UnaryFuncKind { cfretain, cfrelease, cfautorelease, cfmakecollectable };
> +
> + const RetainSummary *getUnarySummary(const FunctionType* FT,
> + UnaryFuncKind func);
> +
> + 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,
> + ArgEffect ReceiverEff = DoNothing,
> + ArgEffect DefaultEff = MayEscape) {
> + RetainSummary Summ(getArgEffects(), RetEff, DefaultEff, ReceiverEff);
> + return getPersistentSummary(Summ);
> + }
> +
> + const RetainSummary *getDoNothingSummary() {
> + return getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing);
> + }
> +
> + const RetainSummary *getDefaultSummary() {
> + return getPersistentSummary(RetEffect::MakeNoRet(),
> + DoNothing, MayEscape);
> + }
> +
> + const RetainSummary *getPersistentStopSummary() {
> + return getPersistentSummary(RetEffect::MakeNoRet(),
> + StopTracking, 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);
> +
> +public:
> + RetainSummaryManager(ASTContext &ctx, bool usesARC)
> + : Ctx(ctx),
> + ARCEnabled(usesARC),
> + AF(BPAlloc), ScratchArgs(AF.getEmptyMap()),
> + ObjCAllocRetE(usesARC ? RetEffect::MakeNotOwned(RetEffect::ObjC)
> + : RetEffect::MakeOwned(RetEffect::ObjC)),
> + ObjCInitRetE(usesARC ? RetEffect::MakeNotOwned(RetEffect::ObjC)
> + : RetEffect::MakeOwnedWhenTrackedReceiver()) {
> + InitializeClassMethodSummaries();
> + InitializeMethodSummaries();
> + }
> +
> + bool canEval(const CallExpr *CE,
> + const FunctionDecl *FD,
> + bool &hasTrustedImplementationAnnotation);
> +
> + bool isTrustedReferenceCountImplementation(const FunctionDecl *FD);
> +
> + const RetainSummary *getSummary(const CallEvent &Call,
> + QualType ReceiverType=QualType());
> +
> + 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 ObjCMethodCall &M,
> + QualType ReceiverType);
> +
> + const RetainSummary *getClassMethodSummary(const ObjCMethodCall &M) {
> + assert(!M.isInstanceMessage());
> + const ObjCInterfaceDecl *Class = M.getReceiverInterface();
> +
> + return getMethodSummary(M.getSelector(), Class, M.getDecl(),
> + M.getResultType(), ObjCClassMethodSummaries);
> + }
> +
> + /// getMethodSummary - This version of getMethodSummary is used to query
> + /// the summary for the current method being analyzed.
> + const RetainSummary *getMethodSummary(const ObjCMethodDecl *MD) {
> + const ObjCInterfaceDecl *ID = MD->getClassInterface();
> + Selector S = MD->getSelector();
> + QualType ResultTy = MD->getReturnType();
> +
> + ObjCMethodSummariesTy *CachedSummaries;
> + if (MD->isInstanceMethod())
> + CachedSummaries = &ObjCMethodSummaries;
> + else
> + CachedSummaries = &ObjCClassMethodSummaries;
> +
> + return getMethodSummary(S, ID, MD, ResultTy, *CachedSummaries);
> + }
> +
> + const RetainSummary *getStandardMethodSummary(const ObjCMethodDecl *MD,
> + Selector S, QualType RetTy);
> +
> + /// Determine if there is a special return effect for this function or method.
> + Optional<RetEffect> getRetEffectFromAnnotations(QualType RetTy,
> + const Decl *D);
> +
> + void updateSummaryFromAnnotations(const RetainSummary *&Summ,
> + const ObjCMethodDecl *MD);
> +
> + void updateSummaryFromAnnotations(const RetainSummary *&Summ,
> + const FunctionDecl *FD);
> +
> + void updateSummaryForCall(const RetainSummary *&Summ,
> + const CallEvent &Call);
> +
> + bool isARCEnabled() const { return ARCEnabled; }
> +
> + RetEffect getObjAllocRetEffect() const { return ObjCAllocRetE; }
> +
> + 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
>
> Added: cfe/trunk/include/clang/StaticAnalyzer/Checkers/SelectorExtras.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Checkers/SelectorExtras.h?rev=340114&view=auto
> ==============================================================================
> --- cfe/trunk/include/clang/StaticAnalyzer/Checkers/SelectorExtras.h (added)
> +++ cfe/trunk/include/clang/StaticAnalyzer/Checkers/SelectorExtras.h Fri Aug 17 18:45:50 2018
> @@ -0,0 +1,39 @@
> +//=== SelectorExtras.h - Helpers for checkers using selectors -----*- C++ -*-=//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
> +
> +#ifndef LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_SELECTOREXTRAS_H
> +#define LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_SELECTOREXTRAS_H
> +
> +#include "clang/AST/ASTContext.h"
> +
> +namespace clang {
> +namespace ento {
> +
> +template <typename... IdentifierInfos>
> +static inline Selector getKeywordSelector(ASTContext &Ctx,
> + IdentifierInfos *... IIs) {
> + static_assert(sizeof...(IdentifierInfos),
> + "keyword selectors must have at least one argument");
> + SmallVector<IdentifierInfo *, 10> II({&Ctx.Idents.get(IIs)...});
> +
> + return Ctx.Selectors.getSelector(II.size(), &II[0]);
> +}
> +
> +template <typename... IdentifierInfos>
> +static inline void lazyInitKeywordSelector(Selector &Sel, ASTContext &Ctx,
> + IdentifierInfos *... IIs) {
> + if (!Sel.isNull())
> + return;
> + Sel = getKeywordSelector(Ctx, IIs...);
> +}
> +
> +} // end namespace ento
> +} // end namespace clang
> +
> +#endif
>
> Modified: cfe/trunk/lib/ARCMigrate/CMakeLists.txt
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ARCMigrate/CMakeLists.txt?rev=340114&r1=340113&r2=340114&view=diff
> ==============================================================================
> --- cfe/trunk/lib/ARCMigrate/CMakeLists.txt (original)
> +++ cfe/trunk/lib/ARCMigrate/CMakeLists.txt Fri Aug 17 18:45:50 2018
> @@ -34,5 +34,4 @@ add_clang_library(clangARCMigrate
> clangRewrite
> clangSema
> clangSerialization
> - clangStaticAnalyzerCheckers
> )
>
> Modified: cfe/trunk/lib/ARCMigrate/ObjCMT.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ARCMigrate/ObjCMT.cpp?rev=340114&r1=340113&r2=340114&view=diff
> ==============================================================================
> --- cfe/trunk/lib/ARCMigrate/ObjCMT.cpp (original)
> +++ cfe/trunk/lib/ARCMigrate/ObjCMT.cpp Fri Aug 17 18:45:50 2018
> @@ -8,7 +8,7 @@
> //===----------------------------------------------------------------------===//
>
> #include "Transforms.h"
> -#include "clang/Analysis/ObjCRetainCount.h"
> +#include "clang/Analysis/RetainSummaryManager.h"
> #include "clang/ARCMigrate/ARCMT.h"
> #include "clang/ARCMigrate/ARCMTActions.h"
> #include "clang/AST/ASTConsumer.h"
> @@ -35,8 +35,8 @@
> #include "llvm/Support/YAMLParser.h"
>
> using namespace clang;
> +using namespace ento;
> using namespace arcmt;
> -using namespace ento::objc_retain;
>
> namespace {
>
>
> Modified: cfe/trunk/lib/Analysis/CMakeLists.txt
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CMakeLists.txt?rev=340114&r1=340113&r2=340114&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Analysis/CMakeLists.txt (original)
> +++ cfe/trunk/lib/Analysis/CMakeLists.txt Fri Aug 17 18:45:50 2018
> @@ -24,6 +24,7 @@ add_clang_library(clangAnalysis
> ProgramPoint.cpp
> PseudoConstantAnalysis.cpp
> ReachableCode.cpp
> + RetainSummaryManager.cpp
> ScanfFormatString.cpp
> ThreadSafety.cpp
> ThreadSafetyCommon.cpp
>
> Added: cfe/trunk/lib/Analysis/RetainSummaryManager.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/RetainSummaryManager.cpp?rev=340114&view=auto
> ==============================================================================
> --- cfe/trunk/lib/Analysis/RetainSummaryManager.cpp (added)
> +++ cfe/trunk/lib/Analysis/RetainSummaryManager.cpp Fri Aug 17 18:45:50 2018
> @@ -0,0 +1,902 @@
> +//== RetainSummaryManager.cpp - Summaries for reference counting --*- C++ -*--//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
> +//
> +// This file defines summaries implementation for retain counting, which
> +// implements a reference count checker for Core Foundation and Cocoa
> +// on (Mac OS X).
> +//
> +//===----------------------------------------------------------------------===//
> +
> +#include "clang/Analysis/RetainSummaryManager.h"
> +#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
> +#include "clang/AST/Attr.h"
> +#include "clang/AST/DeclCXX.h"
> +#include "clang/AST/DeclObjC.h"
> +#include "clang/AST/ParentMap.h"
> +
> +using namespace clang;
> +using namespace ento;
> +
> +ArgEffects RetainSummaryManager::getArgEffects() {
> + ArgEffects AE = ScratchArgs;
> + ScratchArgs = AF.getEmptyMap();
> + return AE;
> +}
> +
> +const RetainSummary *
> +RetainSummaryManager::getPersistentSummary(const RetainSummary &OldSumm) {
> + // Unique "simple" summaries -- those without ArgEffects.
> + if (OldSumm.isSimple()) {
> + ::llvm::FoldingSetNodeID ID;
> + OldSumm.Profile(ID);
> +
> + void *Pos;
> + CachedSummaryNode *N = SimpleSummaries.FindNodeOrInsertPos(ID, Pos);
> +
> + if (!N) {
> + N = (CachedSummaryNode *) BPAlloc.Allocate<CachedSummaryNode>();
> + new (N) CachedSummaryNode(OldSumm);
> + SimpleSummaries.InsertNode(N, Pos);
> + }
> +
> + return &N->getValue();
> + }
> +
> + RetainSummary *Summ = (RetainSummary *) BPAlloc.Allocate<RetainSummary>();
> + new (Summ) RetainSummary(OldSumm);
> + return Summ;
> +}
> +
> +static bool hasRCAnnotation(const Decl *D, StringRef rcAnnotation) {
> + for (const auto *Ann : D->specific_attrs<AnnotateAttr>()) {
> + if (Ann->getAnnotation() == rcAnnotation)
> + return true;
> + }
> + return false;
> +}
> +
> +static bool isRetain(const FunctionDecl *FD, StringRef FName) {
> + return FName.startswith_lower("retain") || FName.endswith_lower("retain");
> +}
> +
> +static bool isRelease(const FunctionDecl *FD, StringRef FName) {
> + return FName.startswith_lower("release") || FName.endswith_lower("release");
> +}
> +
> +static bool isAutorelease(const FunctionDecl *FD, StringRef FName) {
> + return FName.startswith_lower("autorelease") ||
> + FName.endswith_lower("autorelease");
> +}
> +
> +static bool isMakeCollectable(StringRef FName) {
> + return FName.contains_lower("MakeCollectable");
> +}
> +
> +const RetainSummary *
> +RetainSummaryManager::generateSummary(const FunctionDecl *FD,
> + bool &AllowAnnotations) {
> + // We generate "stop" summaries for implicitly defined functions.
> + if (FD->isImplicit()) {
> + return getPersistentStopSummary();
> + }
> +
> + // [PR 3337] Use 'getAs<FunctionType>' to strip away any typedefs on the
> + // function's type.
> + const FunctionType *FT = FD->getType()->getAs<FunctionType>();
> + const IdentifierInfo *II = FD->getIdentifier();
> + if (!II)
> + return getDefaultSummary();
> +
> + StringRef FName = II->getName();
> +
> + // Strip away preceding '_'. Doing this here will effect all the checks
> + // down below.
> + FName = FName.substr(FName.find_first_not_of('_'));
> +
> + // Inspect the result type.
> + QualType RetTy = FT->getReturnType();
> + std::string RetTyName = RetTy.getAsString();
> +
> + // FIXME: This should all be refactored into a chain of "summary lookup"
> + // filters.
> + assert(ScratchArgs.isEmpty());
> +
> + if (FName == "pthread_create" || FName == "pthread_setspecific") {
> + // Part of: <rdar://problem/7299394> and <rdar://problem/11282706>.
> + // This will be addressed better with IPA.
> + return getPersistentStopSummary();
> + } else if(FName == "NSMakeCollectable") {
> + // Handle: id NSMakeCollectable(CFTypeRef)
> + AllowAnnotations = false;
> + return RetTy->isObjCIdType() ? getUnarySummary(FT, cfmakecollectable)
> + : getPersistentStopSummary();
> + } else if (FName == "CFPlugInInstanceCreate") {
> + return getPersistentSummary(RetEffect::MakeNoRet());
> + } else if (FName == "IORegistryEntrySearchCFProperty" ||
> + (RetTyName == "CFMutableDictionaryRef" &&
> + (FName == "IOBSDNameMatching" || FName == "IOServiceMatching" ||
> + FName == "IOServiceNameMatching" ||
> + FName == "IORegistryEntryIDMatching" ||
> + FName == "IOOpenFirmwarePathMatching"))) {
> + // Part of <rdar://problem/6961230>. (IOKit)
> + // This should be addressed using a API table.
> + return getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF), DoNothing,
> + DoNothing);
> + } else if (FName == "IOServiceGetMatchingService" ||
> + FName == "IOServiceGetMatchingServices") {
> + // FIXES: <rdar://problem/6326900>
> + // This should be addressed using a API table. This strcmp is also
> + // a little gross, but there is no need to super optimize here.
> + ScratchArgs = AF.add(ScratchArgs, 1, DecRef);
> + return getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing);
> + } else if (FName == "IOServiceAddNotification" ||
> + FName == "IOServiceAddMatchingNotification") {
> + // Part of <rdar://problem/6961230>. (IOKit)
> + // This should be addressed using a API table.
> + ScratchArgs = AF.add(ScratchArgs, 2, DecRef);
> + return getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing);
> + } else if (FName == "CVPixelBufferCreateWithBytes") {
> + // FIXES: <rdar://problem/7283567>
> + // Eventually this can be improved by recognizing that the pixel
> + // buffer passed to CVPixelBufferCreateWithBytes is released via
> + // a callback and doing full IPA to make sure this is done correctly.
> + // FIXME: This function has an out parameter that returns an
> + // allocated object.
> + ScratchArgs = AF.add(ScratchArgs, 7, StopTracking);
> + return getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing);
> + } else if (FName == "CGBitmapContextCreateWithData") {
> + // FIXES: <rdar://problem/7358899>
> + // Eventually this can be improved by recognizing that 'releaseInfo'
> + // passed to CGBitmapContextCreateWithData is released via
> + // a callback and doing full IPA to make sure this is done correctly.
> + ScratchArgs = AF.add(ScratchArgs, 8, StopTracking);
> + return getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF), DoNothing,
> + DoNothing);
> + } else if (FName == "CVPixelBufferCreateWithPlanarBytes") {
> + // FIXES: <rdar://problem/7283567>
> + // Eventually this can be improved by recognizing that the pixel
> + // buffer passed to CVPixelBufferCreateWithPlanarBytes is released
> + // via a callback and doing full IPA to make sure this is done
> + // correctly.
> + ScratchArgs = AF.add(ScratchArgs, 12, StopTracking);
> + return getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing);
> + } else if (FName == "VTCompressionSessionEncodeFrame") {
> + // The context argument passed to VTCompressionSessionEncodeFrame()
> + // is passed to the callback specified when creating the session
> + // (e.g. with VTCompressionSessionCreate()) which can release it.
> + // To account for this possibility, conservatively stop tracking
> + // the context.
> + ScratchArgs = AF.add(ScratchArgs, 5, StopTracking);
> + return getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing);
> + } else if (FName == "dispatch_set_context" ||
> + FName == "xpc_connection_set_context") {
> + // <rdar://problem/11059275> - The analyzer currently doesn't have
> + // a good way to reason about the finalizer function for libdispatch.
> + // If we pass a context object that is memory managed, stop tracking it.
> + // <rdar://problem/13783514> - Same problem, but for XPC.
> + // FIXME: this hack should possibly go away once we can handle
> + // libdispatch and XPC finalizers.
> + ScratchArgs = AF.add(ScratchArgs, 1, StopTracking);
> + return getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing);
> + } else if (FName.startswith("NSLog")) {
> + return getDoNothingSummary();
> + } else if (FName.startswith("NS") &&
> + (FName.find("Insert") != StringRef::npos)) {
> + // Whitelist NSXXInsertXX, for example NSMapInsertIfAbsent, since they can
> + // be deallocated by NSMapRemove. (radar://11152419)
> + ScratchArgs = AF.add(ScratchArgs, 1, StopTracking);
> + ScratchArgs = AF.add(ScratchArgs, 2, StopTracking);
> + return getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing);
> + }
> +
> + if (RetTy->isPointerType()) {
> + // For CoreFoundation ('CF') types.
> + if (cocoa::isRefType(RetTy, "CF", FName)) {
> + if (isRetain(FD, FName)) {
> + // CFRetain isn't supposed to be annotated. However, this may as well
> + // be a user-made "safe" CFRetain function that is incorrectly
> + // annotated as cf_returns_retained due to lack of better options.
> + // We want to ignore such annotation.
> + AllowAnnotations = false;
> +
> + return getUnarySummary(FT, cfretain);
> + } else if (isAutorelease(FD, FName)) {
> + // The headers use cf_consumed, but we can fully model CFAutorelease
> + // ourselves.
> + AllowAnnotations = false;
> +
> + return getUnarySummary(FT, cfautorelease);
> + } else if (isMakeCollectable(FName)) {
> + AllowAnnotations = false;
> + return getUnarySummary(FT, cfmakecollectable);
> + } else {
> + return getCFCreateGetRuleSummary(FD);
> + }
> + }
> +
> + // For CoreGraphics ('CG') and CoreVideo ('CV') types.
> + if (cocoa::isRefType(RetTy, "CG", FName) ||
> + cocoa::isRefType(RetTy, "CV", FName)) {
> + if (isRetain(FD, FName))
> + return getUnarySummary(FT, cfretain);
> + else
> + return getCFCreateGetRuleSummary(FD);
> + }
> +
> + // For all other CF-style types, use the Create/Get
> + // rule for summaries but don't support Retain functions
> + // with framework-specific prefixes.
> + if (coreFoundation::isCFObjectRef(RetTy)) {
> + return getCFCreateGetRuleSummary(FD);
> + }
> +
> + if (FD->hasAttr<CFAuditedTransferAttr>()) {
> + return getCFCreateGetRuleSummary(FD);
> + }
> + }
> +
> + // Check for release functions, the only kind of functions that we care
> + // about that don't return a pointer type.
> + if (FName.size() >= 2 && FName[0] == 'C' &&
> + (FName[1] == 'F' || FName[1] == 'G')) {
> + // Test for 'CGCF'.
> + FName = FName.substr(FName.startswith("CGCF") ? 4 : 2);
> +
> + if (isRelease(FD, FName))
> + return getUnarySummary(FT, cfrelease);
> + else {
> + assert(ScratchArgs.isEmpty());
> + // Remaining CoreFoundation and CoreGraphics functions.
> + // We use to assume that they all strictly followed the ownership idiom
> + // and that ownership cannot be transferred. While this is technically
> + // correct, many methods allow a tracked object to escape. For example:
> + //
> + // CFMutableDictionaryRef x = CFDictionaryCreateMutable(...);
> + // CFDictionaryAddValue(y, key, x);
> + // CFRelease(x);
> + // ... it is okay to use 'x' since 'y' has a reference to it
> + //
> + // We handle this and similar cases with the follow heuristic. If the
> + // function name contains "InsertValue", "SetValue", "AddValue",
> + // "AppendValue", or "SetAttribute", then we assume that arguments may
> + // "escape." This means that something else holds on to the object,
> + // allowing it be used even after its local retain count drops to 0.
> + ArgEffect E = (StrInStrNoCase(FName, "InsertValue") != StringRef::npos ||
> + StrInStrNoCase(FName, "AddValue") != StringRef::npos ||
> + StrInStrNoCase(FName, "SetValue") != StringRef::npos ||
> + StrInStrNoCase(FName, "AppendValue") != StringRef::npos ||
> + StrInStrNoCase(FName, "SetAttribute") != StringRef::npos)
> + ? MayEscape
> + : DoNothing;
> +
> + return getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, E);
> + }
> + }
> +
> + return getDefaultSummary();
> +}
> +
> +const RetainSummary *
> +RetainSummaryManager::getFunctionSummary(const FunctionDecl *FD) {
> + // If we don't know what function we're calling, use our default summary.
> + if (!FD)
> + return getDefaultSummary();
> +
> + // Look up a summary in our cache of FunctionDecls -> Summaries.
> + FuncSummariesTy::iterator I = FuncSummaries.find(FD);
> + if (I != FuncSummaries.end())
> + return I->second;
> +
> + // No summary? Generate one.
> + bool AllowAnnotations = true;
> + const RetainSummary *S = generateSummary(FD, AllowAnnotations);
> +
> + // Annotations override defaults.
> + if (AllowAnnotations)
> + updateSummaryFromAnnotations(S, FD);
> +
> + FuncSummaries[FD] = S;
> + return S;
> +}
> +
> +//===----------------------------------------------------------------------===//
> +// Summary creation for functions (largely uses of Core Foundation).
> +//===----------------------------------------------------------------------===//
> +
> +static ArgEffect getStopTrackingHardEquivalent(ArgEffect E) {
> + switch (E) {
> + case DoNothing:
> + case Autorelease:
> + case DecRefBridgedTransferred:
> + case IncRef:
> + case IncRefMsg:
> + case MakeCollectable:
> + case UnretainedOutParameter:
> + case RetainedOutParameter:
> + case MayEscape:
> + case StopTracking:
> + case StopTrackingHard:
> + return StopTrackingHard;
> + case DecRef:
> + case DecRefAndStopTrackingHard:
> + return DecRefAndStopTrackingHard;
> + case DecRefMsg:
> + case DecRefMsgAndStopTrackingHard:
> + return DecRefMsgAndStopTrackingHard;
> + case Dealloc:
> + return Dealloc;
> + }
> +
> + llvm_unreachable("Unknown ArgEffect kind");
> +}
> +
> +void RetainSummaryManager::updateSummaryForCall(const RetainSummary *&S,
> + const CallEvent &Call) {
> + if (Call.hasNonZeroCallbackArg()) {
> + ArgEffect RecEffect =
> + getStopTrackingHardEquivalent(S->getReceiverEffect());
> + ArgEffect DefEffect =
> + getStopTrackingHardEquivalent(S->getDefaultArgEffect());
> +
> + ArgEffects CustomArgEffects = S->getArgEffects();
> + for (ArgEffects::iterator I = CustomArgEffects.begin(),
> + E = CustomArgEffects.end();
> + I != E; ++I) {
> + ArgEffect Translated = getStopTrackingHardEquivalent(I->second);
> + if (Translated != DefEffect)
> + ScratchArgs = AF.add(ScratchArgs, I->first, Translated);
> + }
> +
> + RetEffect RE = RetEffect::MakeNoRetHard();
> +
> + // Special cases where the callback argument CANNOT free the return value.
> + // This can generally only happen if we know that the callback will only be
> + // called when the return value is already being deallocated.
> + if (const SimpleFunctionCall *FC = dyn_cast<SimpleFunctionCall>(&Call)) {
> + if (IdentifierInfo *Name = FC->getDecl()->getIdentifier()) {
> + // When the CGBitmapContext is deallocated, the callback here will free
> + // the associated data buffer.
> + // The callback in dispatch_data_create frees the buffer, but not
> + // the data object.
> + if (Name->isStr("CGBitmapContextCreateWithData") ||
> + Name->isStr("dispatch_data_create"))
> + RE = S->getRetEffect();
> + }
> + }
> +
> + S = getPersistentSummary(RE, RecEffect, DefEffect);
> + }
> +
> + // 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.
> + if (const ObjCMethodCall *MC = dyn_cast<ObjCMethodCall>(&Call)) {
> + if (MC->getMethodFamily() == OMF_init && MC->isReceiverSelfOrSuper()) {
> +
> + // Check if the message is not consumed, we know it will not be used in
> + // an assignment, ex: "self = [super init]".
> + const Expr *ME = MC->getOriginExpr();
> + const LocationContext *LCtx = MC->getLocationContext();
> + ParentMap &PM = LCtx->getAnalysisDeclContext()->getParentMap();
> + if (!PM.isConsumedExpr(ME)) {
> + RetainSummaryTemplate ModifiableSummaryTemplate(S, *this);
> + ModifiableSummaryTemplate->setReceiverEffect(DoNothing);
> + ModifiableSummaryTemplate->setRetEffect(RetEffect::MakeNoRet());
> + }
> + }
> + }
> +}
> +
> +const RetainSummary *
> +RetainSummaryManager::getSummary(const CallEvent &Call,
> + QualType ReceiverType) {
> + const RetainSummary *Summ;
> + switch (Call.getKind()) {
> + case CE_Function:
> + Summ = getFunctionSummary(cast<SimpleFunctionCall>(Call).getDecl());
> + break;
> + case CE_CXXMember:
> + case CE_CXXMemberOperator:
> + case CE_Block:
> + case CE_CXXConstructor:
> + case CE_CXXDestructor:
> + case CE_CXXAllocator:
> + // FIXME: These calls are currently unsupported.
> + return getPersistentStopSummary();
> + case CE_ObjCMessage: {
> + const ObjCMethodCall &Msg = cast<ObjCMethodCall>(Call);
> + if (Msg.isInstanceMessage())
> + Summ = getInstanceMethodSummary(Msg, ReceiverType);
> + else
> + Summ = getClassMethodSummary(Msg);
> + break;
> + }
> + }
> +
> + updateSummaryForCall(Summ, Call);
> +
> + assert(Summ && "Unknown call type?");
> + return Summ;
> +}
> +
> +
> +const RetainSummary *
> +RetainSummaryManager::getCFCreateGetRuleSummary(const FunctionDecl *FD) {
> + if (coreFoundation::followsCreateRule(FD))
> + return getCFSummaryCreateRule(FD);
> +
> + return getCFSummaryGetRule(FD);
> +}
> +
> +bool RetainSummaryManager::isTrustedReferenceCountImplementation(
> + const FunctionDecl *FD) {
> + return hasRCAnnotation(FD, "rc_ownership_trusted_implementation");
> +}
> +
> +bool RetainSummaryManager::canEval(const CallExpr *CE,
> + const FunctionDecl *FD,
> + bool &hasTrustedImplementationAnnotation) {
> + // For now, we're only handling the functions that return aliases of their
> + // arguments: CFRetain (and its families).
> + // Eventually we should add other functions we can model entirely,
> + // such as CFRelease, which don't invalidate their arguments or globals.
> + if (CE->getNumArgs() != 1)
> + return false;
> +
> + IdentifierInfo *II = FD->getIdentifier();
> + if (!II)
> + return false;
> +
> + StringRef FName = II->getName();
> + FName = FName.substr(FName.find_first_not_of('_'));
> +
> + QualType ResultTy = CE->getCallReturnType(Ctx);
> + if (ResultTy->isObjCIdType()) {
> + return II->isStr("NSMakeCollectable");
> + } else if (ResultTy->isPointerType()) {
> + // Handle: (CF|CG|CV)Retain
> + // CFAutorelease
> + // It's okay to be a little sloppy here.
> + if (cocoa::isRefType(ResultTy, "CF", FName) ||
> + cocoa::isRefType(ResultTy, "CG", FName) ||
> + cocoa::isRefType(ResultTy, "CV", FName))
> + return isRetain(FD, FName) || isAutorelease(FD, FName) ||
> + isMakeCollectable(FName);
> +
> + const FunctionDecl* FDD = FD->getDefinition();
> + if (FDD && isTrustedReferenceCountImplementation(FDD)) {
> + hasTrustedImplementationAnnotation = true;
> + return true;
> + }
> + }
> +
> + return false;
> +
> +}
> +
> +const RetainSummary *
> +RetainSummaryManager::getUnarySummary(const FunctionType* FT,
> + UnaryFuncKind func) {
> +
> + // Sanity check that this is *really* a unary function. This can
> + // happen if people do weird things.
> + const FunctionProtoType* FTP = dyn_cast<FunctionProtoType>(FT);
> + if (!FTP || FTP->getNumParams() != 1)
> + return getPersistentStopSummary();
> +
> + assert (ScratchArgs.isEmpty());
> +
> + ArgEffect Effect;
> + switch (func) {
> + case cfretain: Effect = IncRef; break;
> + case cfrelease: Effect = DecRef; break;
> + case cfautorelease: Effect = Autorelease; break;
> + case cfmakecollectable: Effect = MakeCollectable; break;
> + }
> +
> + ScratchArgs = AF.add(ScratchArgs, 0, Effect);
> + return getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing);
> +}
> +
> +const RetainSummary *
> +RetainSummaryManager::getCFSummaryCreateRule(const FunctionDecl *FD) {
> + assert (ScratchArgs.isEmpty());
> +
> + return getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF));
> +}
> +
> +const RetainSummary *
> +RetainSummaryManager::getCFSummaryGetRule(const FunctionDecl *FD) {
> + assert (ScratchArgs.isEmpty());
> + return getPersistentSummary(RetEffect::MakeNotOwned(RetEffect::CF),
> + DoNothing, DoNothing);
> +}
> +
> +
> +
> +
> +//===----------------------------------------------------------------------===//
> +// Summary creation for Selectors.
> +//===----------------------------------------------------------------------===//
> +
> +Optional<RetEffect>
> +RetainSummaryManager::getRetEffectFromAnnotations(QualType RetTy,
> + const Decl *D) {
> + if (cocoa::isCocoaObjectRef(RetTy)) {
> + if (D->hasAttr<NSReturnsRetainedAttr>())
> + return ObjCAllocRetE;
> +
> + if (D->hasAttr<NSReturnsNotRetainedAttr>() ||
> + D->hasAttr<NSReturnsAutoreleasedAttr>())
> + return RetEffect::MakeNotOwned(RetEffect::ObjC);
> +
> + } else if (!RetTy->isPointerType()) {
> + return None;
> + }
> +
> + if (D->hasAttr<CFReturnsRetainedAttr>())
> + return RetEffect::MakeOwned(RetEffect::CF);
> + else if (hasRCAnnotation(D, "rc_ownership_returns_retained"))
> + return RetEffect::MakeOwned(RetEffect::Generalized);
> +
> + if (D->hasAttr<CFReturnsNotRetainedAttr>())
> + return RetEffect::MakeNotOwned(RetEffect::CF);
> +
> + return None;
> +}
> +
> +void
> +RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ,
> + const FunctionDecl *FD) {
> + if (!FD)
> + return;
> +
> + assert(Summ && "Must have a summary to add annotations to.");
> + RetainSummaryTemplate Template(Summ, *this);
> +
> + // Effects on the parameters.
> + unsigned parm_idx = 0;
> + for (FunctionDecl::param_const_iterator pi = FD->param_begin(),
> + pe = FD->param_end(); pi != pe; ++pi, ++parm_idx) {
> + const ParmVarDecl *pd = *pi;
> + if (pd->hasAttr<NSConsumedAttr>())
> + Template->addArg(AF, parm_idx, DecRefMsg);
> + else if (pd->hasAttr<CFConsumedAttr>() ||
> + hasRCAnnotation(pd, "rc_ownership_consumed"))
> + Template->addArg(AF, parm_idx, DecRef);
> + else if (pd->hasAttr<CFReturnsRetainedAttr>() ||
> + hasRCAnnotation(pd, "rc_ownership_returns_retained")) {
> + QualType PointeeTy = pd->getType()->getPointeeType();
> + if (!PointeeTy.isNull())
> + if (coreFoundation::isCFObjectRef(PointeeTy))
> + Template->addArg(AF, parm_idx, RetainedOutParameter);
> + } else if (pd->hasAttr<CFReturnsNotRetainedAttr>()) {
> + QualType PointeeTy = pd->getType()->getPointeeType();
> + if (!PointeeTy.isNull())
> + if (coreFoundation::isCFObjectRef(PointeeTy))
> + Template->addArg(AF, parm_idx, UnretainedOutParameter);
> + }
> + }
> +
> + QualType RetTy = FD->getReturnType();
> + if (Optional<RetEffect> RetE = getRetEffectFromAnnotations(RetTy, FD))
> + Template->setRetEffect(*RetE);
> +}
> +
> +void
> +RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ,
> + const ObjCMethodDecl *MD) {
> + if (!MD)
> + return;
> +
> + assert(Summ && "Must have a valid summary to add annotations to");
> + RetainSummaryTemplate Template(Summ, *this);
> +
> + // Effects on the receiver.
> + if (MD->hasAttr<NSConsumesSelfAttr>())
> + Template->setReceiverEffect(DecRefMsg);
> +
> + // Effects on the parameters.
> + unsigned parm_idx = 0;
> + for (ObjCMethodDecl::param_const_iterator
> + pi=MD->param_begin(), pe=MD->param_end();
> + pi != pe; ++pi, ++parm_idx) {
> + const ParmVarDecl *pd = *pi;
> + if (pd->hasAttr<NSConsumedAttr>())
> + Template->addArg(AF, parm_idx, DecRefMsg);
> + else if (pd->hasAttr<CFConsumedAttr>()) {
> + Template->addArg(AF, parm_idx, DecRef);
> + } else if (pd->hasAttr<CFReturnsRetainedAttr>()) {
> + QualType PointeeTy = pd->getType()->getPointeeType();
> + if (!PointeeTy.isNull())
> + if (coreFoundation::isCFObjectRef(PointeeTy))
> + Template->addArg(AF, parm_idx, RetainedOutParameter);
> + } else if (pd->hasAttr<CFReturnsNotRetainedAttr>()) {
> + QualType PointeeTy = pd->getType()->getPointeeType();
> + if (!PointeeTy.isNull())
> + if (coreFoundation::isCFObjectRef(PointeeTy))
> + Template->addArg(AF, parm_idx, UnretainedOutParameter);
> + }
> + }
> +
> + QualType RetTy = MD->getReturnType();
> + if (Optional<RetEffect> RetE = getRetEffectFromAnnotations(RetTy, MD))
> + Template->setRetEffect(*RetE);
> +}
> +
> +const RetainSummary *
> +RetainSummaryManager::getStandardMethodSummary(const ObjCMethodDecl *MD,
> + Selector S, QualType RetTy) {
> + // Any special effects?
> + ArgEffect ReceiverEff = DoNothing;
> + RetEffect ResultEff = RetEffect::MakeNoRet();
> +
> + // Check the method family, and apply any default annotations.
> + switch (MD ? MD->getMethodFamily() : S.getMethodFamily()) {
> + case OMF_None:
> + case OMF_initialize:
> + case OMF_performSelector:
> + // Assume all Objective-C methods follow Cocoa Memory Management rules.
> + // FIXME: Does the non-threaded performSelector family really belong here?
> + // The selector could be, say, @selector(copy).
> + if (cocoa::isCocoaObjectRef(RetTy))
> + ResultEff = RetEffect::MakeNotOwned(RetEffect::ObjC);
> + else if (coreFoundation::isCFObjectRef(RetTy)) {
> + // ObjCMethodDecl currently doesn't consider CF objects as valid return
> + // values for alloc, new, copy, or mutableCopy, so we have to
> + // double-check with the selector. This is ugly, but there aren't that
> + // many Objective-C methods that return CF objects, right?
> + if (MD) {
> + switch (S.getMethodFamily()) {
> + case OMF_alloc:
> + case OMF_new:
> + case OMF_copy:
> + case OMF_mutableCopy:
> + ResultEff = RetEffect::MakeOwned(RetEffect::CF);
> + break;
> + default:
> + ResultEff = RetEffect::MakeNotOwned(RetEffect::CF);
> + break;
> + }
> + } else {
> + ResultEff = RetEffect::MakeNotOwned(RetEffect::CF);
> + }
> + }
> + break;
> + case OMF_init:
> + ResultEff = ObjCInitRetE;
> + ReceiverEff = DecRefMsg;
> + break;
> + case OMF_alloc:
> + case OMF_new:
> + case OMF_copy:
> + case OMF_mutableCopy:
> + if (cocoa::isCocoaObjectRef(RetTy))
> + ResultEff = ObjCAllocRetE;
> + else if (coreFoundation::isCFObjectRef(RetTy))
> + ResultEff = RetEffect::MakeOwned(RetEffect::CF);
> + break;
> + case OMF_autorelease:
> + ReceiverEff = Autorelease;
> + break;
> + case OMF_retain:
> + ReceiverEff = IncRefMsg;
> + break;
> + case OMF_release:
> + ReceiverEff = DecRefMsg;
> + break;
> + case OMF_dealloc:
> + ReceiverEff = Dealloc;
> + break;
> + case OMF_self:
> + // -self is handled specially by the ExprEngine to propagate the receiver.
> + break;
> + case OMF_retainCount:
> + case OMF_finalize:
> + // These methods don't return objects.
> + break;
> + }
> +
> + // If one of the arguments in the selector has the keyword 'delegate' we
> + // should stop tracking the reference count for the receiver. This is
> + // because the reference count is quite possibly handled by a delegate
> + // method.
> + if (S.isKeywordSelector()) {
> + for (unsigned i = 0, e = S.getNumArgs(); i != e; ++i) {
> + StringRef Slot = S.getNameForSlot(i);
> + if (Slot.substr(Slot.size() - 8).equals_lower("delegate")) {
> + if (ResultEff == ObjCInitRetE)
> + ResultEff = RetEffect::MakeNoRetHard();
> + else
> + ReceiverEff = StopTrackingHard;
> + }
> + }
> + }
> +
> + if (ScratchArgs.isEmpty() && ReceiverEff == DoNothing &&
> + ResultEff.getKind() == RetEffect::NoRet)
> + return getDefaultSummary();
> +
> + return getPersistentSummary(ResultEff, ReceiverEff, MayEscape);
> +}
> +
> +const RetainSummary *RetainSummaryManager::getInstanceMethodSummary(
> + const ObjCMethodCall &Msg, QualType ReceiverType) {
> + const ObjCInterfaceDecl *ReceiverClass = nullptr;
> +
> + // We do better tracking of the type of the object than the core ExprEngine.
> + // See if we have its type in our private state.
> + if (!ReceiverType.isNull())
> + if (const auto *PT = ReceiverType->getAs<ObjCObjectPointerType>())
> + ReceiverClass = PT->getInterfaceDecl();
> +
> + // If we don't know what kind of object this is, fall back to its static type.
> + if (!ReceiverClass)
> + ReceiverClass = Msg.getReceiverInterface();
> +
> + // FIXME: The receiver could be a reference to a class, meaning that
> + // we should use the class method.
> + // id x = [NSObject class];
> + // [x performSelector:... withObject:... afterDelay:...];
> + Selector S = Msg.getSelector();
> + const ObjCMethodDecl *Method = Msg.getDecl();
> + if (!Method && ReceiverClass)
> + Method = ReceiverClass->getInstanceMethod(S);
> +
> + return getMethodSummary(S, ReceiverClass, Method, Msg.getResultType(),
> + ObjCMethodSummaries);
> +}
> +
> +const RetainSummary *
> +RetainSummaryManager::getMethodSummary(Se
--
Bruno Cardoso Lopes
http://www.brunocardoso.cc
More information about the cfe-commits
mailing list