xref: /openbsd-src/gnu/llvm/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.h (revision ec727ea710c91afd8ce4f788c5aaa8482b7b69b2)
1e5dd7070Spatrick //==--- RetainCountChecker.h - Checks for leaks and other issues -*- C++ -*--//
2e5dd7070Spatrick //
3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5dd7070Spatrick //
7e5dd7070Spatrick //===----------------------------------------------------------------------===//
8e5dd7070Spatrick //
9e5dd7070Spatrick //  This file defines the methods for RetainCountChecker, which implements
10e5dd7070Spatrick //  a reference count checker for Core Foundation and Cocoa on (Mac OS X).
11e5dd7070Spatrick //
12e5dd7070Spatrick //===----------------------------------------------------------------------===//
13e5dd7070Spatrick 
14e5dd7070Spatrick #ifndef LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_RETAINCOUNTCHECKER_H
15e5dd7070Spatrick #define LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_RETAINCOUNTCHECKER_H
16e5dd7070Spatrick 
17e5dd7070Spatrick #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
18e5dd7070Spatrick #include "RetainCountDiagnostics.h"
19e5dd7070Spatrick #include "clang/AST/Attr.h"
20e5dd7070Spatrick #include "clang/AST/DeclCXX.h"
21e5dd7070Spatrick #include "clang/AST/DeclObjC.h"
22e5dd7070Spatrick #include "clang/AST/ParentMap.h"
23e5dd7070Spatrick #include "clang/Analysis/DomainSpecific/CocoaConventions.h"
24e5dd7070Spatrick #include "clang/Analysis/PathDiagnostic.h"
25e5dd7070Spatrick #include "clang/Analysis/RetainSummaryManager.h"
26e5dd7070Spatrick #include "clang/Basic/LangOptions.h"
27e5dd7070Spatrick #include "clang/Basic/SourceManager.h"
28e5dd7070Spatrick #include "clang/Analysis/SelectorExtras.h"
29e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
30e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/Checker.h"
31e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/CheckerManager.h"
32e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
33e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
34e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
35e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
36e5dd7070Spatrick #include "llvm/ADT/DenseMap.h"
37e5dd7070Spatrick #include "llvm/ADT/FoldingSet.h"
38e5dd7070Spatrick #include "llvm/ADT/ImmutableList.h"
39e5dd7070Spatrick #include "llvm/ADT/ImmutableMap.h"
40e5dd7070Spatrick #include "llvm/ADT/STLExtras.h"
41e5dd7070Spatrick #include "llvm/ADT/SmallString.h"
42e5dd7070Spatrick #include "llvm/ADT/StringExtras.h"
43e5dd7070Spatrick #include <cstdarg>
44e5dd7070Spatrick #include <utility>
45e5dd7070Spatrick 
46e5dd7070Spatrick namespace clang {
47e5dd7070Spatrick namespace ento {
48e5dd7070Spatrick namespace retaincountchecker {
49e5dd7070Spatrick 
50e5dd7070Spatrick /// Metadata on reference.
51e5dd7070Spatrick class RefVal {
52e5dd7070Spatrick public:
53e5dd7070Spatrick   enum Kind {
54e5dd7070Spatrick     Owned = 0, // Owning reference.
55e5dd7070Spatrick     NotOwned,  // Reference is not owned by still valid (not freed).
56e5dd7070Spatrick     Released,  // Object has been released.
57e5dd7070Spatrick     ReturnedOwned, // Returned object passes ownership to caller.
58e5dd7070Spatrick     ReturnedNotOwned, // Return object does not pass ownership to caller.
59e5dd7070Spatrick     ERROR_START,
60e5dd7070Spatrick     ErrorDeallocNotOwned, // -dealloc called on non-owned object.
61e5dd7070Spatrick     ErrorUseAfterRelease, // Object used after released.
62e5dd7070Spatrick     ErrorReleaseNotOwned, // Release of an object that was not owned.
63e5dd7070Spatrick     ERROR_LEAK_START,
64e5dd7070Spatrick     ErrorLeak,  // A memory leak due to excessive reference counts.
65e5dd7070Spatrick     ErrorLeakReturned, // A memory leak due to the returning method not having
66e5dd7070Spatrick                        // the correct naming conventions.
67e5dd7070Spatrick     ErrorOverAutorelease,
68e5dd7070Spatrick     ErrorReturnedNotOwned
69e5dd7070Spatrick   };
70e5dd7070Spatrick 
71e5dd7070Spatrick   /// Tracks how an object referenced by an ivar has been used.
72e5dd7070Spatrick   ///
73e5dd7070Spatrick   /// This accounts for us not knowing if an arbitrary ivar is supposed to be
74e5dd7070Spatrick   /// stored at +0 or +1.
75e5dd7070Spatrick   enum class IvarAccessHistory {
76e5dd7070Spatrick     None,
77e5dd7070Spatrick     AccessedDirectly,
78e5dd7070Spatrick     ReleasedAfterDirectAccess
79e5dd7070Spatrick   };
80e5dd7070Spatrick 
81e5dd7070Spatrick private:
82e5dd7070Spatrick   /// The number of outstanding retains.
83e5dd7070Spatrick   unsigned Cnt;
84e5dd7070Spatrick   /// The number of outstanding autoreleases.
85e5dd7070Spatrick   unsigned ACnt;
86e5dd7070Spatrick   /// The (static) type of the object at the time we started tracking it.
87e5dd7070Spatrick   QualType T;
88e5dd7070Spatrick 
89e5dd7070Spatrick   /// The current state of the object.
90e5dd7070Spatrick   ///
91e5dd7070Spatrick   /// See the RefVal::Kind enum for possible values.
92e5dd7070Spatrick   unsigned RawKind : 5;
93e5dd7070Spatrick 
94e5dd7070Spatrick   /// The kind of object being tracked (CF or ObjC or OSObject), if known.
95e5dd7070Spatrick   ///
96e5dd7070Spatrick   /// See the ObjKind enum for possible values.
97e5dd7070Spatrick   unsigned RawObjectKind : 3;
98e5dd7070Spatrick 
99e5dd7070Spatrick   /// True if the current state and/or retain count may turn out to not be the
100e5dd7070Spatrick   /// best possible approximation of the reference counting state.
101e5dd7070Spatrick   ///
102e5dd7070Spatrick   /// If true, the checker may decide to throw away ("override") this state
103e5dd7070Spatrick   /// in favor of something else when it sees the object being used in new ways.
104e5dd7070Spatrick   ///
105e5dd7070Spatrick   /// This setting should not be propagated to state derived from this state.
106e5dd7070Spatrick   /// Once we start deriving new states, it would be inconsistent to override
107e5dd7070Spatrick   /// them.
108e5dd7070Spatrick   unsigned RawIvarAccessHistory : 2;
109e5dd7070Spatrick 
RefVal(Kind k,ObjKind o,unsigned cnt,unsigned acnt,QualType t,IvarAccessHistory IvarAccess)110e5dd7070Spatrick   RefVal(Kind k, ObjKind o, unsigned cnt, unsigned acnt, QualType t,
111e5dd7070Spatrick          IvarAccessHistory IvarAccess)
112e5dd7070Spatrick     : Cnt(cnt), ACnt(acnt), T(t), RawKind(static_cast<unsigned>(k)),
113e5dd7070Spatrick       RawObjectKind(static_cast<unsigned>(o)),
114e5dd7070Spatrick       RawIvarAccessHistory(static_cast<unsigned>(IvarAccess)) {
115e5dd7070Spatrick     assert(getKind() == k && "not enough bits for the kind");
116e5dd7070Spatrick     assert(getObjKind() == o && "not enough bits for the object kind");
117e5dd7070Spatrick     assert(getIvarAccessHistory() == IvarAccess && "not enough bits");
118e5dd7070Spatrick   }
119e5dd7070Spatrick 
120e5dd7070Spatrick public:
getKind()121e5dd7070Spatrick   Kind getKind() const { return static_cast<Kind>(RawKind); }
122e5dd7070Spatrick 
getObjKind()123e5dd7070Spatrick   ObjKind getObjKind() const {
124e5dd7070Spatrick     return static_cast<ObjKind>(RawObjectKind);
125e5dd7070Spatrick   }
126e5dd7070Spatrick 
getCount()127e5dd7070Spatrick   unsigned getCount() const { return Cnt; }
getAutoreleaseCount()128e5dd7070Spatrick   unsigned getAutoreleaseCount() const { return ACnt; }
getCombinedCounts()129e5dd7070Spatrick   unsigned getCombinedCounts() const { return Cnt + ACnt; }
clearCounts()130e5dd7070Spatrick   void clearCounts() {
131e5dd7070Spatrick     Cnt = 0;
132e5dd7070Spatrick     ACnt = 0;
133e5dd7070Spatrick   }
setCount(unsigned i)134e5dd7070Spatrick   void setCount(unsigned i) {
135e5dd7070Spatrick     Cnt = i;
136e5dd7070Spatrick   }
setAutoreleaseCount(unsigned i)137e5dd7070Spatrick   void setAutoreleaseCount(unsigned i) {
138e5dd7070Spatrick     ACnt = i;
139e5dd7070Spatrick   }
140e5dd7070Spatrick 
getType()141e5dd7070Spatrick   QualType getType() const { return T; }
142e5dd7070Spatrick 
143e5dd7070Spatrick   /// Returns what the analyzer knows about direct accesses to a particular
144e5dd7070Spatrick   /// instance variable.
145e5dd7070Spatrick   ///
146e5dd7070Spatrick   /// If the object with this refcount wasn't originally from an Objective-C
147e5dd7070Spatrick   /// ivar region, this should always return IvarAccessHistory::None.
getIvarAccessHistory()148e5dd7070Spatrick   IvarAccessHistory getIvarAccessHistory() const {
149e5dd7070Spatrick     return static_cast<IvarAccessHistory>(RawIvarAccessHistory);
150e5dd7070Spatrick   }
151e5dd7070Spatrick 
isOwned()152e5dd7070Spatrick   bool isOwned() const {
153e5dd7070Spatrick     return getKind() == Owned;
154e5dd7070Spatrick   }
155e5dd7070Spatrick 
isNotOwned()156e5dd7070Spatrick   bool isNotOwned() const {
157e5dd7070Spatrick     return getKind() == NotOwned;
158e5dd7070Spatrick   }
159e5dd7070Spatrick 
isReturnedOwned()160e5dd7070Spatrick   bool isReturnedOwned() const {
161e5dd7070Spatrick     return getKind() == ReturnedOwned;
162e5dd7070Spatrick   }
163e5dd7070Spatrick 
isReturnedNotOwned()164e5dd7070Spatrick   bool isReturnedNotOwned() const {
165e5dd7070Spatrick     return getKind() == ReturnedNotOwned;
166e5dd7070Spatrick   }
167e5dd7070Spatrick 
168e5dd7070Spatrick   /// Create a state for an object whose lifetime is the responsibility of the
169e5dd7070Spatrick   /// current function, at least partially.
170e5dd7070Spatrick   ///
171e5dd7070Spatrick   /// Most commonly, this is an owned object with a retain count of +1.
makeOwned(ObjKind o,QualType t)172e5dd7070Spatrick   static RefVal makeOwned(ObjKind o, QualType t) {
173e5dd7070Spatrick     return RefVal(Owned, o, /*Count=*/1, 0, t, IvarAccessHistory::None);
174e5dd7070Spatrick   }
175e5dd7070Spatrick 
176e5dd7070Spatrick   /// Create a state for an object whose lifetime is not the responsibility of
177e5dd7070Spatrick   /// the current function.
178e5dd7070Spatrick   ///
179e5dd7070Spatrick   /// Most commonly, this is an unowned object with a retain count of +0.
makeNotOwned(ObjKind o,QualType t)180e5dd7070Spatrick   static RefVal makeNotOwned(ObjKind o, QualType t) {
181e5dd7070Spatrick     return RefVal(NotOwned, o, /*Count=*/0, 0, t, IvarAccessHistory::None);
182e5dd7070Spatrick   }
183e5dd7070Spatrick 
184e5dd7070Spatrick   RefVal operator-(size_t i) const {
185e5dd7070Spatrick     return RefVal(getKind(), getObjKind(), getCount() - i,
186e5dd7070Spatrick                   getAutoreleaseCount(), getType(), getIvarAccessHistory());
187e5dd7070Spatrick   }
188e5dd7070Spatrick 
189e5dd7070Spatrick   RefVal operator+(size_t i) const {
190e5dd7070Spatrick     return RefVal(getKind(), getObjKind(), getCount() + i,
191e5dd7070Spatrick                   getAutoreleaseCount(), getType(), getIvarAccessHistory());
192e5dd7070Spatrick   }
193e5dd7070Spatrick 
194e5dd7070Spatrick   RefVal operator^(Kind k) const {
195e5dd7070Spatrick     return RefVal(k, getObjKind(), getCount(), getAutoreleaseCount(),
196e5dd7070Spatrick                   getType(), getIvarAccessHistory());
197e5dd7070Spatrick   }
198e5dd7070Spatrick 
autorelease()199e5dd7070Spatrick   RefVal autorelease() const {
200e5dd7070Spatrick     return RefVal(getKind(), getObjKind(), getCount(), getAutoreleaseCount()+1,
201e5dd7070Spatrick                   getType(), getIvarAccessHistory());
202e5dd7070Spatrick   }
203e5dd7070Spatrick 
withIvarAccess()204e5dd7070Spatrick   RefVal withIvarAccess() const {
205e5dd7070Spatrick     assert(getIvarAccessHistory() == IvarAccessHistory::None);
206e5dd7070Spatrick     return RefVal(getKind(), getObjKind(), getCount(), getAutoreleaseCount(),
207e5dd7070Spatrick                   getType(), IvarAccessHistory::AccessedDirectly);
208e5dd7070Spatrick   }
209e5dd7070Spatrick 
releaseViaIvar()210e5dd7070Spatrick   RefVal releaseViaIvar() const {
211e5dd7070Spatrick     assert(getIvarAccessHistory() == IvarAccessHistory::AccessedDirectly);
212e5dd7070Spatrick     return RefVal(getKind(), getObjKind(), getCount(), getAutoreleaseCount(),
213e5dd7070Spatrick                   getType(), IvarAccessHistory::ReleasedAfterDirectAccess);
214e5dd7070Spatrick   }
215e5dd7070Spatrick 
216e5dd7070Spatrick   // Comparison, profiling, and pretty-printing.
hasSameState(const RefVal & X)217e5dd7070Spatrick   bool hasSameState(const RefVal &X) const {
218e5dd7070Spatrick     return getKind() == X.getKind() && Cnt == X.Cnt && ACnt == X.ACnt &&
219e5dd7070Spatrick            getIvarAccessHistory() == X.getIvarAccessHistory();
220e5dd7070Spatrick   }
221e5dd7070Spatrick 
222e5dd7070Spatrick   bool operator==(const RefVal& X) const {
223e5dd7070Spatrick     return T == X.T && hasSameState(X) && getObjKind() == X.getObjKind();
224e5dd7070Spatrick   }
225e5dd7070Spatrick 
Profile(llvm::FoldingSetNodeID & ID)226e5dd7070Spatrick   void Profile(llvm::FoldingSetNodeID& ID) const {
227e5dd7070Spatrick     ID.Add(T);
228e5dd7070Spatrick     ID.AddInteger(RawKind);
229e5dd7070Spatrick     ID.AddInteger(Cnt);
230e5dd7070Spatrick     ID.AddInteger(ACnt);
231e5dd7070Spatrick     ID.AddInteger(RawObjectKind);
232e5dd7070Spatrick     ID.AddInteger(RawIvarAccessHistory);
233e5dd7070Spatrick   }
234e5dd7070Spatrick 
235e5dd7070Spatrick   void print(raw_ostream &Out) const;
236e5dd7070Spatrick };
237e5dd7070Spatrick 
238e5dd7070Spatrick class RetainCountChecker
239e5dd7070Spatrick   : public Checker< check::Bind,
240e5dd7070Spatrick                     check::DeadSymbols,
241e5dd7070Spatrick                     check::BeginFunction,
242e5dd7070Spatrick                     check::EndFunction,
243e5dd7070Spatrick                     check::PostStmt<BlockExpr>,
244e5dd7070Spatrick                     check::PostStmt<CastExpr>,
245e5dd7070Spatrick                     check::PostStmt<ObjCArrayLiteral>,
246e5dd7070Spatrick                     check::PostStmt<ObjCDictionaryLiteral>,
247e5dd7070Spatrick                     check::PostStmt<ObjCBoxedExpr>,
248e5dd7070Spatrick                     check::PostStmt<ObjCIvarRefExpr>,
249e5dd7070Spatrick                     check::PostCall,
250e5dd7070Spatrick                     check::RegionChanges,
251e5dd7070Spatrick                     eval::Assume,
252e5dd7070Spatrick                     eval::Call > {
253e5dd7070Spatrick 
254*ec727ea7Spatrick public:
255*ec727ea7Spatrick   std::unique_ptr<RefCountBug> UseAfterRelease;
256*ec727ea7Spatrick   std::unique_ptr<RefCountBug> ReleaseNotOwned;
257*ec727ea7Spatrick   std::unique_ptr<RefCountBug> DeallocNotOwned;
258*ec727ea7Spatrick   std::unique_ptr<RefCountBug> FreeNotOwned;
259*ec727ea7Spatrick   std::unique_ptr<RefCountBug> OverAutorelease;
260*ec727ea7Spatrick   std::unique_ptr<RefCountBug> ReturnNotOwnedForOwned;
261*ec727ea7Spatrick   std::unique_ptr<RefCountBug> LeakWithinFunction;
262*ec727ea7Spatrick   std::unique_ptr<RefCountBug> LeakAtReturn;
263e5dd7070Spatrick 
264e5dd7070Spatrick   mutable std::unique_ptr<RetainSummaryManager> Summaries;
265*ec727ea7Spatrick 
266*ec727ea7Spatrick   static std::unique_ptr<CheckerProgramPointTag> DeallocSentTag;
267*ec727ea7Spatrick   static std::unique_ptr<CheckerProgramPointTag> CastFailTag;
268e5dd7070Spatrick 
269e5dd7070Spatrick   /// Track Objective-C and CoreFoundation objects.
270e5dd7070Spatrick   bool TrackObjCAndCFObjects = false;
271e5dd7070Spatrick 
272e5dd7070Spatrick   /// Track sublcasses of OSObject.
273e5dd7070Spatrick   bool TrackOSObjects = false;
274e5dd7070Spatrick 
275e5dd7070Spatrick   /// Track initial parameters (for the entry point) for NS/CF objects.
276e5dd7070Spatrick   bool TrackNSCFStartParam = false;
277e5dd7070Spatrick 
RetainCountChecker()278e5dd7070Spatrick   RetainCountChecker() {};
279e5dd7070Spatrick 
getSummaryManager(ASTContext & Ctx)280e5dd7070Spatrick   RetainSummaryManager &getSummaryManager(ASTContext &Ctx) const {
281e5dd7070Spatrick     if (!Summaries)
282e5dd7070Spatrick       Summaries.reset(
283e5dd7070Spatrick           new RetainSummaryManager(Ctx, TrackObjCAndCFObjects, TrackOSObjects));
284e5dd7070Spatrick     return *Summaries;
285e5dd7070Spatrick   }
286e5dd7070Spatrick 
getSummaryManager(CheckerContext & C)287e5dd7070Spatrick   RetainSummaryManager &getSummaryManager(CheckerContext &C) const {
288e5dd7070Spatrick     return getSummaryManager(C.getASTContext());
289e5dd7070Spatrick   }
290e5dd7070Spatrick 
291e5dd7070Spatrick   void printState(raw_ostream &Out, ProgramStateRef State,
292e5dd7070Spatrick                   const char *NL, const char *Sep) const override;
293e5dd7070Spatrick 
294e5dd7070Spatrick   void checkBind(SVal loc, SVal val, const Stmt *S, CheckerContext &C) const;
295e5dd7070Spatrick   void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const;
296e5dd7070Spatrick   void checkPostStmt(const CastExpr *CE, CheckerContext &C) const;
297e5dd7070Spatrick 
298e5dd7070Spatrick   void checkPostStmt(const ObjCArrayLiteral *AL, CheckerContext &C) const;
299e5dd7070Spatrick   void checkPostStmt(const ObjCDictionaryLiteral *DL, CheckerContext &C) const;
300e5dd7070Spatrick   void checkPostStmt(const ObjCBoxedExpr *BE, CheckerContext &C) const;
301e5dd7070Spatrick 
302e5dd7070Spatrick   void checkPostStmt(const ObjCIvarRefExpr *IRE, CheckerContext &C) const;
303e5dd7070Spatrick 
304e5dd7070Spatrick   void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
305e5dd7070Spatrick 
306e5dd7070Spatrick   void checkSummary(const RetainSummary &Summ, const CallEvent &Call,
307e5dd7070Spatrick                     CheckerContext &C) const;
308e5dd7070Spatrick 
309e5dd7070Spatrick   void processSummaryOfInlined(const RetainSummary &Summ,
310e5dd7070Spatrick                                const CallEvent &Call,
311e5dd7070Spatrick                                CheckerContext &C) const;
312e5dd7070Spatrick 
313e5dd7070Spatrick   bool evalCall(const CallEvent &Call, CheckerContext &C) const;
314e5dd7070Spatrick 
315e5dd7070Spatrick   ProgramStateRef evalAssume(ProgramStateRef state, SVal Cond,
316e5dd7070Spatrick                                  bool Assumption) const;
317e5dd7070Spatrick 
318e5dd7070Spatrick   ProgramStateRef
319e5dd7070Spatrick   checkRegionChanges(ProgramStateRef state,
320e5dd7070Spatrick                      const InvalidatedSymbols *invalidated,
321e5dd7070Spatrick                      ArrayRef<const MemRegion *> ExplicitRegions,
322e5dd7070Spatrick                      ArrayRef<const MemRegion *> Regions,
323e5dd7070Spatrick                      const LocationContext* LCtx,
324e5dd7070Spatrick                      const CallEvent *Call) const;
325e5dd7070Spatrick 
326e5dd7070Spatrick   ExplodedNode* checkReturnWithRetEffect(const ReturnStmt *S, CheckerContext &C,
327e5dd7070Spatrick                                 ExplodedNode *Pred, RetEffect RE, RefVal X,
328e5dd7070Spatrick                                 SymbolRef Sym, ProgramStateRef state) const;
329e5dd7070Spatrick 
330e5dd7070Spatrick   void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
331e5dd7070Spatrick   void checkBeginFunction(CheckerContext &C) const;
332e5dd7070Spatrick   void checkEndFunction(const ReturnStmt *RS, CheckerContext &C) const;
333e5dd7070Spatrick 
334e5dd7070Spatrick   ProgramStateRef updateSymbol(ProgramStateRef state, SymbolRef sym,
335e5dd7070Spatrick                                RefVal V, ArgEffect E, RefVal::Kind &hasErr,
336e5dd7070Spatrick                                CheckerContext &C) const;
337e5dd7070Spatrick 
338e5dd7070Spatrick   const RefCountBug &errorKindToBugKind(RefVal::Kind ErrorKind,
339e5dd7070Spatrick                                         SymbolRef Sym) const;
340e5dd7070Spatrick 
341e5dd7070Spatrick   void processNonLeakError(ProgramStateRef St, SourceRange ErrorRange,
342e5dd7070Spatrick                            RefVal::Kind ErrorKind, SymbolRef Sym,
343e5dd7070Spatrick                            CheckerContext &C) const;
344e5dd7070Spatrick 
345e5dd7070Spatrick   void processObjCLiterals(CheckerContext &C, const Expr *Ex) const;
346e5dd7070Spatrick 
347e5dd7070Spatrick   ProgramStateRef handleSymbolDeath(ProgramStateRef state,
348e5dd7070Spatrick                                     SymbolRef sid, RefVal V,
349e5dd7070Spatrick                                     SmallVectorImpl<SymbolRef> &Leaked) const;
350e5dd7070Spatrick 
351e5dd7070Spatrick   ProgramStateRef
352e5dd7070Spatrick   handleAutoreleaseCounts(ProgramStateRef state, ExplodedNode *Pred,
353e5dd7070Spatrick                           const ProgramPointTag *Tag, CheckerContext &Ctx,
354e5dd7070Spatrick                           SymbolRef Sym,
355e5dd7070Spatrick                           RefVal V,
356e5dd7070Spatrick                           const ReturnStmt *S=nullptr) const;
357e5dd7070Spatrick 
358e5dd7070Spatrick   ExplodedNode *processLeaks(ProgramStateRef state,
359e5dd7070Spatrick                              SmallVectorImpl<SymbolRef> &Leaked,
360e5dd7070Spatrick                              CheckerContext &Ctx,
361e5dd7070Spatrick                              ExplodedNode *Pred = nullptr) const;
362e5dd7070Spatrick 
getDeallocSentTag()363*ec727ea7Spatrick   static const CheckerProgramPointTag &getDeallocSentTag() {
364*ec727ea7Spatrick     return *DeallocSentTag;
365e5dd7070Spatrick   }
366e5dd7070Spatrick 
getCastFailTag()367*ec727ea7Spatrick   static const CheckerProgramPointTag &getCastFailTag() { return *CastFailTag; }
368e5dd7070Spatrick 
369e5dd7070Spatrick private:
370e5dd7070Spatrick   /// Perform the necessary checks and state adjustments at the end of the
371e5dd7070Spatrick   /// function.
372e5dd7070Spatrick   /// \p S Return statement, may be null.
373e5dd7070Spatrick   ExplodedNode * processReturn(const ReturnStmt *S, CheckerContext &C) const;
374e5dd7070Spatrick };
375e5dd7070Spatrick 
376e5dd7070Spatrick //===----------------------------------------------------------------------===//
377e5dd7070Spatrick // RefBindings - State used to track object reference counts.
378e5dd7070Spatrick //===----------------------------------------------------------------------===//
379e5dd7070Spatrick 
380e5dd7070Spatrick const RefVal *getRefBinding(ProgramStateRef State, SymbolRef Sym);
381e5dd7070Spatrick 
382e5dd7070Spatrick /// Returns true if this stack frame is for an Objective-C method that is a
383e5dd7070Spatrick /// property getter or setter whose body has been synthesized by the analyzer.
isSynthesizedAccessor(const StackFrameContext * SFC)384e5dd7070Spatrick inline bool isSynthesizedAccessor(const StackFrameContext *SFC) {
385e5dd7070Spatrick   auto Method = dyn_cast_or_null<ObjCMethodDecl>(SFC->getDecl());
386e5dd7070Spatrick   if (!Method || !Method->isPropertyAccessor())
387e5dd7070Spatrick     return false;
388e5dd7070Spatrick 
389e5dd7070Spatrick   return SFC->getAnalysisDeclContext()->isBodyAutosynthesized();
390e5dd7070Spatrick }
391e5dd7070Spatrick 
392e5dd7070Spatrick } // end namespace retaincountchecker
393e5dd7070Spatrick } // end namespace ento
394e5dd7070Spatrick } // end namespace clang
395e5dd7070Spatrick 
396e5dd7070Spatrick #endif
397