NSContainers.m revision f2d8fbed93541b74c3a84bf788f151df2d543b27
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 NSMutableArray : NSArray
40
41- (void)addObject:(id)anObject;
42- (void)insertObject:(id)anObject atIndex:(NSUInteger)index;
43- (void)removeLastObject;
44- (void)removeObjectAtIndex:(NSUInteger)index;
45- (void)replaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject;
46
47@end
48
49@interface NSDictionary : NSObject <NSCopying, NSMutableCopying, NSSecureCoding, NSFastEnumeration>
50
51- (NSUInteger)count;
52- (id)objectForKey:(id)aKey;
53- (NSEnumerator *)keyEnumerator;
54
55@end
56
57@interface NSDictionary (NSDictionaryCreation)
58
59+ (id)dictionary;
60+ (id)dictionaryWithObject:(id)object forKey:(id <NSCopying>)key;
61@end
62
63@interface NSMutableDictionary : NSDictionary
64
65- (void)removeObjectForKey:(id)aKey;
66- (void)setObject:(id)anObject forKey:(id <NSCopying>)aKey;
67
68@end
69
70@interface NSMutableDictionary (NSExtendedMutableDictionary)
71
72- (void)addEntriesFromDictionary:(NSDictionary *)otherDictionary;
73- (void)removeAllObjects;
74- (void)removeObjectsForKeys:(NSArray *)keyArray;
75- (void)setDictionary:(NSDictionary *)otherDictionary;
76- (void)setObject:(id)obj forKeyedSubscript:(id <NSCopying>)key __attribute__((availability(macosx,introduced=10.8)));
77
78@end
79
80@interface NSString : NSObject <NSCopying, NSMutableCopying, NSSecureCoding>
81
82@end
83
84@interface NSNull : NSObject <NSCopying, NSSecureCoding>
85+ (NSNull *)null;
86@end
87
88// NSMutableArray API
89void testNilArgNSMutableArray1() {
90  NSMutableArray *marray = [[NSMutableArray alloc] init];
91  [marray addObject:0]; // expected-warning {{Argument to 'NSMutableArray' method 'addObject:' cannot be nil}}
92}
93
94void testNilArgNSMutableArray2() {
95  NSMutableArray *marray = [[NSMutableArray alloc] init];
96  [marray insertObject:0 atIndex:1]; // expected-warning {{Argument to 'NSMutableArray' method 'insertObject:atIndex:' cannot be nil}}
97}
98
99void testNilArgNSMutableArray3() {
100  NSMutableArray *marray = [[NSMutableArray alloc] init];
101  [marray replaceObjectAtIndex:1 withObject:0]; // expected-warning {{Argument to 'NSMutableArray' method 'replaceObjectAtIndex:withObject:' cannot be nil}}
102}
103
104void testNilArgNSMutableArray4() {
105  NSMutableArray *marray = [[NSMutableArray alloc] init];
106  [marray setObject:0 atIndexedSubscript:1]; // expected-warning {{Argument to 'NSMutableArray' method 'setObject:atIndexedSubscript:' cannot be nil}}
107}
108
109void testNilArgNSMutableArray5() {
110  NSMutableArray *marray = [[NSMutableArray alloc] init];
111  marray[1] = 0; // expected-warning {{Array element cannot be nil}}
112}
113
114// NSArray API
115void testNilArgNSArray1() {
116  NSArray *array = [[NSArray alloc] init];
117  NSArray *copyArray = [array arrayByAddingObject:0]; // expected-warning {{Argument to 'NSArray' method 'arrayByAddingObject:' cannot be nil}}
118}
119
120// NSMutableDictionary and NSDictionary APIs.
121void testNilArgNSMutableDictionary1(NSMutableDictionary *d, NSString* key) {
122  [d setObject:0 forKey:key]; // expected-warning {{Value argument to 'setObject:forKey:' cannot be nil}}
123}
124
125void testNilArgNSMutableDictionary2(NSMutableDictionary *d, NSObject *obj) {
126  [d setObject:obj forKey:0]; // expected-warning {{Key argument to 'setObject:forKey:' cannot be nil}}
127}
128
129void testNilArgNSMutableDictionary3(NSMutableDictionary *d) {
130  [d removeObjectForKey:0]; // expected-warning {{Value argument to 'removeObjectForKey:' cannot be nil}}
131}
132
133void testNilArgNSMutableDictionary5(NSMutableDictionary *d, NSString* key) {
134  d[key] = 0; // expected-warning {{Value stored into 'NSMutableDictionary' cannot be nil}}
135}
136void testNilArgNSMutableDictionary6(NSMutableDictionary *d, NSString *key) {
137  if (key)
138    ;
139  d[key] = 0; // expected-warning {{'NSMutableDictionary' key cannot be nil}}
140  // expected-warning@-1 {{Value stored into 'NSMutableDictionary' cannot be nil}}
141}
142
143NSDictionary *testNilArgNSDictionary1(NSString* key) {
144  return [NSDictionary dictionaryWithObject:0 forKey:key]; // expected-warning {{Value argument to 'dictionaryWithObject:forKey:' cannot be nil}}
145}
146NSDictionary *testNilArgNSDictionary2(NSObject *obj) {
147  return [NSDictionary dictionaryWithObject:obj forKey:0]; // expected-warning {{Key argument to 'dictionaryWithObject:forKey:' cannot be nil}}
148}
149
150// Test inline defensive checks suppression.
151void idc(id x) {
152  if (x)
153    ;
154}
155void testIDC(NSMutableDictionary *d, NSString *key) {
156  idc(key);
157  d[key] = @"abc"; // no-warning
158}
159
160@interface Foo {
161@public
162  int x;
163}
164- (int *)getPtr;
165- (int)getInt;
166- (NSMutableDictionary *)getDictPtr;
167@property (retain, readonly, nonatomic) Foo* data;
168- (NSString*) stringForKeyFE: (id<NSCopying>)key;
169@end
170
171void idc2(id x) {
172	if (!x)
173		return;
174}
175Foo *retNil() {
176  return 0;
177}
178
179void testIDC2(Foo *obj) {
180	idc2(obj);
181	*[obj getPtr] = 1; // no-warning
182}
183
184int testIDC3(Foo *obj) {
185	idc2(obj);
186  return 1/[obj getInt];
187}
188
189void testNilReceiverIDC(Foo *obj, NSString *key) {
190	NSMutableDictionary *D = [obj getDictPtr];
191  idc(D);
192  D[key] = @"abc"; // no-warning
193}
194
195void testNilReceiverRetNil2(NSMutableDictionary *D, Foo *FooPtrIn, id value) {
196  NSString* const kKeyIdentifier = @"key";
197	Foo *FooPtr = retNil();
198  NSString *key = [[FooPtr data] stringForKeyFE: kKeyIdentifier];
199  // key is nil because FooPtr is nil. However, FooPtr is set to nil inside an
200  // inlined function, so this error report should be suppressed.
201  [D setObject: value forKey: key]; // no-warning
202}
203
204void testAssumeNSNullNullReturnsNonNil(NSMutableDictionary *Table, id Object,
205                                      id InValue) {
206  id Value = Object ? [Table objectForKey:Object] : [NSNull null];
207  if (!Value) {
208    Value = InValue;
209    [Table setObject:Value forKey:Object]; // no warning
210  }
211}
212
213
214