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