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