aboutsummaryrefslogtreecommitdiff
path: root/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
diff options
context:
space:
mode:
authorAnna Zaks <ganna@apple.com>2012-08-30 19:40:52 +0000
committerAnna Zaks <ganna@apple.com>2012-08-30 19:40:52 +0000
commit05fcbd3dc28f4cba4a6d33e7aeaabb5f6f7837e3 (patch)
treef6a9ec3b6f4134b149b2c9bbdd5302a0c5a77461 /lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
parente788365f513a579b03ff7f49296d5b95645ea3fe (diff)
[analyzer] Do not propagate the [super init] could be nil assumption
from callee to caller. radar://12109638 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@162935 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp')
-rw-r--r--lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp40
1 files changed, 32 insertions, 8 deletions
diff --git a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
index a09324ee6b..e5fbb832a9 100644
--- a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
+++ b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
@@ -718,8 +718,8 @@ void ObjCLoopChecker::checkPostStmt(const ObjCForCollectionStmt *FCS,
namespace {
/// \class ObjCNonNilReturnValueChecker
-/// \brief The checker restricts the return values of APIs known to never
-/// return nil.
+/// \brief The checker restricts the return values of APIs known to
+/// never (or almost never) return 'nil'.
class ObjCNonNilReturnValueChecker
: public Checker<check::PostObjCMessage> {
mutable bool Initialized;
@@ -732,9 +732,18 @@ public:
};
}
+ProgramStateRef assumeExprIsNonNull(const Expr *NonNullExpr,
+ ProgramStateRef State,
+ CheckerContext &C) {
+ SVal Val = State->getSVal(NonNullExpr, C.getLocationContext());
+ if (!isa<DefinedOrUnknownSVal>(Val))
+ return State;
+ return State->assume(cast<DefinedOrUnknownSVal>(Val), true);
+}
+
void ObjCNonNilReturnValueChecker::checkPostObjCMessage(const ObjCMethodCall &M,
CheckerContext &C)
- const {
+ const {
ProgramStateRef State = C.getState();
if (!Initialized) {
@@ -745,19 +754,34 @@ void ObjCNonNilReturnValueChecker::checkPostObjCMessage(const ObjCMethodCall &M,
// Check the receiver type.
if (const ObjCInterfaceDecl *Interface = M.getReceiverInterface()) {
+
+ // Assume that object returned from '[self init]' or '[super init]' is not
+ // 'nil' if we are processing an inlined function/method.
+ //
+ // A defensive callee will (and should) check if the object returned by
+ // '[super init]' is 'nil' before doing it's own initialization. However,
+ // since 'nil' is rarely returned in practice, we should not warn when the
+ // caller to the defensive constructor uses the object in contexts where
+ // 'nil' is not accepted.
+ if (C.isWithinInlined() &&
+ M.getDecl()->getMethodFamily() == OMF_init &&
+ M.isReceiverSelfOrSuper()) {
+ State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
+ }
+
+ // Objects returned from
+ // [NSArray|NSOrderedSet]::[ObjectAtIndex|ObjectAtIndexedSubscript]
+ // are never 'nil'.
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);
+ State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
}
}
}
+ C.addTransition(State);
}
//===----------------------------------------------------------------------===//