aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp26
-rw-r--r--test/Analysis/self-init.m28
2 files changed, 52 insertions, 2 deletions
diff --git a/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp
index 97b58cf79b..89340cc290 100644
--- a/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp
@@ -60,7 +60,8 @@ class ObjCSelfInitChecker : public Checker< check::PreObjCMessage,
check::PreStmt<ReturnStmt>,
check::PreStmt<CallExpr>,
check::PostStmt<CallExpr>,
- check::Location > {
+ check::Location,
+ check::Bind > {
public:
void checkPreObjCMessage(ObjCMessage msg, CheckerContext &C) const;
void checkPostObjCMessage(ObjCMessage msg, CheckerContext &C) const;
@@ -70,6 +71,7 @@ public:
void checkPostStmt(const CallExpr *CE, CheckerContext &C) const;
void checkLocation(SVal location, bool isLoad, const Stmt *S,
CheckerContext &C) const;
+ void checkBind(SVal loc, SVal val, const Stmt *S, CheckerContext &C) const;
void checkPreStmt(const CallOrObjCMessage &CE, CheckerContext &C) const;
void checkPostStmt(const CallOrObjCMessage &CE, CheckerContext &C) const;
@@ -336,6 +338,28 @@ void ObjCSelfInitChecker::checkLocation(SVal location, bool isLoad,
addSelfFlag(state, state->getSVal(cast<Loc>(location)), SelfFlag_Self, C);
}
+
+void ObjCSelfInitChecker::checkBind(SVal loc, SVal val, const Stmt *S,
+ CheckerContext &C) const {
+ // Allow assignment of anything to self. Self is a local variable in the
+ // initializer, so it is legal to assign anything to it, like results of
+ // static functions/method calls. After self is assigned something we cannot
+ // reason about, stop enforcing the rules.
+ // (Only continue checking if the assigned value should be treated as self.)
+ if ((isSelfVar(loc, C)) &&
+ !hasSelfFlag(val, SelfFlag_InitRes, C) &&
+ !hasSelfFlag(val, SelfFlag_Self, C) &&
+ !isSelfVar(val, C)) {
+
+ // Stop tracking the checker-specific state in the state.
+ ProgramStateRef State = C.getState();
+ State = State->remove<CalledInit>();
+ if (SymbolRef sym = loc.getAsSymbol())
+ State = State->remove<SelfFlag>(sym);
+ C.addTransition(State);
+ }
+}
+
// FIXME: A callback should disable checkers at the start of functions.
static bool shouldRunOnFunctionOrMethod(const NamedDecl *ND) {
if (!ND)
diff --git a/test/Analysis/self-init.m b/test/Analysis/self-init.m
index 365096e445..10b0c4da47 100644
--- a/test/Analysis/self-init.m
+++ b/test/Analysis/self-init.m
@@ -1,7 +1,8 @@
// RUN: %clang_cc1 -analyze -analyzer-checker=osx.cocoa.SelfInit -fobjc-default-synthesize-properties -fno-builtin %s -verify
@class NSZone, NSCoder;
-@protocol NSObject- (id)self;
+@protocol NSObject
+- (id)self;
@end
@protocol NSCopying - (id)copyWithZone:(NSZone *)zone;
@end
@@ -254,3 +255,28 @@ extern id _commonInit(MyObj *self);
return self;
}
@end
+
+// Test for radar://11125870: init constructing a special instance.
+typedef signed char BOOL;
+@interface MyClass : NSObject
+@end
+@implementation MyClass
++ (id)specialInstance {
+ return [[MyClass alloc] init];
+}
+- (id)initSpecially:(BOOL)handleSpecially {
+ if ((self = [super init])) {
+ if (handleSpecially) {
+ self = [MyClass specialInstance];
+ }
+ }
+ return self;
+}
+- (id)initSelfSelf {
+ if ((self = [super init])) {
+ self = self;
+ }
+ return self;
+}
+@end
+