diff options
Diffstat (limited to 'clang/test')
-rw-r--r-- | clang/test/CodeGenObjC/parameterized_classes.m | 63 | ||||
-rw-r--r-- | clang/test/PCH/objc_parameterized_classes.m | 5 | ||||
-rw-r--r-- | clang/test/SemaObjC/parameterized_classes.m | 18 | ||||
-rw-r--r-- | clang/test/SemaObjC/parameterized_classes_subst.m | 372 | ||||
-rw-r--r-- | clang/test/SemaObjCXX/Inputs/nullability-pragmas-generics-1.h | 21 | ||||
-rw-r--r-- | clang/test/SemaObjCXX/nullability-pragmas.mm | 12 |
6 files changed, 475 insertions, 16 deletions
diff --git a/clang/test/CodeGenObjC/parameterized_classes.m b/clang/test/CodeGenObjC/parameterized_classes.m new file mode 100644 index 00000000000..1d8e9a25993 --- /dev/null +++ b/clang/test/CodeGenObjC/parameterized_classes.m @@ -0,0 +1,63 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fblocks -fobjc-arc -emit-llvm -o - %s | FileCheck %s + +// Parameterized classes have no effect on code generation; this test +// mainly verifies that CodeGen doesn't assert when substituted types +// in uses of methods don't line up exactly with the parameterized +// types in the method declarations due to type erasure. "Not crash" +// is the only interesting criteria here. + +@protocol NSObject +@end + +@protocol NSCopying +@end + +__attribute__((objc_root_class)) +@interface NSObject <NSObject> +@end + +@interface NSString : NSObject <NSCopying> +@end + +@interface NSMutableArray<T> : NSObject <NSCopying> +@property (copy,nonatomic) T firstObject; +- (void)addObject:(T)object; +- (void)sortWithFunction:(int (*)(T, T))function; +- (void)getObjects:(T __strong *)objects length:(unsigned*)length; +@end + +NSString *getFirstObjectProp(NSMutableArray<NSString *> *array) { + return array.firstObject; +} + +NSString *getFirstObjectMethod(NSMutableArray<NSString *> *array) { + return [array firstObject]; +} + +void addObject(NSMutableArray<NSString *> *array, NSString *obj) { + [array addObject: obj]; +} + +int compareStrings(NSString *x, NSString *y) { return 0; } +int compareBlocks(NSString * (^x)(NSString *), + NSString * (^y)(NSString *)) { return 0; } + +void sortTest(NSMutableArray<NSString *> *array, + NSMutableArray<NSString * (^)(NSString *)> *array2) { + [array sortWithFunction: &compareStrings]; + [array2 sortWithFunction: &compareBlocks]; +} + +void getObjectsTest(NSMutableArray<NSString *> *array) { + NSString * __strong *objects; + unsigned length; + [array getObjects: objects length: &length]; +} + +void printMe(NSString *name) { } + +// CHECK-LABEL: define void @blockTest +void blockTest(NSMutableArray<void (^)(void)> *array, NSString *name) { + // CHECK: call i8* @objc_retainBlock + [array addObject: ^ { printMe(name); }]; +} diff --git a/clang/test/PCH/objc_parameterized_classes.m b/clang/test/PCH/objc_parameterized_classes.m index f4fd0926be3..616d4a2659d 100644 --- a/clang/test/PCH/objc_parameterized_classes.m +++ b/clang/test/PCH/objc_parameterized_classes.m @@ -21,6 +21,7 @@ __attribute__((objc_root_class)) typedef PC1<id, NSObject *> PC1Specialization1; +typedef PC1Specialization1 <NSObject> PC1Specialization2; #else @interface PC1<T : NSObject *, // expected-error{{type bound 'NSObject *' for type parameter 'T' conflicts with implicit bound 'id}} @@ -29,6 +30,8 @@ typedef PC1<id, NSObject *> PC1Specialization1; // expected-note@15{{type parameter 'U' declared here}} @end -typedef PC1Specialization1<id, NSObject *> PC1Specialization2; // expected-error{{type arguments cannot be applied to already-specialized class type 'PC1Specialization1' (aka 'PC1<id,NSObject *>')}} +typedef PC1Specialization1<id, NSObject *> PC1Specialization3; // expected-error{{type arguments cannot be applied to already-specialized class type 'PC1Specialization1' (aka 'PC1<id,NSObject *>')}} + +typedef PC1Specialization2<id, NSObject *> PC1Specialization4; // expected-error{{already-specialized class type 'PC1Specialization2' (aka 'PC1Specialization1<NSObject>')}} #endif diff --git a/clang/test/SemaObjC/parameterized_classes.m b/clang/test/SemaObjC/parameterized_classes.m index bf81ad9a078..9834f7cd11f 100644 --- a/clang/test/SemaObjC/parameterized_classes.m +++ b/clang/test/SemaObjC/parameterized_classes.m @@ -173,29 +173,17 @@ __attribute__((objc_root_class)) T object; } -- (U)method:(V)param; // expected-note{{passing argument to parameter 'param' here}} +- (U)method:(V)param; @end @interface PC20<T, U, V> (Cat1) -- (U)catMethod:(V)param; // expected-note{{passing argument to parameter 'param' here}} +- (U)catMethod:(V)param; @end @interface PC20<X, Y, Z>() -- (X)extMethod:(Y)param; // expected-note{{passing argument to parameter 'param' here}} +- (X)extMethod:(Y)param; @end -void test_PC20_unspecialized(PC20 *pc20) { - // FIXME: replace type parameters with underlying types? - int *ip = [pc20 method: 0]; // expected-warning{{incompatible pointer types initializing 'int *' with an expression of type 'U' (aka 'NSObject *')}} - [pc20 method: ip]; // expected-warning{{incompatible pointer types sending 'int *' to parameter of type 'V' (aka 'NSString *')}} - - ip = [pc20 catMethod: 0]; // expected-warning{{incompatible pointer types assigning to 'int *' from 'U' (aka 'NSObject *')}} - [pc20 catMethod: ip]; // expected-warning{{incompatible pointer types sending 'int *' to parameter of type 'V' (aka 'NSString *')}} - - ip = [pc20 extMethod: 0]; // expected-warning{{incompatible pointer types assigning to 'int *' from 'X' (aka 'id')}} - [pc20 extMethod: ip]; // expected-warning{{incompatible pointer types sending 'int *' to parameter of type 'Y' (aka 'NSObject *')}} -} - // -------------------------------------------------------------------------- // Parsing type arguments. // -------------------------------------------------------------------------- diff --git a/clang/test/SemaObjC/parameterized_classes_subst.m b/clang/test/SemaObjC/parameterized_classes_subst.m new file mode 100644 index 00000000000..186800cddd7 --- /dev/null +++ b/clang/test/SemaObjC/parameterized_classes_subst.m @@ -0,0 +1,372 @@ +// RUN: %clang_cc1 -fblocks -fsyntax-only -Wnullable-to-nonnull-conversion %s -verify +// +// Test the substitution of type arguments for type parameters when +// using parameterized classes in Objective-C. + +__attribute__((objc_root_class)) +@interface NSObject ++ (instancetype)alloc; +- (instancetype)init; +@end + +@protocol NSCopying +@end + +@interface NSString : NSObject <NSCopying> +@end + +@interface NSNumber : NSObject <NSCopying> +@end + +@interface NSArray<T> : NSObject <NSCopying> { +@public + T *data; // don't try this at home +} +- (T)objectAtIndexedSubscript:(int)index; ++ (NSArray<T> *)array; ++ (void)setArray:(NSArray <T> *)array; +@property (copy,nonatomic) T lastObject; +@end + +@interface NSMutableArray<T> : NSArray<T> +-(instancetype)initWithArray:(NSArray<T> *)array; // expected-note{{passing argument}} +- (void)setObject:(T)object atIndexedSubscript:(int)index; // expected-note 2{{passing argument to parameter 'object' here}} +@end + +@interface NSStringArray : NSArray<NSString *> +@end + +@interface NSSet<T> : NSObject <NSCopying> +- (T)firstObject; +@property (nonatomic, copy) NSArray<T> *allObjects; +@end + +// Parameterized inheritance (simple case) +@interface NSMutableSet<U : id<NSCopying>> : NSSet<U> +- (void)addObject:(U)object; // expected-note 7{{passing argument to parameter 'object' here}} +@end + +@interface Widget : NSObject <NSCopying> +@end + +// Non-parameterized class inheriting from a specialization of a +// parameterized class. +@interface WidgetSet : NSMutableSet<Widget *> +@end + +// Parameterized inheritance with a more interesting transformation in +// the specialization. +@interface MutableSetOfArrays<T> : NSMutableSet<NSArray<T>*> +@end + +// Inheriting from an unspecialized form of a parameterized type. +@interface UntypedMutableSet : NSMutableSet +@end + +@interface Window : NSObject +@end + +@interface NSDictionary<K, V> : NSObject <NSCopying> +- (V)objectForKeyedSubscript:(K)key; // expected-note 2{{parameter 'key'}} +@end + +@interface NSMutableDictionary<K : id<NSCopying>, V> : NSDictionary<K, V> +- (void)setObject:(V)object forKeyedSubscript:(K)key; +// expected-note@-1 {{parameter 'object' here}} +// expected-note@-2 {{parameter 'object' here}} +// expected-note@-3 {{parameter 'key' here}} +// expected-note@-4 {{parameter 'key' here}} + +@property (strong) K someRandomKey; +@end + +@interface WindowArray : NSArray<Window *> +@end + +@interface NSSet<T> (Searching) +- (T)findObject:(T)object; +@end + +@interface NSView : NSObject +@end + +@interface NSControl : NSView +- (void)toggle; +@end + +@interface NSViewController<ViewType : NSView *> : NSObject +@property (nonatomic,retain) ViewType view; +@end + +// -------------------------------------------------------------------------- +// Nullability +// -------------------------------------------------------------------------- +typedef NSControl * _Nonnull Nonnull_NSControl; + +@interface NSNullableTest<ViewType : NSView *> : NSObject +- (ViewType)view; +- (nullable ViewType)maybeView; +@end + +@interface NSNullableTest2<ViewType : NSView * _Nullable> : NSObject // expected-error{{type parameter 'ViewType' bound 'NSView * _Nullable' cannot explicitly specify nullability}} +@end + +void test_nullability(void) { + NSControl * _Nonnull nonnull_NSControl; + + // Nullability introduced by substitution. + NSNullableTest<NSControl *> *unspecifiedControl; + nonnull_NSControl = [unspecifiedControl view]; + nonnull_NSControl = [unspecifiedControl maybeView]; // expected-warning{{from nullable pointer 'NSControl * _Nullable' to non-nullable pointer type 'NSControl * _Nonnull'}} + + // Nullability overridden by substitution. + NSNullableTest<Nonnull_NSControl> *nonnullControl; + nonnull_NSControl = [nonnullControl view]; + nonnull_NSControl = [nonnullControl maybeView]; // expected-warning{{from nullable pointer 'Nonnull_NSControl _Nullable' (aka 'NSControl *') to non-nullable pointer type 'NSControl * _Nonnull'}} + + // Nullability cannot be specified directly on a type argument. + NSNullableTest<NSControl * _Nonnull> *nonnullControl2; // expected-error{{type argument 'NSControl *' cannot explicitly specify nullability}} +} + +// -------------------------------------------------------------------------- +// Message sends. +// -------------------------------------------------------------------------- +void test_message_send_result( + NSSet<NSString *> *stringSet, + NSMutableSet<NSString *> *mutStringSet, + WidgetSet *widgetSet, + UntypedMutableSet *untypedMutSet, + MutableSetOfArrays<NSString *> *mutStringArraySet, + NSSet *set, + NSMutableSet *mutSet, + MutableSetOfArrays *mutArraySet, + NSArray<NSString *> *stringArray, + void (^block)(void)) { + int *ip; + ip = [stringSet firstObject]; // expected-warning{{from 'NSString *'}} + ip = [mutStringSet firstObject]; // expected-warning{{from 'NSString *'}} + ip = [widgetSet firstObject]; // expected-warning{{from 'Widget *'}} + ip = [untypedMutSet firstObject]; // expected-warning{{from 'id'}} + ip = [mutStringArraySet firstObject]; // expected-warning{{from 'NSArray<NSString *> *'}} + ip = [set firstObject]; // expected-warning{{from 'id'}} + ip = [mutSet firstObject]; // expected-warning{{from 'id'}} + ip = [mutArraySet firstObject]; // expected-warning{{from 'id'}} + ip = [block firstObject]; // expected-warning{{from 'id'}} + + ip = [stringSet findObject:@"blah"]; // expected-warning{{from 'NSString *'}} + + // Class messages. + ip = [NSSet<NSString *> alloc]; // expected-warning{{from 'NSSet<NSString *> *'}} + ip = [NSSet alloc]; // expected-warning{{from 'NSSet *'}} + ip = [MutableSetOfArrays<NSString *> alloc]; // expected-warning{{from 'MutableSetOfArrays<NSString *> *'}} + ip = [MutableSetOfArrays alloc]; // expected-warning{{from 'MutableSetOfArrays *'}} + ip = [NSArray<NSString *> array]; // expected-warning{{from 'NSArray<NSString *> *'}} + ip = [NSArray<NSString *><NSCopying> array]; // expected-warning{{from 'NSArray<NSString *> *'}} + + ip = [[NSMutableArray<NSString *> alloc] init]; // expected-warning{{from 'NSMutableArray<NSString *> *'}} + + [[NSMutableArray alloc] initWithArray: stringArray]; // okay + [[NSMutableArray<NSString *> alloc] initWithArray: stringArray]; // okay + [[NSMutableArray<NSNumber *> alloc] initWithArray: stringArray]; // expected-warning{{sending 'NSArray<NSString *> *' to parameter of type 'NSArray<NSNumber *> *'}} +} + +void test_message_send_param( + NSMutableSet<NSString *> *mutStringSet, + WidgetSet *widgetSet, + UntypedMutableSet *untypedMutSet, + MutableSetOfArrays<NSString *> *mutStringArraySet, + NSMutableSet *mutSet, + MutableSetOfArrays *mutArraySet, + void (^block)(void)) { + Window *window; + + [mutStringSet addObject: window]; // expected-warning{{parameter of type 'NSString *'}} + [widgetSet addObject: window]; // expected-warning{{parameter of type 'Widget *'}} + [untypedMutSet addObject: window]; // expected-warning{{parameter of incompatible type 'id<NSCopying>'}} + [mutStringArraySet addObject: window]; // expected-warning{{parameter of type 'NSArray<NSString *> *'}} + [mutSet addObject: window]; // expected-warning{{parameter of incompatible type 'id<NSCopying>'}} + [mutArraySet addObject: window]; // expected-warning{{parameter of incompatible type 'id<NSCopying>'}} + [block addObject: window]; // expected-warning{{parameter of incompatible type 'id<NSCopying>'}} +} + +// -------------------------------------------------------------------------- +// Property accesses. +// -------------------------------------------------------------------------- +void test_property_read( + NSSet<NSString *> *stringSet, + NSMutableSet<NSString *> *mutStringSet, + WidgetSet *widgetSet, + UntypedMutableSet *untypedMutSet, + MutableSetOfArrays<NSString *> *mutStringArraySet, + NSSet *set, + NSMutableSet *mutSet, + MutableSetOfArrays *mutArraySet, + NSMutableDictionary *mutDict) { + int *ip; + ip = stringSet.allObjects; // expected-warning{{from 'NSArray<NSString *> *'}} + ip = mutStringSet.allObjects; // expected-warning{{from 'NSArray<NSString *> *'}} + ip = widgetSet.allObjects; // expected-warning{{from 'NSArray<Widget *> *'}} + ip = untypedMutSet.allObjects; // expected-warning{{from 'NSArray *'}} + ip = mutStringArraySet.allObjects; // expected-warning{{from 'NSArray<NSArray<NSString *> *> *'}} + ip = set.allObjects; // expected-warning{{from 'NSArray *'}} + ip = mutSet.allObjects; // expected-warning{{from 'NSArray *'}} + ip = mutArraySet.allObjects; // expected-warning{{from 'NSArray *'}} + + ip = mutDict.someRandomKey; // expected-warning{{from 'id'}} +} + +void test_property_write( + NSMutableSet<NSString *> *mutStringSet, + WidgetSet *widgetSet, + UntypedMutableSet *untypedMutSet, + MutableSetOfArrays<NSString *> *mutStringArraySet, + NSMutableSet *mutSet, + MutableSetOfArrays *mutArraySet, + NSMutableDictionary *mutDict) { + int *ip; + + mutStringSet.allObjects = ip; // expected-warning{{to 'NSArray<NSString *> *'}} + widgetSet.allObjects = ip; // expected-warning{{to 'NSArray<Widget *> *'}} + untypedMutSet.allObjects = ip; // expected-warning{{to 'NSArray *'}} + mutStringArraySet.allObjects = ip; // expected-warning{{to 'NSArray<NSArray<NSString *> *> *'}} + mutSet.allObjects = ip; // expected-warning{{to 'NSArray *'}} + mutArraySet.allObjects = ip; // expected-warning{{to 'NSArray *'}} + + mutDict.someRandomKey = ip; // expected-warning{{to 'id<NSCopying>'}} +} + +// -------------------------------------------------------------------------- +// Subscripting +// -------------------------------------------------------------------------- +void test_subscripting( + NSArray<NSString *> *stringArray, + NSMutableArray<NSString *> *mutStringArray, + NSArray *array, + NSMutableArray *mutArray, + NSDictionary<NSString *, Widget *> *stringWidgetDict, + NSMutableDictionary<NSString *, Widget *> *mutStringWidgetDict, + NSDictionary *dict, + NSMutableDictionary *mutDict) { + int *ip; + NSString *string; + Widget *widget; + Window *window; + + ip = stringArray[0]; // expected-warning{{from 'NSString *'}} + + ip = mutStringArray[0]; // expected-warning{{from 'NSString *'}} + mutStringArray[0] = ip; // expected-warning{{parameter of type 'NSString *'}} + + ip = array[0]; // expected-warning{{from 'id'}} + + ip = mutArray[0]; // expected-warning{{from 'id'}} + mutArray[0] = ip; // expected-warning{{parameter of type 'id'}} + + ip = stringWidgetDict[string]; // expected-warning{{from 'Widget *'}} + widget = stringWidgetDict[widget]; // expected-warning{{to parameter of type 'NSString *'}} + + ip = mutStringWidgetDict[string]; // expected-warning{{from 'Widget *'}} + widget = mutStringWidgetDict[widget]; // expected-warning{{to parameter of type 'NSString *'}} + mutStringWidgetDict[string] = ip; // expected-warning{{to parameter of type 'Widget *'}} + mutStringWidgetDict[widget] = widget; // expected-warning{{to parameter of type 'NSString *'}} + + ip = dict[string]; // expected-warning{{from 'id'}} + + ip = mutDict[string]; // expected-warning{{from 'id'}} + mutDict[string] = ip; // expected-warning{{to parameter of type 'id'}} + + widget = mutDict[window]; + mutDict[window] = widget; // expected-warning{{parameter of incompatible type 'id<NSCopying>'}} +} + +// -------------------------------------------------------------------------- +// Instance variable access. +// -------------------------------------------------------------------------- +void test_instance_variable(NSArray<NSString *> *stringArray, + NSArray *array) { + int *ip; + + ip = stringArray->data; // expected-warning{{from 'NSString **'}} + ip = array->data; // expected-warning{{from 'id *'}} +} + +@implementation WindowArray +- (void)testInstanceVariable { + int *ip; + + ip = data; // expected-warning{{from 'Window **'}} +} +@end + +// -------------------------------------------------------------------------- +// Implicit conversions. +// -------------------------------------------------------------------------- +void test_implicit_conversions(NSArray<NSString *> *stringArray, + NSArray<NSNumber *> *numberArray, + NSMutableArray<NSString *> *mutStringArray, + NSArray *array, + NSMutableArray *mutArray) { + // Specialized -> unspecialized (same level) + array = stringArray; + + // Unspecialized -> specialized (same level) + stringArray = array; + + // Specialized -> specialized failure (same level). + stringArray = numberArray; // expected-warning{{incompatible pointer types assigning to 'NSArray<NSString *> *' from 'NSArray<NSNumber *> *'}} + + // Specialized -> specialized (different levels). + stringArray = mutStringArray; + + // Specialized -> specialized failure (different levels). + numberArray = mutStringArray; // expected-warning{{incompatible pointer types assigning to 'NSArray<NSNumber *> *' from 'NSMutableArray<NSString *> *'}} + + // Unspecialized -> specialized (different levels). + stringArray = mutArray; + + // Specialized -> unspecialized (different levels). + array = mutStringArray; +} + +// -------------------------------------------------------------------------- +// Ternary operator +// -------------------------------------------------------------------------- +void test_ternary_operator(NSArray<NSString *> *stringArray, + NSArray<NSNumber *> *numberArray, + NSMutableArray<NSString *> *mutStringArray, + NSStringArray *stringArray2, + NSArray *array, + NSMutableArray *mutArray, + int cond) { + int *ip; + id object; + + ip = cond ? stringArray : mutStringArray; // expected-warning{{from 'NSArray<NSString *> *'}} + ip = cond ? mutStringArray : stringArray; // expected-warning{{from 'NSArray<NSString *> *'}} + + ip = cond ? stringArray2 : mutStringArray; // expected-warning{{from 'NSArray<NSString *><NSCopying> *'}} + ip = cond ? mutStringArray : stringArray2; // expected-warning{{from 'NSArray<NSString *><NSCopying> *'}} + + ip = cond ? stringArray : mutArray; // FIXME: expected-warning{{from 'NSArray<NSString *> *'}} + + object = cond ? stringArray : numberArray; // expected-warning{{incompatible operand types ('NSArray<NSString *> *' and 'NSArray<NSNumber *> *')}} +} + +// -------------------------------------------------------------------------- +// super +// -------------------------------------------------------------------------- +@implementation NSStringArray +- (void)useSuperMethod { + int *ip; + ip = super.lastObject; // expected-warning{{from 'NSString *'}} + super.lastObject = ip; // expected-warning{{to 'NSString *'}} + ip = [super objectAtIndexedSubscript:0]; // expected-warning{{from 'NSString *'}} +} + ++ (void)useSuperMethod { + int *ip; + ip = super.array; // expected-warning{{from 'NSArray<NSString *> *'}} + super.array = ip; // expected-warning{{to 'NSArray<NSString *> *'}} + ip = [super array]; // expected-warning{{from 'NSArray<NSString *> *'}} +} +@end diff --git a/clang/test/SemaObjCXX/Inputs/nullability-pragmas-generics-1.h b/clang/test/SemaObjCXX/Inputs/nullability-pragmas-generics-1.h new file mode 100644 index 00000000000..9a51fa1e990 --- /dev/null +++ b/clang/test/SemaObjCXX/Inputs/nullability-pragmas-generics-1.h @@ -0,0 +1,21 @@ +#pragma clang assume_nonnull begin + +__attribute__((objc_root_class)) +@interface B +@end + +@interface C : B +@end + +__attribute__((objc_root_class)) +@interface NSGeneric<T : B *> // expected-note{{type parameter 'T' declared here}} +- (T)tee; +- (nullable T)maybeTee; +@end + +typedef NSGeneric<C *> *Generic_with_C; + +#pragma clang assume_nonnull end + +@interface NSGeneric<T : C *>(Blah) // expected-error{{type bound 'C *' for type parameter 'T' conflicts with previous bound 'B *'}} +@end diff --git a/clang/test/SemaObjCXX/nullability-pragmas.mm b/clang/test/SemaObjCXX/nullability-pragmas.mm index dbf4f37f401..817d056a14a 100644 --- a/clang/test/SemaObjCXX/nullability-pragmas.mm +++ b/clang/test/SemaObjCXX/nullability-pragmas.mm @@ -2,6 +2,7 @@ #include "nullability-pragmas-1.h" #include "nullability-pragmas-2.h" +#include "nullability-pragmas-generics-1.h" #if !__has_feature(assume_nonnull) # error assume_nonnull feature is not set @@ -43,3 +44,14 @@ void test_pragmas_1(A * _Nonnull a, AA * _Nonnull aa) { ptr = aa->ivar1; // expected-error{{from incompatible type 'id'}} ptr = aa->ivar2; // expected-error{{from incompatible type 'id _Nonnull'}} } + +void test_pragmas_generics(void) { + float *fp; + + NSGeneric<C *> *genC; + fp = [genC tee]; // expected-error{{from incompatible type 'C *'}} + fp = [genC maybeTee]; // expected-error{{from incompatible type 'C * _Nullable'}} + + Generic_with_C genC2; + fp = genC2; // expected-error{{from incompatible type 'Generic_with_C' (aka 'NSGeneric<C *> *')}} +} |