[analyzer] Add osx.cocoa.NonNilReturnValue checker.

The checker adds assumptions that the return values from the known APIs
are non-nil. Teach the checker about NSArray/NSMutableArray/NSOrderedSet
objectAtIndex, objectAtIndexedSubscript.

llvm-svn: 162398
This commit is contained in:
Anna Zaks 2012-08-22 21:19:56 +00:00
parent 26d3b2a272
commit 5a5a1755f2
3 changed files with 99 additions and 0 deletions

View File

@ -716,6 +716,47 @@ void ObjCLoopChecker::checkPostStmt(const ObjCForCollectionStmt *FCS,
C.addTransition(State);
}
namespace {
/// \class ObjCNonNilReturnValueChecker
/// \brief The checker restricts the return values of APIs known to never
/// return nil.
class ObjCNonNilReturnValueChecker
: public Checker<check::PostObjCMessage> {
mutable bool Initialized;
mutable Selector ObjectAtIndex;
mutable Selector ObjectAtIndexedSubscript;
public:
void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
};
}
void ObjCNonNilReturnValueChecker::checkPostObjCMessage(const ObjCMethodCall &M,
CheckerContext &C)
const {
ProgramStateRef State = C.getState();
if (!Initialized) {
ASTContext &Ctx = C.getASTContext();
ObjectAtIndex = GetUnarySelector("objectAtIndex", Ctx);
ObjectAtIndexedSubscript = GetUnarySelector("objectAtIndexedSubscript", Ctx);
}
// Check the receiver type.
if (const ObjCInterfaceDecl *Interface = M.getReceiverInterface()) {
FoundationClass Cl = findKnownClass(Interface);
if (Cl == FC_NSArray || Cl == FC_NSOrderedSet) {
Selector Sel = M.getSelector();
if (Sel == ObjectAtIndex || Sel == ObjectAtIndexedSubscript) {
// Go ahead and assume the value is non-nil.
SVal Val = State->getSVal(M.getOriginExpr(), C.getLocationContext());
if (!isa<DefinedOrUnknownSVal>(Val))
return;
State = State->assume(cast<DefinedOrUnknownSVal>(Val), true);
C.addTransition(State);
}
}
}
}
//===----------------------------------------------------------------------===//
// Check registration.
@ -744,3 +785,7 @@ void ento::registerVariadicMethodTypeChecker(CheckerManager &mgr) {
void ento::registerObjCLoopChecker(CheckerManager &mgr) {
mgr.registerChecker<ObjCLoopChecker>();
}
void ento::registerObjCNonNilReturnValueChecker(CheckerManager &mgr) {
mgr.registerChecker<ObjCNonNilReturnValueChecker>();
}

View File

@ -397,6 +397,10 @@ def ObjCLoopChecker : Checker<"Loops">,
HelpText<"Improved modeling of loops using Cocoa collection types">,
DescFile<"BasicObjCFoundationChecks.cpp">;
def ObjCNonNilReturnValueChecker : Checker<"NonNilReturnValue">,
HelpText<"Model the APIs that are guaranteed to return a non-nil value">,
DescFile<"BasicObjCFoundationChecks.cpp">;
def NSErrorChecker : Checker<"NSError">,
HelpText<"Check usage of NSError** parameters">,
DescFile<"NSErrorChecker.cpp">;

View File

@ -0,0 +1,50 @@
// RUN: %clang_cc1 -analyze -analyzer-checker=osx.cocoa.NonNilReturnValue,debug.ExprInspection -verify %s
typedef unsigned int NSUInteger;
typedef signed char BOOL;
@protocol NSObject - (BOOL)isEqual:(id)object; @end
@interface NSObject <NSObject> {}
+(id)alloc;
+(id)new;
-(id)init;
-(id)autorelease;
-(id)copy;
- (Class)class;
-(id)retain;
@end
@interface NSArray : NSObject
- (id)objectAtIndex:(unsigned long)index;
@end
@interface NSArray (NSExtendedArray)
- (id)objectAtIndexedSubscript:(NSUInteger)idx;
@end
@interface NSMutableArray : NSArray
- (void)replaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject;
@end
@interface NSOrderedSet : NSObject
@end
@interface NSOrderedSet (NSOrderedSetCreation)
- (id)objectAtIndexedSubscript:(NSUInteger)idx;
@end
void clang_analyzer_eval(id);
void assumeThatNSArrayObjectAtIndexIsNeverNull(NSArray *A, NSUInteger i) {
clang_analyzer_eval([A objectAtIndex: i]); // expected-warning {{TRUE}}
id subscriptObj = A[1];
clang_analyzer_eval(subscriptObj); // expected-warning {{TRUE}}
}
void assumeThatNSMutableArrayObjectAtIndexIsNeverNull(NSMutableArray *A, NSUInteger i) {
clang_analyzer_eval([A objectAtIndex: i]); // expected-warning {{TRUE}}
}
void assumeThatNSArrayObjectAtIndexedSubscriptIsNeverNull(NSOrderedSet *A, NSUInteger i) {
clang_analyzer_eval(A[i]); // expected-warning {{TRUE}}
}