| // 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 |
| |
| void clang_analyzer_eval(int); |
| |
| typedef unsigned long NSUInteger; |
| typedef signed char BOOL; |
| typedef struct _NSZone NSZone; |
| @class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator; |
| @protocol NSObject |
| @end |
| @protocol NSCopying |
| - (id)copyWithZone:(NSZone *)zone; |
| @end |
| @protocol NSMutableCopying |
| - (id)mutableCopyWithZone:(NSZone *)zone; |
| @end |
| @protocol NSCoding |
| - (void)encodeWithCoder:(NSCoder *)aCoder; |
| @end |
| @protocol NSSecureCoding <NSCoding> |
| @required |
| + (BOOL)supportsSecureCoding; |
| @end |
| @interface NSObject <NSObject> {} |
| - (id)init; |
| + (id)alloc; |
| |
| - (id)mutableCopy; |
| @end |
| |
| typedef struct { |
| unsigned long state; |
| id *itemsPtr; |
| unsigned long *mutationsPtr; |
| unsigned long extra[5]; |
| } NSFastEnumerationState; |
| @protocol NSFastEnumeration |
| - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id [])buffer count:(NSUInteger)len; |
| @end |
| |
| @interface NSArray : NSObject <NSCopying, NSMutableCopying, NSSecureCoding, NSFastEnumeration> |
| - (NSUInteger)count; |
| - (id)objectAtIndex:(NSUInteger)index; |
| @end |
| |
| @interface NSArray (NSExtendedArray) |
| - (NSArray *)arrayByAddingObject:(id)anObject; |
| - (void)setObject:(id)obj atIndexedSubscript:(NSUInteger)idx __attribute__((availability(macosx,introduced=10.8))); |
| @end |
| |
| @interface NSArray (NSArrayCreation) |
| + (instancetype)arrayWithObjects:(const id [])objects count:(NSUInteger)cnt; |
| @end |
| |
| @interface NSMutableArray : NSArray |
| |
| - (void)addObject:(id)anObject; |
| - (void)insertObject:(id)anObject atIndex:(NSUInteger)index; |
| - (void)removeLastObject; |
| - (void)removeObjectAtIndex:(NSUInteger)index; |
| - (void)replaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject; |
| |
| @end |
| |
| @interface NSDictionary : NSObject <NSCopying, NSMutableCopying, NSSecureCoding, NSFastEnumeration> |
| |
| - (NSUInteger)count; |
| - (id)objectForKey:(id)aKey; |
| - (NSEnumerator *)keyEnumerator; |
| |
| @end |
| |
| @interface NSDictionary (NSDictionaryCreation) |
| |
| + (id)dictionary; |
| + (id)dictionaryWithObject:(id)object forKey:(id <NSCopying>)key; |
| + (instancetype)dictionaryWithObjects:(const id [])objects forKeys:(const id <NSCopying> [])keys count:(NSUInteger)cnt; |
| |
| @end |
| |
| @interface NSMutableDictionary : NSDictionary |
| |
| - (void)removeObjectForKey:(id)aKey; |
| - (void)setObject:(id)anObject forKey:(id <NSCopying>)aKey; |
| |
| @end |
| |
| @interface NSMutableDictionary (NSExtendedMutableDictionary) |
| |
| - (void)addEntriesFromDictionary:(NSDictionary *)otherDictionary; |
| - (void)removeAllObjects; |
| - (void)removeObjectsForKeys:(NSArray *)keyArray; |
| - (void)setDictionary:(NSDictionary *)otherDictionary; |
| - (void)setObject:(id)obj forKeyedSubscript:(id <NSCopying>)key __attribute__((availability(macosx,introduced=10.8))); |
| |
| @end |
| |
| @interface NSOrderedSet : NSObject <NSFastEnumeration> |
| @end |
| @interface NSOrderedSet (NSOrderedSetCreation) |
| - (NSUInteger)count; |
| @end |
| |
| @interface NSString : NSObject <NSCopying, NSMutableCopying, NSSecureCoding> |
| |
| @end |
| |
| @interface NSNull : NSObject <NSCopying, NSSecureCoding> |
| + (NSNull *)null; |
| @end |
| |
| // NSMutableArray API |
| void testNilArgNSMutableArray1() { |
| NSMutableArray *marray = [[NSMutableArray alloc] init]; |
| [marray addObject:0]; // expected-warning {{Argument to 'NSMutableArray' method 'addObject:' cannot be nil}} |
| } |
| |
| void testNilArgNSMutableArray2() { |
| NSMutableArray *marray = [[NSMutableArray alloc] init]; |
| [marray insertObject:0 atIndex:1]; // expected-warning {{Argument to 'NSMutableArray' method 'insertObject:atIndex:' cannot be nil}} |
| } |
| |
| void testNilArgNSMutableArray3() { |
| NSMutableArray *marray = [[NSMutableArray alloc] init]; |
| [marray replaceObjectAtIndex:1 withObject:0]; // expected-warning {{Argument to 'NSMutableArray' method 'replaceObjectAtIndex:withObject:' cannot be nil}} |
| } |
| |
| void testNilArgNSMutableArray4() { |
| NSMutableArray *marray = [[NSMutableArray alloc] init]; |
| [marray setObject:0 atIndexedSubscript:1]; // expected-warning {{Argument to 'NSMutableArray' method 'setObject:atIndexedSubscript:' cannot be nil}} |
| } |
| |
| void testNilArgNSMutableArray5() { |
| NSMutableArray *marray = [[NSMutableArray alloc] init]; |
| marray[1] = 0; // expected-warning {{Array element cannot be nil}} |
| } |
| |
| // NSArray API |
| void testNilArgNSArray1() { |
| NSArray *array = [[NSArray alloc] init]; |
| NSArray *copyArray = [array arrayByAddingObject:0]; // expected-warning {{Argument to 'NSArray' method 'arrayByAddingObject:' cannot be nil}} |
| } |
| |
| // NSMutableDictionary and NSDictionary APIs. |
| void testNilArgNSMutableDictionary1(NSMutableDictionary *d, NSString* key) { |
| [d setObject:0 forKey:key]; // expected-warning {{Value argument to 'setObject:forKey:' cannot be nil}} |
| } |
| |
| void testNilArgNSMutableDictionary2(NSMutableDictionary *d, NSObject *obj) { |
| [d setObject:obj forKey:0]; // expected-warning {{Key argument to 'setObject:forKey:' cannot be nil}} |
| } |
| |
| void testNilArgNSMutableDictionary3(NSMutableDictionary *d) { |
| [d removeObjectForKey:0]; // expected-warning {{Value argument to 'removeObjectForKey:' cannot be nil}} |
| } |
| |
| void testNilArgNSMutableDictionary5(NSMutableDictionary *d, NSString* key) { |
| d[key] = 0; // no-warning - removing the mapping for the given key |
| } |
| void testNilArgNSMutableDictionary6(NSMutableDictionary *d, NSString *key) { |
| if (key) |
| ; |
| d[key] = 0; // expected-warning {{'NSMutableDictionary' key cannot be nil}} |
| } |
| |
| NSDictionary *testNilArgNSDictionary1(NSString* key) { |
| return [NSDictionary dictionaryWithObject:0 forKey:key]; // expected-warning {{Value argument to 'dictionaryWithObject:forKey:' cannot be nil}} |
| } |
| NSDictionary *testNilArgNSDictionary2(NSObject *obj) { |
| return [NSDictionary dictionaryWithObject:obj forKey:0]; // expected-warning {{Key argument to 'dictionaryWithObject:forKey:' cannot be nil}} |
| } |
| |
| id testCreateDictionaryLiteralKey(id value, id nilKey) { |
| if (nilKey) |
| ; |
| return @{@"abc":value, nilKey:@"abc"}; // expected-warning {{Dictionary key cannot be nil}} |
| } |
| |
| id testCreateDictionaryLiteralValue(id nilValue) { |
| if (nilValue) |
| ; |
| return @{@"abc":nilValue}; // expected-warning {{Dictionary value cannot be nil}} |
| } |
| |
| id testCreateDictionaryLiteral(id nilValue, id nilKey) { |
| if (nilValue) |
| ; |
| if (nilKey) |
| ; |
| return @{@"abc":nilValue, nilKey:@"abc"}; // expected-warning {{Dictionary key cannot be nil}} |
| // expected-warning@-1 {{Dictionary value cannot be nil}} |
| } |
| |
| id testCreateArrayLiteral(id myNil) { |
| if (myNil) |
| ; |
| return @[ @"a", myNil, @"c" ]; // expected-warning {{Array element cannot be nil}} |
| } |
| |
| // Test inline defensive checks suppression. |
| void idc(id x) { |
| if (x) |
| ; |
| } |
| void testIDC(NSMutableDictionary *d, NSString *key) { |
| idc(key); |
| d[key] = @"abc"; // no-warning |
| } |
| |
| @interface Foo { |
| @public |
| int x; |
| } |
| - (int *)getPtr; |
| - (int)getInt; |
| - (NSMutableDictionary *)getDictPtr; |
| @property (retain, readonly, nonatomic) Foo* data; |
| - (NSString*) stringForKeyFE: (id<NSCopying>)key; |
| @end |
| |
| void idc2(id x) { |
| if (!x) |
| return; |
| } |
| Foo *retNil() { |
| return 0; |
| } |
| |
| void testIDC2(Foo *obj) { |
| idc2(obj); |
| *[obj getPtr] = 1; // no-warning |
| } |
| |
| int testIDC3(Foo *obj) { |
| idc2(obj); |
| return 1/[obj getInt]; |
| } |
| |
| void testNilReceiverIDC(Foo *obj, NSString *key) { |
| NSMutableDictionary *D = [obj getDictPtr]; |
| idc(D); |
| D[key] = @"abc"; // no-warning |
| } |
| |
| void testNilReceiverRetNil2(NSMutableDictionary *D, Foo *FooPtrIn, id value) { |
| NSString* const kKeyIdentifier = @"key"; |
| Foo *FooPtr = retNil(); |
| NSString *key = [[FooPtr data] stringForKeyFE: kKeyIdentifier]; |
| // key is nil because FooPtr is nil. However, FooPtr is set to nil inside an |
| // inlined function, so this error report should be suppressed. |
| [D setObject: value forKey: key]; // no-warning |
| } |
| |
| void testAssumeNSNullNullReturnsNonNil(NSMutableDictionary *Table, id Object, |
| id InValue) { |
| id Value = Object ? [Table objectForKey:Object] : [NSNull null]; |
| if (!Value) { |
| Value = InValue; |
| [Table setObject:Value forKey:Object]; // no warning |
| } |
| } |
| |
| void testCollectionIsNotEmptyWhenCountIsGreaterThanZero(NSMutableDictionary *D){ |
| if ([D count] > 0) { // Count is greater than zero. |
| NSString *s = 0; |
| for (NSString *key in D) { |
| s = key; // Loop is always entered. |
| } |
| [D removeObjectForKey:s]; // no warning |
| } |
| } |
| |
| void testCountAwareNSOrderedSet(NSOrderedSet *containers, int *validptr) { |
| int *x = 0; |
| NSUInteger containerCount = [containers count]; |
| if (containerCount > 0) |
| x = validptr; |
| for (id c in containers) { |
| *x = 1; // no warning |
| } |
| } |
| |
| void testLiteralsNonNil() { |
| clang_analyzer_eval(!!@[]); // expected-warning{{TRUE}} |
| clang_analyzer_eval(!!@{}); // expected-warning{{TRUE}} |
| } |
| |
| @interface NSMutableArray (MySafeAdd) |
| - (void)addObject:(id)obj safe:(BOOL)safe; |
| @end |
| |
| void testArrayCategory(NSMutableArray *arr) { |
| [arr addObject:0 safe:1]; // no-warning |
| } |
| |
| @interface MyView : NSObject |
| -(NSArray *)subviews; |
| @end |
| |
| void testNoReportWhenReceiverNil(NSMutableArray *array, int b) { |
| // Don't warn about adding nil to a container when the receiver is also |
| // definitely nil. |
| if (array == 0) { |
| [array addObject:0]; // no-warning |
| } |
| |
| MyView *view = b ? [[MyView alloc] init] : 0; |
| NSMutableArray *subviews = [[view subviews] mutableCopy]; |
| // When view is nil, subviews is also nil so there should be no warning |
| // here either. |
| [subviews addObject:view]; // no-warning |
| } |