forked from OSchip/llvm-project
[analyzer] Objective-C object literals are always non-nil.
<rdar://problem/15999214> llvm-svn: 201007
This commit is contained in:
parent
b3b52a7532
commit
4393aa7efb
|
@ -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);
|
||||
|
|
|
@ -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}}
|
||||
}
|
||||
|
||||
|
|
|
@ -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}}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue