1 // RUN: %clang_cc1 -fblocks -fsyntax-only -Wnullable-to-nonnull-conversion %s -verify 2 // 3 // Test the substitution of type arguments for type parameters when 4 // using parameterized classes in Objective-C. 5 6 @protocol NSObject 7 @end 8 9 __attribute__((objc_root_class)) 10 @interface NSObject <NSObject> 11 + (instancetype)alloc; 12 - (instancetype)init; 13 @end 14 15 @protocol NSCopying 16 @end 17 18 @interface NSString : NSObject <NSCopying> 19 @end 20 21 @interface NSMutableString : NSString 22 @end 23 24 @interface NSNumber : NSObject <NSCopying> 25 @end 26 27 @interface NSArray<T> : NSObject <NSCopying> { 28 @public 29 T *data; // don't try this at home 30 } 31 - (T)objectAtIndexedSubscript:(int)index; 32 + (NSArray<T> *)array; 33 + (void)setArray:(NSArray <T> *)array; 34 @property (copy,nonatomic) T lastObject; 35 @end 36 37 @interface NSMutableArray<T> : NSArray<T> 38 -(instancetype)initWithArray:(NSArray<T> *)array; // expected-note{{passing argument}} 39 - (void)setObject:(T)object atIndexedSubscript:(int)index; // expected-note 2{{passing argument to parameter 'object' here}} 40 @end 41 42 @interface NSStringArray : NSArray<NSString *> 43 @end 44 45 @interface NSSet<T> : NSObject <NSCopying> 46 - (T)firstObject; 47 @property (nonatomic, copy) NSArray<T> *allObjects; 48 @end 49 50 // Parameterized inheritance (simple case) 51 @interface NSMutableSet<U : id<NSCopying>> : NSSet<U> 52 - (void)addObject:(U)object; // expected-note 7{{passing argument to parameter 'object' here}} 53 @end 54 55 @interface Widget : NSObject <NSCopying> 56 @end 57 58 // Non-parameterized class inheriting from a specialization of a 59 // parameterized class. 60 @interface WidgetSet : NSMutableSet<Widget *> 61 @end 62 63 // Parameterized inheritance with a more interesting transformation in 64 // the specialization. 65 @interface MutableSetOfArrays<T> : NSMutableSet<NSArray<T>*> 66 @end 67 68 // Inheriting from an unspecialized form of a parameterized type. 69 @interface UntypedMutableSet : NSMutableSet 70 @end 71 72 @interface Window : NSObject 73 @end 74 75 @interface NSDictionary<K, V> : NSObject <NSCopying> 76 - (V)objectForKeyedSubscript:(K)key; // expected-note 2{{parameter 'key'}} 77 @end 78 79 @interface NSMutableDictionary<K : id<NSCopying>, V> : NSDictionary<K, V> 80 - (void)setObject:(V)object forKeyedSubscript:(K)key; 81 // expected-note@-1 {{parameter 'object' here}} 82 // expected-note@-2 {{parameter 'object' here}} 83 // expected-note@-3 {{parameter 'key' here}} 84 // expected-note@-4 {{parameter 'key' here}} 85 86 @property (strong) K someRandomKey; 87 @end 88 89 @interface WindowArray : NSArray<Window *> 90 @end 91 92 @interface NSSet<T> (Searching) 93 - (T)findObject:(T)object; 94 @end 95 96 @interface NSView : NSObject 97 @end 98 99 @interface NSControl : NSView 100 - (void)toggle; 101 @end 102 103 @interface NSViewController<ViewType : NSView *> : NSObject 104 @property (nonatomic,retain) ViewType view; 105 @end 106 107 // -------------------------------------------------------------------------- 108 // Nullability 109 // -------------------------------------------------------------------------- 110 typedef NSControl * _Nonnull Nonnull_NSControl; 111 112 @interface NSNullableTest<ViewType : NSView *> : NSObject 113 - (ViewType)view; 114 - (nullable ViewType)maybeView; 115 @end 116 117 @interface NSNullableTest2<ViewType : NSView * _Nullable> : NSObject // expected-error{{type parameter 'ViewType' bound 'NSView * _Nullable' cannot explicitly specify nullability}} 118 @end 119 120 void test_nullability(void) { 121 NSControl * _Nonnull nonnull_NSControl; 122 123 // Nullability introduced by substitution. 124 NSNullableTest<NSControl *> *unspecifiedControl; 125 nonnull_NSControl = [unspecifiedControl view]; 126 nonnull_NSControl = [unspecifiedControl maybeView]; // expected-warning{{from nullable pointer 'NSControl * _Nullable' to non-nullable pointer type 'NSControl * _Nonnull'}} 127 128 // Nullability overridden by substitution. 129 NSNullableTest<Nonnull_NSControl> *nonnullControl; 130 nonnull_NSControl = [nonnullControl view]; 131 nonnull_NSControl = [nonnullControl maybeView]; // expected-warning{{from nullable pointer 'Nonnull_NSControl _Nullable' (aka 'NSControl *') to non-nullable pointer type 'NSControl * _Nonnull'}} 132 133 // Nullability cannot be specified directly on a type argument. 134 NSNullableTest<NSControl * _Nonnull> *nonnullControl2; // expected-error{{type argument 'NSControl *' cannot explicitly specify nullability}} 135 } 136 137 // -------------------------------------------------------------------------- 138 // Message sends. 139 // -------------------------------------------------------------------------- 140 void test_message_send_result( 141 NSSet<NSString *> *stringSet, 142 NSMutableSet<NSString *> *mutStringSet, 143 WidgetSet *widgetSet, 144 UntypedMutableSet *untypedMutSet, 145 MutableSetOfArrays<NSString *> *mutStringArraySet, 146 NSSet *set, 147 NSMutableSet *mutSet, 148 MutableSetOfArrays *mutArraySet, 149 NSArray<NSString *> *stringArray, 150 NSArray<__kindof NSString *> *kindofStringArray, 151 void (^block)(void)) { 152 int *ip; 153 ip = [stringSet firstObject]; // expected-warning{{from 'NSString *'}} 154 ip = [mutStringSet firstObject]; // expected-warning{{from 'NSString *'}} 155 ip = [widgetSet firstObject]; // expected-warning{{from 'Widget *'}} 156 ip = [untypedMutSet firstObject]; // expected-warning{{from 'id'}} 157 ip = [mutStringArraySet firstObject]; // expected-warning{{from 'NSArray<NSString *> *'}} 158 ip = [set firstObject]; // expected-warning{{from 'id'}} 159 ip = [mutSet firstObject]; // expected-warning{{from 'id'}} 160 ip = [mutArraySet firstObject]; // expected-warning{{from 'id'}} 161 ip = [block firstObject]; // expected-warning{{from 'id'}} 162 163 ip = [stringSet findObject:@"blah"]; // expected-warning{{from 'NSString *'}} 164 165 // Class messages. 166 ip = [NSSet<NSString *> alloc]; // expected-warning{{from 'NSSet<NSString *> *'}} 167 ip = [NSSet alloc]; // expected-warning{{from 'NSSet *'}} 168 ip = [MutableSetOfArrays<NSString *> alloc]; // expected-warning{{from 'MutableSetOfArrays<NSString *> *'}} 169 ip = [MutableSetOfArrays alloc]; // expected-warning{{from 'MutableSetOfArrays *'}} 170 ip = [NSArray<NSString *> array]; // expected-warning{{from 'NSArray<NSString *> *'}} 171 ip = [NSArray<NSString *><NSCopying> array]; // expected-warning{{from 'NSArray<NSString *> *'}} 172 173 ip = [[NSMutableArray<NSString *> alloc] init]; // expected-warning{{from 'NSMutableArray<NSString *> *'}} 174 175 [[NSMutableArray alloc] initWithArray: stringArray]; // okay 176 [[NSMutableArray<NSString *> alloc] initWithArray: stringArray]; // okay 177 [[NSMutableArray<NSNumber *> alloc] initWithArray: stringArray]; // expected-warning{{sending 'NSArray<NSString *> *' to parameter of type 'NSArray<NSNumber *> *'}} 178 179 ip = [[[NSViewController alloc] init] view]; // expected-warning{{from '__kindof NSView *'}} 180 [[[[NSViewController alloc] init] view] toggle]; 181 182 NSMutableString *mutStr = kindofStringArray[0]; 183 NSNumber *number = kindofStringArray[0]; // expected-warning{{of type '__kindof NSString *'}} 184 } 185 186 void test_message_send_param( 187 NSMutableSet<NSString *> *mutStringSet, 188 WidgetSet *widgetSet, 189 UntypedMutableSet *untypedMutSet, 190 MutableSetOfArrays<NSString *> *mutStringArraySet, 191 NSMutableSet *mutSet, 192 MutableSetOfArrays *mutArraySet, 193 void (^block)(void)) { 194 Window *window; 195 196 [mutStringSet addObject: window]; // expected-warning{{parameter of type 'NSString *'}} 197 [widgetSet addObject: window]; // expected-warning{{parameter of type 'Widget *'}} 198 [untypedMutSet addObject: window]; // expected-warning{{parameter of incompatible type 'id<NSCopying>'}} 199 [mutStringArraySet addObject: window]; // expected-warning{{parameter of type 'NSArray<NSString *> *'}} 200 [mutSet addObject: window]; // expected-warning{{parameter of incompatible type 'id<NSCopying>'}} 201 [mutArraySet addObject: window]; // expected-warning{{parameter of incompatible type 'id<NSCopying>'}} 202 [block addObject: window]; // expected-warning{{parameter of incompatible type 'id<NSCopying>'}} 203 } 204 205 // -------------------------------------------------------------------------- 206 // Property accesses. 207 // -------------------------------------------------------------------------- 208 void test_property_read( 209 NSSet<NSString *> *stringSet, 210 NSMutableSet<NSString *> *mutStringSet, 211 WidgetSet *widgetSet, 212 UntypedMutableSet *untypedMutSet, 213 MutableSetOfArrays<NSString *> *mutStringArraySet, 214 NSSet *set, 215 NSMutableSet *mutSet, 216 MutableSetOfArrays *mutArraySet, 217 NSMutableDictionary *mutDict) { 218 int *ip; 219 ip = stringSet.allObjects; // expected-warning{{from 'NSArray<NSString *> *'}} 220 ip = mutStringSet.allObjects; // expected-warning{{from 'NSArray<NSString *> *'}} 221 ip = widgetSet.allObjects; // expected-warning{{from 'NSArray<Widget *> *'}} 222 ip = untypedMutSet.allObjects; // expected-warning{{from 'NSArray *'}} 223 ip = mutStringArraySet.allObjects; // expected-warning{{from 'NSArray<NSArray<NSString *> *> *'}} 224 ip = set.allObjects; // expected-warning{{from 'NSArray *'}} 225 ip = mutSet.allObjects; // expected-warning{{from 'NSArray *'}} 226 ip = mutArraySet.allObjects; // expected-warning{{from 'NSArray *'}} 227 228 ip = mutDict.someRandomKey; // expected-warning{{from '__kindof id<NSCopying>'}} 229 230 ip = [[NSViewController alloc] init].view; // expected-warning{{from '__kindof NSView *'}} 231 } 232 233 void test_property_write( 234 NSMutableSet<NSString *> *mutStringSet, 235 WidgetSet *widgetSet, 236 UntypedMutableSet *untypedMutSet, 237 MutableSetOfArrays<NSString *> *mutStringArraySet, 238 NSMutableSet *mutSet, 239 MutableSetOfArrays *mutArraySet, 240 NSMutableDictionary *mutDict) { 241 int *ip; 242 243 mutStringSet.allObjects = ip; // expected-warning{{to 'NSArray<NSString *> *'}} 244 widgetSet.allObjects = ip; // expected-warning{{to 'NSArray<Widget *> *'}} 245 untypedMutSet.allObjects = ip; // expected-warning{{to 'NSArray *'}} 246 mutStringArraySet.allObjects = ip; // expected-warning{{to 'NSArray<NSArray<NSString *> *> *'}} 247 mutSet.allObjects = ip; // expected-warning{{to 'NSArray *'}} 248 mutArraySet.allObjects = ip; // expected-warning{{to 'NSArray *'}} 249 250 mutDict.someRandomKey = ip; // expected-warning{{to 'id<NSCopying>'}} 251 } 252 253 // -------------------------------------------------------------------------- 254 // Subscripting 255 // -------------------------------------------------------------------------- 256 void test_subscripting( 257 NSArray<NSString *> *stringArray, 258 NSMutableArray<NSString *> *mutStringArray, 259 NSArray *array, 260 NSMutableArray *mutArray, 261 NSDictionary<NSString *, Widget *> *stringWidgetDict, 262 NSMutableDictionary<NSString *, Widget *> *mutStringWidgetDict, 263 NSDictionary *dict, 264 NSMutableDictionary *mutDict) { 265 int *ip; 266 NSString *string; 267 Widget *widget; 268 Window *window; 269 270 ip = stringArray[0]; // expected-warning{{from 'NSString *'}} 271 272 ip = mutStringArray[0]; // expected-warning{{from 'NSString *'}} 273 mutStringArray[0] = ip; // expected-warning{{parameter of type 'NSString *'}} 274 275 ip = array[0]; // expected-warning{{from 'id'}} 276 277 ip = mutArray[0]; // expected-warning{{from 'id'}} 278 mutArray[0] = ip; // expected-warning{{parameter of type 'id'}} 279 280 ip = stringWidgetDict[string]; // expected-warning{{from 'Widget *'}} 281 widget = stringWidgetDict[widget]; // expected-warning{{to parameter of type 'NSString *'}} 282 283 ip = mutStringWidgetDict[string]; // expected-warning{{from 'Widget *'}} 284 widget = mutStringWidgetDict[widget]; // expected-warning{{to parameter of type 'NSString *'}} 285 mutStringWidgetDict[string] = ip; // expected-warning{{to parameter of type 'Widget *'}} 286 mutStringWidgetDict[widget] = widget; // expected-warning{{to parameter of type 'NSString *'}} 287 288 ip = dict[string]; // expected-warning{{from 'id'}} 289 290 ip = mutDict[string]; // expected-warning{{from 'id'}} 291 mutDict[string] = ip; // expected-warning{{to parameter of type 'id'}} 292 293 widget = mutDict[window]; 294 mutDict[window] = widget; // expected-warning{{parameter of incompatible type 'id<NSCopying>'}} 295 } 296 297 // -------------------------------------------------------------------------- 298 // Instance variable access. 299 // -------------------------------------------------------------------------- 300 void test_instance_variable(NSArray<NSString *> *stringArray, 301 NSArray *array) { 302 int *ip; 303 304 ip = stringArray->data; // expected-warning{{from 'NSString **'}} 305 ip = array->data; // expected-warning{{from 'id *'}} 306 } 307 308 @implementation WindowArray 309 - (void)testInstanceVariable { 310 int *ip; 311 312 ip = data; // expected-warning{{from 'Window **'}} 313 } 314 @end 315 316 // -------------------------------------------------------------------------- 317 // Implicit conversions. 318 // -------------------------------------------------------------------------- 319 void test_implicit_conversions(NSArray<NSString *> *stringArray, 320 NSArray<NSNumber *> *numberArray, 321 NSMutableArray<NSString *> *mutStringArray, 322 NSArray *array, 323 NSMutableArray *mutArray) { 324 // Specialized -> unspecialized (same level) 325 array = stringArray; 326 327 // Unspecialized -> specialized (same level) 328 stringArray = array; 329 330 // Specialized -> specialized failure (same level). 331 stringArray = numberArray; // expected-warning{{incompatible pointer types assigning to 'NSArray<NSString *> *' from 'NSArray<NSNumber *> *'}} 332 333 // Specialized -> specialized (different levels). 334 stringArray = mutStringArray; 335 336 // Specialized -> specialized failure (different levels). 337 numberArray = mutStringArray; // expected-warning{{incompatible pointer types assigning to 'NSArray<NSNumber *> *' from 'NSMutableArray<NSString *> *'}} 338 339 // Unspecialized -> specialized (different levels). 340 stringArray = mutArray; 341 342 // Specialized -> unspecialized (different levels). 343 array = mutStringArray; 344 } 345 346 @interface NSCovariant1<__covariant T> 347 @end 348 349 @interface NSContravariant1<__contravariant T> 350 @end 351 352 void test_variance(NSCovariant1<NSString *> *covariant1, 353 NSCovariant1<NSMutableString *> *covariant2, 354 NSCovariant1<NSString *(^)(void)> *covariant3, 355 NSCovariant1<NSMutableString *(^)(void)> *covariant4, 356 NSCovariant1<id> *covariant5, 357 NSCovariant1<id<NSCopying>> *covariant6, 358 NSContravariant1<NSString *> *contravariant1, 359 NSContravariant1<NSMutableString *> *contravariant2) { 360 covariant1 = covariant2; // okay 361 covariant2 = covariant1; // expected-warning{{incompatible pointer types assigning to 'NSCovariant1<NSMutableString *> *' from 'NSCovariant1<NSString *> *'}} 362 363 covariant3 = covariant4; // okay 364 covariant4 = covariant3; // expected-warning{{incompatible pointer types assigning to 'NSCovariant1<NSMutableString *(^)(void)> *' from 'NSCovariant1<NSString *(^)(void)> *'}} 365 366 covariant5 = covariant1; // okay 367 covariant1 = covariant5; // okay: id is promiscuous 368 369 covariant5 = covariant3; // okay 370 covariant3 = covariant5; // okay 371 372 contravariant1 = contravariant2; // expected-warning{{incompatible pointer types assigning to 'NSContravariant1<NSString *> *' from 'NSContravariant1<NSMutableString *> *'}} 373 contravariant2 = contravariant1; // okay 374 } 375 376 // -------------------------------------------------------------------------- 377 // Ternary operator 378 // -------------------------------------------------------------------------- 379 void test_ternary_operator(NSArray<NSString *> *stringArray, 380 NSArray<NSNumber *> *numberArray, 381 NSMutableArray<NSString *> *mutStringArray, 382 NSStringArray *stringArray2, 383 NSArray *array, 384 NSMutableArray *mutArray, 385 int cond) { 386 int *ip; 387 id object; 388 389 ip = cond ? stringArray : mutStringArray; // expected-warning{{from 'NSArray<NSString *> *'}} 390 ip = cond ? mutStringArray : stringArray; // expected-warning{{from 'NSArray<NSString *> *'}} 391 392 ip = cond ? stringArray2 : mutStringArray; // expected-warning{{from 'NSArray<NSString *> *'}} 393 ip = cond ? mutStringArray : stringArray2; // expected-warning{{from 'NSArray<NSString *> *'}} 394 395 ip = cond ? stringArray : mutArray; // expected-warning{{from 'NSArray *'}} 396 397 ip = cond ? stringArray2 : mutArray; // expected-warning{{from 'NSArray *'}} 398 399 ip = cond ? mutArray : stringArray; // expected-warning{{from 'NSArray *'}} 400 401 ip = cond ? mutArray : stringArray2; // expected-warning{{from 'NSArray *'}} 402 403 object = cond ? stringArray : numberArray; // expected-warning{{incompatible operand types ('NSArray<NSString *> *' and 'NSArray<NSNumber *> *')}} 404 } 405 406 // -------------------------------------------------------------------------- 407 // super 408 // -------------------------------------------------------------------------- 409 @implementation NSStringArray 410 - (void)useSuperMethod { 411 int *ip; 412 ip = super.lastObject; // expected-warning{{from 'NSString *'}} 413 super.lastObject = ip; // expected-warning{{to 'NSString *'}} 414 ip = [super objectAtIndexedSubscript:0]; // expected-warning{{from 'NSString *'}} 415 } 416 417 + (void)useSuperMethod { 418 int *ip; 419 ip = super.array; // expected-warning{{from 'NSArray<NSString *> *'}} 420 super.array = ip; // expected-warning{{to 'NSArray<NSString *> *'}} 421 ip = [super array]; // expected-warning{{from 'NSArray<NSString *> *'}} 422 } 423 @end 424 425 // -------------------------------------------------------------------------- 426 // warning about likely protocol/class name typos. 427 // -------------------------------------------------------------------------- 428 typedef NSArray<NSObject> ArrayOfNSObjectWarning; // expected-warning{{parameterized class 'NSArray' already conforms to the protocols listed; did you forget a '*'?}} 429