| //==-- 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_OBJCRETAINCOUNT_H |
| #define LLVM_CLANG_OBJCRETAINCOUNT_H |
| |
| namespace clang { 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, |
| |
| /// The argument acts as if has been passed to CFMakeCollectable, which |
| /// transfers the object to the Garbage Collector under GC. |
| MakeCollectable, |
| |
| /// 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 owned (+1) symbol and |
| /// that it should be treated as freshly allocated. |
| OwnedAllocatedSymbol, |
| /// 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 |
| }; |
| |
| 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 == OwnedAllocatedSymbol || |
| 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, bool isAllocated = false) { |
| return RetEffect(isAllocated ? OwnedAllocatedSymbol : 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. |
| llvm::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 |
| |