return E;
}
+/// Returns true when the return statement is a syntactic 'return self' in
+/// Objective-C.
+static bool isReturnSelf(const ReturnStmt *RS, CheckerContext &C) {
+ const ImplicitParamDecl *SelfDecl =
+ C.getCurrentAnalysisDeclContext()->getSelfDecl();
+ if (!SelfDecl)
+ return false;
+
+ const Expr *ReturnExpr = lookThroughImplicitCasts(RS->getRetValue());
+ auto *RefExpr = dyn_cast<DeclRefExpr>(ReturnExpr);
+ if (!RefExpr)
+ return false;
+
+ return RefExpr->getDecl() == SelfDecl;
+}
+
/// This method check when nullable pointer or null value is returned from a
/// function that has nonnull return type.
///
if (!RetSVal)
return;
+ bool IsReturnSelfInObjCInit = false;
+
QualType RequiredRetType;
AnalysisDeclContext *DeclCtxt =
C.getLocationContext()->getAnalysisDeclContext();
const Decl *D = DeclCtxt->getDecl();
- if (auto *MD = dyn_cast<ObjCMethodDecl>(D))
+ if (auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
RequiredRetType = MD->getReturnType();
- else if (auto *FD = dyn_cast<FunctionDecl>(D))
+ // Suppress diagnostics for returns of nil that are syntactic returns of
+ // self in ObjC initializers. This avoids warning under the common idiom of
+ // a defensive check of the result of a call to super:
+ // if (self = [super init]) {
+ // ...
+ // }
+ // return self; // no-warning
+ IsReturnSelfInObjCInit = (MD->getMethodFamily() == OMF_init) &&
+ isReturnSelf(S, C);
+ } else if (auto *FD = dyn_cast<FunctionDecl>(D)) {
RequiredRetType = FD->getReturnType();
- else
+ } else {
return;
+ }
NullConstraint Nullness = getNullConstraint(*RetSVal, State);
if (Filter.CheckNullReturnedFromNonnull &&
Nullness == NullConstraint::IsNull &&
RetExprTypeLevelNullability != Nullability::Nonnull &&
- RequiredNullability == Nullability::Nonnull) {
+ RequiredNullability == Nullability::Nonnull &&
+ !IsReturnSelfInObjCInit) {
static CheckerProgramPointTag Tag(this, "NullReturnedFromNonnull");
ExplodedNode *N = C.generateErrorNode(State, &Tag);
if (!N)
// RUN: %clang_cc1 -fobjc-arc -analyze -analyzer-checker=core,nullability -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,nullability -verify %s
#define nil 0
#define BOOL int
return p;
}
-@interface SomeClass : NSObject
+
+@interface SomeClass : NSObject {
+ int instanceVar;
+}
@end
@implementation SomeClass (MethodReturn)
+- (id)initWithSomething:(int)i {
+ if (self = [super init]) {
+ instanceVar = i;
+ }
+
+ return self;
+}
+
- (TestObject * _Nonnull)testReturnsNullableInNonnullIndirectly {
TestObject *local = getNullableTestObject();
return local; // expected-warning {{Nullable pointer is returned from a function that is expected to return a non-null value}}
return p; // no-warning
}
@end
+
+@interface ClassWithInitializers : NSObject
+@end
+
+@implementation ClassWithInitializers
+- (instancetype _Nonnull)initWithNonnullReturnAndSelfCheckingIdiom {
+ // This defensive check is a common-enough idiom that we filter don't want
+ // to issue a diagnostic for it,
+ if (self = [super init]) {
+ }
+
+ return self; // no-warning
+}
+
+- (instancetype _Nonnull)initWithNonnullReturnAndNilReturnViaLocal {
+ self = [super init];
+ // This leaks, but we're not checking for that here.
+
+ ClassWithInitializers *other = nil;
+ // Still warn when when not returning via self.
+ return other; // expected-warning {{Null is returned from a function that is expected to return a non-null value}}
+}
+@end
+
+@interface SubClassWithInitializers : ClassWithInitializers
+@end
+
+@implementation SubClassWithInitializers
+// Note: Because this is overridding
+// -[ClassWithInitializers initWithNonnullReturnAndSelfCheckingIdiom],
+// the return type of this method becomes implicitly id _Nonnull.
+- (id)initWithNonnullReturnAndSelfCheckingIdiom {
+ if (self = [super initWithNonnullReturnAndSelfCheckingIdiom]) {
+ }
+
+ return self; // no-warning
+}
+@end