[analyzer] Objective-C object literals are always non-nil.

<rdar://problem/15999214>

llvm-svn: 201007
This commit is contained in:
Jordan Rose 2014-02-08 00:04:14 +00:00
parent b3b52a7532
commit 4393aa7efb
3 changed files with 50 additions and 7 deletions

View File

@ -1139,7 +1139,10 @@ namespace {
/// \brief The checker restricts the return values of APIs known to
/// never (or almost never) return 'nil'.
class ObjCNonNilReturnValueChecker
: public Checker<check::PostObjCMessage> {
: public Checker<check::PostObjCMessage,
check::PostStmt<ObjCArrayLiteral>,
check::PostStmt<ObjCDictionaryLiteral>,
check::PostStmt<ObjCBoxedExpr> > {
mutable bool Initialized;
mutable Selector ObjectAtIndex;
mutable Selector ObjectAtIndexedSubscript;
@ -1147,13 +1150,32 @@ class ObjCNonNilReturnValueChecker
public:
ObjCNonNilReturnValueChecker() : Initialized(false) {}
ProgramStateRef assumeExprIsNonNull(const Expr *NonNullExpr,
ProgramStateRef State,
CheckerContext &C) const;
void assumeExprIsNonNull(const Expr *E, CheckerContext &C) const {
C.addTransition(assumeExprIsNonNull(E, C.getState(), C));
}
void checkPostStmt(const ObjCArrayLiteral *E, CheckerContext &C) const {
assumeExprIsNonNull(E, C);
}
void checkPostStmt(const ObjCDictionaryLiteral *E, CheckerContext &C) const {
assumeExprIsNonNull(E, C);
}
void checkPostStmt(const ObjCBoxedExpr *E, CheckerContext &C) const {
assumeExprIsNonNull(E, C);
}
void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
};
}
static ProgramStateRef assumeExprIsNonNull(const Expr *NonNullExpr,
ProgramStateRef State,
CheckerContext &C) {
ProgramStateRef
ObjCNonNilReturnValueChecker::assumeExprIsNonNull(const Expr *NonNullExpr,
ProgramStateRef State,
CheckerContext &C) const {
SVal Val = State->getSVal(NonNullExpr, C.getLocationContext());
if (Optional<DefinedOrUnknownSVal> DV = Val.getAs<DefinedOrUnknownSVal>())
return State->assume(*DV, true);

View File

@ -1,4 +1,7 @@
// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.NonNilReturnValue,osx.cocoa.NilArg,osx.cocoa.Loops -verify -Wno-objc-root-class %s
// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.NonNilReturnValue,osx.cocoa.NilArg,osx.cocoa.Loops,debug.ExprInspection -verify -Wno-objc-root-class %s
void clang_analyzer_eval(int);
typedef unsigned long NSUInteger;
typedef signed char BOOL;
typedef struct _NSZone NSZone;
@ -276,3 +279,8 @@ void testCountAwareNSOrderedSet(NSOrderedSet *containers, int *validptr) {
}
}
void testLiteralsNonNil() {
clang_analyzer_eval(!!@[]); // expected-warning{{TRUE}}
clang_analyzer_eval(!!@{}); // expected-warning{{TRUE}}
}

View File

@ -1,4 +1,6 @@
// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc -analyzer-store=region -verify %s
// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,osx.cocoa.NonNilReturnValue,debug.ExprInspection -analyzer-store=region -verify %s
void clang_analyzer_eval(int);
typedef signed char BOOL;
typedef long NSInteger;
@ -41,4 +43,15 @@ id const_char_pointer(int *x) {
if (x)
return @(3);
return @(*x); // expected-warning {{Dereference of null pointer (loaded from variable 'x')}}
}
}
void checkNonNil() {
clang_analyzer_eval(!!@3); // expected-warning{{TRUE}}
clang_analyzer_eval(!!@(3+4)); // expected-warning{{TRUE}}
clang_analyzer_eval(!!@(57.0)); // expected-warning{{TRUE}}
const char *str = "abc";
clang_analyzer_eval(!!@(str)); // expected-warning{{TRUE}}
clang_analyzer_eval(!!@__objc_yes); // expected-warning{{TRUE}}
}