llvm-project/clang/test/Analysis/DeallocMissingRelease.m

926 lines
21 KiB
Objective-C

// 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"
#define NON_ARC !__has_feature(objc_arc)
#if NON_ARC
#define WEAK_ON_ARC
#else
#define WEAK_ON_ARC __weak
#endif
// No diagnostics expected under ARC.
#if !NON_ARC
// expected-no-diagnostics
#endif
// Do not warn about missing release in -dealloc for ivars.
@interface MyIvarClass1 : NSObject {
NSObject *_ivar;
}
@end
@implementation MyIvarClass1
- (instancetype)initWithIvar:(NSObject *)ivar
{
self = [super init];
if (!self)
return nil;
#if NON_ARC
_ivar = [ivar retain];
#endif
return self;
}
- (void)dealloc
{
#if NON_ARC
[super dealloc];
#endif
}
@end
@interface MyIvarClass2 : NSObject {
NSObject *_ivar;
}
- (NSObject *)ivar;
- (void)setIvar:(NSObject *)ivar;
@end
@implementation MyIvarClass2
- (instancetype)init
{
self = [super init];
return self;
}
- (void)dealloc
{
#if NON_ARC
[super dealloc];
#endif
}
- (NSObject *)ivar
{
return _ivar;
}
- (void)setIvar:(NSObject *)ivar
{
#if NON_ARC
[_ivar release];
_ivar = [ivar retain];
#else
_ivar = ivar;
#endif
}
@end
// Warn about missing release in -dealloc for properties.
@interface MyPropertyClass1 : NSObject
@property (copy) NSObject *ivar;
@end
@implementation MyPropertyClass1
- (void)dealloc
{
#if NON_ARC
[super dealloc]; // expected-warning {{The '_ivar' ivar in 'MyPropertyClass1' was copied by a synthesized property but not released before '[super dealloc]'}}
#endif
}
@end
@interface MyPropertyClass2 : NSObject
@property (retain) NSObject *ivar;
@end
@implementation MyPropertyClass2
- (void)dealloc
{
#if NON_ARC
[super dealloc]; // expected-warning {{The '_ivar' ivar in 'MyPropertyClass2' was retained by a synthesized property but not released before '[super dealloc]'}}
#endif
}
@end
@interface MyPropertyClass3 : NSObject {
NSObject *_ivar;
}
@property (retain) NSObject *ivar;
@end
@implementation MyPropertyClass3
@synthesize ivar = _ivar;
- (void)dealloc
{
#if NON_ARC
[super dealloc]; // expected-warning {{The '_ivar' ivar in 'MyPropertyClass3' was retained by a synthesized property but not released before '[super dealloc]'}}
#endif
}
@end
@interface MyPropertyClass4 : NSObject {
void (^_blockPropertyIvar)(void);
}
@property (copy) void (^blockProperty)(void);
@property (copy) void (^blockProperty2)(void);
@property (copy) void (^blockProperty3)(void);
@end
@implementation MyPropertyClass4
@synthesize blockProperty = _blockPropertyIvar;
- (void)dealloc
{
#if NON_ARC
[_blockProperty2 release];
Block_release(_blockProperty3);
[super dealloc]; // expected-warning {{The '_blockPropertyIvar' ivar in 'MyPropertyClass4' was copied by a synthesized property but not released before '[super dealloc]'}}
#endif
}
@end
@interface MyPropertyClass5 : NSObject {
WEAK_ON_ARC NSObject *_ivar;
}
@property (weak) NSObject *ivar;
@end
@implementation MyPropertyClass5
@synthesize ivar = _ivar;
- (void)dealloc
{
#if NON_ARC
[super dealloc]; // no-warning because it is a weak property
#endif
}
@end
@interface MyPropertyClassWithReturnInDealloc : NSObject {
NSObject *_ivar;
}
@property (retain) NSObject *ivar;
@end
@implementation MyPropertyClassWithReturnInDealloc
@synthesize ivar = _ivar;
- (void)dealloc
{
return;
#if NON_ARC
// expected-warning@-2{{The '_ivar' ivar in 'MyPropertyClassWithReturnInDealloc' was retained by a synthesized property but not released before '[super dealloc]'}}
[super dealloc];
#endif
}
@end
@interface MyPropertyClassWithReleaseInOtherInstance : NSObject {
NSObject *_ivar;
MyPropertyClassWithReleaseInOtherInstance *_other;
}
@property (retain) NSObject *ivar;
-(void)releaseIvars;
@end
@implementation MyPropertyClassWithReleaseInOtherInstance
@synthesize ivar = _ivar;
-(void)releaseIvars; {
#if NON_ARC
[_ivar release];
#endif
}
- (void)dealloc
{
[_other releaseIvars];
#if NON_ARC
[super dealloc]; // expected-warning {{The '_ivar' ivar in 'MyPropertyClassWithReleaseInOtherInstance' was retained by a synthesized property but not released before '[super dealloc]'}}
#endif
}
@end
@interface MyPropertyClassWithNeitherReturnNorSuperDealloc : NSObject {
NSObject *_ivar;
}
@property (retain) NSObject *ivar;
@end
@implementation MyPropertyClassWithNeitherReturnNorSuperDealloc
@synthesize ivar = _ivar;
- (void)dealloc
{
}
#if NON_ARC
// expected-warning@-2 {{method possibly missing a [super dealloc] call}} (From Sema)
// expected-warning@-3{{The '_ivar' ivar in 'MyPropertyClassWithNeitherReturnNorSuperDealloc' was retained by a synthesized property but not released before '[super dealloc]'}}
#endif
@end
// <rdar://problem/6380411>: 'myproperty' has kind 'assign' and thus the
// assignment through the setter does not perform a release.
@interface MyObject : NSObject {
id __unsafe_unretained _myproperty;
}
@property(assign) id myproperty;
@end
@implementation MyObject
@synthesize myproperty=_myproperty; // no-warning
- (void)dealloc {
// Don't claim that myproperty is released since it the property
// has the 'assign' attribute.
self.myproperty = 0; // no-warning
#if NON_ARC
[super dealloc];
#endif
}
@end
@interface ClassWithControlFlowInRelease : NSObject {
BOOL _ivar1;
}
@property (retain) NSObject *ivar2;
@end
@implementation ClassWithControlFlowInRelease
- (void)dealloc; {
if (_ivar1) {
// We really should warn because there is a path through -dealloc on which
// _ivar2 is not released.
#if NON_ARC
[_ivar2 release];
#endif
}
#if NON_ARC
[super dealloc]; // expected-warning {{The '_ivar2' ivar in 'ClassWithControlFlowInRelease' was retained by a synthesized property but not released before '[super dealloc]'}}
#endif
}
@end
// Don't warn when the property is nil'd out in -dealloc
@interface ClassWithNildOutProperty : NSObject
@property (retain) NSObject *ivar;
@property (assign) int *intPtrProp;
@end
@implementation ClassWithNildOutProperty
- (void)dealloc; {
self.ivar = nil;
// Make sure to handle setting a non-retainable property to 0.
self.intPtrProp = 0;
#if NON_ARC
[super dealloc]; // no-warning
#endif
}
@end
// Do warn when the ivar but not the property is nil'd out in -dealloc
@interface ClassWithNildOutIvar : NSObject
@property (retain) NSObject *ivar;
@end
@implementation ClassWithNildOutIvar
- (void)dealloc; {
// Oops. Meant self.ivar = nil
_ivar = nil;
#if NON_ARC
[super dealloc]; // expected-warning {{The '_ivar' ivar in 'ClassWithNildOutIvar' was retained by a synthesized property but not released before '[super dealloc]'}}
#endif
}
@end
// Do warn when the ivar is updated to a different value that is then
// released.
@interface ClassWithUpdatedIvar : NSObject
@property (retain) NSObject *ivar;
@end
@implementation ClassWithUpdatedIvar
- (void)dealloc; {
_ivar = [[NSObject alloc] init];
#if NON_ARC
[_ivar release];
#endif
#if NON_ARC
[super dealloc]; // expected-warning {{The '_ivar' ivar in 'ClassWithUpdatedIvar' was retained by a synthesized property but not released before '[super dealloc]'}}
#endif
}
@end
// Don't warn when the property is nil'd out with a setter in -dealloc
@interface ClassWithNildOutPropertyViaSetter : NSObject
@property (retain) NSObject *ivar;
@end
@implementation ClassWithNildOutPropertyViaSetter
- (void)dealloc; {
[self setIvar:nil];
#if NON_ARC
[super dealloc]; // no-warning
#endif
}
@end
// Don't warn about missing releases when -dealloc helpers are called.
@interface ClassWithDeallocHelpers : NSObject
@property (retain) NSObject *ivarReleasedInMethod;
@property (retain) NSObject *propNilledOutInMethod;
@property (retain) NSObject *ivarReleasedInFunction;
@property (retain) NSObject *propNilledOutInFunction;
@property (retain) NSObject *ivarNeverReleased;
- (void)invalidateInMethod;
@end
void ReleaseValueHelper(NSObject *iv) {
#if NON_ARC
[iv release];
#endif
}
void NilOutPropertyHelper(ClassWithDeallocHelpers *o) {
o.propNilledOutInFunction = nil;
}
@implementation ClassWithDeallocHelpers
- (void)invalidateInMethod {
#if NON_ARC
[_ivarReleasedInMethod release];
#endif
self.propNilledOutInMethod = nil;
}
- (void)dealloc; {
ReleaseValueHelper(_ivarReleasedInFunction);
NilOutPropertyHelper(self);
[self invalidateInMethod];
#if NON_ARC
[super dealloc]; // expected-warning {{The '_ivarNeverReleased' ivar in 'ClassWithDeallocHelpers' was retained by a synthesized property but not released before '[super dealloc]'}}
#endif
}
@end
// Don't warn when self in -dealloc escapes.
@interface ClassWhereSelfEscapesViaMethodCall : NSObject
@property (retain) NSObject *ivar; // no-warning
@end
@interface ClassWhereSelfEscapesViaMethodCall (Other)
- (void)invalidate; // In other translation unit.
@end
@implementation ClassWhereSelfEscapesViaMethodCall
- (void)dealloc; {
[self invalidate];
#if NON_ARC
[super dealloc];
#endif
} // no-warning
@end
@interface ClassWhereSelfEscapesViaPropertyAccess : NSObject
@property (retain) NSObject *ivar;
@end
@interface ClassWhereSelfEscapesViaPropertyAccess (Other)
// The implementation of this property is unknown and therefore could
// release ivar.
@property (retain) NSObject *otherIvar;
@end
@implementation ClassWhereSelfEscapesViaPropertyAccess
- (void)dealloc; {
self.otherIvar = nil;
#if NON_ARC
[super dealloc];
#endif
} // no-warning
@end
// Don't treat self as escaping when setter called on *synthesized*
// property.
@interface ClassWhereSelfEscapesViaSynthesizedPropertyAccess : NSObject
@property (retain) NSObject *ivar;
@property (retain) NSObject *otherIvar;
@end
@implementation ClassWhereSelfEscapesViaSynthesizedPropertyAccess
- (void)dealloc; {
self.otherIvar = nil;
#if NON_ARC
[super dealloc]; // expected-warning {{The '_ivar' ivar in 'ClassWhereSelfEscapesViaSynthesizedPropertyAccess' was retained by a synthesized property but not released before '[super dealloc]'}}
#endif
}
@end
// Don't treat calls to system headers as escapes
@interface ClassWhereSelfEscapesViaCallToSystem : NSObject
@property (retain) NSObject *ivar1;
@property (retain) NSObject *ivar2;
@property (retain) NSObject *ivar3;
@property (retain) NSObject *ivar4;
@property (retain) NSObject *ivar5;
@property (retain) NSObject *ivar6;
@end
@implementation ClassWhereSelfEscapesViaCallToSystem
- (void)dealloc; {
#if NON_ARC
[_ivar2 release];
if (_ivar3) {
[_ivar3 release];
}
#endif
[[NSRunLoop currentRunLoop] cancelPerformSelectorsWithTarget:self];
[[NSNotificationCenter defaultCenter] removeObserver:self];
#if NON_ARC
[_ivar4 release];
if (_ivar5) {
[_ivar5 release];
}
#endif
[[NSNotificationCenter defaultCenter] removeObserver:self];
#if NON_ARC
if (_ivar6) {
[_ivar6 release];
}
[super dealloc]; // expected-warning {{The '_ivar1' ivar in 'ClassWhereSelfEscapesViaCallToSystem' was retained by a synthesized property but not released before '[super dealloc]'}}
#endif
}
@end
// Don't warn when value escapes.
@interface ClassWhereIvarValueEscapes : NSObject
@property (retain) NSObject *ivar;
@end
void ReleaseMe(id arg);
@implementation ClassWhereIvarValueEscapes
- (void)dealloc; {
ReleaseMe(_ivar);
#if NON_ARC
[super dealloc];
#endif
} // no-warning
@end
// Don't warn when value is known to be nil.
@interface ClassWhereIvarIsNil : NSObject
@property (retain) NSObject *ivarIsNil;
@end
@implementation ClassWhereIvarIsNil
- (void)dealloc; {
#if NON_ARC
if (_ivarIsNil)
[_ivarIsNil release];
[super dealloc];
#endif
} // no-warning
@end
// Don't warn for non-retainable properties.
@interface ClassWithNonRetainableProperty : NSObject
@property (assign) int *ivar; // no-warning
@end
@implementation ClassWithNonRetainableProperty
- (void)dealloc; {
#if NON_ARC
[super dealloc];
#endif
} // no-warning
@end
@interface SuperClassOfClassWithInlinedSuperDealloc : NSObject
@property (retain) NSObject *propInSuper;
@end
@implementation SuperClassOfClassWithInlinedSuperDealloc
- (void)dealloc {
#if NON_ARC
[super dealloc]; // expected-warning {{The '_propInSuper' ivar in 'SuperClassOfClassWithInlinedSuperDealloc' was retained by a synthesized property but not released before '[super dealloc]'}}
#endif
}
@end
@interface ClassWithInlinedSuperDealloc : SuperClassOfClassWithInlinedSuperDealloc
@property (retain) NSObject *propInSub;
@end
@implementation ClassWithInlinedSuperDealloc
- (void)dealloc {
#if NON_ARC
[super dealloc]; // expected-warning {{The '_propInSub' ivar in 'ClassWithInlinedSuperDealloc' was retained by a synthesized property but not released before '[super dealloc]'}}
#endif
}
@end
@interface SuperClassOfClassWithInlinedSuperDeallocAndInvalidation : NSObject
@property (retain) NSObject *propInSuper;
- (void)invalidate;
@end
@implementation SuperClassOfClassWithInlinedSuperDeallocAndInvalidation
- (void)invalidate {
#if NON_ARC
[_propInSuper release];
#endif
_propInSuper = nil;
}
- (void)dealloc {
[self invalidate];
#if NON_ARC
[super dealloc]; // no-warning
#endif
}
@end
@interface ClassWithInlinedSuperDeallocAndInvalidation : SuperClassOfClassWithInlinedSuperDeallocAndInvalidation
@property (retain) NSObject *propInSub;
@end
@implementation ClassWithInlinedSuperDeallocAndInvalidation
- (void)invalidate {
#if NON_ARC
[_propInSub release];
#endif
[super invalidate];
}
- (void)dealloc {
#if NON_ARC
[super dealloc]; // no-warning
#endif
}
@end
@interface SuperClassOfClassThatEscapesBeforeInliningSuper : NSObject
@property (retain) NSObject *propInSuper;
@end
@implementation SuperClassOfClassThatEscapesBeforeInliningSuper
- (void)dealloc {
#if NON_ARC
[super dealloc]; // expected-warning {{The '_propInSuper' ivar in 'SuperClassOfClassThatEscapesBeforeInliningSuper' was retained by a synthesized property but not released before '[super dealloc]'}}
#endif
}
@end
@interface ClassThatEscapesBeforeInliningSuper : SuperClassOfClassThatEscapesBeforeInliningSuper
@property (retain) NSObject *propInSub;
@end
@interface ClassThatEscapesBeforeInliningSuper (Other)
- (void)invalidate; // No implementation in translation unit.
@end
@implementation ClassThatEscapesBeforeInliningSuper
- (void)dealloc {
[self invalidate];
#if NON_ARC
[super dealloc]; // no-warning
#endif
}
@end
#if NON_ARC
@interface ReleaseIvarInField : NSObject {
int _tag;
union {
NSObject *field1;
NSObject *field2;
} _someUnion;
struct {
NSObject *field1;
} _someStruct;
}
@end
@implementation ReleaseIvarInField
- (void)dealloc {
if (_tag) {
[_someUnion.field1 release];
} else {
[_someUnion.field2 release];
}
[_someStruct.field1 release];
[super dealloc];
}
@end
#endif
struct SomeStruct {
int f;
};
@interface ZeroOutStructWithSetter : NSObject
@property(assign) struct SomeStruct s;
@end
@implementation ZeroOutStructWithSetter
- (void)dealloc {
struct SomeStruct zeroedS;
zeroedS.f = 0;
self.s = zeroedS;
#if NON_ARC
[super dealloc];
#endif
}
@end
#if NON_ARC
@interface ReleaseIvarInArray : NSObject {
NSObject *_array[3];
}
@end
@implementation ReleaseIvarInArray
- (void)dealloc {
for (int i = 0; i < 3; i++) {
[_array[i] release];
}
[super dealloc];
}
@end
#endif
// Don't warn about missing releases for subclasses of SenTestCase or
// for classes that are not subclasses of NSObject.
@interface SenTestCase : NSObject {}
@end
@interface MyClassTest : SenTestCase
@property (retain) NSObject *ivar;
@end
@implementation MyClassTest
-(void)tearDown {
#if NON_ARC
[_ivar release];
#endif
}
-(void)dealloc; {
#if NON_ARC
[super dealloc]; // no-warning
#endif
}
@end
@interface XCTestCase : NSObject {}
@end
@interface MyClassXCTest : XCTestCase
@property (retain) NSObject *ivar;
@end
@implementation MyClassXCTest
-(void)tearDown {
#if NON_ARC
[_ivar release];
#endif
}
-(void)dealloc; {
#if NON_ARC
[super dealloc]; // no-warning
#endif
}
@end
__attribute__((objc_root_class))
@interface NonNSObjectMissingDealloc
@property (retain) NSObject *ivar;
@end
@implementation NonNSObjectMissingDealloc
-(void)dealloc; {
}
@end
// Warn about calling -dealloc rather than release by mistake.
@interface CallDeallocOnRetainPropIvar : NSObject {
NSObject *okToDeallocDirectly;
}
@property (retain) NSObject *ivar;
@end
@implementation CallDeallocOnRetainPropIvar
- (void)dealloc
{
#if NON_ARC
// Only warn for synthesized ivars.
[okToDeallocDirectly dealloc]; // no-warning
[_ivar dealloc]; // expected-warning {{'_ivar' should be released rather than deallocated}}
[super dealloc];
#endif
}
@end
// CIFilter special cases.
// By design, -[CIFilter dealloc] releases (by calling -setValue: forKey: with
// 'nil') all ivars (even in its *subclasses*) with names starting with
// 'input' or that are backed by properties with names starting with 'input'.
// The Dealloc checker needs to take particular care to not warn about missing
// releases in this case -- if the user adds a release quiet the
// warning it may result in an over release.
@interface ImmediateSubCIFilter : CIFilter {
NSObject *inputIvar;
NSObject *nonInputIvar;
NSObject *notPrefixedButBackingPrefixedProperty;
NSObject *inputPrefixedButBackingNonPrefixedProperty;
}
@property(retain) NSObject *inputIvar;
@property(retain) NSObject *nonInputIvar;
@property(retain) NSObject *inputAutoSynthesizedIvar;
@property(retain) NSObject *inputExplicitlySynthesizedToNonPrefixedIvar;
@property(retain) NSObject *nonPrefixedPropertyBackedByExplicitlySynthesizedPrefixedIvar;
@end
@implementation ImmediateSubCIFilter
@synthesize inputIvar = inputIvar;
@synthesize nonInputIvar = nonInputIvar;
@synthesize inputExplicitlySynthesizedToNonPrefixedIvar = notPrefixedButBackingPrefixedProperty;
@synthesize nonPrefixedPropertyBackedByExplicitlySynthesizedPrefixedIvar = inputPrefixedButBackingNonPrefixedProperty;
- (void)dealloc {
#if NON_ARC
// We don't want warnings here for:
// inputIvar
// inputAutoSynthesizedIvar
// inputExplicitlySynthesizedToNonPrefixedIvar
// inputPrefixedButBackingNonPrefixedProperty
[super dealloc];
// expected-warning@-1 {{The 'nonInputIvar' ivar in 'ImmediateSubCIFilter' was retained by a synthesized property but not released before '[super dealloc]'}}
#endif
}
@end
@interface SubSubCIFilter : CIFilter {
NSObject *inputIvarInSub;
}
@property(retain) NSObject *inputIvarInSub;
@end
@implementation SubSubCIFilter
@synthesize inputIvarInSub = inputIvarInSub;
- (void)dealloc {
// Don't warn about inputIvarInSub.
#if NON_ARC
[super dealloc];
#endif
}
@end
@interface OverreleasingCIFilter : CIFilter {
NSObject *inputIvar;
}
@property(retain) NSObject *inputIvar;
@end
@implementation OverreleasingCIFilter
@synthesize inputIvar = inputIvar;
- (void)dealloc {
#if NON_ARC
// This is an over release because CIFilter's dealloc will also release it.
[inputIvar release]; // expected-warning {{The 'inputIvar' ivar in 'OverreleasingCIFilter' will be released by '-[CIFilter dealloc]' but also released here}}
[super dealloc]; // no-warning
#endif
}
@end
@interface NotMissingDeallocCIFilter : CIFilter {
NSObject *inputIvar;
}
@property(retain) NSObject *inputIvar;
@end
@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;
@end
@implementation ClassWithRetainPropWithIBOutletIvarButNoSetter
@synthesize ivarForOutlet;
- (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;
@end
@implementation ClassWithRetainPropWithIBOutletIvarAndShadowingReadWrite
@synthesize ivarForOutlet;
- (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