1// RUN: %clang_cc1 -fblocks -fsyntax-only %s -verify -Wmethod-signatures 2 3// Tests Objective-C 'kindof' types. 4 5#if !__has_feature(objc_kindof) 6#error does not support __kindof 7#endif 8 9@protocol NSObject 10@end 11 12@protocol NSCopying 13- (id)copy; 14+ (Class)classCopy; 15@end 16 17@protocol NSRandomProto 18- (void)randomMethod; 19+ (void)randomClassMethod; 20@end 21 22__attribute__((objc_root_class)) 23@interface NSObject <NSObject> 24- (NSObject *)retain; 25@end 26 27@interface NSString : NSObject <NSCopying> // expected-note{{receiver is instance of class declared here}} 28- (void)compare:(NSString *)string; 29- (NSString *)stringByAppendingString:(NSString *)string; 30+ (instancetype)string; 31@end 32 33@interface NSMutableString : NSString 34- (void)appendString:(NSString *)string; 35@end 36 37@interface NSNumber : NSObject <NSCopying> 38- (NSNumber *)numberByAddingNumber:(NSNumber *)number; 39@end 40 41// --------------------------------------------------------------------------- 42// Parsing and semantic analysis for __kindof 43// --------------------------------------------------------------------------- 44 45// Test proper application of __kindof. 46typedef __kindof NSObject *typedef1; 47typedef NSObject __kindof *typedef2; 48typedef __kindof NSObject<NSCopying> typedef3; 49typedef NSObject<NSCopying> __kindof *typedef4; 50typedef __kindof id<NSCopying> typedef5; 51typedef __kindof Class<NSCopying> typedef6; 52 53// Test redundancy of __kindof. 54typedef __kindof id __kindof redundant_typedef1; 55typedef __kindof NSObject __kindof *redundant_typedef2; 56 57// Test application of __kindof to typedefs. 58typedef NSObject *NSObject_ptr_typedef; 59typedef NSObject NSObject_typedef; 60typedef __kindof NSObject_ptr_typedef typedef_typedef1; 61typedef __kindof NSObject_typedef typedef_typedef2; 62 63// Test application of __kindof to non-object types. 64typedef __kindof int nonobject_typedef1; // expected-error{{'__kindof' specifier cannot be applied to non-object type 'int'}} 65typedef NSObject **NSObject_ptr_ptr; 66typedef __kindof NSObject_ptr_ptr nonobject_typedef2; // expected-error{{'__kindof' specifier cannot be applied to non-object type 'NSObject_ptr_ptr' (aka 'NSObject **')}} 67 68// Test application of __kindof outside of the decl-specifiers. 69typedef NSObject * __kindof bad_specifier_location1; // expected-error{{'__kindof' type specifier must precede the declarator}} 70typedef NSObject bad_specifier_location2 __kindof; // expected-error{{expected ';' after top level declarator}} 71// expected-warning@-1{{declaration does not declare anything}} 72 73// --------------------------------------------------------------------------- 74// Pretty printing of __kindof 75// --------------------------------------------------------------------------- 76void test_pretty_print(int *ip) { 77 __kindof NSObject *kindof_NSObject; 78 ip = kindof_NSObject; // expected-warning{{from '__kindof NSObject *'}} 79 80 __kindof NSObject_ptr_typedef kindof_NSObject_ptr; 81 ip = kindof_NSObject_ptr; // expected-warning{{from '__kindof NSObject_ptr_typedef'}} 82 83 __kindof id <NSCopying> *kindof_NSCopying; 84 ip = kindof_NSCopying; // expected-warning{{from '__kindof id<NSCopying> *'}} 85 86 __kindof NSObject_ptr_typedef *kindof_NSObject_ptr_typedef; 87 ip = kindof_NSObject_ptr_typedef; // expected-warning{{from '__kindof NSObject_ptr_typedef *'}} 88} 89 90// --------------------------------------------------------------------------- 91// Basic implicit conversions (dropping __kindof, upcasts, etc.) 92// --------------------------------------------------------------------------- 93void test_add_remove_kindof_conversions(void) { 94 __kindof NSObject *kindof_NSObject_obj; 95 NSObject *NSObject_obj; 96 97 // Conversion back and forth 98 kindof_NSObject_obj = NSObject_obj; 99 NSObject_obj = kindof_NSObject_obj; 100 101 // Qualified-id conversion back and forth. 102 __kindof id <NSCopying> kindof_id_NSCopying_obj; 103 id <NSCopying> id_NSCopying_obj; 104 kindof_id_NSCopying_obj = id_NSCopying_obj; 105 id_NSCopying_obj = kindof_id_NSCopying_obj; 106} 107 108void test_upcast_conversions(void) { 109 __kindof NSObject *kindof_NSObject_obj; 110 NSObject *NSObject_obj; 111 112 // Upcasts 113 __kindof NSString *kindof_NSString_obj; 114 NSString *NSString_obj; 115 kindof_NSObject_obj = kindof_NSString_obj; 116 kindof_NSObject_obj = NSString_obj; 117 NSObject_obj = kindof_NSString_obj; 118 NSObject_obj = NSString_obj; 119 120 // "Upcasts" with qualified-id. 121 __kindof id <NSCopying> kindof_id_NSCopying_obj; 122 id <NSCopying> id_NSCopying_obj; 123 kindof_id_NSCopying_obj = kindof_NSString_obj; 124 kindof_id_NSCopying_obj = NSString_obj; 125 id_NSCopying_obj = kindof_NSString_obj; 126 id_NSCopying_obj = NSString_obj; 127} 128 129 130void test_ptr_object_conversions(void) { 131 __kindof NSObject **ptr_kindof_NSObject_obj; 132 NSObject **ptr_NSObject_obj; 133 134 // Conversions back and forth. 135 ptr_kindof_NSObject_obj = ptr_NSObject_obj; 136 ptr_NSObject_obj = ptr_kindof_NSObject_obj; 137 138 // Conversions back and forth with qualified-id. 139 __kindof id <NSCopying> *ptr_kindof_id_NSCopying_obj; 140 id <NSCopying> *ptr_id_NSCopying_obj; 141 ptr_kindof_id_NSCopying_obj = ptr_id_NSCopying_obj; 142 ptr_id_NSCopying_obj = ptr_kindof_id_NSCopying_obj; 143 144 // Upcasts. 145 __kindof NSString **ptr_kindof_NSString_obj; 146 NSString **ptr_NSString_obj; 147 ptr_kindof_NSObject_obj = ptr_kindof_NSString_obj; 148 ptr_kindof_NSObject_obj = ptr_NSString_obj; 149 ptr_NSObject_obj = ptr_kindof_NSString_obj; 150 ptr_NSObject_obj = ptr_NSString_obj; 151} 152 153// --------------------------------------------------------------------------- 154// Implicit downcasting 155// --------------------------------------------------------------------------- 156void test_downcast_conversions(void) { 157 __kindof NSObject *kindof_NSObject_obj; 158 NSObject *NSObject_obj; 159 __kindof NSString *kindof_NSString_obj; 160 NSString *NSString_obj; 161 162 // Implicit downcasting. 163 kindof_NSString_obj = kindof_NSObject_obj; 164 kindof_NSString_obj = NSObject_obj; // expected-warning{{assigning to '__kindof NSString *' from 'NSObject *'}} 165 NSString_obj = kindof_NSObject_obj; 166 NSString_obj = NSObject_obj; // expected-warning{{assigning to 'NSString *' from 'NSObject *'}} 167 168 // Implicit downcasting with qualified id. 169 __kindof id <NSCopying> kindof_NSCopying_obj; 170 id <NSCopying> NSCopying_obj; 171 kindof_NSString_obj = kindof_NSCopying_obj; 172 kindof_NSString_obj = NSCopying_obj; // expected-warning{{from incompatible type 'id<NSCopying>'}} 173 NSString_obj = kindof_NSCopying_obj; 174 NSString_obj = NSCopying_obj; // expected-warning{{from incompatible type 'id<NSCopying>'}} 175 kindof_NSObject_obj = kindof_NSCopying_obj; 176 kindof_NSObject_obj = NSCopying_obj; // expected-warning{{from incompatible type 'id<NSCopying>'}} 177 NSObject_obj = kindof_NSCopying_obj; 178 NSObject_obj = NSCopying_obj; // expected-warning{{from incompatible type 'id<NSCopying>'}} 179} 180 181void test_crosscast_conversions(void) { 182 __kindof NSString *kindof_NSString_obj; 183 NSString *NSString_obj; 184 __kindof NSNumber *kindof_NSNumber_obj; 185 NSNumber *NSNumber_obj; 186 187 NSString_obj = kindof_NSNumber_obj; // expected-warning{{from '__kindof NSNumber *'}} 188} 189 190@interface NSCell : NSObject 191@end 192@interface NSCellSub : NSCell 193@end 194@interface NSCellSub2 : NSCell 195@end 196@interface NSCellSubSub : NSCellSub 197@end 198 199typedef signed char BOOL; 200void test_conditional(BOOL flag) { 201 NSCellSubSub *result; 202 __kindof NSCellSub *kindof_Sub; 203 NSCell *cell; 204 NSCellSub *sub; 205 NSCellSub2 *sub2; 206 NSCellSubSub *subsub; 207 208 // LHS is kindof NSCellSub, RHS is NSCell --> kindof NSCell 209 // LHS is kindof NSCellSub, RHS is NSCellSub --> kindof NSCellSub 210 // LHS is kindof NSCellSub, RHS is NSCellSub2 --> kindof NSCell 211 // LHS is kindof NSCellSub, RHS is NSCellSubSub --> kindof NSCellSub 212 result = flag ? kindof_Sub : cell; 213 result = flag ? kindof_Sub : sub; 214 result = flag ? kindof_Sub : sub2; 215 result = flag ? kindof_Sub : subsub; 216 217 result = flag ? cell : kindof_Sub; 218 result = flag ? sub : kindof_Sub; 219 result = flag ? sub2 : kindof_Sub; 220 result = flag ? subsub : kindof_Sub; 221} 222 223// --------------------------------------------------------------------------- 224// Blocks 225// --------------------------------------------------------------------------- 226void test_block_conversions(void) { 227 // Adding/removing __kindof from return type. 228 __kindof NSString *(^kindof_NSString_void_block)(void); 229 NSString *(^NSString_void_block)(void); 230 kindof_NSString_void_block = NSString_void_block; 231 NSString_void_block = kindof_NSString_void_block; 232 233 // Covariant return type. 234 __kindof NSMutableString *(^kindof_NSMutableString_void_block)(void); 235 NSMutableString *(^NSMutableString_void_block)(void); 236 kindof_NSString_void_block = NSMutableString_void_block; 237 NSString_void_block = kindof_NSMutableString_void_block; 238 kindof_NSString_void_block = NSMutableString_void_block; 239 NSString_void_block = kindof_NSMutableString_void_block; 240 241 // "Covariant" return type via downcasting rule. 242 kindof_NSMutableString_void_block = NSString_void_block; // expected-error{{from 'NSString *(^)(void)'}} 243 NSMutableString_void_block = kindof_NSString_void_block; 244 kindof_NSMutableString_void_block = NSString_void_block; // expected-error{{from 'NSString *(^)(void)'}} 245 NSMutableString_void_block = kindof_NSString_void_block; 246 247 // Cross-casted return type. 248 __kindof NSNumber *(^kindof_NSNumber_void_block)(void); 249 NSNumber *(^NSNumber_void_block)(void); 250 kindof_NSString_void_block = NSNumber_void_block; // expected-error{{from 'NSNumber *(^)(void)'}} 251 NSString_void_block = kindof_NSNumber_void_block; // expected-error{{'__kindof NSNumber *(^)(void)'}} 252 kindof_NSString_void_block = NSNumber_void_block; // expected-error{{from 'NSNumber *(^)(void)'}} 253 NSString_void_block = kindof_NSNumber_void_block; // expected-error{{'__kindof NSNumber *(^)(void)'}} 254 255 // Adding/removing __kindof from argument type. 256 void (^void_kindof_NSString_block)(__kindof NSString *); 257 void (^void_NSString_block)(NSString *); 258 void_kindof_NSString_block = void_NSString_block; 259 void_NSString_block = void_kindof_NSString_block; 260 261 // Contravariant argument type. 262 void (^void_kindof_NSMutableString_block)(__kindof NSMutableString *); 263 void (^void_NSMutableString_block)(NSMutableString *); 264 void_kindof_NSMutableString_block = void_kindof_NSString_block; 265 void_kindof_NSMutableString_block = void_NSString_block; 266 void_NSMutableString_block = void_kindof_NSString_block; 267 void_NSMutableString_block = void_NSString_block; 268 269 // "Contravariant" argument type via downcasting rule. 270 void_kindof_NSString_block = void_kindof_NSMutableString_block; 271 void_kindof_NSString_block = void_NSMutableString_block; 272 void_NSString_block = void_kindof_NSMutableString_block; // expected-error{{from 'void (^)(__kindof NSMutableString *)'}} 273 void_NSString_block = void_NSMutableString_block; // expected-error{{from 'void (^)(NSMutableString *)'}} 274} 275 276// --------------------------------------------------------------------------- 277// Messaging __kindof types. 278// --------------------------------------------------------------------------- 279void message_kindof_object(__kindof NSString *kindof_NSString) { 280 [kindof_NSString retain]; // in superclass 281 [kindof_NSString stringByAppendingString:0]; // in class 282 [kindof_NSString appendString:0]; // in subclass 283 [kindof_NSString numberByAddingNumber: 0]; // expected-warning{{instance method '-numberByAddingNumber:' not found (return type defaults to 'id')}} 284 [kindof_NSString randomMethod]; // in protocol 285} 286 287void message_kindof_qualified_id(__kindof id <NSCopying> kindof_NSCopying) { 288 [kindof_NSCopying copy]; // in protocol 289 [kindof_NSCopying stringByAppendingString:0]; // in some class 290 [kindof_NSCopying randomMethod]; // in unrelated protocol 291} 292 293void message_kindof_qualified_class( 294 __kindof Class <NSCopying> kindof_NSCopying) { 295 [kindof_NSCopying classCopy]; // in protocol 296 [kindof_NSCopying string]; // in some class 297 [kindof_NSCopying randomClassMethod]; // in unrelated protocol 298} 299 300// Make sure we don't emit warning about multiple methods found. 301typedef int NSInteger; 302@interface Foo : NSObject 303- (NSString*)test; 304@end 305@interface Bar : NSObject 306- (NSInteger)test; 307@end 308void test(__kindof Bar *kBar) { 309 [kBar test]; 310} 311 312// Make sure we don't emit warning about no method found. 313@interface A : NSObject 314@property (readonly, getter=isActive) BOOL active; 315@end 316@interface B : NSObject 317@property (getter=isActive, readonly) BOOL active; 318@end 319void foo() { 320 __kindof B *NSApp; 321 if ([NSApp isActive]) { 322 } 323} 324 325typedef const struct CGPath *CGPathRef; 326@interface C : NSObject 327@property (copy) NSString *path; 328@end 329@interface D : NSObject 330@property CGPathRef path __attribute__((availability(macosx,unavailable))); 331@end 332// Make sure we choose "NSString *path" for [s1 path]. 333void bar(id s1, id s2) { 334 return [[s1 path] compare:[s2 path]]; 335} 336 337// --------------------------------------------------------------------------- 338// __kindof within specialized types 339// --------------------------------------------------------------------------- 340@interface NSArray<T> : NSObject 341@end 342 343void implicit_convert_array(NSArray<__kindof NSString *> *kindofStringsArray, 344 NSArray<NSString *> *stringsArray, 345 NSArray<__kindof NSMutableString *> 346 *kindofMutStringsArray, 347 NSArray<NSMutableString *> *mutStringsArray) { 348 // Adding/removing __kindof is okay. 349 kindofStringsArray = stringsArray; 350 stringsArray = kindofStringsArray; 351 352 // Other covariant and contravariant conversions still not permitted. 353 kindofStringsArray = mutStringsArray; // expected-warning{{incompatible pointer types}} 354 stringsArray = kindofMutStringsArray; // expected-warning{{incompatible pointer types}} 355 mutStringsArray = kindofStringsArray; // expected-warning{{incompatible pointer types}} 356 357 // Adding/removing nested __kindof is okay. 358 NSArray<NSArray<__kindof NSString *> *> *kindofStringsArrayArray; 359 NSArray<NSArray<NSString *> *> *stringsArrayArray; 360 kindofStringsArrayArray = stringsArrayArray; 361 stringsArrayArray = kindofStringsArrayArray; 362} 363 364// --------------------------------------------------------------------------- 365// __kindof + nullability 366// --------------------------------------------------------------------------- 367 368void testNullability() { 369 // The base type being a pointer type tickles the bug. 370 extern __kindof id <NSCopying> _Nonnull getSomeCopyable(); 371 NSString *string = getSomeCopyable(); // no-warning 372 373 void processCopyable(__typeof(getSomeCopyable()) string); 374 processCopyable(0); // expected-warning{{null passed to a callee that requires a non-null argument}} 375} 376 377// Make sure that we don't emit a warning about conflicting parameter types 378// between __kindof id and id. 379@interface A2 : NSObject 380- (void)test:(__kindof id)T; 381@end 382@implementation A2 383- (void)test:(id)T { 384} 385@end 386 387@interface NSGeneric<ObjectType> : NSObject 388- (void)test:(__kindof ObjectType)T; 389- (void)mapUsingBlock:(id (^)(__kindof ObjectType))block; 390@end 391@implementation NSGeneric 392- (void)test:(id)T { 393} 394- (void)mapUsingBlock:(id (^)(id))block { 395} 396@end 397 398// Check that clang doesn't crash when a type parameter is illegal. 399@interface Array1<T> : NSObject 400@end 401 402@interface I1 : NSObject 403@end 404 405@interface Array1<__kindof I1*>(extensions1) // expected-error{{expected type parameter name}} 406@end 407 408@interface Array2<T1, T2, T3> : NSObject 409@end 410 411@interface Array2<T, T, __kindof I1*>(extensions2) // expected-error{{expected type parameter name}} expected-error{{redeclaration of type parameter 'T'}} 412@end 413