| 1 | // RUN: %clang_cc1 -fsyntax-only -fblocks -Woverriding-method-mismatch -Wno-nullability-declspec -Wnullable-to-nonnull-conversion %s -verify |
| 2 | |
| 3 | __attribute__((objc_root_class)) |
| 4 | @interface NSFoo |
| 5 | - (void)methodTakingIntPtr:(_Nonnull int *)ptr; |
| 6 | - (_Nonnull int *)methodReturningIntPtr; |
| 7 | @end |
| 8 | |
| 9 | // Nullability applies to all pointer types. |
| 10 | typedef NSFoo * _Nonnull nonnull_NSFoo_ptr; |
| 11 | typedef id _Nonnull nonnull_id; |
| 12 | typedef SEL _Nonnull nonnull_SEL; |
| 13 | |
| 14 | // Nullability can move into Objective-C pointer types. |
| 15 | typedef _Nonnull NSFoo * nonnull_NSFoo_ptr_2; |
| 16 | |
| 17 | // Conflicts from nullability moving into Objective-C pointer type. |
| 18 | typedef _Nonnull NSFoo * _Nullable conflict_NSFoo_ptr_2; // expected-error{{'_Nonnull' cannot be applied to non-pointer type 'NSFoo'}} |
| 19 | |
| 20 | void testBlocksPrinting(NSFoo * _Nullable (^bp)(int)) { |
| 21 | int *ip = bp; // expected-error{{'NSFoo * _Nullable (^)(int)'}} |
| 22 | } |
| 23 | |
| 24 | // Check returning nil from a _Nonnull-returning method. |
| 25 | @implementation NSFoo |
| 26 | - (void)methodTakingIntPtr:(_Nonnull int *)ptr { } |
| 27 | - (_Nonnull int *)methodReturningIntPtr { |
| 28 | return 0; // no warning |
| 29 | } |
| 30 | @end |
| 31 | |
| 32 | // Context-sensitive keywords and property attributes for nullability. |
| 33 | __attribute__((objc_root_class)) |
| 34 | @interface NSBar |
| 35 | - (nonnull NSFoo *)methodWithFoo:(nonnull NSFoo *)foo; |
| 36 | |
| 37 | - (nonnull NSFoo **)invalidMethod1; // expected-error{{nullability keyword 'nonnull' cannot be applied to multi-level pointer type 'NSFoo **'}} |
| 38 | // expected-note@-1{{use nullability type specifier '_Nonnull' to affect the innermost pointer type of 'NSFoo **'}} |
| 39 | - (nonnull NSFoo * _Nullable)conflictingMethod1; // expected-error{{nullability specifier 'nonnull' conflicts with existing specifier '_Nullable'}} |
| 40 | - (nonnull NSFoo * _Nonnull)redundantMethod1; // expected-warning{{duplicate nullability specifier 'nonnull'}} |
| 41 | |
| 42 | @property(nonnull,retain) NSFoo *property1; |
| 43 | @property(nullable,assign) NSFoo ** invalidProperty1; // expected-error{{nullability keyword 'nullable' cannot be applied to multi-level pointer type 'NSFoo **'}} |
| 44 | // expected-note@-1{{use nullability type specifier '_Nullable' to affect the innermost pointer type of 'NSFoo **'}} |
| 45 | @property(null_unspecified,retain) NSFoo * _Nullable conflictingProperty1; // expected-error{{nullability specifier 'null_unspecified' conflicts with existing specifier '_Nullable'}} |
| 46 | @property(retain,nonnull) NSFoo * _Nonnull redundantProperty1; // expected-warning{{duplicate nullability specifier 'nonnull'}} |
| 47 | |
| 48 | @property(null_unspecified,retain,nullable) NSFoo *conflictingProperty3; // expected-error{{nullability specifier 'nullable' conflicts with existing specifier 'null_unspecified'}} |
| 49 | @property(nullable,retain,nullable) NSFoo *redundantProperty3; // expected-warning{{duplicate nullability specifier 'nullable'}} |
| 50 | @end |
| 51 | |
| 52 | @interface NSBar () |
| 53 | @property(nonnull,retain) NSFoo *property2; |
| 54 | @property(nullable,assign) NSFoo ** invalidProperty2; // expected-error{{nullability keyword 'nullable' cannot be applied to multi-level pointer type 'NSFoo **'}} |
| 55 | // expected-note@-1{{use nullability type specifier '_Nullable' to affect the innermost pointer type of 'NSFoo **'}} |
| 56 | @property(null_unspecified,retain) NSFoo * _Nullable conflictingProperty2; // expected-error{{nullability specifier 'null_unspecified' conflicts with existing specifier '_Nullable'}} |
| 57 | @property(retain,nonnull) NSFoo * _Nonnull redundantProperty2; // expected-warning{{duplicate nullability specifier 'nonnull'}} |
| 58 | @end |
| 59 | |
| 60 | void test_accepts_nonnull_null_pointer_literal(NSFoo *foo, _Nonnull NSBar *bar) { |
| 61 | [foo methodTakingIntPtr: 0]; // expected-warning{{null passed to a callee that requires a non-null argument}} |
| 62 | [bar methodWithFoo: 0]; // expected-warning{{null passed to a callee that requires a non-null argument}} |
| 63 | bar.property1 = 0; // expected-warning{{null passed to a callee that requires a non-null argument}} |
| 64 | bar.property2 = 0; // expected-warning{{null passed to a callee that requires a non-null argument}} |
| 65 | [bar setProperty1: 0]; // expected-warning{{null passed to a callee that requires a non-null argument}} |
| 66 | [bar setProperty2: 0]; // expected-warning{{null passed to a callee that requires a non-null argument}} |
| 67 | int *ptr = bar.property1; // expected-warning{{incompatible pointer types initializing 'int *' with an expression of type 'NSFoo * _Nonnull'}} |
| 68 | } |
| 69 | |
| 70 | // Check returning nil from a nonnull-returning method. |
| 71 | @implementation NSBar |
| 72 | - (nonnull NSFoo *)methodWithFoo:(nonnull NSFoo *)foo { |
| 73 | return 0; // no warning |
| 74 | } |
| 75 | |
| 76 | - (NSFoo **)invalidMethod1 { |
| 77 | return 0; |
| 78 | } |
| 79 | |
| 80 | - (NSFoo *)conflictingMethod1 { |
| 81 | return 0; // no warning |
| 82 | } |
| 83 | - (NSFoo *)redundantMethod1 { |
| 84 | int *ip = 0; |
| 85 | return ip; // expected-warning{{result type 'NSFoo * _Nonnull'}} |
| 86 | } |
| 87 | @end |
| 88 | |
| 89 | __attribute__((objc_root_class)) |
| 90 | @interface NSMerge |
| 91 | - (nonnull NSFoo *)methodA:(nonnull NSFoo*)foo; |
| 92 | - (nonnull NSFoo *)methodB:(nonnull NSFoo*)foo; |
| 93 | - (NSFoo *)methodC:(NSFoo*)foo; |
| 94 | @end |
| 95 | |
| 96 | @implementation NSMerge |
| 97 | - (NSFoo *)methodA:(NSFoo*)foo { |
| 98 | int *ptr = foo; // expected-warning{{incompatible pointer types initializing 'int *' with an expression of type 'NSFoo * _Nonnull'}} |
| 99 | return ptr; // expected-warning{{result type 'NSFoo * _Nonnull'}} |
| 100 | } |
| 101 | |
| 102 | - (nullable NSFoo *)methodB:(null_unspecified NSFoo*)foo { // expected-error{{nullability specifier 'nullable' conflicts with existing specifier 'nonnull'}} \ |
| 103 | // expected-error{{nullability specifier 'null_unspecified' conflicts with existing specifier 'nonnull'}} |
| 104 | return 0; |
| 105 | } |
| 106 | |
| 107 | - (nonnull NSFoo *)methodC:(nullable NSFoo*)foo { |
| 108 | int *ip = 0; |
| 109 | return ip; // expected-warning{{result type 'NSFoo * _Nonnull'}} |
| 110 | } |
| 111 | @end |
| 112 | |
| 113 | // Checking merging of nullability when sending a message. |
| 114 | @interface NSMergeReceiver |
| 115 | - (id)returnsNone; |
| 116 | - (nonnull id)returnsNonNull; |
| 117 | - (nullable id)returnsNullable; |
| 118 | - (null_unspecified id)returnsNullUnspecified; |
| 119 | @end |
| 120 | |
| 121 | void test_receiver_merge(NSMergeReceiver *none, |
| 122 | _Nonnull NSMergeReceiver *nonnull, |
| 123 | _Nullable NSMergeReceiver *nullable, |
| 124 | _Null_unspecified NSMergeReceiver *null_unspecified) { |
| 125 | int *ptr; |
| 126 | |
| 127 | ptr = [nullable returnsNullable]; // expected-warning{{'id _Nullable'}} |
| 128 | ptr = [nullable returnsNullUnspecified]; // expected-warning{{'id _Nullable'}} |
| 129 | ptr = [nullable returnsNonNull]; // expected-warning{{'id _Nullable'}} |
| 130 | ptr = [nullable returnsNone]; // expected-warning{{'id _Nullable'}} |
| 131 | |
| 132 | ptr = [null_unspecified returnsNullable]; // expected-warning{{'id _Nullable'}} |
| 133 | ptr = [null_unspecified returnsNullUnspecified]; // expected-warning{{'id _Null_unspecified'}} |
| 134 | ptr = [null_unspecified returnsNonNull]; // expected-warning{{'id _Null_unspecified'}} |
| 135 | ptr = [null_unspecified returnsNone]; // expected-warning{{'id'}} |
| 136 | |
| 137 | ptr = [nonnull returnsNullable]; // expected-warning{{'id _Nullable'}} |
| 138 | ptr = [nonnull returnsNullUnspecified]; // expected-warning{{'id _Null_unspecified'}} |
| 139 | ptr = [nonnull returnsNonNull]; // expected-warning{{'id _Nonnull'}} |
| 140 | ptr = [nonnull returnsNone]; // expected-warning{{'id'}} |
| 141 | |
| 142 | ptr = [none returnsNullable]; // expected-warning{{'id _Nullable'}} |
| 143 | ptr = [none returnsNullUnspecified]; // expected-warning{{'id'}} |
| 144 | ptr = [none returnsNonNull]; // expected-warning{{'id'}} |
| 145 | ptr = [none returnsNone]; // expected-warning{{'id'}} |
| 146 | |
| 147 | } |
| 148 | |
| 149 | // instancetype |
| 150 | @protocol Initializable |
| 151 | - (instancetype)initWithBlah:(id)blah; |
| 152 | @end |
| 153 | |
| 154 | __attribute__((objc_root_class)) |
| 155 | @interface InitializableClass <Initializable> |
| 156 | - (nonnull instancetype)initWithBlah:(nonnull id)blah; |
| 157 | - (nullable instancetype)returnMe; |
| 158 | + (nullable instancetype)returnInstanceOfMe; |
| 159 | |
| 160 | - (nonnull instancetype _Nullable)initWithBlah2:(nonnull id)blah; // expected-error {{nullability specifier 'nonnull' conflicts with existing specifier '_Nullable'}} |
| 161 | - (instancetype _Nullable)returnMe2; |
| 162 | + (_Nonnull instancetype)returnInstanceOfMe2; |
| 163 | @end |
| 164 | |
| 165 | void test_instancetype(InitializableClass * _Nonnull ic, id _Nonnull object) { |
| 166 | int *ip = [ic returnMe]; // expected-warning{{incompatible pointer types initializing 'int *' with an expression of type 'InitializableClass * _Nullable'}} |
| 167 | ip = [InitializableClass returnMe]; // expected-warning{{incompatible pointer types assigning to 'int *' from 'id _Nullable'}} |
| 168 | ip = [InitializableClass returnInstanceOfMe]; // expected-warning{{incompatible pointer types assigning to 'int *' from 'InitializableClass * _Nullable'}} |
| 169 | ip = [object returnMe]; // expected-warning{{incompatible pointer types assigning to 'int *' from 'id _Nullable'}} |
| 170 | |
| 171 | ip = [ic returnMe2]; // expected-warning{{incompatible pointer types assigning to 'int *' from 'InitializableClass * _Nullable'}} |
| 172 | ip = [InitializableClass returnInstanceOfMe2]; // expected-warning{{incompatible pointer types assigning to 'int *' from 'InitializableClass * _Nonnull'}} |
| 173 | } |
| 174 | |
| 175 | // Check null_resettable getters/setters. |
| 176 | __attribute__((objc_root_class)) |
| 177 | @interface NSResettable |
| 178 | @property(null_resettable,retain) NSResettable *resettable1; // expected-note{{passing argument to parameter 'resettable1' here}} |
| 179 | @property(null_resettable,retain,nonatomic) NSResettable *resettable2; |
| 180 | @property(null_resettable,retain,nonatomic) NSResettable *resettable3; |
| 181 | @property(null_resettable,retain,nonatomic) NSResettable *resettable4; |
| 182 | @property(null_resettable,retain,nonatomic) NSResettable *resettable5; |
| 183 | @property(null_resettable,retain,nonatomic) NSResettable *resettable6; |
| 184 | @end |
| 185 | |
| 186 | void test_null_resettable(NSResettable *r, int *ip) { |
| 187 | [r setResettable1:ip]; // expected-warning{{incompatible pointer types sending 'int *' to parameter of type 'NSResettable * _Nullable'}} |
| 188 | r.resettable1 = ip; // expected-warning{{incompatible pointer types assigning to 'NSResettable * _Nullable' from 'int *'}} |
| 189 | } |
| 190 | |
| 191 | @implementation NSResettable // expected-warning{{synthesized setter 'setResettable4:' for null_resettable property 'resettable4' does not handle nil}} |
| 192 | - (NSResettable *)resettable1 { |
| 193 | int *ip = 0; |
| 194 | return ip; // expected-warning{{result type 'NSResettable * _Nonnull'}} |
| 195 | } |
| 196 | |
| 197 | - (void)setResettable1:(NSResettable *)param { |
| 198 | } |
| 199 | |
| 200 | @synthesize resettable2; // no warning; not synthesized |
| 201 | @synthesize resettable3; // expected-warning{{synthesized setter 'setResettable3:' for null_resettable property 'resettable3' does not handle nil}} |
| 202 | |
| 203 | - (void)setResettable2:(NSResettable *)param { |
| 204 | } |
| 205 | |
| 206 | @dynamic resettable5; |
| 207 | |
| 208 | - (NSResettable *)resettable6 { |
| 209 | return 0; // no warning |
| 210 | } |
| 211 | @end |
| 212 | |
| 213 | // rdar://problem/19814852 |
| 214 | @interface MultiProp |
| 215 | @property (nullable, copy) id a, b, c; |
| 216 | @property (nullable, copy) MultiProp *d, *(^e)(int); |
| 217 | @end |
| 218 | |
| 219 | void testMultiProp(MultiProp *foo) { |
| 220 | int *ip; |
| 221 | ip = foo.a; // expected-warning{{from 'id _Nullable'}} |
| 222 | ip = foo.d; // expected-warning{{from 'MultiProp * _Nullable'}} |
| 223 | ip = foo.e; // expected-error{{incompatible type 'MultiProp *(^ _Nullable)(int)'}} |
| 224 | } |
| 225 | |
| 226 | void testBlockLiterals() { |
| 227 | (void)(^id(void) { return 0; }); |
| 228 | (void)(^id _Nullable (void) { return 0; }); |
| 229 | (void)(^ _Nullable id(void) { return 0; }); |
| 230 | |
| 231 | int *x = (^ _Nullable id(void) { return 0; })(); // expected-warning{{incompatible pointer types initializing 'int *' with an expression of type 'id _Nullable'}} |
| 232 | } |
| 233 | |
| 234 | // Check nullability of conditional expressions. |
| 235 | void conditional_expr(int c) { |
| 236 | NSFoo * _Nonnull p; |
| 237 | NSFoo * _Nonnull nonnullP; |
| 238 | NSFoo * _Nullable nullableP; |
| 239 | NSFoo * _Null_unspecified unspecifiedP; |
| 240 | NSFoo *noneP; |
| 241 | |
| 242 | p = c ? nonnullP : nonnullP; |
| 243 | p = c ? nonnullP : nullableP; // expected-warning{{implicit conversion from nullable pointer 'NSFoo * _Nullable' to non-nullable pointer type 'NSFoo * _Nonnull'}} |
| 244 | p = c ? nonnullP : unspecifiedP; |
| 245 | p = c ? nonnullP : noneP; |
| 246 | p = c ? nullableP : nonnullP; // expected-warning{{implicit conversion from nullable pointer 'NSFoo * _Nullable' to non-nullable pointer type 'NSFoo * _Nonnull'}} |
| 247 | p = c ? nullableP : nullableP; // expected-warning{{implicit conversion from nullable pointer 'NSFoo * _Nullable' to non-nullable pointer type 'NSFoo * _Nonnull'}} |
| 248 | p = c ? nullableP : unspecifiedP; // expected-warning{{implicit conversion from nullable pointer 'NSFoo * _Nullable' to non-nullable pointer type 'NSFoo * _Nonnull'}} |
| 249 | p = c ? nullableP : noneP; // expected-warning{{implicit conversion from nullable pointer 'NSFoo * _Nullable' to non-nullable pointer type 'NSFoo * _Nonnull'}} |
| 250 | p = c ? unspecifiedP : nonnullP; |
| 251 | p = c ? unspecifiedP : nullableP; // expected-warning{{implicit conversion from nullable pointer 'NSFoo * _Nullable' to non-nullable pointer type 'NSFoo * _Nonnull'}} |
| 252 | p = c ? unspecifiedP : unspecifiedP; |
| 253 | p = c ? unspecifiedP : noneP; |
| 254 | p = c ? noneP : nonnullP; |
| 255 | p = c ? noneP : nullableP; // expected-warning{{implicit conversion from nullable pointer 'NSFoo * _Nullable' to non-nullable pointer type 'NSFoo * _Nonnull'}} |
| 256 | p = c ? noneP : unspecifiedP; |
| 257 | p = c ? noneP : noneP; |
| 258 | } |
| 259 | |
| 260 | typedef int INTS[4]; |
| 261 | @interface ArraysInMethods |
| 262 | - (void)simple:(int [_Nonnull 2])x; |
| 263 | - (void)nested:(void *_Nullable [_Nonnull 2])x; |
| 264 | - (void)nestedBad:(int [2][_Nonnull 2])x; // expected-error {{nullability specifier '_Nonnull' cannot be applied to non-pointer type 'int [2]'}} |
| 265 | |
| 266 | - (void)withTypedef:(INTS _Nonnull)x; |
| 267 | - (void)withTypedefBad:(INTS _Nonnull[2])x; // expected-error{{nullability specifier '_Nonnull' cannot be applied to non-pointer type 'INTS' (aka 'int [4]')}} |
| 268 | |
| 269 | - (void)simpleSugar:(nonnull int [2])x; |
| 270 | - (void)nestedSugar:(nonnull void *_Nullable [2])x; // expected-error {{nullability keyword 'nonnull' cannot be applied to multi-level pointer type 'void * _Nullable [2]'}} expected-note {{use nullability type specifier '_Nonnull' to affect the innermost pointer type of 'void * _Nullable [2]'}} |
| 271 | - (void)sugarWithTypedef:(nonnull INTS)x; |
| 272 | @end |
| 273 | |
| 274 | void test(ArraysInMethods *obj) { |
| 275 | [obj simple:0]; // expected-warning {{null passed to a callee that requires a non-null argument}} |
| 276 | [obj nested:0]; // expected-warning {{null passed to a callee that requires a non-null argument}} |
| 277 | [obj withTypedef:0]; // expected-warning {{null passed to a callee that requires a non-null argument}} |
| 278 | |
| 279 | [obj simpleSugar:0]; // expected-warning {{null passed to a callee that requires a non-null argument}} |
| 280 | [obj sugarWithTypedef:0]; // expected-warning {{null passed to a callee that requires a non-null argument}} |
| 281 | } |
| 282 | |
| 283 | // Check that we don't propagate the nullability specifier on the receiver to |
| 284 | // the result type of a message send if the result type cannot have a |
| 285 | // nullability specifier. |
| 286 | @interface C0 |
| 287 | -(int) count; |
| 288 | @end |
| 289 | |
| 290 | void testMessageSendResultType(C0 * _Nullable c0) { |
| 291 | int *p = [c0 count]; // expected-warning {{incompatible integer to pointer conversion initializing 'int *' with an expression of type 'int'}} |
| 292 | } |
| 293 | |