/* * Copyright (c) 2017-present, Facebook, Inc. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ #import #import "Library.h" int* __nullable returnsNull(); typedef struct s_ { int x; } S; @interface T : NSObject - (NSObject* _Nullable)nullableMethod; - (T* _Nullable)nullableT; @property(nonatomic) S structProperty; @property(nonatomic) S* pointerProperty; @end @implementation T { int* unnanotatedField; int* __nullable nullableField; int* nonnullField; } - (void)assignNullableFieldToNullOkay { nullableField = nil; } - (void)assignUnnanotatedFieldToNullBad { unnanotatedField = nil; } - (void)assignNonnullFieldToNullBad { nonnullField = nil; } - (void)testNullableFieldForNullOkay { if (nullableField == nil) { } } - (void)testUnnanotatedFieldForNullBad { if (unnanotatedField == nil) { } } - (int)DeadStoreFP_testUnnanotatedFieldInClosureBad { int (^testField)(int defaultValue); testField = ^(int defaultValue) { if (unnanotatedField != nil) { return *unnanotatedField; } else { return defaultValue; } }; return testField(42); } - (void)testNonnullFieldForNullBad { if (nonnullField == nil) { } } - (void)dereferenceUnnanotatedFieldOkay { *unnanotatedField = 42; } - (void)dereferenceNonnullFieldOkay { *nonnullField = 42; } - (void)dereferenceNullableFieldBad { *nullableField = 42; } - (void)dereferenceUnnanotatedFieldAfterTestForNullBad { if (unnanotatedField == nil) { *unnanotatedField = 42; } } - (void)FP_dereferenceNonnullFieldAfterTestForNullOkay { if (nonnullField == nil) { *nonnullField = 42; } } - (void)dereferenceNullableFunctionBad { int* p = returnsNull(); *p = 42; } - (void)dereferenceNullableFunction1Ok { int* p = returnsNull(); if (p) { *p = 42; } } - (void)dereferenceNullableFunction2Ok { int* p = returnsNull(); if (p != nil) { *p = 42; } } - (NSObject* _Nullable)nullableMethod { return nil; } - (NSString*)dereferenceNullableMethodOkay { NSObject* nullableObject = [self nullableMethod]; return [nullableObject description]; // does not report here } - (void)reassigningNullableObjectOkay { NSObject* nullableObject = [self nullableMethod]; nullableObject = nil; // does not report here } - (NSArray*)nullableObjectInNSArrayBad { NSObject* nullableObject = [self nullableMethod]; NSArray* array = @[ nullableObject ]; // reports here return array; } - (NSArray*)nullableMethodCheckedForNullAndReturnOkay { NSObject* nullableObject = [self nullableMethod]; NSArray* array; if (nullableObject == nil) { return array; } array = @[ nullableObject ]; // does not report here return array; } - (NSArray*)secondElementNullableObjectInNSArrayBad { NSObject* allocatedObject = [NSObject alloc]; NSObject* nullableObject = [self nullableMethod]; NSArray* array = @[ allocatedObject, nullableObject ]; // reports here return array; } - (NSArray*)nullableObjectInNSArrayOkay { NSObject* nullableObject = [self nullableMethod]; NSArray* array; if (nullableObject) { array = @[ nullableObject ]; // reports here } else { array = @[ @"String" ]; } return array; } - (NSArray*)URLWithStringOkay { NSURL* url = [NSURL URLWithString:@"some/url/string"]; NSArray* array = @[ url ]; // reports here } - (NSDictionary*)nullableValueInNSDictionaryBad { NSObject* nullableValue = [self nullableMethod]; NSMutableDictionary* dict = [NSMutableDictionary dictionaryWithObjectsAndKeys:@"key", nullableValue, nil]; // reports here return dict; } - (NSDictionary*)nullableKeyInNSDictionaryBad { NSObject* nullableKey = [self nullableMethod]; NSMutableDictionary* dict = [NSMutableDictionary dictionaryWithObjectsAndKeys:nullableKey, @"value", nil]; // reports here return dict; } - (NSDictionary*)nullableKeyInNSDictionaryInitBad { NSObject* nullableKey = [self nullableMethod]; NSDictionary* dict = [[NSDictionary alloc] initWithObjectsAndKeys:nullableKey, @"value", nil]; // reports here return dict; } - (NSDictionary*)nullableValueInNSDictionaryInitBad { NSObject* nullableValue = [self nullableMethod]; NSDictionary* dict = [[NSDictionary alloc] initWithObjectsAndKeys:@"key", nullableValue, nil]; // reports here return dict; } - (NSDictionary*)nullableKeyInNSDictionaryInitLiteralBad { NSObject* nullableKey = [self nullableMethod]; NSDictionary* dict = @{nullableKey : @"value"}; // reports here return dict; } - (NSDictionary*)nullableValueInNSDictionaryInitLiteralBad { NSObject* nullableValue = [self nullableMethod]; NSDictionary* dict = @{@"key" : nullableValue}; // reports here return dict; } - (NSDictionary*)indirectNullableKeyInNSDictionaryBad { NSObject* nullableKey = [self nullableMethod]; NSString* nullableKeyString = [nullableKey description]; NSDictionary* dict = [[NSDictionary alloc] initWithObjectsAndKeys:nullableKeyString, @"value", nil]; // reports here return dict; } - (NSArray*)createArrayByAddingNilBad { NSArray* array = @[ [NSObject alloc] ]; return [array arrayByAddingObject:[self nullableMethod]]; } - (NSDictionary*)setNullableObjectInDictionaryBad { NSMutableDictionary* mutableDict = [NSMutableDictionary dictionary]; [mutableDict setObject:[self nullableMethod] forKey:@"key"]; // reports here return mutableDict; } - (NSArray*)addNullableObjectInMutableArrayBad { NSMutableArray* mutableArray = [[NSMutableArray alloc] init]; [mutableArray addObject:[self nullableMethod]]; // reports here return mutableArray; } - (NSArray*)insertNullableObjectInMutableArrayBad { NSMutableArray* mutableArray = [[NSMutableArray alloc] init]; [mutableArray insertObject:[self nullableMethod] atIndex:0]; // reports here return mutableArray; } - (NSArray*)propagateNullabilityOnMethodCallBad { NSObject* nullableObject = [self nullableMethod]; NSString* nullableString = [nullableObject description]; // returns nil if nullableObject is nil return @[ nullableString ]; // reports here } - (S*)shouldPropagateNullabilityOnPointerTypeBad { T* nullableT = [self nullableT]; S* s = nullableT.pointerProperty; // returns nil when nullableT is nil s->x = 42; // reports here return s; } - (S)shouldNotPropagateNullabilityOnNonPointerTypeGood { T* nullableT = [self nullableT]; S s = nullableT.structProperty; // returns an empty struct when nullabeT is nil s.x = 42; // does not report here return s; } - (NSArray*)pointerAssignmentWithSubtypeOkay:(NSString*)string { NSObject* nullableObject = [self nullableMethod]; nullableObject = string; NSArray* array = @[ nullableObject ]; // does not report here return array; } - (NSArray*)dereferenceLibraryMethodOk:(L*)object { NSObject* nullableObject = [object libraryMethod]; NSArray* array = @[ nullableObject ]; // does not report here return array; } - (NSArray*)dereferenceNullableLibraryMethodBad:(L*)object { NSObject* nullableObject = [object nullableLibraryMethod]; NSArray* array = @[ nullableObject ]; // reports here return array; } @end @protocol P - (NSObject* _Nullable)nullableMethod; @end NSDictionary* callNullableMethodFromProtocolBad(id

pObject) { NSObject* nullableObject = [pObject nullableMethod]; return @{@"key" : nullableObject}; }