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 | |