NSContainers.m revision 2ffcd18b845d4f855074ff7011c46e20616e08fd
1// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.NonNilReturnValue,osx.cocoa.NilArg,osx.cocoa.Loops -verify -Wno-objc-root-class %s 2typedef unsigned long NSUInteger; 3typedef signed char BOOL; 4typedef struct _NSZone NSZone; 5@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator; 6@protocol NSObject 7@end 8@protocol NSCopying 9- (id)copyWithZone:(NSZone *)zone; 10@end 11@protocol NSMutableCopying 12- (id)mutableCopyWithZone:(NSZone *)zone; 13@end 14@protocol NSCoding 15- (void)encodeWithCoder:(NSCoder *)aCoder; 16@end 17@protocol NSSecureCoding <NSCoding> 18@required 19+ (BOOL)supportsSecureCoding; 20@end 21@interface NSObject <NSObject> {} 22- (id)init; 23+ (id)alloc; 24@end 25 26typedef struct { 27 unsigned long state; 28 id *itemsPtr; 29 unsigned long *mutationsPtr; 30 unsigned long extra[5]; 31} NSFastEnumerationState; 32@protocol NSFastEnumeration 33- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id [])buffer count:(NSUInteger)len; 34@end 35 36@interface NSArray : NSObject <NSCopying, NSMutableCopying, NSSecureCoding, NSFastEnumeration> 37- (NSUInteger)count; 38- (id)objectAtIndex:(NSUInteger)index; 39@end 40 41@interface NSArray (NSExtendedArray) 42- (NSArray *)arrayByAddingObject:(id)anObject; 43- (void)setObject:(id)obj atIndexedSubscript:(NSUInteger)idx __attribute__((availability(macosx,introduced=10.8))); 44@end 45 46@interface NSArray (NSArrayCreation) 47+ (instancetype)arrayWithObjects:(const id [])objects count:(NSUInteger)cnt; 48@end 49 50@interface NSMutableArray : NSArray 51 52- (void)addObject:(id)anObject; 53- (void)insertObject:(id)anObject atIndex:(NSUInteger)index; 54- (void)removeLastObject; 55- (void)removeObjectAtIndex:(NSUInteger)index; 56- (void)replaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject; 57 58@end 59 60@interface NSDictionary : NSObject <NSCopying, NSMutableCopying, NSSecureCoding, NSFastEnumeration> 61 62- (NSUInteger)count; 63- (id)objectForKey:(id)aKey; 64- (NSEnumerator *)keyEnumerator; 65 66@end 67 68@interface NSDictionary (NSDictionaryCreation) 69 70+ (id)dictionary; 71+ (id)dictionaryWithObject:(id)object forKey:(id <NSCopying>)key; 72+ (instancetype)dictionaryWithObjects:(const id [])objects forKeys:(const id <NSCopying> [])keys count:(NSUInteger)cnt; 73 74@end 75 76@interface NSMutableDictionary : NSDictionary 77 78- (void)removeObjectForKey:(id)aKey; 79- (void)setObject:(id)anObject forKey:(id <NSCopying>)aKey; 80 81@end 82 83@interface NSMutableDictionary (NSExtendedMutableDictionary) 84 85- (void)addEntriesFromDictionary:(NSDictionary *)otherDictionary; 86- (void)removeAllObjects; 87- (void)removeObjectsForKeys:(NSArray *)keyArray; 88- (void)setDictionary:(NSDictionary *)otherDictionary; 89- (void)setObject:(id)obj forKeyedSubscript:(id <NSCopying>)key __attribute__((availability(macosx,introduced=10.8))); 90 91@end 92 93@interface NSString : NSObject <NSCopying, NSMutableCopying, NSSecureCoding> 94 95@end 96 97@interface NSNull : NSObject <NSCopying, NSSecureCoding> 98+ (NSNull *)null; 99@end 100 101// NSMutableArray API 102void testNilArgNSMutableArray1() { 103 NSMutableArray *marray = [[NSMutableArray alloc] init]; 104 [marray addObject:0]; // expected-warning {{Argument to 'NSMutableArray' method 'addObject:' cannot be nil}} 105} 106 107void testNilArgNSMutableArray2() { 108 NSMutableArray *marray = [[NSMutableArray alloc] init]; 109 [marray insertObject:0 atIndex:1]; // expected-warning {{Argument to 'NSMutableArray' method 'insertObject:atIndex:' cannot be nil}} 110} 111 112void testNilArgNSMutableArray3() { 113 NSMutableArray *marray = [[NSMutableArray alloc] init]; 114 [marray replaceObjectAtIndex:1 withObject:0]; // expected-warning {{Argument to 'NSMutableArray' method 'replaceObjectAtIndex:withObject:' cannot be nil}} 115} 116 117void testNilArgNSMutableArray4() { 118 NSMutableArray *marray = [[NSMutableArray alloc] init]; 119 [marray setObject:0 atIndexedSubscript:1]; // expected-warning {{Argument to 'NSMutableArray' method 'setObject:atIndexedSubscript:' cannot be nil}} 120} 121 122void testNilArgNSMutableArray5() { 123 NSMutableArray *marray = [[NSMutableArray alloc] init]; 124 marray[1] = 0; // expected-warning {{Array element cannot be nil}} 125} 126 127// NSArray API 128void testNilArgNSArray1() { 129 NSArray *array = [[NSArray alloc] init]; 130 NSArray *copyArray = [array arrayByAddingObject:0]; // expected-warning {{Argument to 'NSArray' method 'arrayByAddingObject:' cannot be nil}} 131} 132 133// NSMutableDictionary and NSDictionary APIs. 134void testNilArgNSMutableDictionary1(NSMutableDictionary *d, NSString* key) { 135 [d setObject:0 forKey:key]; // expected-warning {{Value argument to 'setObject:forKey:' cannot be nil}} 136} 137 138void testNilArgNSMutableDictionary2(NSMutableDictionary *d, NSObject *obj) { 139 [d setObject:obj forKey:0]; // expected-warning {{Key argument to 'setObject:forKey:' cannot be nil}} 140} 141 142void testNilArgNSMutableDictionary3(NSMutableDictionary *d) { 143 [d removeObjectForKey:0]; // expected-warning {{Value argument to 'removeObjectForKey:' cannot be nil}} 144} 145 146void testNilArgNSMutableDictionary5(NSMutableDictionary *d, NSString* key) { 147 d[key] = 0; // expected-warning {{Value stored into 'NSMutableDictionary' cannot be nil}} 148} 149void testNilArgNSMutableDictionary6(NSMutableDictionary *d, NSString *key) { 150 if (key) 151 ; 152 d[key] = 0; // expected-warning {{'NSMutableDictionary' key cannot be nil}} 153 // expected-warning@-1 {{Value stored into 'NSMutableDictionary' cannot be nil}} 154} 155 156NSDictionary *testNilArgNSDictionary1(NSString* key) { 157 return [NSDictionary dictionaryWithObject:0 forKey:key]; // expected-warning {{Value argument to 'dictionaryWithObject:forKey:' cannot be nil}} 158} 159NSDictionary *testNilArgNSDictionary2(NSObject *obj) { 160 return [NSDictionary dictionaryWithObject:obj forKey:0]; // expected-warning {{Key argument to 'dictionaryWithObject:forKey:' cannot be nil}} 161} 162 163id testCreateDictionaryLiteralKey(id value, id nilKey) { 164 if (nilKey) 165 ; 166 return @{@"abc":value, nilKey:@"abc"}; // expected-warning {{Dictionary key cannot be nil}} 167} 168 169id testCreateDictionaryLiteralValue(id nilValue) { 170 if (nilValue) 171 ; 172 return @{@"abc":nilValue}; // expected-warning {{Dictionary value cannot be nil}} 173} 174 175id testCreateDictionaryLiteral(id nilValue, id nilKey) { 176 if (nilValue) 177 ; 178 if (nilKey) 179 ; 180 return @{@"abc":nilValue, nilKey:@"abc"}; // expected-warning {{Dictionary key cannot be nil}} 181 // expected-warning@-1 {{Dictionary value cannot be nil}} 182} 183 184id testCreateArrayLiteral(id myNil) { 185 if (myNil) 186 ; 187 return @[ @"a", myNil, @"c" ]; // expected-warning {{Array element cannot be nil}} 188} 189 190// Test inline defensive checks suppression. 191void idc(id x) { 192 if (x) 193 ; 194} 195void testIDC(NSMutableDictionary *d, NSString *key) { 196 idc(key); 197 d[key] = @"abc"; // no-warning 198} 199 200@interface Foo { 201@public 202 int x; 203} 204- (int *)getPtr; 205- (int)getInt; 206- (NSMutableDictionary *)getDictPtr; 207@property (retain, readonly, nonatomic) Foo* data; 208- (NSString*) stringForKeyFE: (id<NSCopying>)key; 209@end 210 211void idc2(id x) { 212 if (!x) 213 return; 214} 215Foo *retNil() { 216 return 0; 217} 218 219void testIDC2(Foo *obj) { 220 idc2(obj); 221 *[obj getPtr] = 1; // no-warning 222} 223 224int testIDC3(Foo *obj) { 225 idc2(obj); 226 return 1/[obj getInt]; 227} 228 229void testNilReceiverIDC(Foo *obj, NSString *key) { 230 NSMutableDictionary *D = [obj getDictPtr]; 231 idc(D); 232 D[key] = @"abc"; // no-warning 233} 234 235void testNilReceiverRetNil2(NSMutableDictionary *D, Foo *FooPtrIn, id value) { 236 NSString* const kKeyIdentifier = @"key"; 237 Foo *FooPtr = retNil(); 238 NSString *key = [[FooPtr data] stringForKeyFE: kKeyIdentifier]; 239 // key is nil because FooPtr is nil. However, FooPtr is set to nil inside an 240 // inlined function, so this error report should be suppressed. 241 [D setObject: value forKey: key]; // no-warning 242} 243 244void testAssumeNSNullNullReturnsNonNil(NSMutableDictionary *Table, id Object, 245 id InValue) { 246 id Value = Object ? [Table objectForKey:Object] : [NSNull null]; 247 if (!Value) { 248 Value = InValue; 249 [Table setObject:Value forKey:Object]; // no warning 250 } 251} 252 253void testCollectionIsNotEmptyWhenCountIsGreaterThanZero(NSMutableDictionary *D){ 254 if ([D count] > 0) { // Count is greater than zero. 255 NSString *s = 0; 256 for (NSString *key in D) { 257 s = key; // Loop is always entered. 258 } 259 [D removeObjectForKey:s]; // no warning 260 } 261} 262 263 264