r340114 - [analyzer] [NFC] Split up RetainSummaryManager from RetainCountChecker
George Karpenkov via cfe-commits
cfe-commits at lists.llvm.org
Tue Aug 21 11:55:58 PDT 2018
Apologies! I’m really confused now how was it able to build without modules at all.
> On Aug 17, 2018, at 8:24 PM, Bruno Cardoso Lopes <bruno.cardoso at gmail.com> wrote:
>
> 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 <mailto: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 <http://www.brunocardoso.cc/>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20180821/a69f2075/attachment-0001.html>
More information about the cfe-commits
mailing list