llvm-project/clang/test/Analysis/NSContainers.m

201 lines
6.1 KiB
Objective-C

// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.NilArg -verify -Wno-objc-root-class %s
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 NSFastEnumeration
@end
@protocol NSSecureCoding <NSCoding>
@required
+ (BOOL)supportsSecureCoding;
@end
@interface NSObject <NSObject> {}
- (id)init;
+ (id)alloc;
@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 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;
@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 NSString : NSObject <NSCopying, NSMutableCopying, NSSecureCoding>
@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; // expected-warning {{Value stored into 'NSMutableDictionary' cannot be nil}}
}
void testNilArgNSMutableDictionary6(NSMutableDictionary *d, NSString *key) {
if (key)
;
d[key] = 0; // expected-warning {{'NSMutableDictionary' key cannot be nil}}
// expected-warning@-1 {{Value stored into 'NSMutableDictionary' 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}}
}
// 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
}