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

248 lines
5.6 KiB
Objective-C

// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,debug.ExprInspection -analyzer-store=region -verify -Wno-objc-root-class %s
void clang_analyzer_eval(int);
typedef signed char BOOL;
typedef unsigned int NSUInteger;
typedef struct _NSZone NSZone;
@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator;
@protocol NSObject - (BOOL)isEqual:(id)object; @end
@protocol NSCopying - (id)copyWithZone:(NSZone *)zone; @end
@protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder; @end
@protocol NSMutableCopying - (id)mutableCopyWithZone:(NSZone *)zone; @end
@interface NSObject <NSObject> {}
+(id)alloc;
-(id)init;
-(id)autorelease;
-(id)copy;
-(id)retain;
-(oneway void)release;
@end
@interface NSString : NSObject <NSCopying, NSMutableCopying, NSCoding>
- (NSUInteger)length;
-(id)initWithFormat:(NSString *)f,...;
-(BOOL)isEqualToString:(NSString *)s;
+ (id)string;
@end
@interface NSNumber : NSObject {}
+(id)alloc;
-(id)initWithInteger:(int)i;
@end
// rdar://6946338
@interface Test1 : NSObject {
NSString *text;
}
-(id)myMethod;
@property (nonatomic, assign) NSString *text;
@end
@implementation Test1
@synthesize text;
-(id)myMethod {
Test1 *cell = [[[Test1 alloc] init] autorelease];
NSString *string1 = [[NSString alloc] initWithFormat:@"test %f", 0.0]; // expected-warning {{Potential leak}}
cell.text = string1;
return cell;
}
@end
// rdar://8824416
@interface MyNumber : NSObject
{
NSNumber* _myNumber;
}
- (id)initWithNumber:(NSNumber *)number;
@property (nonatomic, readonly) NSNumber* myNumber;
@property (nonatomic, readonly) NSNumber* newMyNumber;
@end
@implementation MyNumber
@synthesize myNumber=_myNumber;
- (id)initWithNumber:(NSNumber *)number
{
self = [super init];
if ( self )
{
_myNumber = [number copy];
}
return self;
}
- (NSNumber*)newMyNumber
{
if ( _myNumber )
return [_myNumber retain];
return [[NSNumber alloc] initWithInteger:1];
}
- (id)valueForUndefinedKey:(NSString*)key
{
id value = 0;
if ([key isEqualToString:@"MyIvarNumberAsPropertyOverReleased"])
value = self.myNumber; // _myNumber will be over released, since the value returned from self.myNumber is not retained.
else if ([key isEqualToString:@"MyIvarNumberAsPropertyOk"])
value = [self.myNumber retain]; // this line fixes the over release
else if ([key isEqualToString:@"MyIvarNumberAsNewMyNumber"])
value = self.newMyNumber; // this one is ok, since value is returned retained
else
value = [[NSNumber alloc] initWithInteger:0];
return [value autorelease]; // expected-warning {{Object autoreleased too many times}}
}
@end
NSNumber* numberFromMyNumberProperty(MyNumber* aMyNumber)
{
NSNumber* result = aMyNumber.myNumber;
return [result autorelease]; // expected-warning {{Object autoreleased too many times}}
}
// rdar://6611873
@interface Person : NSObject {
NSString *_name;
}
@property (retain) NSString * name;
@end
@implementation Person
@synthesize name = _name;
@end
void rdar6611873() {
Person *p = [[[Person alloc] init] autorelease];
p.name = [[NSString string] retain]; // expected-warning {{leak}}
p.name = [[NSString alloc] init]; // expected-warning {{leak}}
}
@interface SubPerson : Person
-(NSString *)foo;
@end
@implementation SubPerson
-(NSString *)foo {
return super.name;
}
@end
// <rdar://problem/9241180> Static analyzer doesn't detect uninitialized variable issues for property accesses
@interface RDar9241180
@property (readwrite,assign) id x;
-(id)testAnalyzer1:(int) y;
-(void)testAnalyzer2;
@end
@implementation RDar9241180
@synthesize x;
-(id)testAnalyzer1:(int)y {
RDar9241180 *o;
if (y && o.x) // expected-warning {{Property access on an uninitialized object pointer}}
return o;
return o; // expected-warning {{Undefined or garbage value returned to caller}}
}
-(void)testAnalyzer2 {
id y;
self.x = y; // expected-warning {{Argument for property setter is an uninitialized value}}
}
@end
//------
// Property accessor synthesis
//------
void testConsistency(Person *p) {
clang_analyzer_eval(p.name == p.name); // expected-warning{{TRUE}}
extern void doSomethingWithPerson(Person *p);
id origName = p.name;
clang_analyzer_eval(p.name == origName); // expected-warning{{TRUE}}
doSomethingWithPerson(p);
clang_analyzer_eval(p.name == origName); // expected-warning{{UNKNOWN}}
}
void testOverrelease(Person *p) {
[p.name release]; // expected-warning{{not owned}}
}
@interface IntWrapper
@property int value;
@end
@implementation IntWrapper
@synthesize value;
@end
void testConsistencyInt(IntWrapper *w) {
clang_analyzer_eval(w.value == w.value); // expected-warning{{TRUE}}
int origValue = w.value;
if (origValue != 42)
return;
clang_analyzer_eval(w.value == 42); // expected-warning{{TRUE}}
}
void testConsistencyInt2(IntWrapper *w) {
if (w.value != 42)
return;
clang_analyzer_eval(w.value == 42); // expected-warning{{TRUE}}
}
typedef struct {
int value;
} IntWrapperStruct;
@interface StructWrapper
@property IntWrapperStruct inner;
@end
@implementation StructWrapper
@synthesize inner;
@end
void testConsistencyStruct(StructWrapper *w) {
clang_analyzer_eval(w.inner.value == w.inner.value); // expected-warning{{TRUE}}
int origValue = w.inner.value;
if (origValue != 42)
return;
clang_analyzer_eval(w.inner.value == 42); // expected-warning{{TRUE}}
}
@interface OpaqueIntWrapper
@property int value;
@end
// For now, don't assume a property is implemented using an ivar unless we can
// actually see that it is.
void testOpaqueConsistency(OpaqueIntWrapper *w) {
clang_analyzer_eval(w.value == w.value); // expected-warning{{UNKNOWN}}
}