]> granicus.if.org Git - clang/commitdiff
Augment retain/release checker to not warn about tracked objects passed as arguments...
authorTed Kremenek <kremenek@apple.com>
Mon, 2 May 2011 19:42:42 +0000 (19:42 +0000)
committerTed Kremenek <kremenek@apple.com>
Mon, 2 May 2011 19:42:42 +0000 (19:42 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@130711 91177308-0d34-0410-b5e6-96231b3b80d8

16 files changed:
include/clang/StaticAnalyzer/Core/Checker.h
include/clang/StaticAnalyzer/Core/CheckerManager.h
include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
include/clang/StaticAnalyzer/Core/PathSensitive/GRState.h
include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h
lib/StaticAnalyzer/Checkers/CStringChecker.cpp
lib/StaticAnalyzer/Core/BasicStore.cpp
lib/StaticAnalyzer/Core/CFRefCount.cpp
lib/StaticAnalyzer/Core/CheckerManager.cpp
lib/StaticAnalyzer/Core/ExprEngine.cpp
lib/StaticAnalyzer/Core/FlatStore.cpp
lib/StaticAnalyzer/Core/GRState.cpp
lib/StaticAnalyzer/Core/RegionStore.cpp
test/Analysis/retain-release.m
test/Analysis/retain-release.mm [new file with mode: 0644]

index 8c2ffc690887fc17821ba8251be837ec7693192e..86e30eb5239c4f6cf026d3160cb19ee57c01e8e9 100644 (file)
@@ -240,9 +240,11 @@ public:
 class RegionChanges {
   template <typename CHECKER>
   static const GRState *_checkRegionChanges(void *checker, const GRState *state,
+                            const StoreManager::InvalidatedSymbols *invalidated,
                                             const MemRegion * const *Begin,
                                             const MemRegion * const *End) {
-    return ((const CHECKER *)checker)->checkRegionChanges(state, Begin, End);
+    return ((const CHECKER *)checker)->checkRegionChanges(state, invalidated,
+                                                          Begin, End);
   }
   template <typename CHECKER>
   static bool _wantsRegionChangeUpdate(void *checker, const GRState *state) {
index 92ec0388e500b1ad115342807960eba782517417..cee0d4d8bd0ea850c551ffcd6edd681860ad004f 100644 (file)
@@ -18,6 +18,7 @@
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/FoldingSet.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/Store.h"
 #include <vector>
 
 namespace clang {
@@ -49,6 +50,18 @@ public:
 
 template <typename T> class CheckerFn;
 
+template <typename RET, typename P1, typename P2, typename P3, typename P4>
+class CheckerFn<RET(P1, P2, P3, P4)> {
+  typedef RET (*Func)(void *, P1, P2, P3, P4);
+  Func Fn;
+public:
+  void *Checker;
+  CheckerFn(void *checker, Func fn) : Fn(fn), Checker(checker) { }
+  RET operator()(P1 p1, P2 p2, P3 p3, P4 p4) const { 
+    return Fn(Checker, p1, p2, p3, p4);
+  } 
+};
+
 template <typename RET, typename P1, typename P2, typename P3>
 class CheckerFn<RET(P1, P2, P3)> {
   typedef RET (*Func)(void *, P1, P2, P3);
@@ -224,9 +237,11 @@ public:
   bool wantsRegionChangeUpdate(const GRState *state);
 
   /// \brief Run checkers for region changes.
-  const GRState *runCheckersForRegionChanges(const GRState *state,
-                                             const MemRegion * const *Begin,
-                                             const MemRegion * const *End);
+  const GRState *
+  runCheckersForRegionChanges(const GRState *state,
+                            const StoreManager::InvalidatedSymbols *invalidated,
+                              const MemRegion * const *Begin,
+                              const MemRegion * const *End);
 
   /// \brief Run checkers for handling assumptions on symbolic values.
   const GRState *runCheckersForEvalAssume(const GRState *state,
@@ -283,6 +298,7 @@ public:
   typedef CheckerFn<void (const GRState *,SymbolReaper &)> CheckLiveSymbolsFunc;
   
   typedef CheckerFn<const GRState * (const GRState *,
+                                const StoreManager::InvalidatedSymbols *symbols,
                                      const MemRegion * const *begin,
                                      const MemRegion * const *end)>
       CheckRegionChangesFunc;
index 8cd743f68f567d64ee3cf5c8938a6535a49e6607..99df4f0fdbe642cf86409c07c093eb51ebaca442 100644 (file)
@@ -188,9 +188,11 @@ public:
 
   /// processRegionChanges - Called by GRStateManager whenever a change is made
   ///  to the store. Used to update checkers that track region values.
-  const GRState* processRegionChanges(const GRState *state,
-                                      const MemRegion * const *Begin,
-                                      const MemRegion * const *End);
+  const GRState *
+  processRegionChanges(const GRState *state,
+                       const StoreManager::InvalidatedSymbols *invalidated,
+                       const MemRegion * const *Begin,
+                       const MemRegion * const *End);
 
   virtual GRStateManager& getStateManager() { return StateMgr; }
 
index a957c897b92aeacde1ca9a6f4db2e1722ef4e74e..0d61d0e620eb63d422c9ec2fde8d28613c7335a3 100644 (file)
@@ -368,6 +368,12 @@ private:
     assert(refCount > 0);
     --refCount;
   }
+  
+  const GRState *invalidateRegionsImpl(const MemRegion * const *Begin,
+                                       const MemRegion * const *End,
+                                       const Expr *E, unsigned BlockCount,
+                                       StoreManager::InvalidatedSymbols &IS,
+                                       bool invalidateGlobals) const;
 };
 
 class GRStateSet {
index 21c6ae760cc8d7acd292c3617b1bf8ae1597738b..cdbdf64515b4bd1f2dacf12ddb285f87ec638e3b 100644 (file)
@@ -188,7 +188,7 @@ public:
                                      const MemRegion * const *Begin,
                                      const MemRegion * const *End,
                                      const Expr *E, unsigned Count,
-                                     InvalidatedSymbols *IS,
+                                     InvalidatedSymbols &IS,
                                      bool invalidateGlobals,
                                      InvalidatedRegions *Regions) = 0;
 
index 3d6f9fa15b73e2e1c67a3f6f56b331c3b70791a7..1f6ea3d8c7322491132c3fdb44e0cc0744a2c95c 100644 (file)
@@ -15,6 +15,7 @@
 
 #include "clang/Analysis/ProgramPoint.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/Store.h"
 
 namespace clang {
 
@@ -95,13 +96,17 @@ public:
 
   /// processRegionChanges - Called by GRStateManager whenever a change is made
   ///  to the store. Used to update checkers that track region values.
-  virtual const GRState* processRegionChanges(const GRState* state,
-                                              const MemRegion* const *Begin,
-                                              const MemRegion* const *End) = 0;
+  virtual const GRState *
+  processRegionChanges(const GRState *state,
+                       const StoreManager::InvalidatedSymbols *invalidated,
+                       const MemRegion* const *Begin,
+                       const MemRegion* const *End) = 0;
 
-  inline const GRState* processRegionChange(const GRState* state,
-                                            const MemRegion* MR) {
-    return processRegionChanges(state, &MR, &MR+1);
+
+  inline const GRState *
+  processRegionChange(const GRState* state,
+                      const MemRegion* MR) {
+    return processRegionChanges(state, 0, &MR, &MR+1);
   }
 
   /// Called by CoreEngine when the analysis worklist is either empty or the
index 4f9c641edfd6793884df55acfae86125f58cbf19..f4b9a3e90ca6ec6e8d58ea51ae8f596bf3c833b8 100644 (file)
@@ -42,6 +42,7 @@ public:
   bool wantsRegionChangeUpdate(const GRState *state) const;
 
   const GRState *checkRegionChanges(const GRState *state,
+                                    const StoreManager::InvalidatedSymbols *,
                                     const MemRegion * const *Begin,
                                     const MemRegion * const *End) const;
 
@@ -1305,6 +1306,7 @@ bool CStringChecker::wantsRegionChangeUpdate(const GRState *state) const {
 
 const GRState *
 CStringChecker::checkRegionChanges(const GRState *state,
+                                   const StoreManager::InvalidatedSymbols *,
                                    const MemRegion * const *Begin,
                                    const MemRegion * const *End) const {
   CStringLength::EntryMap Entries = state->get<CStringLength>();
index 4faa84ca2660ad8f80d741ace70e1067423089cc..7c9f45a474c109885e2a5ffcefc6a512c54ce53d 100644 (file)
@@ -49,11 +49,11 @@ public:
   SVal Retrieve(Store store, Loc loc, QualType T = QualType());
 
   StoreRef invalidateRegion(Store store, const MemRegion *R, const Expr *E,
-                            unsigned Count, InvalidatedSymbols *IS);
+                            unsigned Count, InvalidatedSymbols &IS);
 
   StoreRef invalidateRegions(Store store, const MemRegion * const *Begin,
                              const MemRegion * const *End, const Expr *E,
-                             unsigned Count, InvalidatedSymbols *IS,
+                             unsigned Count, InvalidatedSymbols &IS,
                              bool invalidateGlobals,
                              InvalidatedRegions *Regions);
 
@@ -538,7 +538,7 @@ StoreRef BasicStoreManager::invalidateRegions(Store store,
                                               const MemRegion * const *I,
                                               const MemRegion * const *End,
                                               const Expr *E, unsigned Count,
-                                              InvalidatedSymbols *IS,
+                                              InvalidatedSymbols &IS,
                                               bool invalidateGlobals,
                                               InvalidatedRegions *Regions) {
   StoreRef newStore(store, *this);
@@ -587,18 +587,16 @@ StoreRef BasicStoreManager::invalidateRegion(Store store,
                                              const MemRegion *R,
                                              const Expr *E,
                                              unsigned Count,
-                                             InvalidatedSymbols *IS) {
+                                             InvalidatedSymbols &IS) {
   R = R->StripCasts();
 
   if (!(isa<VarRegion>(R) || isa<ObjCIvarRegion>(R)))
       return StoreRef(store, *this);
 
-  if (IS) {
-    BindingsTy B = GetBindings(store);
-    if (BindingsTy::data_type *Val = B.lookup(R)) {
-      if (SymbolRef Sym = Val->getAsSymbol())
-        IS->insert(Sym);
-    }
+  BindingsTy B = GetBindings(store);
+  if (BindingsTy::data_type *Val = B.lookup(R)) {
+    if (SymbolRef Sym = Val->getAsSymbol())
+      IS.insert(Sym);
   }
 
   QualType T = cast<TypedRegion>(R)->getValueType();
index d9b1ce825cea188f6d88c66b87692715e218e00d..9fd7fc7d4cbe8c7a887c88c8d77e2244d03cb00d 100644 (file)
@@ -2494,6 +2494,23 @@ static QualType GetReturnType(const Expr* RetE, ASTContext& Ctx) {
   return RetTy;
 }
 
+
+// HACK: Symbols that have ref-count state that are referenced directly
+//  (not as structure or array elements, or via bindings) by an argument
+//  should not have their ref-count state stripped after we have
+//  done an invalidation pass.
+//
+// FIXME: This is a global to currently share between CFRefCount and
+// RetainReleaseChecker.  Eventually all functionality in CFRefCount should
+// be migrated to RetainReleaseChecker, and we can make this a non-global.
+llvm::DenseSet<SymbolRef> WhitelistedSymbols;
+namespace {
+struct ResetWhiteList {
+  ResetWhiteList() {}
+  ~ResetWhiteList() { WhitelistedSymbols.clear(); } 
+};
+}
+
 void CFRefCount::evalSummary(ExplodedNodeSet& Dst,
                              ExprEngine& Eng,
                              StmtNodeBuilder& Builder,
@@ -2510,12 +2527,9 @@ void CFRefCount::evalSummary(ExplodedNodeSet& Dst,
   SymbolRef ErrorSym = 0;
 
   llvm::SmallVector<const MemRegion*, 10> RegionsToInvalidate;
-
-  // HACK: Symbols that have ref-count state that are referenced directly
-  //  (not as structure or array elements, or via bindings) by an argument
-  //  should not have their ref-count state stripped after we have
-  //  done an invalidation pass.
-  llvm::DenseSet<SymbolRef> WhitelistedSymbols;
+  
+  // Use RAII to make sure the whitelist is properly cleared.
+  ResetWhiteList resetWhiteList;
 
   // Invalidate all instance variables of the receiver of a message.
   // FIXME: We should be able to do better with inter-procedural analysis.
@@ -2624,21 +2638,13 @@ void CFRefCount::evalSummary(ExplodedNodeSet& Dst,
 
   // NOTE: Even if RegionsToInvalidate is empty, we must still invalidate
   //  global variables.
+  // NOTE: RetainReleaseChecker handles the actual invalidation of symbols.
   state = state->invalidateRegions(RegionsToInvalidate.data(),
                                    RegionsToInvalidate.data() +
                                    RegionsToInvalidate.size(),
                                    Ex, Count, &IS,
                                    /* invalidateGlobals = */ true);
 
-  for (StoreManager::InvalidatedSymbols::iterator I = IS.begin(),
-       E = IS.end(); I!=E; ++I) {
-    SymbolRef sym = *I;
-    if (WhitelistedSymbols.count(sym))
-      continue;
-    // Remove any existing reference-count binding.
-    state = state->remove<RefBindings>(*I);
-  }
-
   // Evaluate the effect on the message receiver.
   if (!ErrorRange.isValid() && Receiver) {
     SymbolRef Sym = Receiver.getSValAsScalarOrLoc(state).getAsLocSymbol();
@@ -3418,12 +3424,43 @@ void CFRefCount::ProcessNonLeakError(ExplodedNodeSet& Dst,
 
 namespace {
 class RetainReleaseChecker
-  : public Checker< check::PostStmt<BlockExpr> > {
+  : public Checker< check::PostStmt<BlockExpr>, check::RegionChanges > {
 public:
+    bool wantsRegionUpdate;
+    
+    RetainReleaseChecker() : wantsRegionUpdate(true) {}
+    
+    
     void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const;
+    const GRState *checkRegionChanges(const GRState *state,
+                            const StoreManager::InvalidatedSymbols *invalidated,
+                                      const MemRegion * const *begin,
+                                      const MemRegion * const *end) const;
+                                          
+    bool wantsRegionChangeUpdate(const GRState *state) const {
+      return wantsRegionUpdate;
+    }
 };
 } // end anonymous namespace
 
+const GRState *
+RetainReleaseChecker::checkRegionChanges(const GRState *state,
+                            const StoreManager::InvalidatedSymbols *invalidated,
+                                         const MemRegion * const *begin,
+                                         const MemRegion * const *end) const {
+  if (!invalidated)
+    return state;
+
+  for (StoreManager::InvalidatedSymbols::const_iterator I=invalidated->begin(),
+       E = invalidated->end(); I!=E; ++I) {
+    SymbolRef sym = *I;
+    if (WhitelistedSymbols.count(sym))
+      continue;
+    // Remove any existing reference-count binding.
+    state = state->remove<RefBindings>(sym);
+  }
+  return state;
+}
 
 void RetainReleaseChecker::checkPostStmt(const BlockExpr *BE,
                                          CheckerContext &C) const {
index 4a2549091cb4b0e9cc480f0cfcb4039cd62ec273..78c8b8bda225e3bb1c43803168e3f2ceebfdb272 100644 (file)
@@ -345,6 +345,7 @@ bool CheckerManager::wantsRegionChangeUpdate(const GRState *state) {
 /// \brief Run checkers for region changes.
 const GRState *
 CheckerManager::runCheckersForRegionChanges(const GRState *state,
+                            const StoreManager::InvalidatedSymbols *invalidated,
                                             const MemRegion * const *Begin,
                                             const MemRegion * const *End) {
   for (unsigned i = 0, e = RegionChangesCheckers.size(); i != e; ++i) {
@@ -352,7 +353,7 @@ CheckerManager::runCheckersForRegionChanges(const GRState *state,
     // bail out.
     if (!state)
       return NULL;
-    state = RegionChangesCheckers[i].CheckFn(state, Begin, End);
+    state = RegionChangesCheckers[i].CheckFn(state, invalidated, Begin, End);
   }
   return state;
 }
index 657420d06f06d8eb3f747c253dd78d4d7c93cc48..69ef4cfc4cad443365c86d81541f321af544e28e 100644 (file)
@@ -179,9 +179,11 @@ bool ExprEngine::wantsRegionChangeUpdate(const GRState* state) {
 
 const GRState *
 ExprEngine::processRegionChanges(const GRState *state,
-                                   const MemRegion * const *Begin,
-                                   const MemRegion * const *End) {
-  return getCheckerManager().runCheckersForRegionChanges(state, Begin, End);
+                            const StoreManager::InvalidatedSymbols *invalidated,
+                                 const MemRegion * const *Begin,
+                                 const MemRegion * const *End) {
+  return getCheckerManager().runCheckersForRegionChanges(state, invalidated,
+                                                         Begin, End);
 }
 
 void ExprEngine::processEndWorklist(bool hasWorkRemaining) {
index 7bdca6b7f17db16c19d180f7b06e22643fd0ccbd..ca867aebded4098fd387ff7fb7597f71f1445721 100644 (file)
@@ -59,7 +59,7 @@ public:
   
   StoreRef invalidateRegions(Store store, const MemRegion * const *I,
                              const MemRegion * const *E, const Expr *Ex,
-                             unsigned Count, InvalidatedSymbols *IS,
+                             unsigned Count, InvalidatedSymbols &IS,
                              bool invalidateGlobals,
                              InvalidatedRegions *Regions);
 
@@ -175,7 +175,7 @@ StoreRef FlatStoreManager::invalidateRegions(Store store,
                                              const MemRegion * const *I,
                                              const MemRegion * const *E,
                                              const Expr *Ex, unsigned Count,
-                                             InvalidatedSymbols *IS,
+                                             InvalidatedSymbols &IS,
                                              bool invalidateGlobals,
                                              InvalidatedRegions *Regions) {
   assert(false && "Not implemented");
index 7b216775b8e66239454bfbc2a3ec71be4143d363..0f6ff1ef588c33ec1b98f802d0c4eaa6e6360635 100644 (file)
@@ -141,6 +141,20 @@ const GRState *GRState::invalidateRegions(const MemRegion * const *Begin,
                                           const Expr *E, unsigned Count,
                                           StoreManager::InvalidatedSymbols *IS,
                                           bool invalidateGlobals) const {
+  if (!IS) {
+    StoreManager::InvalidatedSymbols invalidated;
+    return invalidateRegionsImpl(Begin, End, E, Count,
+                             invalidated, invalidateGlobals);
+  }
+  return invalidateRegionsImpl(Begin, End, E, Count, *IS, invalidateGlobals);
+}
+
+const GRState *
+GRState::invalidateRegionsImpl(const MemRegion * const *Begin,
+                               const MemRegion * const *End,
+                               const Expr *E, unsigned Count,
+                               StoreManager::InvalidatedSymbols &IS,
+                               bool invalidateGlobals) const {
   GRStateManager &Mgr = getStateManager();
   SubEngine* Eng = Mgr.getOwningEngine();
  
@@ -150,7 +164,7 @@ const GRState *GRState::invalidateRegions(const MemRegion * const *Begin,
       = Mgr.StoreMgr->invalidateRegions(getStore(), Begin, End, E, Count, IS,
                                         invalidateGlobals, &Regions);
     const GRState *newState = makeWithStore(newStore);
-    return Eng->processRegionChanges(newState,
+    return Eng->processRegionChanges(newState, &IS,
                                      &Regions.front(),
                                      &Regions.back()+1);
   }
index 4522f976e648f348adcc6c81fb3c69bdb0c49dc7..fe17773fc72057001ab42f45abf0e194460ca369 100644 (file)
@@ -240,7 +240,7 @@ public:
                              const MemRegion * const *Begin,
                              const MemRegion * const *End,
                              const Expr *E, unsigned Count,
-                             InvalidatedSymbols *IS,
+                             InvalidatedSymbols &IS,
                              bool invalidateGlobals,
                              InvalidatedRegions *Regions);
 
@@ -586,14 +586,14 @@ class invalidateRegionsWorker : public ClusterAnalysis<invalidateRegionsWorker>
 {
   const Expr *Ex;
   unsigned Count;
-  StoreManager::InvalidatedSymbols *IS;
+  StoreManager::InvalidatedSymbols &IS;
   StoreManager::InvalidatedRegions *Regions;
 public:
   invalidateRegionsWorker(RegionStoreManager &rm,
                           GRStateManager &stateMgr,
                           RegionBindings b,
                           const Expr *ex, unsigned count,
-                          StoreManager::InvalidatedSymbols *is,
+                          StoreManager::InvalidatedSymbols &is,
                           StoreManager::InvalidatedRegions *r,
                           bool includeGlobals)
     : ClusterAnalysis<invalidateRegionsWorker>(rm, stateMgr, b, includeGlobals),
@@ -609,9 +609,8 @@ private:
 
 void invalidateRegionsWorker::VisitBinding(SVal V) {
   // A symbol?  Mark it touched by the invalidation.
-  if (IS)
-    if (SymbolRef Sym = V.getAsSymbol())
-      IS->insert(Sym);
+  if (SymbolRef Sym = V.getAsSymbol())
+    IS.insert(Sym);
 
   if (const MemRegion *R = V.getAsRegion()) {
     AddToWorkList(R);
@@ -648,11 +647,9 @@ void invalidateRegionsWorker::VisitCluster(const MemRegion *baseR,
 }
 
 void invalidateRegionsWorker::VisitBaseRegion(const MemRegion *baseR) {
-  if (IS) {
-    // Symbolic region?  Mark that symbol touched by the invalidation.
-    if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(baseR))
-      IS->insert(SR->getSymbol());
-  }
+  // Symbolic region?  Mark that symbol touched by the invalidation.
+  if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(baseR))
+    IS.insert(SR->getSymbol());
 
   // BlockDataRegion?  If so, invalidate captured variables that are passed
   // by reference.
@@ -724,7 +721,7 @@ StoreRef RegionStoreManager::invalidateRegions(Store store,
                                                const MemRegion * const *I,
                                                const MemRegion * const *E,
                                                const Expr *Ex, unsigned Count,
-                                               InvalidatedSymbols *IS,
+                                               InvalidatedSymbols &IS,
                                                bool invalidateGlobals,
                                                InvalidatedRegions *Regions) {
   invalidateRegionsWorker W(*this, StateMgr,
index 6782c90375f62f90c0026c42cc49cb6a3045404c..fa65b0875b2c9da402e76df9a486a00af285fadf 100644 (file)
@@ -280,7 +280,7 @@ CFAbsoluteTime f1() {
   CFRelease(date);
   CFDateGetAbsoluteTime(date); // no-warning
   CFRelease(date);
-  t = CFDateGetAbsoluteTime(date);   // expected-warning{{Reference-counted object is used after it is released.}}
+  t = CFDateGetAbsoluteTime(date);   // expected-warning{{Reference-counted object is used after it is released}}
   return t;
 }
 
@@ -291,7 +291,7 @@ CFAbsoluteTime f2() {
   CFRelease(date);
   CFDateGetAbsoluteTime(date); // no-warning
   [((NSDate*) date) release];
-  t = CFDateGetAbsoluteTime(date);   // expected-warning{{Reference-counted object is used after it is released.}}
+  t = CFDateGetAbsoluteTime(date);   // expected-warning{{Reference-counted object is used after it is released}}
   return t;
 }
 
diff --git a/test/Analysis/retain-release.mm b/test/Analysis/retain-release.mm
new file mode 100644 (file)
index 0000000..47d615f
--- /dev/null
@@ -0,0 +1,284 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease -analyzer-store=region -fblocks -verify %s
+
+#if __has_feature(attribute_ns_returns_retained)
+#define NS_RETURNS_RETAINED __attribute__((ns_returns_retained))
+#endif
+#if __has_feature(attribute_cf_returns_retained)
+#define CF_RETURNS_RETAINED __attribute__((cf_returns_retained))
+#endif
+#if __has_feature(attribute_ns_returns_not_retained)
+#define NS_RETURNS_NOT_RETAINED __attribute__((ns_returns_not_retained))
+#endif
+#if __has_feature(attribute_cf_returns_not_retained)
+#define CF_RETURNS_NOT_RETAINED __attribute__((cf_returns_not_retained))
+#endif
+#if __has_feature(attribute_ns_consumes_self)
+#define NS_CONSUMES_SELF __attribute__((ns_consumes_self))
+#endif
+#if __has_feature(attribute_ns_consumed)
+#define NS_CONSUMED __attribute__((ns_consumed))
+#endif
+#if __has_feature(attribute_cf_consumed)
+#define CF_CONSUMED __attribute__((cf_consumed))
+#endif
+
+//===----------------------------------------------------------------------===//
+// The following code is reduced using delta-debugging from Mac OS X headers:
+//
+// #include <Cocoa/Cocoa.h>
+// #include <CoreFoundation/CoreFoundation.h>
+// #include <DiskArbitration/DiskArbitration.h>
+// #include <QuartzCore/QuartzCore.h>
+// #include <Quartz/Quartz.h>
+// #include <IOKit/IOKitLib.h>
+//
+// It includes the basic definitions for the test cases below.
+//===----------------------------------------------------------------------===//
+
+typedef unsigned int __darwin_natural_t;
+typedef unsigned long uintptr_t;
+typedef unsigned int uint32_t;
+typedef unsigned long long uint64_t;
+typedef unsigned int UInt32;
+typedef signed long CFIndex;
+typedef struct {
+    CFIndex location;
+    CFIndex length;
+} CFRange;
+static __inline__ __attribute__((always_inline)) CFRange CFRangeMake(CFIndex loc, CFIndex len) {
+    CFRange range;
+    range.location = loc;
+    range.length = len;
+    return range;
+}
+typedef const void * CFTypeRef;
+typedef const struct __CFString * CFStringRef;
+typedef const struct __CFAllocator * CFAllocatorRef;
+extern const CFAllocatorRef kCFAllocatorDefault;
+extern CFTypeRef CFRetain(CFTypeRef cf);
+extern void CFRelease(CFTypeRef cf);
+typedef struct {
+}
+CFArrayCallBacks;
+extern const CFArrayCallBacks kCFTypeArrayCallBacks;
+typedef const struct __CFArray * CFArrayRef;
+typedef struct __CFArray * CFMutableArrayRef;
+extern CFMutableArrayRef CFArrayCreateMutable(CFAllocatorRef allocator, CFIndex capacity, const CFArrayCallBacks *callBacks);
+extern const void *CFArrayGetValueAtIndex(CFArrayRef theArray, CFIndex idx);
+extern void CFArrayAppendValue(CFMutableArrayRef theArray, const void *value);
+typedef struct {
+}
+CFDictionaryKeyCallBacks;
+extern const CFDictionaryKeyCallBacks kCFTypeDictionaryKeyCallBacks;
+typedef struct {
+}
+CFDictionaryValueCallBacks;
+extern const CFDictionaryValueCallBacks kCFTypeDictionaryValueCallBacks;
+typedef const struct __CFDictionary * CFDictionaryRef;
+typedef struct __CFDictionary * CFMutableDictionaryRef;
+extern CFMutableDictionaryRef CFDictionaryCreateMutable(CFAllocatorRef allocator, CFIndex capacity, const CFDictionaryKeyCallBacks *keyCallBacks, const CFDictionaryValueCallBacks *valueCallBacks);
+typedef UInt32 CFStringEncoding;
+enum {
+kCFStringEncodingMacRoman = 0,     kCFStringEncodingWindowsLatin1 = 0x0500,     kCFStringEncodingISOLatin1 = 0x0201,     kCFStringEncodingNextStepLatin = 0x0B01,     kCFStringEncodingASCII = 0x0600,     kCFStringEncodingUnicode = 0x0100,     kCFStringEncodingUTF8 = 0x08000100,     kCFStringEncodingNonLossyASCII = 0x0BFF      ,     kCFStringEncodingUTF16 = 0x0100,     kCFStringEncodingUTF16BE = 0x10000100,     kCFStringEncodingUTF16LE = 0x14000100,      kCFStringEncodingUTF32 = 0x0c000100,     kCFStringEncodingUTF32BE = 0x18000100,     kCFStringEncodingUTF32LE = 0x1c000100  };
+extern CFStringRef CFStringCreateWithCString(CFAllocatorRef alloc, const char *cStr, CFStringEncoding encoding);
+typedef double CFTimeInterval;
+typedef CFTimeInterval CFAbsoluteTime;
+extern CFAbsoluteTime CFAbsoluteTimeGetCurrent(void);
+typedef const struct __CFDate * CFDateRef;
+extern CFDateRef CFDateCreate(CFAllocatorRef allocator, CFAbsoluteTime at);
+extern CFAbsoluteTime CFDateGetAbsoluteTime(CFDateRef theDate);
+typedef __darwin_natural_t natural_t;
+typedef natural_t mach_port_name_t;
+typedef mach_port_name_t mach_port_t;
+typedef int kern_return_t;
+typedef kern_return_t mach_error_t;
+enum {
+kCFNumberSInt8Type = 1,     kCFNumberSInt16Type = 2,     kCFNumberSInt32Type = 3,     kCFNumberSInt64Type = 4,     kCFNumberFloat32Type = 5,     kCFNumberFloat64Type = 6,      kCFNumberCharType = 7,     kCFNumberShortType = 8,     kCFNumberIntType = 9,     kCFNumberLongType = 10,     kCFNumberLongLongType = 11,     kCFNumberFloatType = 12,     kCFNumberDoubleType = 13,      kCFNumberCFIndexType = 14,      kCFNumberNSIntegerType = 15,     kCFNumberCGFloatType = 16,     kCFNumberMaxType = 16    };
+typedef CFIndex CFNumberType;
+typedef const struct __CFNumber * CFNumberRef;
+extern CFNumberRef CFNumberCreate(CFAllocatorRef allocator, CFNumberType theType, const void *valuePtr);
+typedef const struct __CFAttributedString *CFAttributedStringRef;
+typedef struct __CFAttributedString *CFMutableAttributedStringRef;
+extern CFAttributedStringRef CFAttributedStringCreate(CFAllocatorRef alloc, CFStringRef str, CFDictionaryRef attributes) ;
+extern CFMutableAttributedStringRef CFAttributedStringCreateMutableCopy(CFAllocatorRef alloc, CFIndex maxLength, CFAttributedStringRef aStr) ;
+extern void CFAttributedStringSetAttribute(CFMutableAttributedStringRef aStr, CFRange range, CFStringRef attrName, CFTypeRef value) ;
+typedef signed char BOOL;
+typedef unsigned long NSUInteger;
+@class NSString, Protocol;
+extern void NSLog(NSString *format, ...) __attribute__((format(__NSString__, 1, 2)));
+typedef struct _NSZone NSZone;
+@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator;
+@protocol NSObject
+- (BOOL)isEqual:(id)object;
+- (id)retain;
+- (oneway void)release;
+- (id)autorelease;
+@end  @protocol NSCopying  - (id)copyWithZone:(NSZone *)zone;
+@end  @protocol NSMutableCopying  - (id)mutableCopyWithZone:(NSZone *)zone;
+@end  @protocol NSCoding  - (void)encodeWithCoder:(NSCoder *)aCoder;
+@end
+@interface NSObject <NSObject> {}
++ (id)allocWithZone:(NSZone *)zone;
++ (id)alloc;
+- (void)dealloc;
+@end
+@interface NSObject (NSCoderMethods)
+- (id)awakeAfterUsingCoder:(NSCoder *)aDecoder;
+@end
+extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone);
+typedef struct {
+}
+NSFastEnumerationState;
+@protocol NSFastEnumeration  - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len;
+@end           @class NSString, NSDictionary;
+@interface NSValue : NSObject <NSCopying, NSCoding>  - (void)getValue:(void *)value;
+@end  @interface NSNumber : NSValue  - (char)charValue;
+- (id)initWithInt:(int)value;
+@end   @class NSString;
+@interface NSArray : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration>  - (NSUInteger)count;
+@end  @interface NSArray (NSArrayCreation)  + (id)array;
+@end       @interface NSAutoreleasePool : NSObject {
+}
+- (void)drain;
+@end extern NSString * const NSBundleDidLoadNotification;
+typedef double NSTimeInterval;
+@interface NSDate : NSObject <NSCopying, NSCoding>  - (NSTimeInterval)timeIntervalSinceReferenceDate;
+@end            typedef unsigned short unichar;
+@interface NSString : NSObject <NSCopying, NSMutableCopying, NSCoding>    - (NSUInteger)length;
+- ( const char *)UTF8String;
+- (id)initWithUTF8String:(const char *)nullTerminatedCString;
++ (id)stringWithUTF8String:(const char *)nullTerminatedCString;
+@end        @class NSString, NSURL, NSError;
+@interface NSData : NSObject <NSCopying, NSMutableCopying, NSCoding>  - (NSUInteger)length;
++ (id)dataWithBytesNoCopy:(void *)bytes length:(NSUInteger)length;
++ (id)dataWithBytesNoCopy:(void *)bytes length:(NSUInteger)length freeWhenDone:(BOOL)b;
+@end   @class NSLocale, NSDate, NSCalendar, NSTimeZone, NSError, NSArray, NSMutableDictionary;
+@interface NSDictionary : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration>  - (NSUInteger)count;
+@end    @interface NSMutableDictionary : NSDictionary  - (void)removeObjectForKey:(id)aKey;
+- (void)setObject:(id)anObject forKey:(id)aKey;
+@end  @interface NSMutableDictionary (NSMutableDictionaryCreation)  + (id)dictionaryWithCapacity:(NSUInteger)numItems;
+@end  typedef double CGFloat;
+struct CGSize {
+};
+typedef struct CGSize CGSize;
+struct CGRect {
+};
+typedef struct CGRect CGRect;
+typedef mach_port_t io_object_t;
+typedef char io_name_t[128];
+typedef io_object_t io_iterator_t;
+typedef io_object_t io_service_t;
+typedef struct IONotificationPort * IONotificationPortRef;
+typedef void (*IOServiceMatchingCallback)(  void * refcon,  io_iterator_t iterator );
+io_service_t IOServiceGetMatchingService(  mach_port_t masterPort,  CFDictionaryRef matching );
+kern_return_t IOServiceGetMatchingServices(  mach_port_t masterPort,  CFDictionaryRef matching,  io_iterator_t * existing );
+kern_return_t IOServiceAddNotification(  mach_port_t masterPort,  const io_name_t notificationType,  CFDictionaryRef matching,  mach_port_t wakePort,  uintptr_t reference,  io_iterator_t * notification ) __attribute__((deprecated));
+kern_return_t IOServiceAddMatchingNotification(  IONotificationPortRef notifyPort,  const io_name_t notificationType,  CFDictionaryRef matching,         IOServiceMatchingCallback callback,         void * refCon,  io_iterator_t * notification );
+CFMutableDictionaryRef IOServiceMatching(  const char * name );
+CFMutableDictionaryRef IOServiceNameMatching(  const char * name );
+CFMutableDictionaryRef IOBSDNameMatching(  mach_port_t masterPort,  uint32_t options,  const char * bsdName );
+CFMutableDictionaryRef IOOpenFirmwarePathMatching(  mach_port_t masterPort,  uint32_t options,  const char * path );
+CFMutableDictionaryRef IORegistryEntryIDMatching(  uint64_t entryID );
+typedef struct __DASession * DASessionRef;
+extern DASessionRef DASessionCreate( CFAllocatorRef allocator );
+typedef struct __DADisk * DADiskRef;
+extern DADiskRef DADiskCreateFromBSDName( CFAllocatorRef allocator, DASessionRef session, const char * name );
+extern DADiskRef DADiskCreateFromIOMedia( CFAllocatorRef allocator, DASessionRef session, io_service_t media );
+extern CFDictionaryRef DADiskCopyDescription( DADiskRef disk );
+extern DADiskRef DADiskCopyWholeDisk( DADiskRef disk );
+@interface NSTask : NSObject - (id)init;
+@end                    typedef struct CGColorSpace *CGColorSpaceRef;
+typedef struct CGImage *CGImageRef;
+typedef struct CGLayer *CGLayerRef;
+@interface NSResponder : NSObject <NSCoding> {
+}
+@end    @protocol NSAnimatablePropertyContainer      - (id)animator;
+@end  extern NSString *NSAnimationTriggerOrderIn ;
+@interface NSView : NSResponder  <NSAnimatablePropertyContainer>  {
+}
+@end @protocol NSValidatedUserInterfaceItem - (SEL)action;
+@end   @protocol NSUserInterfaceValidations - (BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)anItem;
+@end  @class NSDate, NSDictionary, NSError, NSException, NSNotification;
+@interface NSApplication : NSResponder <NSUserInterfaceValidations> {
+}
+@end   enum {
+NSTerminateCancel = 0,         NSTerminateNow = 1,         NSTerminateLater = 2 };
+typedef NSUInteger NSApplicationTerminateReply;
+@protocol NSApplicationDelegate <NSObject> @optional        - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender;
+@end  @class NSAttributedString, NSEvent, NSFont, NSFormatter, NSImage, NSMenu, NSText, NSView, NSTextView;
+@interface NSCell : NSObject <NSCopying, NSCoding> {
+}
+@end @class NSTextField, NSPanel, NSArray, NSWindow, NSImage, NSButton, NSError;
+typedef struct {
+}
+CVTimeStamp;
+@interface CIImage : NSObject <NSCoding, NSCopying> {
+}
+typedef int CIFormat;
+@end  enum {
+kDAReturnSuccess = 0,     kDAReturnError = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x01,     kDAReturnBusy = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x02,     kDAReturnBadArgument = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x03,     kDAReturnExclusiveAccess = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x04,     kDAReturnNoResources = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x05,     kDAReturnNotFound = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x06,     kDAReturnNotMounted = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x07,     kDAReturnNotPermitted = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x08,     kDAReturnNotPrivileged = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x09,     kDAReturnNotReady = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x0A,     kDAReturnNotWritable = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x0B,     kDAReturnUnsupported = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x0C };
+typedef mach_error_t DAReturn;
+typedef const struct __DADissenter * DADissenterRef;
+extern DADissenterRef DADissenterCreate( CFAllocatorRef allocator, DAReturn status, CFStringRef string );
+@interface CIContext: NSObject {
+}
+- (CGImageRef)createCGImage:(CIImage *)im fromRect:(CGRect)r;
+- (CGImageRef)createCGImage:(CIImage *)im fromRect:(CGRect)r     format:(CIFormat)f colorSpace:(CGColorSpaceRef)cs;
+- (CGLayerRef)createCGLayerWithSize:(CGSize)size info:(CFDictionaryRef)d;
+@end extern NSString* const QCRendererEventKey;
+@protocol QCCompositionRenderer - (NSDictionary*) attributes;
+@end   @interface QCRenderer : NSObject <QCCompositionRenderer> {
+}
+- (id) createSnapshotImageOfType:(NSString*)type;
+@end  extern NSString* const QCViewDidStartRenderingNotification;
+@interface QCView : NSView <QCCompositionRenderer> {
+}
+- (id) createSnapshotImageOfType:(NSString*)type;
+@end    enum {
+ICEXIFOrientation1 = 1,     ICEXIFOrientation2 = 2,     ICEXIFOrientation3 = 3,     ICEXIFOrientation4 = 4,     ICEXIFOrientation5 = 5,     ICEXIFOrientation6 = 6,     ICEXIFOrientation7 = 7,     ICEXIFOrientation8 = 8, };
+@class ICDevice;
+@protocol ICDeviceDelegate <NSObject>  @required      - (void)didRemoveDevice:(ICDevice*)device;
+@end extern NSString *const ICScannerStatusWarmingUp;
+@class ICScannerDevice;
+@protocol ICScannerDeviceDelegate <ICDeviceDelegate>  @optional       - (void)scannerDeviceDidBecomeAvailable:(ICScannerDevice*)scanner;
+@end
+
+typedef long unsigned int __darwin_size_t;
+typedef __darwin_size_t size_t;
+typedef unsigned long CFTypeID;
+struct CGPoint {
+  CGFloat x;
+  CGFloat y;
+};
+typedef struct CGPoint CGPoint;
+typedef struct CGGradient *CGGradientRef;
+typedef uint32_t CGGradientDrawingOptions;
+extern CFTypeID CGGradientGetTypeID(void);
+extern CGGradientRef CGGradientCreateWithColorComponents(CGColorSpaceRef
+  space, const CGFloat components[], const CGFloat locations[], size_t count);
+extern CGGradientRef CGGradientCreateWithColors(CGColorSpaceRef space,
+  CFArrayRef colors, const CGFloat locations[]);
+extern CGGradientRef CGGradientRetain(CGGradientRef gradient);
+extern void CGGradientRelease(CGGradientRef gradient);
+typedef struct CGContext *CGContextRef;
+extern void CGContextDrawLinearGradient(CGContextRef context,
+    CGGradientRef gradient, CGPoint startPoint, CGPoint endPoint,
+    CGGradientDrawingOptions options);
+extern CGColorSpaceRef CGColorSpaceCreateDeviceRGB(void);
+
+//===----------------------------------------------------------------------===//
+// Test cases.
+//===----------------------------------------------------------------------===//
+
+class SmartPointer {
+  id x;
+public:
+  SmartPointer(id x) : x(x) {}
+  ~SmartPointer() { [x release]; }
+};
+
+void test_smartpointer_1() {
+  id x = [[NSObject alloc] init];  // no-warning
+  SmartPointer foo(x);
+}
+