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// -------------------------------------------------------------------------- 110typedef 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 120void 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// -------------------------------------------------------------------------- 140void 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 186void 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// -------------------------------------------------------------------------- 208void 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 233void 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// -------------------------------------------------------------------------- 256void 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// -------------------------------------------------------------------------- 300void 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// -------------------------------------------------------------------------- 319void 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 352void 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// -------------------------------------------------------------------------- 379void 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// -------------------------------------------------------------------------- 428typedef NSArray<NSObject> ArrayOfNSObjectWarning; // expected-warning{{parameterized class 'NSArray' already conforms to the protocols listed; did you forget a '*'?}} 429