Home | History | Annotate | Download | only in SemaObjC
      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