[clang-cl] Ignore /Wv and /Wv:17 flags
[llvm-project.git] / clang / test / Analysis / generics.m
blob21fa29d6ece21b6d5da06e8e7b8e97d2e57d20a7
1 // RUN: %clang_analyze_cc1 -analyzer-checker=core,osx.cocoa.ObjCGenerics,alpha.core.DynamicTypeChecker -verify -Wno-objc-method-access %s
2 // RUN: %clang_analyze_cc1 -analyzer-checker=core,osx.cocoa.ObjCGenerics,alpha.core.DynamicTypeChecker -verify -Wno-objc-method-access %s -analyzer-output=plist -o %t.plist
3 // RUN: %normalize_plist <%t.plist | diff -ub %S/Inputs/expected-plists/generics.m.plist -
5 #if !__has_feature(objc_generics)
6 #  error Compiler does not support Objective-C generics?
7 #endif
9 #if !__has_feature(objc_generics_variance)
10 #  error Compiler does not support co- and contr-variance?
11 #endif
13 #define nil 0
14 typedef unsigned long NSUInteger;
15 typedef int BOOL;
17 @protocol NSObject
18 + (id)alloc;
19 - (id)init;
20 @end
22 @protocol NSCopying
23 @end
25 __attribute__((objc_root_class))
26 @interface NSObject <NSObject>
27 @end
29 @interface NSString : NSObject <NSCopying>
30 @end
32 @interface NSMutableString : NSString
33 @end
35 @interface NSNumber : NSObject <NSCopying>
36 @end
38 @interface NSSet : NSObject <NSCopying>
39 @end
41 @interface NSArray<__covariant ObjectType> : NSObject
42 + (instancetype)arrayWithObjects:(const ObjectType [])objects count:(NSUInteger)count;
43 + (instancetype)getEmpty;
44 + (NSArray<ObjectType> *)getEmpty2;
45 - (BOOL)contains:(ObjectType)obj;
46 - (BOOL)containsObject:(ObjectType)anObject;
47 - (ObjectType)getObjAtIndex:(NSUInteger)idx;
48 - (ObjectType)objectAtIndexedSubscript:(NSUInteger)idx;
49 - (NSArray<ObjectType> *)arrayByAddingObject:(ObjectType)anObject;
50 @property(readonly) ObjectType firstObject;
51 @end
53 @interface NSMutableArray<ObjectType> : NSArray<ObjectType>
54 - (void)addObject:(ObjectType)anObject;
55 - (instancetype)init;
56 @end
58 @interface MutableArray<ObjectType> : NSArray<ObjectType>
59 - (void)addObject:(ObjectType)anObject;
60 @end
62 @interface LegacyMutableArray : MutableArray
63 @end
65 @interface LegacySpecialMutableArray : LegacyMutableArray
66 @end
68 @interface BuggyMutableArray<T> : MutableArray
69 @end
71 @interface BuggySpecialMutableArray<T> : BuggyMutableArray<T>
72 @end
74 @interface MyMutableStringArray : MutableArray<NSString *>
75 @end
77 @interface ExceptionalArray<ExceptionType> : MutableArray<NSString *>
78 - (ExceptionType) getException;
79 @end
81 @interface UnrelatedType : NSObject<NSCopying>
82 @end
84 int getUnknown(void);
85 NSArray *getStuff(void);
86 NSArray *getTypedStuff(void) {
87   NSArray<NSNumber *> *c = getStuff();
88   return c;
91 void doStuff(NSArray<NSNumber *> *);
92 void withArrString(NSArray<NSString *> *);
93 void withArrMutableString(NSArray<NSMutableString *> *);
94 void withMutArrString(MutableArray<NSString *> *);
95 void withMutArrMutableString(MutableArray<NSMutableString *> *);
97 void incompatibleTypesErased(NSArray *a, NSMutableArray<NSString *> *b,
98                              NSArray<NSNumber *> *c,
99                              NSMutableArray *d) {
100   a = b;
101   c = a; // expected-warning  {{Conversion from value of type 'NSMutableArray<NSString *> *' to incompatible type 'NSArray<NSNumber *> *'}}
102   [a contains: [[NSNumber alloc] init]];
103   [a contains: [[NSString alloc] init]];
104   doStuff(a); // expected-warning {{Conversion}}
106   d = b;
107   [d addObject: [[NSNumber alloc] init]]; // expected-warning {{Conversion from value of type 'NSNumber *' to incompatible type 'NSString *'}}
110 void crossProceduralErasedTypes(void) {
111   NSArray<NSString *> *a = getTypedStuff(); // expected-warning {{Conversion}}
114 void incompatibleTypesErasedReverseConversion(NSMutableArray *a,
115                                               NSMutableArray<NSString *> *b) {
116   b = a;
117   [a contains: [[NSNumber alloc] init]];
118   [a contains: [[NSString alloc] init]];
119   doStuff(a); // expected-warning {{Conversion}}
121   [a addObject: [[NSNumber alloc] init]]; // expected-warning {{Conversion from value of type 'NSNumber *' to incompatible type 'NSString *'}}
124 void idErasedIncompatibleTypesReverseConversion(id a, NSMutableArray<NSString *> *b) {
125   b = a;
126   [a contains: [[NSNumber alloc] init]];
127   [a contains: [[NSString alloc] init]];
128   doStuff(a); // expected-warning {{Conversion}}
130   [a addObject:[[NSNumber alloc] init]]; // expected-warning {{Conversion from value of type 'NSNumber *' to incompatible type 'NSString *'}}
133 void idErasedIncompatibleTypes(id a, NSMutableArray<NSString *> *b,
134                                NSArray<NSNumber *> *c) {
135   a = b;
136   c = a; // expected-warning {{Conversion}}
137   [a contains: [[NSNumber alloc] init]];
138   [a contains: [[NSString alloc] init]];
139   doStuff(a); // expected-warning {{Conversion}}
141   [a addObject:[[NSNumber alloc] init]]; // expected-warning {{Conversion from value of type 'NSNumber *' to incompatible type 'NSString *'}}
144 void pathSensitiveInference(MutableArray *m, MutableArray<NSString *> *a,
145                             MutableArray<NSMutableString *> *b) {
146   if (getUnknown() == 5) {
147     m = a;  
148     [m contains: [[NSString alloc] init]];
149   } else {
150     m = b;
151     [m contains: [[NSMutableString alloc] init]];
152   }
153   [m addObject: [[NSString alloc] init]]; // expected-warning {{Conversion}}
154   [m addObject: [[NSMutableString alloc] init]];
157 void verifyAPIusage(id a, MutableArray<NSString *> *b) {
158   b = a;
159   doStuff(a); // expected-warning {{Conversion}}
162 void dontInferFromExplicitCastsOnUnspecialized(MutableArray *a,
163                         MutableArray<NSMutableString *> *b) {
164   b = (MutableArray<NSMutableString *> *)a;
165   [a addObject: [[NSString alloc] init]]; // no-warning
168 void dontWarnOnExplicitCastsAfterInference(MutableArray *a) {
169   withMutArrString(a);
170   withMutArrMutableString((MutableArray<NSMutableString *> *)a); // no-warning
173 void dontDiagnoseOnExplicitCrossCasts(MutableArray<NSSet *> *a,
174                         MutableArray<NSMutableString *> *b) {
175   // Treat an explicit cast to a specialized type as an indication that
176   // Objective-C's type system is not expressive enough to represent a
177   // the invariant the programmer wanted. After an explicit cast, do not
178   // warn about potential generics shenanigans.
179   b = (MutableArray<NSMutableString *> *)a; // no-warning
180   [a addObject: [[NSSet alloc] init]]; // no-warning
181   [b addObject: [[NSMutableString alloc] init]]; //no-warning
184 void subtypeOfGeneric(id d, MyMutableStringArray *a,
185                        MutableArray<NSString *> *b,
186                        MutableArray<NSNumber *> *c) {
187   d = a;
188   b = d;
189   c = d; // expected-warning {{Conversion}}
192 void genericSubtypeOfGeneric(id d, ExceptionalArray<NSString *> *a,
193                              MutableArray<NSString *> *b,
194                              MutableArray<NSNumber *> *c) {
195   d = a;
196   [d contains: [[NSString alloc] init]];
197   [d contains: [[NSNumber alloc] init]];
198   b = d;
199   c = d; // expected-warning {{Conversion}}
201   [d addObject: [[NSNumber alloc] init]]; // expected-warning {{Conversion from value of type 'NSNumber *' to incompatible type 'NSString *'}}
204 void genericSubtypeOfGenericReverse(id d, ExceptionalArray<NSString *> *a,
205                                     MutableArray<NSString *> *b,
206                                     MutableArray<NSNumber *> *c) {
207   a = d;
208   [d contains: [[NSString alloc] init]];
209   [d contains: [[NSNumber alloc] init]];
210   b = d;
211   c = d; // expected-warning {{Conversion}}
213  [d addObject: [[NSNumber alloc] init]]; // expected-warning {{Conversion from value of type 'NSNumber *' to incompatible type 'NSString *'}}
216 void inferenceFromAPI(id a) {
217   // Here the type parameter is invariant. There should be a warning every time
218   // when the type parameter changes during the conversions.
219   withMutArrString(a);
220   withMutArrMutableString(a); // expected-warning {{Conversion}}
223 void inferenceFromAPI2(id a) {
224   withMutArrMutableString(a);
225   withMutArrString(a); // expected-warning {{Conversion}}
228 void inferenceFromAPIWithLegacyTypes(LegacyMutableArray *a) {
229   withMutArrMutableString(a);
230   withMutArrString(a); // expected-warning {{Conversion}}
233 void inferenceFromAPIWithLegacyTypes2(LegacySpecialMutableArray *a) {
234   withMutArrString(a);
235   withMutArrMutableString(a); // expected-warning {{Conversion}}
238 void inferenceFromAPIWithLegacyTypes3(__kindof NSArray<NSString *> *a) {
239   LegacyMutableArray *b = a;
240   withMutArrString(b);
241   withMutArrMutableString(b); // expected-warning {{Conversion}}
244 void inferenceFromAPIWithBuggyTypes(BuggyMutableArray<NSMutableString *> *a) {
245   withMutArrString(a);
246   withMutArrMutableString(a); // expected-warning {{Conversion}}
249 void InferenceFromAPIWithBuggyTypes2(BuggySpecialMutableArray<NSMutableString *> *a) {
250   withMutArrMutableString(a);
251   withMutArrString(a); // expected-warning {{Conversion}}
254 void InferenceFromAPIWithBuggyTypes3(MutableArray<NSMutableString *> *a) {
255   id b = a;
256   withMutArrMutableString((BuggyMutableArray<NSMutableString *> *)b);
257   withMutArrString(b); // expected-warning {{Conversion}}
260 void InferenceFromAPIWithBuggyTypes4(__kindof NSArray<NSString *> *a) {
261   BuggyMutableArray<NSMutableString *> *b = a;
262   withMutArrString(b);
263   withMutArrMutableString(b); // expected-warning {{Conversion}}
266 NSArray<NSString *> *getStrings(void);
267 void enforceDynamicRulesInsteadOfStatic(NSArray<NSNumber *> *a) {
268   NSArray *b = a;
269   // Valid uses of NSArray of NSNumbers.
270   b = getStrings();
271   // Valid uses of NSArray of NSStrings.
274 void workWithProperties(NSArray<NSNumber *> *a) {
275   NSArray *b = a;
276   NSString *str = [b getObjAtIndex: 0]; // expected-warning {{Object has a dynamic type 'NSNumber *' which is incompatible with static type 'NSString *'}}
277   NSNumber *num = [b getObjAtIndex: 0];
278   str = [b firstObject]; // expected-warning {{Object has a dynamic type 'NSNumber *' which is incompatible with static type 'NSString *'}}
279   num = [b firstObject];
280   str = b.firstObject; // expected-warning {{Object has a dynamic type 'NSNumber *' which is incompatible with static type 'NSString *'}}
281   num = b.firstObject;
282   str = b[0]; // expected-warning {{Object has a dynamic type 'NSNumber *' which is incompatible with static type 'NSString *'}}
283   num = b[0];
286 void findMethodDeclInTrackedType(id m, NSArray<NSMutableString *> *a,
287                                  MutableArray<NSMutableString *> *b) {
288   a = b;
289   if (getUnknown() == 5) {
290     m = a;  
291     [m addObject: [[NSString alloc] init]]; // expected-warning {{Conversion}}
292   } else {
293     m = b;
294     [m addObject: [[NSMutableString alloc] init]];
295   }
298 void findMethodDeclInTrackedType2(__kindof NSArray<NSString *> *a,
299                                   MutableArray<NSMutableString *> *b) {
300   a = b;
301   if (getUnknown() == 5) {
302     [a addObject: [[NSString alloc] init]]; // expected-warning {{Conversion}}
303   } else {
304     [a addObject: [[NSMutableString alloc] init]];
305   }
308 void testUnannotatedLiterals(void) {
309   // ObjCArrayLiterals are not specialized in the AST. 
310   NSArray *arr = @[@"A", @"B"];
311   [arr contains: [[NSNumber alloc] init]];
314 void testAnnotatedLiterals(void) {
315   NSArray<NSString *> *arr = @[@"A", @"B"];
316   NSArray *arr2 = arr;
317   [arr2 contains: [[NSNumber alloc] init]];
320 void nonExistentMethodDoesNotCrash(id a, MutableArray<NSMutableString *> *b) {
321   a = b;
322   [a nonExistentMethod];
325 void trackedClassVariables(void) {
326   Class c = [NSArray<NSString *> class];
327   NSArray<NSNumber *> *a = [c getEmpty]; // expected-warning {{Conversion}}
328   a = [c getEmpty2]; // expected-warning {{Conversion}}
331 void nestedCollections(NSArray<NSArray<NSNumber *> *> *mat, NSArray<NSString *> *row) {
332   id temp = row;
333   [mat contains: temp]; // expected-warning {{Conversion}}
336 void testMistmatchedTypeCast(MutableArray<NSMutableString *> *a) {
337   MutableArray *b = (MutableArray<NSNumber *> *)a;
338   [b addObject: [[NSNumber alloc] init]];
339   id c = (UnrelatedType *)a;
340   [c addObject: [[NSNumber alloc] init]];
341   [c addObject: [[NSString alloc] init]];
344 void returnCollectionToIdVariable(NSArray<NSArray<NSString *> *> *arr) {
345   NSArray *erased = arr;
346   id a = [erased firstObject];
347   NSArray<NSNumber *> *res = a; // expected-warning {{Conversion}}
350 void eraseSpecialization(NSArray<NSArray<NSString *> *> *arr) {
351   NSArray *erased = arr;
352   NSArray* a = [erased firstObject];
353   NSArray<NSNumber *> *res = a; // expected-warning {{Conversion}}
356 void returnToUnrelatedType(NSArray<NSArray<NSString *> *> *arr) {
357   NSArray *erased = arr;
358   NSSet* a = [erased firstObject]; // expected-warning {{Object has a dynamic type 'NSArray<NSString *> *' which is incompatible with static type 'NSSet *'}}
359   (void)a;
362 void returnToIdVariable(NSArray<NSString *> *arr) {
363   NSArray *erased = arr;
364   id a = [erased firstObject];
365   NSNumber *res = a; // expected-warning {{Object has a dynamic type 'NSString *' which is incompatible with static type 'NSNumber *'}}
368 @interface UnrelatedTypeGeneric<T> : NSObject<NSCopying>
369 - (void)takesType:(T)v;
370 @end
372 void testGetMostInformativeDerivedForId(NSArray<NSString *> *a,
373                                   UnrelatedTypeGeneric<NSString *> *b) {
374   id idB = b;
375   a = idB; // expected-warning {{Conversion from value of type 'UnrelatedTypeGeneric<NSString *> *' to incompatible type 'NSArray<NSString *> *'}}
377   // rdar://problem/26086914 crash here caused by symbolic type being unrelated
378   // to compile-time source type of cast.
379   id x = a; // Compile-time type is NSArray<>, Symbolic type is UnrelatedTypeGeneric<>.
380   [x takesType:[[NSNumber alloc] init]]; // expected-warning {{Conversion from value of type 'NSNumber *' to incompatible type 'NSString *'}}
383 void testArgumentAfterUpcastToRootWithCovariantTypeParameter(NSArray<NSString *> *allStrings, NSNumber *number) {
384   NSArray<NSObject *> *allObjects = allStrings; // no-warning
385   NSArray<NSObject *> *moreObjects = [allObjects arrayByAddingObject:number]; // no-warning
388 void testArgumentAfterUpcastWithCovariantTypeParameter(NSArray<NSMutableString *> *allMutableStrings, NSNumber *number) {
389   NSArray<NSString *> *allStrings = allMutableStrings; // no-warning
390   id numberAsId = number;
391   NSArray<NSString *> *moreStrings = [allStrings arrayByAddingObject:numberAsId]; // Sema: expected-warning {{Object has a dynamic type 'NSNumber *' which is incompatible with static type 'NSString *'}}
394 void testArgumentAfterCastToUnspecializedWithCovariantTypeParameter(NSArray<NSMutableString *> *allMutableStrings, NSNumber *number) {
395   NSArray *allStrings = allMutableStrings; // no-warning
396   id numberAsId = number;
398   NSArray *moreStringsUnspecialized = [allStrings arrayByAddingObject:numberAsId]; // no-warning
400   // Ideally the analyzer would warn here.
401   NSArray<NSString *> *moreStringsSpecialized = [allStrings arrayByAddingObject:numberAsId];
404 void testCallToMethodWithCovariantParameterOnInstanceOfSubclassWithInvariantParameter(NSMutableArray<NSMutableString *> *mutableArrayOfMutableStrings, NSString *someString) {
405   NSArray<NSString *> *arrayOfStrings = mutableArrayOfMutableStrings;
406   [arrayOfStrings containsObject:someString]; // no-warning