Home | History | Annotate | Download | only in SemaObjC
      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.
     46 typedef __kindof NSObject *typedef1;
     47 typedef NSObject __kindof *typedef2;
     48 typedef __kindof NSObject<NSCopying> typedef3;
     49 typedef NSObject<NSCopying> __kindof *typedef4;
     50 typedef __kindof id<NSCopying> typedef5;
     51 typedef __kindof Class<NSCopying> typedef6;
     52 
     53 // Test redundancy of __kindof.
     54 typedef __kindof id __kindof redundant_typedef1;
     55 typedef __kindof NSObject __kindof *redundant_typedef2;
     56 
     57 // Test application of __kindof to typedefs.
     58 typedef NSObject *NSObject_ptr_typedef;
     59 typedef NSObject NSObject_typedef;
     60 typedef __kindof NSObject_ptr_typedef typedef_typedef1;
     61 typedef __kindof NSObject_typedef typedef_typedef2;
     62 
     63 // Test application of __kindof to non-object types.
     64 typedef __kindof int nonobject_typedef1; // expected-error{{'__kindof' specifier cannot be applied to non-object type 'int'}}
     65 typedef NSObject **NSObject_ptr_ptr;
     66 typedef __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.
     69 typedef NSObject * __kindof bad_specifier_location1; // expected-error{{'__kindof' type specifier must precede the declarator}}
     70 typedef 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 // ---------------------------------------------------------------------------
     76 void 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 // ---------------------------------------------------------------------------
     93 void 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 
    108 void 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 
    130 void 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 // ---------------------------------------------------------------------------
    156 void 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 
    181 void 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 
    199 typedef signed char BOOL;
    200 void 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 // ---------------------------------------------------------------------------
    226 void 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 // ---------------------------------------------------------------------------
    279 void 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 
    287 void 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 
    293 void 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.
    301 typedef int NSInteger;
    302 @interface Foo : NSObject
    303 - (NSString*)test;
    304 @end
    305 @interface Bar : NSObject
    306 - (NSInteger)test;
    307 @end
    308 void 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
    319 void foo() {
    320   __kindof B *NSApp;
    321   if ([NSApp isActive]) {
    322   }
    323 }
    324 
    325 typedef 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].
    333 void 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 
    343 void 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 
    368 void 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