diff options
Diffstat (limited to 'test/Analysis/objc_invalidation.m')
-rw-r--r-- | test/Analysis/objc_invalidation.m | 199 |
1 files changed, 191 insertions, 8 deletions
diff --git a/test/Analysis/objc_invalidation.m b/test/Analysis/objc_invalidation.m index 357c5e8..a6f5ec3 100644 --- a/test/Analysis/objc_invalidation.m +++ b/test/Analysis/objc_invalidation.m @@ -1,4 +1,11 @@ -// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.osx.cocoa.InstanceVariableInvalidation -fobjc-default-synthesize-properties -verify %s +// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.osx.cocoa.InstanceVariableInvalidation -DRUN_IVAR_INVALIDATION -fobjc-default-synthesize-properties -verify %s +// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.osx.cocoa.MissingInvalidationMethod -DRUN_MISSING_INVALIDATION_METHOD -fobjc-default-synthesize-properties -verify %s +extern void __assert_fail (__const char *__assertion, __const char *__file, + unsigned int __line, __const char *__function) + __attribute__ ((__noreturn__)); + +#define assert(expr) \ + ((expr) ? (void)(0) : __assert_fail (#expr, __FILE__, __LINE__, __func__)) @protocol NSObject @end @@ -29,12 +36,22 @@ extern void NSLog(NSString *format, ...) __attribute__((format(__NSString__, 1, - (void) invalidate2 __attribute__((annotate("objc_instance_variable_invalidator"))); @end +@protocol Invalidation3; +@protocol Invalidation2; + @interface Invalidation2Class <Invalidation2> @end @interface Invalidation1Class <Invalidation1> @end +@interface ClassWithInvalidationMethodInCategory <NSObject> +@end + +@interface ClassWithInvalidationMethodInCategory () +- (void) invalidate __attribute__((annotate("objc_instance_variable_invalidator"))); +@end + @interface SomeInvalidationImplementingObject: NSObject <Invalidation3, Invalidation2> { SomeInvalidationImplementingObject *ObjA; // invalidation in the parent } @@ -65,6 +82,11 @@ extern void NSLog(NSString *format, ...) __attribute__((format(__NSString__, 1, SomeInvalidationImplementingObject *_Prop5; // property with @synthesize, invalidate via getter method SomeInvalidationImplementingObject *_Prop8; + // Ivars invalidated by the partial invalidator. + SomeInvalidationImplementingObject *Ivar9; + SomeInvalidationImplementingObject *_Prop10; + SomeInvalidationImplementingObject *Ivar11; + // No warnings on these as they are not invalidatable. NSObject *NIvar1; NSObject *NObj2; @@ -92,15 +114,21 @@ extern void NSLog(NSString *format, ...) __attribute__((format(__NSString__, 1, -(void)invalidate; +// Partial invalidators invalidate only some ivars. They are guaranteed to be +// called before the invalidation methods. +-(void)partialInvalidator1 __attribute__((annotate("objc_instance_variable_invalidator_partial"))); +-(void)partialInvalidator2 __attribute__((annotate("objc_instance_variable_invalidator_partial"))); @end @interface SomeSubclassInvalidatableObject() @property (assign) SomeInvalidationImplementingObject* Prop8; +@property (assign) SomeInvalidationImplementingObject* Prop10; @end @implementation SomeSubclassInvalidatableObject{ @private SomeInvalidationImplementingObject *Ivar5; + ClassWithInvalidationMethodInCategory *Ivar13; } @synthesize Prop7 = _propIvar; @@ -108,6 +136,7 @@ extern void NSLog(NSString *format, ...) __attribute__((format(__NSString__, 1, @synthesize Prop5 = _Prop5; @synthesize Prop4 = _Prop4; @synthesize Prop8 = _Prop8; +@synthesize Prop10 = _Prop10; - (void) setProp1: (SomeInvalidationImplementingObject*) InObj { @@ -143,11 +172,165 @@ extern void NSLog(NSString *format, ...) __attribute__((format(__NSString__, 1, NSLog(@"%@", _Ivar4); [super invalidate]; } -// expected-warning@-1 {{Instance variable Ivar1 needs to be invalidated}} - // expected-warning@-2 {{Instance variable MultipleProtocols needs to be invalidated}} - // expected-warning@-3 {{Instance variable MultInheritance needs to be invalidated}} - // expected-warning@-4 {{Property SynthIvarProp needs to be invalidated or set to nil}} - // expected-warning@-5 {{Instance variable _Ivar3 needs to be invalidated}} - // expected-warning@-6 {{Instance variable _Ivar4 needs to be invalidated}} - // expected-warning@-7 {{Instance variable Ivar5 needs to be invalidated or set to nil}} +#if RUN_IVAR_INVALIDATION +// expected-warning@-2 {{Instance variable Ivar1 needs to be invalidated}} +// expected-warning@-3 {{Instance variable MultipleProtocols needs to be invalidated}} +// expected-warning@-4 {{Instance variable MultInheritance needs to be invalidated}} +// expected-warning@-5 {{Property SynthIvarProp needs to be invalidated or set to nil}} +// expected-warning@-6 {{Instance variable _Ivar3 needs to be invalidated}} +// expected-warning@-7 {{Instance variable _Ivar4 needs to be invalidated}} +// expected-warning@-8 {{Instance variable Ivar5 needs to be invalidated or set to nil}} +// expected-warning@-9 {{Instance variable Ivar13 needs to be invalidated or set to nil}} +#endif + +-(void)partialInvalidator1 { + [Ivar9 invalidate]; + [_Prop10 invalidate]; +} + +-(void)partialInvalidator2 { + [Ivar11 invalidate]; +} + +@end + +// Example, where the same property is inherited through +// the parent and directly through a protocol. If a property backing ivar is +// synthesized in the parent, let the parent invalidate it. + +@protocol IDEBuildable <NSObject> +@property (readonly, strong) id <Invalidation2> ObjB; +@end + +@interface Parent : NSObject <IDEBuildable, Invalidation2> { + Invalidation2Class *_ObjB; // Invalidation of ObjB happens in the parent. +} +@end + +@interface Child: Parent <Invalidation2, IDEBuildable> +@end + +@implementation Parent{ + @private + Invalidation2Class *Ivar10; + Invalidation2Class *Ivar11; + Invalidation2Class *Ivar12; +} + +@synthesize ObjB = _ObjB; +- (void)invalidate{ + _ObjB = ((void*)0); + + assert(Ivar10 == 0); + + if (__builtin_expect(!(Ivar11 == ((void*)0)), 0)) + assert(0); + + assert(0 == Ivar12); + +} +@end + +@implementation Child +- (void)invalidate{ + // no-warning +} +@end + +@protocol Invalidation <NSObject> +- (void)invalidate __attribute__((annotate("objc_instance_variable_invalidator"))); +@end + +@interface Foo : NSObject <Invalidation> +@end + +@class FooBar; +@protocol FooBar_Protocol <NSObject> +@end + +@interface MissingInvalidationMethod : Foo <FooBar_Protocol> +@property (assign) MissingInvalidationMethod *foobar15_warn; +#if RUN_IVAR_INVALIDATION +// expected-warning@-2 {{Property foobar15_warn needs to be invalidated; no invalidation method is defined in the @implementation for MissingInvalidationMethod}} +#endif +@end +@implementation MissingInvalidationMethod +@end + +@interface MissingInvalidationMethod2 : Foo <FooBar_Protocol> { + Foo *Ivar1; +#if RUN_IVAR_INVALIDATION +// expected-warning@-2 {{Instance variable Ivar1 needs to be invalidated; no invalidation method is defined in the @implementation for MissingInvalidationMethod2}} +#endif +} +@end +@implementation MissingInvalidationMethod2 +@end + +@interface MissingInvalidationMethodDecl : NSObject { + Foo *Ivar1; +#if RUN_MISSING_INVALIDATION_METHOD +// expected-warning@-2 {{Instance variable Ivar1 needs to be invalidated; no invalidation method is declared for MissingInvalidationMethodDecl}} +#endif +} +@end +@implementation MissingInvalidationMethodDecl +@end + +@interface MissingInvalidationMethodDecl2 : NSObject { +@private + Foo *_foo1; +#if RUN_MISSING_INVALIDATION_METHOD +// expected-warning@-2 {{Instance variable _foo1 needs to be invalidated; no invalidation method is declared for MissingInvalidationMethodDecl2}} +#endif +} +@property (strong) Foo *bar1; @end +@implementation MissingInvalidationMethodDecl2 +@end + +@interface InvalidatedInPartial : SomeInvalidationImplementingObject { + SomeInvalidationImplementingObject *Ivar1; + SomeInvalidationImplementingObject *Ivar2; +} +-(void)partialInvalidator __attribute__((annotate("objc_instance_variable_invalidator_partial"))); +@end +@implementation InvalidatedInPartial +-(void)partialInvalidator { + [Ivar1 invalidate]; + Ivar2 = 0; +} +@end + +@interface NotInvalidatedInPartial : SomeInvalidationImplementingObject { + SomeInvalidationImplementingObject *Ivar1; +} +-(void)partialInvalidator __attribute__((annotate("objc_instance_variable_invalidator_partial"))); +-(void)partialInvalidatorCallsPartial __attribute__((annotate("objc_instance_variable_invalidator_partial"))); +@end +@implementation NotInvalidatedInPartial +-(void)partialInvalidator { +} +-(void)partialInvalidatorCallsPartial { + [self partialInvalidator]; +} + +-(void)invalidate { +} +#if RUN_IVAR_INVALIDATION +// expected-warning@-2 {{Instance variable Ivar1 needs to be invalidated or set to nil}} +#endif +@end + +// False negative. +@interface PartialCallsFull : SomeInvalidationImplementingObject { + SomeInvalidationImplementingObject *Ivar1; +} +-(void)partialInvalidator __attribute__((annotate("objc_instance_variable_invalidator_partial"))); +@end +@implementation PartialCallsFull +-(void)partialInvalidator { + [self invalidate]; +} // TODO: It would be nice to check that the full invalidation method actually invalidates the ivar. +@end + |