1//==-- ObjCRetainCount.h - Retain count summaries for Cocoa -------*- C++ -*--//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10//  This file defines the core data structures for retain count "summaries"
11//  for Objective-C and Core Foundation APIs.  These summaries are used
12//  by the static analyzer to summarize the retain/release effects of
13//  function and method calls.  This drives a path-sensitive typestate
14//  analysis in the static analyzer, but can also potentially be used by
15//  other clients.
16//
17//===----------------------------------------------------------------------===//
18
19#ifndef LLVM_CLANG_STATICANALYZER_CHECKERS_OBJCRETAINCOUNT_H
20#define LLVM_CLANG_STATICANALYZER_CHECKERS_OBJCRETAINCOUNT_H
21
22#include "clang/Basic/LLVM.h"
23#include "llvm/ADT/ArrayRef.h"
24#include "llvm/ADT/SmallVector.h"
25
26namespace clang {
27class FunctionDecl;
28class ObjCMethodDecl;
29
30namespace ento { namespace objc_retain {
31
32/// An ArgEffect summarizes the retain count behavior on an argument or receiver
33/// to a function or method.
34enum ArgEffect {
35  /// There is no effect.
36  DoNothing,
37
38  /// The argument is treated as if an -autorelease message had been sent to
39  /// the referenced object.
40  Autorelease,
41
42  /// The argument is treated as if an -dealloc message had been sent to
43  /// the referenced object.
44  Dealloc,
45
46  /// The argument has its reference count decreased by 1.  This is as
47  /// if CFRelease has been called on the argument.
48  DecRef,
49
50  /// The argument has its reference count decreased by 1.  This is as
51  /// if a -release message has been sent to the argument.  This differs
52  /// in behavior from DecRef when GC is enabled.
53  DecRefMsg,
54
55  /// The argument has its reference count decreased by 1 to model
56  /// a transferred bridge cast under ARC.
57  DecRefBridgedTransferred,
58
59  /// The argument has its reference count increased by 1.  This is as
60  /// if a -retain message has been sent to the argument.  This differs
61  /// in behavior from IncRef when GC is enabled.
62  IncRefMsg,
63
64  /// The argument has its reference count increased by 1.  This is as
65  /// if CFRetain has been called on the argument.
66  IncRef,
67
68  /// The argument acts as if has been passed to CFMakeCollectable, which
69  /// transfers the object to the Garbage Collector under GC.
70  MakeCollectable,
71
72  /// The argument is a pointer to a retain-counted object; on exit, the new
73  /// value of the pointer is a +0 value or NULL.
74  UnretainedOutParameter,
75
76  /// The argument is a pointer to a retain-counted object; on exit, the new
77  /// value of the pointer is a +1 value or NULL.
78  RetainedOutParameter,
79
80  /// The argument is treated as potentially escaping, meaning that
81  /// even when its reference count hits 0 it should be treated as still
82  /// possibly being alive as someone else *may* be holding onto the object.
83  MayEscape,
84
85  /// All typestate tracking of the object ceases.  This is usually employed
86  /// when the effect of the call is completely unknown.
87  StopTracking,
88
89  /// All typestate tracking of the object ceases.  Unlike StopTracking,
90  /// this is also enforced when the method body is inlined.
91  ///
92  /// In some cases, we obtain a better summary for this checker
93  /// by looking at the call site than by inlining the function.
94  /// Signifies that we should stop tracking the symbol even if
95  /// the function is inlined.
96  StopTrackingHard,
97
98  /// Performs the combined functionality of DecRef and StopTrackingHard.
99  ///
100  /// The models the effect that the called function decrements the reference
101  /// count of the argument and all typestate tracking on that argument
102  /// should cease.
103  DecRefAndStopTrackingHard,
104
105  /// Performs the combined functionality of DecRefMsg and StopTrackingHard.
106  ///
107  /// The models the effect that the called function decrements the reference
108  /// count of the argument and all typestate tracking on that argument
109  /// should cease.
110  DecRefMsgAndStopTrackingHard
111};
112
113/// RetEffect summarizes a call's retain/release behavior with respect
114/// to its return value.
115class RetEffect {
116public:
117  enum Kind {
118    /// Indicates that no retain count information is tracked for
119    /// the return value.
120    NoRet,
121    /// Indicates that the returned value is an owned (+1) symbol.
122    OwnedSymbol,
123    /// Indicates that the returned value is an object with retain count
124    /// semantics but that it is not owned (+0).  This is the default
125    /// for getters, etc.
126    NotOwnedSymbol,
127    /// Indicates that the object is not owned and controlled by the
128    /// Garbage collector.
129    GCNotOwnedSymbol,
130    /// Indicates that the return value is an owned object when the
131    /// receiver is also a tracked object.
132    OwnedWhenTrackedReceiver,
133    // Treat this function as returning a non-tracked symbol even if
134    // the function has been inlined. This is used where the call
135    // site summary is more presise than the summary indirectly produced
136    // by inlining the function
137    NoRetHard
138  };
139
140  /// Determines the object kind of a tracked object.
141  enum ObjKind {
142    /// Indicates that the tracked object is a CF object.  This is
143    /// important between GC and non-GC code.
144    CF,
145    /// Indicates that the tracked object is an Objective-C object.
146    ObjC,
147    /// Indicates that the tracked object could be a CF or Objective-C object.
148    AnyObj
149  };
150
151private:
152  Kind K;
153  ObjKind O;
154
155  RetEffect(Kind k, ObjKind o = AnyObj) : K(k), O(o) {}
156
157public:
158  Kind getKind() const { return K; }
159
160  ObjKind getObjKind() const { return O; }
161
162  bool isOwned() const {
163    return K == OwnedSymbol || K == OwnedWhenTrackedReceiver;
164  }
165
166  bool notOwned() const {
167    return K == NotOwnedSymbol;
168  }
169
170  bool operator==(const RetEffect &Other) const {
171    return K == Other.K && O == Other.O;
172  }
173
174  static RetEffect MakeOwnedWhenTrackedReceiver() {
175    return RetEffect(OwnedWhenTrackedReceiver, ObjC);
176  }
177
178  static RetEffect MakeOwned(ObjKind o) {
179    return RetEffect(OwnedSymbol, o);
180  }
181  static RetEffect MakeNotOwned(ObjKind o) {
182    return RetEffect(NotOwnedSymbol, o);
183  }
184  static RetEffect MakeGCNotOwned() {
185    return RetEffect(GCNotOwnedSymbol, ObjC);
186  }
187  static RetEffect MakeNoRet() {
188    return RetEffect(NoRet);
189  }
190  static RetEffect MakeNoRetHard() {
191    return RetEffect(NoRetHard);
192  }
193};
194
195/// Encapsulates the retain count semantics on the arguments, return value,
196/// and receiver (if any) of a function/method call.
197///
198/// Note that construction of these objects is not highly efficient.  That
199/// is okay for clients where creating these objects isn't really a bottleneck.
200/// The purpose of the API is to provide something simple.  The actual
201/// static analyzer checker that implements retain/release typestate
202/// tracking uses something more efficient.
203class CallEffects {
204  llvm::SmallVector<ArgEffect, 10> Args;
205  RetEffect Ret;
206  ArgEffect Receiver;
207
208  CallEffects(const RetEffect &R) : Ret(R) {}
209
210public:
211  /// Returns the argument effects for a call.
212  ArrayRef<ArgEffect> getArgs() const { return Args; }
213
214  /// Returns the effects on the receiver.
215  ArgEffect getReceiver() const { return Receiver; }
216
217  /// Returns the effect on the return value.
218  RetEffect getReturnValue() const { return Ret; }
219
220  /// Return the CallEfect for a given Objective-C method.
221  static CallEffects getEffect(const ObjCMethodDecl *MD);
222
223  /// Return the CallEfect for a given C/C++ function.
224  static CallEffects getEffect(const FunctionDecl *FD);
225};
226
227}}}
228
229#endif
230
231