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@interface TypedefTypeParam<T> : NSObject 108typedef T AliasT; 109- (void)test:(AliasT)object; 110// expected-note@-1 {{parameter 'object' here}} 111@end 112 113// -------------------------------------------------------------------------- 114// Nullability 115// -------------------------------------------------------------------------- 116typedef NSControl * _Nonnull Nonnull_NSControl; 117 118@interface NSNullableTest<ViewType : NSView *> : NSObject 119- (ViewType)view; 120- (nullable ViewType)maybeView; 121@end 122 123@interface NSNullableTest2<ViewType : NSView * _Nullable> : NSObject // expected-error{{type parameter 'ViewType' bound 'NSView * _Nullable' cannot explicitly specify nullability}} 124@end 125 126void test_nullability(void) { 127 NSControl * _Nonnull nonnull_NSControl; 128 129 // Nullability introduced by substitution. 130 NSNullableTest<NSControl *> *unspecifiedControl; 131 nonnull_NSControl = [unspecifiedControl view]; 132 nonnull_NSControl = [unspecifiedControl maybeView]; // expected-warning{{from nullable pointer 'NSControl * _Nullable' to non-nullable pointer type 'NSControl * _Nonnull'}} 133 134 // Nullability overridden by substitution. 135 NSNullableTest<Nonnull_NSControl> *nonnullControl; 136 nonnull_NSControl = [nonnullControl view]; 137 nonnull_NSControl = [nonnullControl maybeView]; // expected-warning{{from nullable pointer 'Nonnull_NSControl _Nullable' (aka 'NSControl *') to non-nullable pointer type 'NSControl * _Nonnull'}} 138 139 // Nullability cannot be specified directly on a type argument. 140 NSNullableTest<NSControl * _Nonnull> *nonnullControl2; // expected-error{{type argument 'NSControl *' cannot explicitly specify nullability}} 141} 142 143// -------------------------------------------------------------------------- 144// Message sends. 145// -------------------------------------------------------------------------- 146void test_message_send_result( 147 NSSet<NSString *> *stringSet, 148 NSMutableSet<NSString *> *mutStringSet, 149 WidgetSet *widgetSet, 150 UntypedMutableSet *untypedMutSet, 151 MutableSetOfArrays<NSString *> *mutStringArraySet, 152 NSSet *set, 153 NSMutableSet *mutSet, 154 MutableSetOfArrays *mutArraySet, 155 NSArray<NSString *> *stringArray, 156 NSArray<__kindof NSString *> *kindofStringArray, 157 void (^block)(void)) { 158 int *ip; 159 ip = [stringSet firstObject]; // expected-warning{{from 'NSString *'}} 160 ip = [mutStringSet firstObject]; // expected-warning{{from 'NSString *'}} 161 ip = [widgetSet firstObject]; // expected-warning{{from 'Widget *'}} 162 ip = [untypedMutSet firstObject]; // expected-warning{{from 'id'}} 163 ip = [mutStringArraySet firstObject]; // expected-warning{{from 'NSArray<NSString *> *'}} 164 ip = [set firstObject]; // expected-warning{{from 'id'}} 165 ip = [mutSet firstObject]; // expected-warning{{from 'id'}} 166 ip = [mutArraySet firstObject]; // expected-warning{{from 'id'}} 167 ip = [block firstObject]; // expected-warning{{from 'id'}} 168 169 ip = [stringSet findObject:@"blah"]; // expected-warning{{from 'NSString *'}} 170 171 // Class messages. 172 ip = [NSSet<NSString *> alloc]; // expected-warning{{from 'NSSet<NSString *> *'}} 173 ip = [NSSet alloc]; // expected-warning{{from 'NSSet *'}} 174 ip = [MutableSetOfArrays<NSString *> alloc]; // expected-warning{{from 'MutableSetOfArrays<NSString *> *'}} 175 ip = [MutableSetOfArrays alloc]; // expected-warning{{from 'MutableSetOfArrays *'}} 176 ip = [NSArray<NSString *> array]; // expected-warning{{from 'NSArray<NSString *> *'}} 177 ip = [NSArray<NSString *><NSCopying> array]; // expected-warning{{from 'NSArray<NSString *> *'}} 178 179 ip = [[NSMutableArray<NSString *> alloc] init]; // expected-warning{{from 'NSMutableArray<NSString *> *'}} 180 181 [[NSMutableArray alloc] initWithArray: stringArray]; // okay 182 [[NSMutableArray<NSString *> alloc] initWithArray: stringArray]; // okay 183 [[NSMutableArray<NSNumber *> alloc] initWithArray: stringArray]; // expected-warning{{sending 'NSArray<NSString *> *' to parameter of type 'NSArray<NSNumber *> *'}} 184 185 ip = [[[NSViewController alloc] init] view]; // expected-warning{{from '__kindof NSView *'}} 186 [[[[NSViewController alloc] init] view] toggle]; 187 188 NSMutableString *mutStr = kindofStringArray[0]; 189 NSNumber *number = kindofStringArray[0]; // expected-warning{{of type '__kindof NSString *'}} 190} 191 192void test_message_send_param( 193 NSMutableSet<NSString *> *mutStringSet, 194 WidgetSet *widgetSet, 195 UntypedMutableSet *untypedMutSet, 196 MutableSetOfArrays<NSString *> *mutStringArraySet, 197 NSMutableSet *mutSet, 198 MutableSetOfArrays *mutArraySet, 199 TypedefTypeParam<NSString *> *typedefTypeParam, 200 void (^block)(void)) { 201 Window *window; 202 203 [mutStringSet addObject: window]; // expected-warning{{parameter of type 'NSString *'}} 204 [widgetSet addObject: window]; // expected-warning{{parameter of type 'Widget *'}} 205 [untypedMutSet addObject: window]; // expected-warning{{parameter of incompatible type 'id<NSCopying>'}} 206 [mutStringArraySet addObject: window]; // expected-warning{{parameter of type 'NSArray<NSString *> *'}} 207 [mutSet addObject: window]; // expected-warning{{parameter of incompatible type 'id<NSCopying>'}} 208 [mutArraySet addObject: window]; // expected-warning{{parameter of incompatible type 'id<NSCopying>'}} 209 [typedefTypeParam test: window]; // expected-warning{{parameter of type 'NSString *'}} 210 [block addObject: window]; // expected-warning{{parameter of incompatible type 'id<NSCopying>'}} 211} 212 213// -------------------------------------------------------------------------- 214// Property accesses. 215// -------------------------------------------------------------------------- 216void test_property_read( 217 NSSet<NSString *> *stringSet, 218 NSMutableSet<NSString *> *mutStringSet, 219 WidgetSet *widgetSet, 220 UntypedMutableSet *untypedMutSet, 221 MutableSetOfArrays<NSString *> *mutStringArraySet, 222 NSSet *set, 223 NSMutableSet *mutSet, 224 MutableSetOfArrays *mutArraySet, 225 NSMutableDictionary *mutDict) { 226 int *ip; 227 ip = stringSet.allObjects; // expected-warning{{from 'NSArray<NSString *> *'}} 228 ip = mutStringSet.allObjects; // expected-warning{{from 'NSArray<NSString *> *'}} 229 ip = widgetSet.allObjects; // expected-warning{{from 'NSArray<Widget *> *'}} 230 ip = untypedMutSet.allObjects; // expected-warning{{from 'NSArray *'}} 231 ip = mutStringArraySet.allObjects; // expected-warning{{from 'NSArray<NSArray<NSString *> *> *'}} 232 ip = set.allObjects; // expected-warning{{from 'NSArray *'}} 233 ip = mutSet.allObjects; // expected-warning{{from 'NSArray *'}} 234 ip = mutArraySet.allObjects; // expected-warning{{from 'NSArray *'}} 235 236 ip = mutDict.someRandomKey; // expected-warning{{from '__kindof id<NSCopying>'}} 237 238 ip = [[NSViewController alloc] init].view; // expected-warning{{from '__kindof NSView *'}} 239} 240 241void test_property_write( 242 NSMutableSet<NSString *> *mutStringSet, 243 WidgetSet *widgetSet, 244 UntypedMutableSet *untypedMutSet, 245 MutableSetOfArrays<NSString *> *mutStringArraySet, 246 NSMutableSet *mutSet, 247 MutableSetOfArrays *mutArraySet, 248 NSMutableDictionary *mutDict) { 249 int *ip; 250 251 mutStringSet.allObjects = ip; // expected-warning{{to 'NSArray<NSString *> *'}} 252 widgetSet.allObjects = ip; // expected-warning{{to 'NSArray<Widget *> *'}} 253 untypedMutSet.allObjects = ip; // expected-warning{{to 'NSArray *'}} 254 mutStringArraySet.allObjects = ip; // expected-warning{{to 'NSArray<NSArray<NSString *> *> *'}} 255 mutSet.allObjects = ip; // expected-warning{{to 'NSArray *'}} 256 mutArraySet.allObjects = ip; // expected-warning{{to 'NSArray *'}} 257 258 mutDict.someRandomKey = ip; // expected-warning{{to 'id<NSCopying>'}} 259} 260 261// -------------------------------------------------------------------------- 262// Subscripting 263// -------------------------------------------------------------------------- 264void test_subscripting( 265 NSArray<NSString *> *stringArray, 266 NSMutableArray<NSString *> *mutStringArray, 267 NSArray *array, 268 NSMutableArray *mutArray, 269 NSDictionary<NSString *, Widget *> *stringWidgetDict, 270 NSMutableDictionary<NSString *, Widget *> *mutStringWidgetDict, 271 NSDictionary *dict, 272 NSMutableDictionary *mutDict) { 273 int *ip; 274 NSString *string; 275 Widget *widget; 276 Window *window; 277 278 ip = stringArray[0]; // expected-warning{{from 'NSString *'}} 279 280 ip = mutStringArray[0]; // expected-warning{{from 'NSString *'}} 281 mutStringArray[0] = ip; // expected-warning{{parameter of type 'NSString *'}} 282 283 ip = array[0]; // expected-warning{{from 'id'}} 284 285 ip = mutArray[0]; // expected-warning{{from 'id'}} 286 mutArray[0] = ip; // expected-warning{{parameter of type 'id'}} 287 288 ip = stringWidgetDict[string]; // expected-warning{{from 'Widget *'}} 289 widget = stringWidgetDict[widget]; // expected-warning{{to parameter of type 'NSString *'}} 290 291 ip = mutStringWidgetDict[string]; // expected-warning{{from 'Widget *'}} 292 widget = mutStringWidgetDict[widget]; // expected-warning{{to parameter of type 'NSString *'}} 293 mutStringWidgetDict[string] = ip; // expected-warning{{to parameter of type 'Widget *'}} 294 mutStringWidgetDict[widget] = widget; // expected-warning{{to parameter of type 'NSString *'}} 295 296 ip = dict[string]; // expected-warning{{from 'id'}} 297 298 ip = mutDict[string]; // expected-warning{{from 'id'}} 299 mutDict[string] = ip; // expected-warning{{to parameter of type 'id'}} 300 301 widget = mutDict[window]; 302 mutDict[window] = widget; // expected-warning{{parameter of incompatible type 'id<NSCopying>'}} 303} 304 305// -------------------------------------------------------------------------- 306// Instance variable access. 307// -------------------------------------------------------------------------- 308void test_instance_variable(NSArray<NSString *> *stringArray, 309 NSArray *array) { 310 int *ip; 311 312 ip = stringArray->data; // expected-warning{{from 'NSString **'}} 313 ip = array->data; // expected-warning{{from 'id *'}} 314} 315 316@implementation WindowArray 317- (void)testInstanceVariable { 318 int *ip; 319 320 ip = data; // expected-warning{{from 'Window **'}} 321} 322@end 323 324// -------------------------------------------------------------------------- 325// Implicit conversions. 326// -------------------------------------------------------------------------- 327void test_implicit_conversions(NSArray<NSString *> *stringArray, 328 NSArray<NSNumber *> *numberArray, 329 NSMutableArray<NSString *> *mutStringArray, 330 NSArray *array, 331 NSMutableArray *mutArray) { 332 // Specialized -> unspecialized (same level) 333 array = stringArray; 334 335 // Unspecialized -> specialized (same level) 336 stringArray = array; 337 338 // Specialized -> specialized failure (same level). 339 stringArray = numberArray; // expected-warning{{incompatible pointer types assigning to 'NSArray<NSString *> *' from 'NSArray<NSNumber *> *'}} 340 341 // Specialized -> specialized (different levels). 342 stringArray = mutStringArray; 343 344 // Specialized -> specialized failure (different levels). 345 numberArray = mutStringArray; // expected-warning{{incompatible pointer types assigning to 'NSArray<NSNumber *> *' from 'NSMutableArray<NSString *> *'}} 346 347 // Unspecialized -> specialized (different levels). 348 stringArray = mutArray; 349 350 // Specialized -> unspecialized (different levels). 351 array = mutStringArray; 352} 353 354@interface NSCovariant1<__covariant T> 355@end 356 357@interface NSContravariant1<__contravariant T> 358@end 359 360void test_variance(NSCovariant1<NSString *> *covariant1, 361 NSCovariant1<NSMutableString *> *covariant2, 362 NSCovariant1<NSString *(^)(void)> *covariant3, 363 NSCovariant1<NSMutableString *(^)(void)> *covariant4, 364 NSCovariant1<id> *covariant5, 365 NSCovariant1<id<NSCopying>> *covariant6, 366 NSContravariant1<NSString *> *contravariant1, 367 NSContravariant1<NSMutableString *> *contravariant2) { 368 covariant1 = covariant2; // okay 369 covariant2 = covariant1; // expected-warning{{incompatible pointer types assigning to 'NSCovariant1<NSMutableString *> *' from 'NSCovariant1<NSString *> *'}} 370 371 covariant3 = covariant4; // okay 372 covariant4 = covariant3; // expected-warning{{incompatible pointer types assigning to 'NSCovariant1<NSMutableString *(^)(void)> *' from 'NSCovariant1<NSString *(^)(void)> *'}} 373 374 covariant5 = covariant1; // okay 375 covariant1 = covariant5; // okay: id is promiscuous 376 377 covariant5 = covariant3; // okay 378 covariant3 = covariant5; // okay 379 380 contravariant1 = contravariant2; // expected-warning{{incompatible pointer types assigning to 'NSContravariant1<NSString *> *' from 'NSContravariant1<NSMutableString *> *'}} 381 contravariant2 = contravariant1; // okay 382} 383 384// -------------------------------------------------------------------------- 385// Ternary operator 386// -------------------------------------------------------------------------- 387void test_ternary_operator(NSArray<NSString *> *stringArray, 388 NSArray<NSNumber *> *numberArray, 389 NSMutableArray<NSString *> *mutStringArray, 390 NSStringArray *stringArray2, 391 NSArray *array, 392 NSMutableArray *mutArray, 393 int cond) { 394 int *ip; 395 id object; 396 397 ip = cond ? stringArray : mutStringArray; // expected-warning{{from 'NSArray<NSString *> *'}} 398 ip = cond ? mutStringArray : stringArray; // expected-warning{{from 'NSArray<NSString *> *'}} 399 400 ip = cond ? stringArray2 : mutStringArray; // expected-warning{{from 'NSArray<NSString *> *'}} 401 ip = cond ? mutStringArray : stringArray2; // expected-warning{{from 'NSArray<NSString *> *'}} 402 403 ip = cond ? stringArray : mutArray; // expected-warning{{from 'NSArray *'}} 404 405 ip = cond ? stringArray2 : mutArray; // expected-warning{{from 'NSArray *'}} 406 407 ip = cond ? mutArray : stringArray; // expected-warning{{from 'NSArray *'}} 408 409 ip = cond ? mutArray : stringArray2; // expected-warning{{from 'NSArray *'}} 410 411 object = cond ? stringArray : numberArray; // expected-warning{{incompatible operand types ('NSArray<NSString *> *' and 'NSArray<NSNumber *> *')}} 412} 413 414// -------------------------------------------------------------------------- 415// super 416// -------------------------------------------------------------------------- 417@implementation NSStringArray 418- (void)useSuperMethod { 419 int *ip; 420 ip = super.lastObject; // expected-warning{{from 'NSString *'}} 421 super.lastObject = ip; // expected-warning{{to 'NSString *'}} 422 ip = [super objectAtIndexedSubscript:0]; // expected-warning{{from 'NSString *'}} 423} 424 425+ (void)useSuperMethod { 426 int *ip; 427 ip = super.array; // expected-warning{{from 'NSArray<NSString *> *'}} 428 super.array = ip; // expected-warning{{to 'NSArray<NSString *> *'}} 429 ip = [super array]; // expected-warning{{from 'NSArray<NSString *> *'}} 430} 431@end 432 433// -------------------------------------------------------------------------- 434// warning about likely protocol/class name typos. 435// -------------------------------------------------------------------------- 436typedef NSArray<NSObject> ArrayOfNSObjectWarning; // expected-warning{{parameterized class 'NSArray' already conforms to the protocols listed; did you forget a '*'?}} 437 438@interface MyMutableDictionary<KeyType, ObjectType> : NSObject 439- (void)setObject:(ObjectType)obj forKeyedSubscript:(KeyType <NSCopying>)key; // expected-note{{passing argument to parameter 'obj' here}} \ 440 // expected-note{{passing argument to parameter 'key' here}} 441@end 442 443void bar(MyMutableDictionary<NSString *, NSString *> *stringsByString, 444 NSNumber *n1, NSNumber *n2) { 445 // We warn here when the key types do not match. 446 stringsByString[n1] = n2; // expected-warning{{incompatible pointer types sending 'NSNumber *' to parameter of type 'NSString *'}} \ 447 // expected-warning{{incompatible pointer types sending 'NSNumber *' to parameter of type 'NSString<NSCopying> *'}} 448} 449 450@interface MyTest<K, V> : NSObject <NSCopying> 451- (V)test:(K)key; 452- (V)test2:(K)key; // expected-note{{previous definition is here}} 453- (void)mapUsingBlock:(id (^)(V))block; 454- (void)mapUsingBlock2:(id (^)(V))block; // expected-note{{previous definition is here}} 455@end 456 457@implementation MyTest 458- (id)test:(id)key { 459 return key; 460} 461- (int)test2:(id)key{ // expected-warning{{conflicting return type in implementation}} 462 return 0; 463} 464- (void)mapUsingBlock:(id (^)(id))block { 465} 466- (void)mapUsingBlock2:(id)block { // expected-warning{{conflicting parameter types in implementation}} 467} 468@end 469 470// -------------------------------------------------------------------------- 471// Use a type parameter as a type argument. 472// -------------------------------------------------------------------------- 473// Type bounds in a category/extension are omitted. 474@interface ParameterizedContainer<T : id<NSCopying>> 475- (ParameterizedContainer<T> *)inInterface; 476@end 477@interface ParameterizedContainer<T> (Cat) 478- (ParameterizedContainer<T> *)inCategory; 479@end 480@interface ParameterizedContainer<U> () 481- (ParameterizedContainer<U> *)inExtension; 482@end 483