From 6457ad233504a2af01fd859f363539180e9c73c5 Mon Sep 17 00:00:00 2001 From: Anna Zaks Date: Mon, 18 Mar 2013 20:46:56 +0000 Subject: [PATCH] =?utf8?q?[analyzer]=20Warn=20when=20a=20=E2=80=98nil?= =?utf8?q?=E2=80=99=20object=20is=20added=20to=20NSArray=20or=20NSMutableA?= =?utf8?q?rray.?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit llvm-svn: 177318 --- .../Checkers/BasicObjCFoundationChecks.cpp | 37 +++++++++-- clang/test/Analysis/NSContainers.m | 76 ++++++++++++++++++++++ 2 files changed, 109 insertions(+), 4 deletions(-) create mode 100644 clang/test/Analysis/NSContainers.m diff --git a/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp b/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp index fdb6bbb..a6bcb69 100644 --- a/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp @@ -127,8 +127,13 @@ void NilArgChecker::checkPreObjCMessage(const ObjCMethodCall &msg, const ObjCInterfaceDecl *ID = msg.getReceiverInterface(); if (!ID) return; - - if (findKnownClass(ID) == FC_NSString) { + + FoundationClass Class = findKnownClass(ID); + + static const unsigned InvalidArgIndex = UINT_MAX; + unsigned Arg = InvalidArgIndex; + + if (Class == FC_NSString) { Selector S = msg.getSelector(); if (S.isUnarySelector()) @@ -152,10 +157,34 @@ void NilArgChecker::checkPreObjCMessage(const ObjCMethodCall &msg, Name == "compare:options:range:locale:" || Name == "componentsSeparatedByCharactersInSet:" || Name == "initWithFormat:") { - if (isNil(msg.getArgSVal(0))) - WarnNilArg(C, msg, 0); + Arg = 0; + } + } else if (Class == FC_NSArray) { + Selector S = msg.getSelector(); + + if (S.isUnarySelector()) + return; + + if (S.getNameForSlot(0).equals("addObject")) { + Arg = 0; + } else if (S.getNameForSlot(0).equals("insertObject") && + S.getNameForSlot(1).equals("atIndex")) { + Arg = 0; + } else if (S.getNameForSlot(0).equals("replaceObjectAtIndex") && + S.getNameForSlot(1).equals("withObject")) { + Arg = 1; + } else if (S.getNameForSlot(0).equals("setObject") && + S.getNameForSlot(1).equals("atIndexedSubscript")) { + Arg = 0; + } else if (S.getNameForSlot(0).equals("arrayByAddingObject")) { + Arg = 0; } } + + // If argument is '0', report a warning. + if ((Arg != InvalidArgIndex) && isNil(msg.getArgSVal(Arg))) + WarnNilArg(C, msg, Arg); + } //===----------------------------------------------------------------------===// diff --git a/clang/test/Analysis/NSContainers.m b/clang/test/Analysis/NSContainers.m new file mode 100644 index 0000000..7542a02 --- /dev/null +++ b/clang/test/Analysis/NSContainers.m @@ -0,0 +1,76 @@ +// 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 +@required ++ (BOOL)supportsSecureCoding; +@end +@interface NSObject {} +- (id)init; ++ (id)alloc; +@end + +@interface NSArray : NSObject + +- (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 + +// NSMutableArray API +void testNilArg1() { + NSMutableArray *marray = [[NSMutableArray alloc] init]; + [marray addObject:0]; // expected-warning {{Argument to 'NSMutableArray' method 'addObject:' cannot be nil}} +} + +void testNilArg2() { + NSMutableArray *marray = [[NSMutableArray alloc] init]; + [marray insertObject:0 atIndex:1]; // expected-warning {{Argument to 'NSMutableArray' method 'insertObject:atIndex:' cannot be nil}} +} + +void testNilArg3() { + NSMutableArray *marray = [[NSMutableArray alloc] init]; + [marray replaceObjectAtIndex:1 withObject:0]; // expected-warning {{Argument to 'NSMutableArray' method 'replaceObjectAtIndex:withObject:' cannot be nil}} +} + +void testNilArg4() { + NSMutableArray *marray = [[NSMutableArray alloc] init]; + [marray setObject:0 atIndexedSubscript:1]; // expected-warning {{Argument to 'NSMutableArray' method 'setObject:atIndexedSubscript:' cannot be nil}} +} + +// NSArray API +void testNilArg5() { + NSArray *array = [[NSArray alloc] init]; + NSArray *copyArray = [array arrayByAddingObject:0]; // expected-warning {{Argument to 'NSArray' method 'arrayByAddingObject:' cannot be nil}} +} + -- 2.7.4