10b57cec5SDimitry Andric //==--- RetainCountChecker.h - Checks for leaks and other issues -*- C++ -*--//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric //  This file defines the methods for RetainCountChecker, which implements
100b57cec5SDimitry Andric //  a reference count checker for Core Foundation and Cocoa on (Mac OS X).
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #ifndef LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_RETAINCOUNTCHECKER_H
150b57cec5SDimitry Andric #define LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_RETAINCOUNTCHECKER_H
160b57cec5SDimitry Andric 
170b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
180b57cec5SDimitry Andric #include "RetainCountDiagnostics.h"
190b57cec5SDimitry Andric #include "clang/AST/Attr.h"
200b57cec5SDimitry Andric #include "clang/AST/DeclCXX.h"
210b57cec5SDimitry Andric #include "clang/AST/DeclObjC.h"
220b57cec5SDimitry Andric #include "clang/AST/ParentMap.h"
230b57cec5SDimitry Andric #include "clang/Analysis/DomainSpecific/CocoaConventions.h"
24a7dea167SDimitry Andric #include "clang/Analysis/PathDiagnostic.h"
250b57cec5SDimitry Andric #include "clang/Analysis/RetainSummaryManager.h"
260b57cec5SDimitry Andric #include "clang/Basic/LangOptions.h"
270b57cec5SDimitry Andric #include "clang/Basic/SourceManager.h"
280b57cec5SDimitry Andric #include "clang/Analysis/SelectorExtras.h"
290b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
300b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/Checker.h"
310b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/CheckerManager.h"
320b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
330b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
340b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
350b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
360b57cec5SDimitry Andric #include "llvm/ADT/DenseMap.h"
370b57cec5SDimitry Andric #include "llvm/ADT/FoldingSet.h"
380b57cec5SDimitry Andric #include "llvm/ADT/ImmutableList.h"
390b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h"
400b57cec5SDimitry Andric #include "llvm/ADT/SmallString.h"
410b57cec5SDimitry Andric #include "llvm/ADT/StringExtras.h"
420b57cec5SDimitry Andric #include <cstdarg>
430b57cec5SDimitry Andric #include <utility>
440b57cec5SDimitry Andric 
450b57cec5SDimitry Andric namespace clang {
460b57cec5SDimitry Andric namespace ento {
470b57cec5SDimitry Andric namespace retaincountchecker {
480b57cec5SDimitry Andric 
490b57cec5SDimitry Andric /// Metadata on reference.
500b57cec5SDimitry Andric class RefVal {
510b57cec5SDimitry Andric public:
520b57cec5SDimitry Andric   enum Kind {
530b57cec5SDimitry Andric     Owned = 0, // Owning reference.
540b57cec5SDimitry Andric     NotOwned,  // Reference is not owned by still valid (not freed).
550b57cec5SDimitry Andric     Released,  // Object has been released.
560b57cec5SDimitry Andric     ReturnedOwned, // Returned object passes ownership to caller.
570b57cec5SDimitry Andric     ReturnedNotOwned, // Return object does not pass ownership to caller.
580b57cec5SDimitry Andric     ERROR_START,
590b57cec5SDimitry Andric     ErrorDeallocNotOwned, // -dealloc called on non-owned object.
600b57cec5SDimitry Andric     ErrorUseAfterRelease, // Object used after released.
610b57cec5SDimitry Andric     ErrorReleaseNotOwned, // Release of an object that was not owned.
620b57cec5SDimitry Andric     ERROR_LEAK_START,
630b57cec5SDimitry Andric     ErrorLeak,  // A memory leak due to excessive reference counts.
640b57cec5SDimitry Andric     ErrorLeakReturned, // A memory leak due to the returning method not having
650b57cec5SDimitry Andric                        // the correct naming conventions.
660b57cec5SDimitry Andric     ErrorOverAutorelease,
670b57cec5SDimitry Andric     ErrorReturnedNotOwned
680b57cec5SDimitry Andric   };
690b57cec5SDimitry Andric 
700b57cec5SDimitry Andric   /// Tracks how an object referenced by an ivar has been used.
710b57cec5SDimitry Andric   ///
720b57cec5SDimitry Andric   /// This accounts for us not knowing if an arbitrary ivar is supposed to be
730b57cec5SDimitry Andric   /// stored at +0 or +1.
740b57cec5SDimitry Andric   enum class IvarAccessHistory {
750b57cec5SDimitry Andric     None,
760b57cec5SDimitry Andric     AccessedDirectly,
770b57cec5SDimitry Andric     ReleasedAfterDirectAccess
780b57cec5SDimitry Andric   };
790b57cec5SDimitry Andric 
800b57cec5SDimitry Andric private:
810b57cec5SDimitry Andric   /// The number of outstanding retains.
820b57cec5SDimitry Andric   unsigned Cnt;
830b57cec5SDimitry Andric   /// The number of outstanding autoreleases.
840b57cec5SDimitry Andric   unsigned ACnt;
850b57cec5SDimitry Andric   /// The (static) type of the object at the time we started tracking it.
860b57cec5SDimitry Andric   QualType T;
870b57cec5SDimitry Andric 
880b57cec5SDimitry Andric   /// The current state of the object.
890b57cec5SDimitry Andric   ///
900b57cec5SDimitry Andric   /// See the RefVal::Kind enum for possible values.
910b57cec5SDimitry Andric   unsigned RawKind : 5;
920b57cec5SDimitry Andric 
930b57cec5SDimitry Andric   /// The kind of object being tracked (CF or ObjC or OSObject), if known.
940b57cec5SDimitry Andric   ///
950b57cec5SDimitry Andric   /// See the ObjKind enum for possible values.
960b57cec5SDimitry Andric   unsigned RawObjectKind : 3;
970b57cec5SDimitry Andric 
980b57cec5SDimitry Andric   /// True if the current state and/or retain count may turn out to not be the
990b57cec5SDimitry Andric   /// best possible approximation of the reference counting state.
1000b57cec5SDimitry Andric   ///
1010b57cec5SDimitry Andric   /// If true, the checker may decide to throw away ("override") this state
1020b57cec5SDimitry Andric   /// in favor of something else when it sees the object being used in new ways.
1030b57cec5SDimitry Andric   ///
1040b57cec5SDimitry Andric   /// This setting should not be propagated to state derived from this state.
1050b57cec5SDimitry Andric   /// Once we start deriving new states, it would be inconsistent to override
1060b57cec5SDimitry Andric   /// them.
1070b57cec5SDimitry Andric   unsigned RawIvarAccessHistory : 2;
1080b57cec5SDimitry Andric 
1090b57cec5SDimitry Andric   RefVal(Kind k, ObjKind o, unsigned cnt, unsigned acnt, QualType t,
1100b57cec5SDimitry Andric          IvarAccessHistory IvarAccess)
1110b57cec5SDimitry Andric     : Cnt(cnt), ACnt(acnt), T(t), RawKind(static_cast<unsigned>(k)),
1120b57cec5SDimitry Andric       RawObjectKind(static_cast<unsigned>(o)),
1130b57cec5SDimitry Andric       RawIvarAccessHistory(static_cast<unsigned>(IvarAccess)) {
1140b57cec5SDimitry Andric     assert(getKind() == k && "not enough bits for the kind");
1150b57cec5SDimitry Andric     assert(getObjKind() == o && "not enough bits for the object kind");
1160b57cec5SDimitry Andric     assert(getIvarAccessHistory() == IvarAccess && "not enough bits");
1170b57cec5SDimitry Andric   }
1180b57cec5SDimitry Andric 
1190b57cec5SDimitry Andric public:
1200b57cec5SDimitry Andric   Kind getKind() const { return static_cast<Kind>(RawKind); }
1210b57cec5SDimitry Andric 
1220b57cec5SDimitry Andric   ObjKind getObjKind() const {
1230b57cec5SDimitry Andric     return static_cast<ObjKind>(RawObjectKind);
1240b57cec5SDimitry Andric   }
1250b57cec5SDimitry Andric 
1260b57cec5SDimitry Andric   unsigned getCount() const { return Cnt; }
1270b57cec5SDimitry Andric   unsigned getAutoreleaseCount() const { return ACnt; }
1280b57cec5SDimitry Andric   unsigned getCombinedCounts() const { return Cnt + ACnt; }
1290b57cec5SDimitry Andric   void clearCounts() {
1300b57cec5SDimitry Andric     Cnt = 0;
1310b57cec5SDimitry Andric     ACnt = 0;
1320b57cec5SDimitry Andric   }
1330b57cec5SDimitry Andric   void setCount(unsigned i) {
1340b57cec5SDimitry Andric     Cnt = i;
1350b57cec5SDimitry Andric   }
1360b57cec5SDimitry Andric   void setAutoreleaseCount(unsigned i) {
1370b57cec5SDimitry Andric     ACnt = i;
1380b57cec5SDimitry Andric   }
1390b57cec5SDimitry Andric 
1400b57cec5SDimitry Andric   QualType getType() const { return T; }
1410b57cec5SDimitry Andric 
1420b57cec5SDimitry Andric   /// Returns what the analyzer knows about direct accesses to a particular
1430b57cec5SDimitry Andric   /// instance variable.
1440b57cec5SDimitry Andric   ///
1450b57cec5SDimitry Andric   /// If the object with this refcount wasn't originally from an Objective-C
1460b57cec5SDimitry Andric   /// ivar region, this should always return IvarAccessHistory::None.
1470b57cec5SDimitry Andric   IvarAccessHistory getIvarAccessHistory() const {
1480b57cec5SDimitry Andric     return static_cast<IvarAccessHistory>(RawIvarAccessHistory);
1490b57cec5SDimitry Andric   }
1500b57cec5SDimitry Andric 
1510b57cec5SDimitry Andric   bool isOwned() const {
1520b57cec5SDimitry Andric     return getKind() == Owned;
1530b57cec5SDimitry Andric   }
1540b57cec5SDimitry Andric 
1550b57cec5SDimitry Andric   bool isNotOwned() const {
1560b57cec5SDimitry Andric     return getKind() == NotOwned;
1570b57cec5SDimitry Andric   }
1580b57cec5SDimitry Andric 
1590b57cec5SDimitry Andric   bool isReturnedOwned() const {
1600b57cec5SDimitry Andric     return getKind() == ReturnedOwned;
1610b57cec5SDimitry Andric   }
1620b57cec5SDimitry Andric 
1630b57cec5SDimitry Andric   bool isReturnedNotOwned() const {
1640b57cec5SDimitry Andric     return getKind() == ReturnedNotOwned;
1650b57cec5SDimitry Andric   }
1660b57cec5SDimitry Andric 
1670b57cec5SDimitry Andric   /// Create a state for an object whose lifetime is the responsibility of the
1680b57cec5SDimitry Andric   /// current function, at least partially.
1690b57cec5SDimitry Andric   ///
1700b57cec5SDimitry Andric   /// Most commonly, this is an owned object with a retain count of +1.
1710b57cec5SDimitry Andric   static RefVal makeOwned(ObjKind o, QualType t) {
1720b57cec5SDimitry Andric     return RefVal(Owned, o, /*Count=*/1, 0, t, IvarAccessHistory::None);
1730b57cec5SDimitry Andric   }
1740b57cec5SDimitry Andric 
1750b57cec5SDimitry Andric   /// Create a state for an object whose lifetime is not the responsibility of
1760b57cec5SDimitry Andric   /// the current function.
1770b57cec5SDimitry Andric   ///
1780b57cec5SDimitry Andric   /// Most commonly, this is an unowned object with a retain count of +0.
1790b57cec5SDimitry Andric   static RefVal makeNotOwned(ObjKind o, QualType t) {
1800b57cec5SDimitry Andric     return RefVal(NotOwned, o, /*Count=*/0, 0, t, IvarAccessHistory::None);
1810b57cec5SDimitry Andric   }
1820b57cec5SDimitry Andric 
1830b57cec5SDimitry Andric   RefVal operator-(size_t i) const {
1840b57cec5SDimitry Andric     return RefVal(getKind(), getObjKind(), getCount() - i,
1850b57cec5SDimitry Andric                   getAutoreleaseCount(), getType(), getIvarAccessHistory());
1860b57cec5SDimitry Andric   }
1870b57cec5SDimitry Andric 
1880b57cec5SDimitry Andric   RefVal operator+(size_t i) const {
1890b57cec5SDimitry Andric     return RefVal(getKind(), getObjKind(), getCount() + i,
1900b57cec5SDimitry Andric                   getAutoreleaseCount(), getType(), getIvarAccessHistory());
1910b57cec5SDimitry Andric   }
1920b57cec5SDimitry Andric 
1930b57cec5SDimitry Andric   RefVal operator^(Kind k) const {
1940b57cec5SDimitry Andric     return RefVal(k, getObjKind(), getCount(), getAutoreleaseCount(),
1950b57cec5SDimitry Andric                   getType(), getIvarAccessHistory());
1960b57cec5SDimitry Andric   }
1970b57cec5SDimitry Andric 
1980b57cec5SDimitry Andric   RefVal autorelease() const {
1990b57cec5SDimitry Andric     return RefVal(getKind(), getObjKind(), getCount(), getAutoreleaseCount()+1,
2000b57cec5SDimitry Andric                   getType(), getIvarAccessHistory());
2010b57cec5SDimitry Andric   }
2020b57cec5SDimitry Andric 
2030b57cec5SDimitry Andric   RefVal withIvarAccess() const {
2040b57cec5SDimitry Andric     assert(getIvarAccessHistory() == IvarAccessHistory::None);
2050b57cec5SDimitry Andric     return RefVal(getKind(), getObjKind(), getCount(), getAutoreleaseCount(),
2060b57cec5SDimitry Andric                   getType(), IvarAccessHistory::AccessedDirectly);
2070b57cec5SDimitry Andric   }
2080b57cec5SDimitry Andric 
2090b57cec5SDimitry Andric   RefVal releaseViaIvar() const {
2100b57cec5SDimitry Andric     assert(getIvarAccessHistory() == IvarAccessHistory::AccessedDirectly);
2110b57cec5SDimitry Andric     return RefVal(getKind(), getObjKind(), getCount(), getAutoreleaseCount(),
2120b57cec5SDimitry Andric                   getType(), IvarAccessHistory::ReleasedAfterDirectAccess);
2130b57cec5SDimitry Andric   }
2140b57cec5SDimitry Andric 
2150b57cec5SDimitry Andric   // Comparison, profiling, and pretty-printing.
2160b57cec5SDimitry Andric   bool hasSameState(const RefVal &X) const {
2170b57cec5SDimitry Andric     return getKind() == X.getKind() && Cnt == X.Cnt && ACnt == X.ACnt &&
2180b57cec5SDimitry Andric            getIvarAccessHistory() == X.getIvarAccessHistory();
2190b57cec5SDimitry Andric   }
2200b57cec5SDimitry Andric 
2210b57cec5SDimitry Andric   bool operator==(const RefVal& X) const {
2220b57cec5SDimitry Andric     return T == X.T && hasSameState(X) && getObjKind() == X.getObjKind();
2230b57cec5SDimitry Andric   }
2240b57cec5SDimitry Andric 
2250b57cec5SDimitry Andric   void Profile(llvm::FoldingSetNodeID& ID) const {
2260b57cec5SDimitry Andric     ID.Add(T);
2270b57cec5SDimitry Andric     ID.AddInteger(RawKind);
2280b57cec5SDimitry Andric     ID.AddInteger(Cnt);
2290b57cec5SDimitry Andric     ID.AddInteger(ACnt);
2300b57cec5SDimitry Andric     ID.AddInteger(RawObjectKind);
2310b57cec5SDimitry Andric     ID.AddInteger(RawIvarAccessHistory);
2320b57cec5SDimitry Andric   }
2330b57cec5SDimitry Andric 
2340b57cec5SDimitry Andric   void print(raw_ostream &Out) const;
2350b57cec5SDimitry Andric };
2360b57cec5SDimitry Andric 
2370b57cec5SDimitry Andric class RetainCountChecker
2380b57cec5SDimitry Andric   : public Checker< check::Bind,
2390b57cec5SDimitry Andric                     check::DeadSymbols,
2400b57cec5SDimitry Andric                     check::BeginFunction,
2410b57cec5SDimitry Andric                     check::EndFunction,
2420b57cec5SDimitry Andric                     check::PostStmt<BlockExpr>,
2430b57cec5SDimitry Andric                     check::PostStmt<CastExpr>,
2440b57cec5SDimitry Andric                     check::PostStmt<ObjCArrayLiteral>,
2450b57cec5SDimitry Andric                     check::PostStmt<ObjCDictionaryLiteral>,
2460b57cec5SDimitry Andric                     check::PostStmt<ObjCBoxedExpr>,
2470b57cec5SDimitry Andric                     check::PostStmt<ObjCIvarRefExpr>,
2480b57cec5SDimitry Andric                     check::PostCall,
2490b57cec5SDimitry Andric                     check::RegionChanges,
2500b57cec5SDimitry Andric                     eval::Assume,
2510b57cec5SDimitry Andric                     eval::Call > {
2520b57cec5SDimitry Andric 
253*5ffd83dbSDimitry Andric public:
254*5ffd83dbSDimitry Andric   std::unique_ptr<RefCountBug> UseAfterRelease;
255*5ffd83dbSDimitry Andric   std::unique_ptr<RefCountBug> ReleaseNotOwned;
256*5ffd83dbSDimitry Andric   std::unique_ptr<RefCountBug> DeallocNotOwned;
257*5ffd83dbSDimitry Andric   std::unique_ptr<RefCountBug> FreeNotOwned;
258*5ffd83dbSDimitry Andric   std::unique_ptr<RefCountBug> OverAutorelease;
259*5ffd83dbSDimitry Andric   std::unique_ptr<RefCountBug> ReturnNotOwnedForOwned;
260*5ffd83dbSDimitry Andric   std::unique_ptr<RefCountBug> LeakWithinFunction;
261*5ffd83dbSDimitry Andric   std::unique_ptr<RefCountBug> LeakAtReturn;
2620b57cec5SDimitry Andric 
2630b57cec5SDimitry Andric   mutable std::unique_ptr<RetainSummaryManager> Summaries;
264*5ffd83dbSDimitry Andric 
265*5ffd83dbSDimitry Andric   static std::unique_ptr<CheckerProgramPointTag> DeallocSentTag;
266*5ffd83dbSDimitry Andric   static std::unique_ptr<CheckerProgramPointTag> CastFailTag;
2670b57cec5SDimitry Andric 
2680b57cec5SDimitry Andric   /// Track Objective-C and CoreFoundation objects.
2690b57cec5SDimitry Andric   bool TrackObjCAndCFObjects = false;
2700b57cec5SDimitry Andric 
2710b57cec5SDimitry Andric   /// Track sublcasses of OSObject.
2720b57cec5SDimitry Andric   bool TrackOSObjects = false;
2730b57cec5SDimitry Andric 
2740b57cec5SDimitry Andric   /// Track initial parameters (for the entry point) for NS/CF objects.
2750b57cec5SDimitry Andric   bool TrackNSCFStartParam = false;
2760b57cec5SDimitry Andric 
2770b57cec5SDimitry Andric   RetainCountChecker() {};
2780b57cec5SDimitry Andric 
2790b57cec5SDimitry Andric   RetainSummaryManager &getSummaryManager(ASTContext &Ctx) const {
2800b57cec5SDimitry Andric     if (!Summaries)
2810b57cec5SDimitry Andric       Summaries.reset(
2820b57cec5SDimitry Andric           new RetainSummaryManager(Ctx, TrackObjCAndCFObjects, TrackOSObjects));
2830b57cec5SDimitry Andric     return *Summaries;
2840b57cec5SDimitry Andric   }
2850b57cec5SDimitry Andric 
2860b57cec5SDimitry Andric   RetainSummaryManager &getSummaryManager(CheckerContext &C) const {
2870b57cec5SDimitry Andric     return getSummaryManager(C.getASTContext());
2880b57cec5SDimitry Andric   }
2890b57cec5SDimitry Andric 
2900b57cec5SDimitry Andric   void printState(raw_ostream &Out, ProgramStateRef State,
2910b57cec5SDimitry Andric                   const char *NL, const char *Sep) const override;
2920b57cec5SDimitry Andric 
2930b57cec5SDimitry Andric   void checkBind(SVal loc, SVal val, const Stmt *S, CheckerContext &C) const;
2940b57cec5SDimitry Andric   void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const;
2950b57cec5SDimitry Andric   void checkPostStmt(const CastExpr *CE, CheckerContext &C) const;
2960b57cec5SDimitry Andric 
2970b57cec5SDimitry Andric   void checkPostStmt(const ObjCArrayLiteral *AL, CheckerContext &C) const;
2980b57cec5SDimitry Andric   void checkPostStmt(const ObjCDictionaryLiteral *DL, CheckerContext &C) const;
2990b57cec5SDimitry Andric   void checkPostStmt(const ObjCBoxedExpr *BE, CheckerContext &C) const;
3000b57cec5SDimitry Andric 
3010b57cec5SDimitry Andric   void checkPostStmt(const ObjCIvarRefExpr *IRE, CheckerContext &C) const;
3020b57cec5SDimitry Andric 
3030b57cec5SDimitry Andric   void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
3040b57cec5SDimitry Andric 
3050b57cec5SDimitry Andric   void checkSummary(const RetainSummary &Summ, const CallEvent &Call,
3060b57cec5SDimitry Andric                     CheckerContext &C) const;
3070b57cec5SDimitry Andric 
3080b57cec5SDimitry Andric   void processSummaryOfInlined(const RetainSummary &Summ,
3090b57cec5SDimitry Andric                                const CallEvent &Call,
3100b57cec5SDimitry Andric                                CheckerContext &C) const;
3110b57cec5SDimitry Andric 
3120b57cec5SDimitry Andric   bool evalCall(const CallEvent &Call, CheckerContext &C) const;
3130b57cec5SDimitry Andric 
3140b57cec5SDimitry Andric   ProgramStateRef evalAssume(ProgramStateRef state, SVal Cond,
3150b57cec5SDimitry Andric                                  bool Assumption) const;
3160b57cec5SDimitry Andric 
3170b57cec5SDimitry Andric   ProgramStateRef
3180b57cec5SDimitry Andric   checkRegionChanges(ProgramStateRef state,
3190b57cec5SDimitry Andric                      const InvalidatedSymbols *invalidated,
3200b57cec5SDimitry Andric                      ArrayRef<const MemRegion *> ExplicitRegions,
3210b57cec5SDimitry Andric                      ArrayRef<const MemRegion *> Regions,
3220b57cec5SDimitry Andric                      const LocationContext* LCtx,
3230b57cec5SDimitry Andric                      const CallEvent *Call) const;
3240b57cec5SDimitry Andric 
3250b57cec5SDimitry Andric   ExplodedNode* checkReturnWithRetEffect(const ReturnStmt *S, CheckerContext &C,
3260b57cec5SDimitry Andric                                 ExplodedNode *Pred, RetEffect RE, RefVal X,
3270b57cec5SDimitry Andric                                 SymbolRef Sym, ProgramStateRef state) const;
3280b57cec5SDimitry Andric 
3290b57cec5SDimitry Andric   void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
3300b57cec5SDimitry Andric   void checkBeginFunction(CheckerContext &C) const;
3310b57cec5SDimitry Andric   void checkEndFunction(const ReturnStmt *RS, CheckerContext &C) const;
3320b57cec5SDimitry Andric 
3330b57cec5SDimitry Andric   ProgramStateRef updateSymbol(ProgramStateRef state, SymbolRef sym,
3340b57cec5SDimitry Andric                                RefVal V, ArgEffect E, RefVal::Kind &hasErr,
3350b57cec5SDimitry Andric                                CheckerContext &C) const;
3360b57cec5SDimitry Andric 
3370b57cec5SDimitry Andric   const RefCountBug &errorKindToBugKind(RefVal::Kind ErrorKind,
3380b57cec5SDimitry Andric                                         SymbolRef Sym) const;
3390b57cec5SDimitry Andric 
3400b57cec5SDimitry Andric   void processNonLeakError(ProgramStateRef St, SourceRange ErrorRange,
3410b57cec5SDimitry Andric                            RefVal::Kind ErrorKind, SymbolRef Sym,
3420b57cec5SDimitry Andric                            CheckerContext &C) const;
3430b57cec5SDimitry Andric 
3440b57cec5SDimitry Andric   void processObjCLiterals(CheckerContext &C, const Expr *Ex) const;
3450b57cec5SDimitry Andric 
3460b57cec5SDimitry Andric   ProgramStateRef handleSymbolDeath(ProgramStateRef state,
3470b57cec5SDimitry Andric                                     SymbolRef sid, RefVal V,
3480b57cec5SDimitry Andric                                     SmallVectorImpl<SymbolRef> &Leaked) const;
3490b57cec5SDimitry Andric 
3500b57cec5SDimitry Andric   ProgramStateRef
3510b57cec5SDimitry Andric   handleAutoreleaseCounts(ProgramStateRef state, ExplodedNode *Pred,
3520b57cec5SDimitry Andric                           const ProgramPointTag *Tag, CheckerContext &Ctx,
3530b57cec5SDimitry Andric                           SymbolRef Sym,
3540b57cec5SDimitry Andric                           RefVal V,
3550b57cec5SDimitry Andric                           const ReturnStmt *S=nullptr) const;
3560b57cec5SDimitry Andric 
3570b57cec5SDimitry Andric   ExplodedNode *processLeaks(ProgramStateRef state,
3580b57cec5SDimitry Andric                              SmallVectorImpl<SymbolRef> &Leaked,
3590b57cec5SDimitry Andric                              CheckerContext &Ctx,
3600b57cec5SDimitry Andric                              ExplodedNode *Pred = nullptr) const;
3610b57cec5SDimitry Andric 
362*5ffd83dbSDimitry Andric   static const CheckerProgramPointTag &getDeallocSentTag() {
363*5ffd83dbSDimitry Andric     return *DeallocSentTag;
3640b57cec5SDimitry Andric   }
3650b57cec5SDimitry Andric 
366*5ffd83dbSDimitry Andric   static const CheckerProgramPointTag &getCastFailTag() { return *CastFailTag; }
3670b57cec5SDimitry Andric 
3680b57cec5SDimitry Andric private:
3690b57cec5SDimitry Andric   /// Perform the necessary checks and state adjustments at the end of the
3700b57cec5SDimitry Andric   /// function.
3710b57cec5SDimitry Andric   /// \p S Return statement, may be null.
3720b57cec5SDimitry Andric   ExplodedNode * processReturn(const ReturnStmt *S, CheckerContext &C) const;
3730b57cec5SDimitry Andric };
3740b57cec5SDimitry Andric 
3750b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
3760b57cec5SDimitry Andric // RefBindings - State used to track object reference counts.
3770b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
3780b57cec5SDimitry Andric 
3790b57cec5SDimitry Andric const RefVal *getRefBinding(ProgramStateRef State, SymbolRef Sym);
3800b57cec5SDimitry Andric 
3810b57cec5SDimitry Andric /// Returns true if this stack frame is for an Objective-C method that is a
3820b57cec5SDimitry Andric /// property getter or setter whose body has been synthesized by the analyzer.
3830b57cec5SDimitry Andric inline bool isSynthesizedAccessor(const StackFrameContext *SFC) {
3840b57cec5SDimitry Andric   auto Method = dyn_cast_or_null<ObjCMethodDecl>(SFC->getDecl());
3850b57cec5SDimitry Andric   if (!Method || !Method->isPropertyAccessor())
3860b57cec5SDimitry Andric     return false;
3870b57cec5SDimitry Andric 
3880b57cec5SDimitry Andric   return SFC->getAnalysisDeclContext()->isBodyAutosynthesized();
3890b57cec5SDimitry Andric }
3900b57cec5SDimitry Andric 
3910b57cec5SDimitry Andric } // end namespace retaincountchecker
3920b57cec5SDimitry Andric } // end namespace ento
3930b57cec5SDimitry Andric } // end namespace clang
3940b57cec5SDimitry Andric 
3950b57cec5SDimitry Andric #endif
396