#include "clang/AST/Expr.h"
#include "clang/AST/ExprObjC.h"
#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/TargetInfo.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
bool classHasSeparateTeardown(const ObjCInterfaceDecl *ID) const;
bool isReleasedByCIFilterDealloc(const ObjCPropertyImplDecl *PropImpl) const;
+ bool isNibLoadedIvarWithoutRetain(const ObjCPropertyImplDecl *PropImpl) const;
};
} // End anonymous namespace.
if (isReleasedByCIFilterDealloc(PropImpl))
return ReleaseRequirement::MustNotReleaseDirectly;
+ if (isNibLoadedIvarWithoutRetain(PropImpl))
+ return ReleaseRequirement::Unknown;
+
return ReleaseRequirement::MustRelease;
case ObjCPropertyDecl::Weak:
return false;
}
+/// Returns whether the ivar backing the property is an IBOutlet that
+/// has its value set by nib loading code without retaining the value.
+///
+/// On macOS, if there is no setter, the nib-loading code sets the ivar
+/// directly, without retaining the value,
+///
+/// On iOS and its derivatives, the nib-loading code will call
+/// -setValue:forKey:, which retains the value before directly setting the ivar.
+bool ObjCDeallocChecker::isNibLoadedIvarWithoutRetain(
+ const ObjCPropertyImplDecl *PropImpl) const {
+ const ObjCIvarDecl *IvarDecl = PropImpl->getPropertyIvarDecl();
+ if (!IvarDecl->hasAttr<IBOutletAttr>())
+ return false;
+
+ const llvm::Triple &Target =
+ IvarDecl->getASTContext().getTargetInfo().getTriple();
+
+ if (!Target.isMacOSX())
+ return false;
+
+ if (PropImpl->getPropertyDecl()->getSetterMethodDecl())
+ return false;
+
+ return true;
+}
+
void ento::registerObjCDeallocChecker(CheckerManager &Mgr) {
const LangOptions &LangOpts = Mgr.getLangOpts();
// These checker only makes sense under MRR.
-// RUN: %clang_cc1 -analyze -analyzer-checker=osx.cocoa.Dealloc -fblocks -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=osx.cocoa.Dealloc -fblocks -triple x86_64-apple-ios4.0 -DMACOS=0 -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=osx.cocoa.Dealloc -fblocks -triple x86_64-apple-macosx10.6.0 -DMACOS=1 -verify %s
// RUN: %clang_cc1 -analyze -analyzer-checker=osx.cocoa.Dealloc -fblocks -triple x86_64-apple-darwin10 -fobjc-arc -fobjc-runtime-has-weak -verify %s
#include "Inputs/system-header-simulator-for-objc-dealloc.h"
@implementation NotMissingDeallocCIFilter // no-warning
@synthesize inputIvar = inputIvar;
@end
+
+
+@interface ClassWithRetainPropWithIBOutletIvarButNoSetter : NSObject {
+ // On macOS, the nib-loading code will set the ivar directly without
+ // retaining value (unike iOS, where it is retained). This means that
+ // on macOS we should not warn about a missing release for a property backed
+ // by an IBOutlet ivar when that property does not have a setter.
+ IBOutlet NSObject *ivarForOutlet;
+}
+
+@property (readonly, retain) NSObject *ivarForOutlet;
+#if NON_ARC && !MACOS
+// expected-note@-2 {{Property is declared here}}
+#endif
+@end
+
+@implementation ClassWithRetainPropWithIBOutletIvarButNoSetter
+
+@synthesize ivarForOutlet;
+#if NON_ARC && !MACOS
+// expected-note@-2 {{Property is synthesized here}}
+#endif
+- (void)dealloc {
+
+#if NON_ARC
+ [super dealloc];
+#if !MACOS
+// expected-warning@-2{{The 'ivarForOutlet' ivar in 'ClassWithRetainPropWithIBOutletIvarButNoSetter' was retained by a synthesized property but not released before '[super dealloc]'}}
+#endif
+#endif
+}
+
+@end
+
+@interface ClassWithRetainPropWithIBOutletIvarAndShadowingReadWrite : NSObject {
+ IBOutlet NSObject *ivarForOutlet;
+}
+
+@property (readonly, retain) NSObject *ivarForOutlet;
+
+@end
+
+@interface ClassWithRetainPropWithIBOutletIvarAndShadowingReadWrite ()
+
+// Since there is a shadowing readwrite property, there will be a retaining
+// setter and so the ivar will be retained by nib-loading code even on
+// macOS and therefore must be released.
+@property (readwrite, retain) NSObject *ivarForOutlet;
+#if NON_ARC
+// expected-note@-2 {{Property is declared here}}
+#endif
+@end
+
+@implementation ClassWithRetainPropWithIBOutletIvarAndShadowingReadWrite
+
+@synthesize ivarForOutlet;
+#if NON_ARC
+// expected-note@-2 {{Property is synthesized here}}
+#endif
+- (void)dealloc {
+
+#if NON_ARC
+ [super dealloc];
+// expected-warning@-1{{The 'ivarForOutlet' ivar in 'ClassWithRetainPropWithIBOutletIvarAndShadowingReadWrite' was retained by a synthesized property but not released before '[super dealloc]'}}
+#endif
+}
+
+@end