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