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