blob: f90ee9093592ca84fa918a4897f7c95304b299e9 [file] [log] [blame]
Douglas Gregore83b9562015-07-07 03:57:53 +00001// 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
Douglas Gregor10dc9d82015-07-07 03:58:28 +00006@protocol NSObject
7@end
8
Douglas Gregore83b9562015-07-07 03:57:53 +00009__attribute__((objc_root_class))
Douglas Gregor10dc9d82015-07-07 03:58:28 +000010@interface NSObject <NSObject>
Douglas Gregore83b9562015-07-07 03:57:53 +000011+ (instancetype)alloc;
12- (instancetype)init;
13@end
14
15@protocol NSCopying
16@end
17
18@interface NSString : NSObject <NSCopying>
19@end
20
Douglas Gregorab209d82015-07-07 03:58:42 +000021@interface NSMutableString : NSString
22@end
23
Douglas Gregore83b9562015-07-07 03:57:53 +000024@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,
Douglas Gregorab209d82015-07-07 03:58:42 +0000150 NSArray<__kindof NSString *> *kindofStringArray,
Douglas Gregore83b9562015-07-07 03:57:53 +0000151 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 *> *'}}
Douglas Gregorab209d82015-07-07 03:58:42 +0000178
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 *'}}
Douglas Gregore83b9562015-07-07 03:57:53 +0000184}
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
Douglas Gregorab209d82015-07-07 03:58:42 +0000228 ip = mutDict.someRandomKey; // expected-warning{{from '__kindof id<NSCopying>'}}
229
230 ip = [[NSViewController alloc] init].view; // expected-warning{{from '__kindof NSView *'}}
Douglas Gregore83b9562015-07-07 03:57:53 +0000231}
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
Douglas Gregor1ac1b632015-07-07 03:58:54 +0000346@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
Douglas Gregore83b9562015-07-07 03:57:53 +0000376// --------------------------------------------------------------------------
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
Douglas Gregorc5e07f52015-07-07 03:58:01 +0000392 ip = cond ? stringArray2 : mutStringArray; // expected-warning{{from 'NSArray<NSString *> *'}}
393 ip = cond ? mutStringArray : stringArray2; // expected-warning{{from 'NSArray<NSString *> *'}}
Douglas Gregore83b9562015-07-07 03:57:53 +0000394
Douglas Gregorc5e07f52015-07-07 03:58:01 +0000395 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 *'}}
Douglas Gregore83b9562015-07-07 03:57:53 +0000402
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
Douglas Gregor10dc9d82015-07-07 03:58:28 +0000424
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 '*'?}}