Clang Project

clang_source_code/test/SemaObjC/parameterized_classes_subst.m
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// rdar://25060179
439@interface MyMutableDictionary<KeyType, ObjectType> : NSObject
440- (void)setObject:(ObjectType)obj forKeyedSubscript:(KeyType <NSCopying>)key; // expected-note{{passing argument to parameter 'obj' here}} \
441    // expected-note{{passing argument to parameter 'key' here}}
442@end
443
444void bar(MyMutableDictionary<NSString *, NSString *> *stringsByString,
445                             NSNumber *n1, NSNumber *n2) {
446  // We warn here when the key types do not match.
447  stringsByString[n1] = n2; // expected-warning{{incompatible pointer types sending 'NSNumber *' to parameter of type 'NSString *'}} \
448    // expected-warning{{incompatible pointer types sending 'NSNumber *' to parameter of type 'NSString<NSCopying> *'}}
449}
450
451@interface MyTest<K, V> : NSObject <NSCopying>
452- (V)test:(K)key;
453- (V)test2:(K)key; // expected-note{{previous definition is here}}
454- (void)mapUsingBlock:(id (^)(V))block;
455- (void)mapUsingBlock2:(id (^)(V))block; // expected-note{{previous definition is here}}
456@end
457
458@implementation MyTest
459- (id)test:(id)key {
460  return key;
461}
462- (int)test2:(id)key{ // expected-warning{{conflicting return type in implementation}}
463  return 0;
464}
465- (void)mapUsingBlock:(id (^)(id))block {
466}
467- (void)mapUsingBlock2:(id)block { // expected-warning{{conflicting parameter types in implementation}}
468}
469@end
470