diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2015-08-07 23:02:44 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2015-08-07 23:02:44 +0000 |
commit | 51ece4aae5857052d224ce52277924c74685714e (patch) | |
tree | ca13cf9e2e8c2499f61f1246e455efd2804abd36 /test/SemaObjC | |
parent | c192b3dcffd5e672a2b2e1730e2440febb4fb192 (diff) |
Notes
Diffstat (limited to 'test/SemaObjC')
-rw-r--r-- | test/SemaObjC/block-type-safety.m | 8 | ||||
-rw-r--r-- | test/SemaObjC/conditional-expr-8.m | 33 | ||||
-rw-r--r-- | test/SemaObjC/conditional-expr.m | 11 | ||||
-rw-r--r-- | test/SemaObjC/interface-1.m | 2 | ||||
-rw-r--r-- | test/SemaObjC/kindof.m | 304 | ||||
-rw-r--r-- | test/SemaObjC/objc2-merge-gc-attribue-decl.m | 16 | ||||
-rw-r--r-- | test/SemaObjC/parameterized_classes.m | 357 | ||||
-rw-r--r-- | test/SemaObjC/parameterized_classes_collection_literal.m | 52 | ||||
-rw-r--r-- | test/SemaObjC/parameterized_classes_subst.m | 428 | ||||
-rw-r--r-- | test/SemaObjC/protocol-archane.m | 4 | ||||
-rw-r--r-- | test/SemaObjC/protocol-warn.m | 2 |
11 files changed, 1206 insertions, 11 deletions
diff --git a/test/SemaObjC/block-type-safety.m b/test/SemaObjC/block-type-safety.m index b2c4398dc3c51..96c781b6a561c 100644 --- a/test/SemaObjC/block-type-safety.m +++ b/test/SemaObjC/block-type-safety.m @@ -198,3 +198,11 @@ void Test3() { NSObject<NSObject, P1, NSCopying> *NSO5 = aBlock; // expected-error {{initializing 'NSObject<NSObject,P1,NSCopying> *' with an expression of incompatible type 'void (^)()'}} NSObject<NSCopying> *NSO6 = aBlock; // Ok } + +// rdar://problem/19420731 +typedef NSObject<P1> NSObject_P1; +typedef NSObject_P1<P2> NSObject_P1_P2; + +void Test4(void (^handler)(NSObject_P1_P2 *p)) { + Test4(^(NSObject<P2> *p) { }); +} diff --git a/test/SemaObjC/conditional-expr-8.m b/test/SemaObjC/conditional-expr-8.m index beddd205a9071..35f4e75314bd1 100644 --- a/test/SemaObjC/conditional-expr-8.m +++ b/test/SemaObjC/conditional-expr-8.m @@ -1,7 +1,7 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s // expected-no-diagnostics -// rdar://9296866 +// rdar://9296866 @interface NSResponder @end @@ -24,3 +24,34 @@ } @end +// rdar://problem/19572837 +@protocol NSObject +@end + +__attribute__((objc_root_class)) +@interface NSObject <NSObject> +@end + +@protocol Goable <NSObject> +- (void)go; +@end + +@protocol Drivable <Goable> +- (void)drive; +@end + +@interface Car : NSObject +- (NSObject <Goable> *)bestGoable:(NSObject <Goable> *)drivable; +@end + +@interface Car(Category) <Drivable> +@end + +@interface Truck : Car +@end + +@implementation Truck +- (NSObject <Goable> *)bestGoable:(NSObject <Goable> *)drivable value:(int)value{ + return value > 0 ? self : drivable; +} +@end diff --git a/test/SemaObjC/conditional-expr.m b/test/SemaObjC/conditional-expr.m index 71e108cce673b..71bdb1b2d341b 100644 --- a/test/SemaObjC/conditional-expr.m +++ b/test/SemaObjC/conditional-expr.m @@ -51,6 +51,10 @@ @end @protocol P2 @end +@protocol P3 <P1> +@end +@protocol P4 <P1> +@end @interface A <P0> @end @@ -64,6 +68,9 @@ @interface D @end +@interface E : A +@end + void f0(id<P0> x) { x.intProp = 1; } @@ -118,3 +125,7 @@ void f11(int a, id<P0> x, id<P1> y) { void f12(int a, A<P0> *x, A<P1> *y) { A<P1>* l0 = (a ? x : y ); // expected-warning {{incompatible pointer types initializing 'A<P1> *' with an expression of type 'A<P0> *'}} } + +void f13(int a, B<P3, P0> *x, E<P0, P4> *y) { + int *ip = a ? x : y; // expected-warning{{expression of type 'A<P1> *'}} +} diff --git a/test/SemaObjC/interface-1.m b/test/SemaObjC/interface-1.m index 79fbad8ba4bfb..0e47fa08bd77a 100644 --- a/test/SemaObjC/interface-1.m +++ b/test/SemaObjC/interface-1.m @@ -3,7 +3,7 @@ @interface NSWhatever : NSObject // expected-error {{cannot find interface declaration for 'NSObject'}} -<NSCopying> // expected-error {{cannot find protocol declaration for 'NSCopying'}} +<NSCopying> // expected-error {{no type or protocol named 'NSCopying'}} @end diff --git a/test/SemaObjC/kindof.m b/test/SemaObjC/kindof.m new file mode 100644 index 0000000000000..b19e423720788 --- /dev/null +++ b/test/SemaObjC/kindof.m @@ -0,0 +1,304 @@ +// RUN: %clang_cc1 -fblocks -fsyntax-only %s -verify + +// Tests Objective-C 'kindof' types. + +#if !__has_feature(objc_kindof) +#error does not support __kindof +#endif + +@protocol NSObject +@end + +@protocol NSCopying +- (id)copy; ++ (Class)classCopy; +@end + +@protocol NSRandomProto +- (void)randomMethod; ++ (void)randomClassMethod; +@end + +__attribute__((objc_root_class)) +@interface NSObject <NSObject> +- (NSObject *)retain; +@end + +@interface NSString : NSObject <NSCopying> +- (NSString *)stringByAppendingString:(NSString *)string; ++ (instancetype)string; +@end + +@interface NSMutableString : NSString +- (void)appendString:(NSString *)string; +@end + +@interface NSNumber : NSObject <NSCopying> +- (NSNumber *)numberByAddingNumber:(NSNumber *)number; +@end + +// --------------------------------------------------------------------------- +// Parsing and semantic analysis for __kindof +// --------------------------------------------------------------------------- + +// Test proper application of __kindof. +typedef __kindof NSObject *typedef1; +typedef NSObject __kindof *typedef2; +typedef __kindof NSObject<NSCopying> typedef3; +typedef NSObject<NSCopying> __kindof *typedef4; +typedef __kindof id<NSCopying> typedef5; +typedef __kindof Class<NSCopying> typedef6; + +// Test redundancy of __kindof. +typedef __kindof id __kindof redundant_typedef1; +typedef __kindof NSObject __kindof *redundant_typedef2; + +// Test application of __kindof to typedefs. +typedef NSObject *NSObject_ptr_typedef; +typedef NSObject NSObject_typedef; +typedef __kindof NSObject_ptr_typedef typedef_typedef1; +typedef __kindof NSObject_typedef typedef_typedef2; + +// Test application of __kindof to non-object types. +typedef __kindof int nonobject_typedef1; // expected-error{{'__kindof' specifier cannot be applied to non-object type 'int'}} +typedef NSObject **NSObject_ptr_ptr; +typedef __kindof NSObject_ptr_ptr nonobject_typedef2; // expected-error{{'__kindof' specifier cannot be applied to non-object type 'NSObject_ptr_ptr' (aka 'NSObject **')}} + +// Test application of __kindof outside of the decl-specifiers. +typedef NSObject * __kindof bad_specifier_location1; // expected-error{{'__kindof' type specifier must precede the declarator}} +typedef NSObject bad_specifier_location2 __kindof; // expected-error{{expected ';' after top level declarator}} +// expected-warning@-1{{declaration does not declare anything}} + +// --------------------------------------------------------------------------- +// Pretty printing of __kindof +// --------------------------------------------------------------------------- +void test_pretty_print(int *ip) { + __kindof NSObject *kindof_NSObject; + ip = kindof_NSObject; // expected-warning{{from '__kindof NSObject *'}} + + __kindof NSObject_ptr_typedef kindof_NSObject_ptr; + ip = kindof_NSObject_ptr; // expected-warning{{from '__kindof NSObject_ptr_typedef'}} + + __kindof id <NSCopying> *kindof_NSCopying; + ip = kindof_NSCopying; // expected-warning{{from '__kindof id<NSCopying> *'}} + + __kindof NSObject_ptr_typedef *kindof_NSObject_ptr_typedef; + ip = kindof_NSObject_ptr_typedef; // expected-warning{{from '__kindof NSObject_ptr_typedef *'}} +} + +// --------------------------------------------------------------------------- +// Basic implicit conversions (dropping __kindof, upcasts, etc.) +// --------------------------------------------------------------------------- +void test_add_remove_kindof_conversions(void) { + __kindof NSObject *kindof_NSObject_obj; + NSObject *NSObject_obj; + + // Conversion back and forth + kindof_NSObject_obj = NSObject_obj; + NSObject_obj = kindof_NSObject_obj; + + // Qualified-id conversion back and forth. + __kindof id <NSCopying> kindof_id_NSCopying_obj; + id <NSCopying> id_NSCopying_obj; + kindof_id_NSCopying_obj = id_NSCopying_obj; + id_NSCopying_obj = kindof_id_NSCopying_obj; +} + +void test_upcast_conversions(void) { + __kindof NSObject *kindof_NSObject_obj; + NSObject *NSObject_obj; + + // Upcasts + __kindof NSString *kindof_NSString_obj; + NSString *NSString_obj; + kindof_NSObject_obj = kindof_NSString_obj; + kindof_NSObject_obj = NSString_obj; + NSObject_obj = kindof_NSString_obj; + NSObject_obj = NSString_obj; + + // "Upcasts" with qualified-id. + __kindof id <NSCopying> kindof_id_NSCopying_obj; + id <NSCopying> id_NSCopying_obj; + kindof_id_NSCopying_obj = kindof_NSString_obj; + kindof_id_NSCopying_obj = NSString_obj; + id_NSCopying_obj = kindof_NSString_obj; + id_NSCopying_obj = NSString_obj; +} + + +void test_ptr_object_conversions(void) { + __kindof NSObject **ptr_kindof_NSObject_obj; + NSObject **ptr_NSObject_obj; + + // Conversions back and forth. + ptr_kindof_NSObject_obj = ptr_NSObject_obj; + ptr_NSObject_obj = ptr_kindof_NSObject_obj; + + // Conversions back and forth with qualified-id. + __kindof id <NSCopying> *ptr_kindof_id_NSCopying_obj; + id <NSCopying> *ptr_id_NSCopying_obj; + ptr_kindof_id_NSCopying_obj = ptr_id_NSCopying_obj; + ptr_id_NSCopying_obj = ptr_kindof_id_NSCopying_obj; + + // Upcasts. + __kindof NSString **ptr_kindof_NSString_obj; + NSString **ptr_NSString_obj; + ptr_kindof_NSObject_obj = ptr_kindof_NSString_obj; + ptr_kindof_NSObject_obj = ptr_NSString_obj; + ptr_NSObject_obj = ptr_kindof_NSString_obj; + ptr_NSObject_obj = ptr_NSString_obj; +} + +// --------------------------------------------------------------------------- +// Implicit downcasting +// --------------------------------------------------------------------------- +void test_downcast_conversions(void) { + __kindof NSObject *kindof_NSObject_obj; + NSObject *NSObject_obj; + __kindof NSString *kindof_NSString_obj; + NSString *NSString_obj; + + // Implicit downcasting. + kindof_NSString_obj = kindof_NSObject_obj; + kindof_NSString_obj = NSObject_obj; // expected-warning{{assigning to '__kindof NSString *' from 'NSObject *'}} + NSString_obj = kindof_NSObject_obj; + NSString_obj = NSObject_obj; // expected-warning{{assigning to 'NSString *' from 'NSObject *'}} + + // Implicit downcasting with qualified id. + __kindof id <NSCopying> kindof_NSCopying_obj; + id <NSCopying> NSCopying_obj; + kindof_NSString_obj = kindof_NSCopying_obj; + kindof_NSString_obj = NSCopying_obj; // expected-warning{{from incompatible type 'id<NSCopying>'}} + NSString_obj = kindof_NSCopying_obj; + NSString_obj = NSCopying_obj; // expected-warning{{from incompatible type 'id<NSCopying>'}} + kindof_NSObject_obj = kindof_NSCopying_obj; + kindof_NSObject_obj = NSCopying_obj; // expected-warning{{from incompatible type 'id<NSCopying>'}} + NSObject_obj = kindof_NSCopying_obj; + NSObject_obj = NSCopying_obj; // expected-warning{{from incompatible type 'id<NSCopying>'}} +} + +void test_crosscast_conversions(void) { + __kindof NSString *kindof_NSString_obj; + NSString *NSString_obj; + __kindof NSNumber *kindof_NSNumber_obj; + NSNumber *NSNumber_obj; + + NSString_obj = kindof_NSNumber_obj; // expected-warning{{from '__kindof NSNumber *'}} +} + +// --------------------------------------------------------------------------- +// Blocks +// --------------------------------------------------------------------------- +void test_block_conversions(void) { + // Adding/removing __kindof from return type. + __kindof NSString *(^kindof_NSString_void_block)(void); + NSString *(^NSString_void_block)(void); + kindof_NSString_void_block = NSString_void_block; + NSString_void_block = kindof_NSString_void_block; + + // Covariant return type. + __kindof NSMutableString *(^kindof_NSMutableString_void_block)(void); + NSMutableString *(^NSMutableString_void_block)(void); + kindof_NSString_void_block = NSMutableString_void_block; + NSString_void_block = kindof_NSMutableString_void_block; + kindof_NSString_void_block = NSMutableString_void_block; + NSString_void_block = kindof_NSMutableString_void_block; + + // "Covariant" return type via downcasting rule. + kindof_NSMutableString_void_block = NSString_void_block; // expected-error{{from 'NSString *(^)(void)'}} + NSMutableString_void_block = kindof_NSString_void_block; + kindof_NSMutableString_void_block = NSString_void_block; // expected-error{{from 'NSString *(^)(void)'}} + NSMutableString_void_block = kindof_NSString_void_block; + + // Cross-casted return type. + __kindof NSNumber *(^kindof_NSNumber_void_block)(void); + NSNumber *(^NSNumber_void_block)(void); + kindof_NSString_void_block = NSNumber_void_block; // expected-error{{from 'NSNumber *(^)(void)'}} + NSString_void_block = kindof_NSNumber_void_block; // expected-error{{'__kindof NSNumber *(^)(void)'}} + kindof_NSString_void_block = NSNumber_void_block; // expected-error{{from 'NSNumber *(^)(void)'}} + NSString_void_block = kindof_NSNumber_void_block; // expected-error{{'__kindof NSNumber *(^)(void)'}} + + // Adding/removing __kindof from argument type. + void (^void_kindof_NSString_block)(__kindof NSString *); + void (^void_NSString_block)(NSString *); + void_kindof_NSString_block = void_NSString_block; + void_NSString_block = void_kindof_NSString_block; + + // Contravariant argument type. + void (^void_kindof_NSMutableString_block)(__kindof NSMutableString *); + void (^void_NSMutableString_block)(NSMutableString *); + void_kindof_NSMutableString_block = void_kindof_NSString_block; + void_kindof_NSMutableString_block = void_NSString_block; + void_NSMutableString_block = void_kindof_NSString_block; + void_NSMutableString_block = void_NSString_block; + + // "Contravariant" argument type via downcasting rule. + void_kindof_NSString_block = void_kindof_NSMutableString_block; + void_kindof_NSString_block = void_NSMutableString_block; + void_NSString_block = void_kindof_NSMutableString_block; // expected-error{{from 'void (^)(__kindof NSMutableString *)'}} + void_NSString_block = void_NSMutableString_block; // expected-error{{from 'void (^)(NSMutableString *)'}} +} + +// --------------------------------------------------------------------------- +// Messaging __kindof types. +// --------------------------------------------------------------------------- +void message_kindof_object(__kindof NSString *kindof_NSString) { + [kindof_NSString retain]; // in superclass + [kindof_NSString stringByAppendingString:0]; // in class + [kindof_NSString appendString:0]; // in subclass + [kindof_NSString numberByAddingNumber: 0]; // FIXME: in unrelated class + [kindof_NSString randomMethod]; // in protocol +} + +void message_kindof_qualified_id(__kindof id <NSCopying> kindof_NSCopying) { + [kindof_NSCopying copy]; // in protocol + [kindof_NSCopying stringByAppendingString:0]; // in some class + [kindof_NSCopying randomMethod]; // in unrelated protocol +} + +void message_kindof_qualified_class( + __kindof Class <NSCopying> kindof_NSCopying) { + [kindof_NSCopying classCopy]; // in protocol + [kindof_NSCopying string]; // in some class + [kindof_NSCopying randomClassMethod]; // in unrelated protocol +} + +// --------------------------------------------------------------------------- +// __kindof within specialized types +// --------------------------------------------------------------------------- +@interface NSArray<T> : NSObject +@end + +void implicit_convert_array(NSArray<__kindof NSString *> *kindofStringsArray, + NSArray<NSString *> *stringsArray, + NSArray<__kindof NSMutableString *> + *kindofMutStringsArray, + NSArray<NSMutableString *> *mutStringsArray) { + // Adding/removing __kindof is okay. + kindofStringsArray = stringsArray; + stringsArray = kindofStringsArray; + + // Other covariant and contravariant conversions still not permitted. + kindofStringsArray = mutStringsArray; // expected-warning{{incompatible pointer types}} + stringsArray = kindofMutStringsArray; // expected-warning{{incompatible pointer types}} + mutStringsArray = kindofStringsArray; // expected-warning{{incompatible pointer types}} + + // Adding/removing nested __kindof is okay. + NSArray<NSArray<__kindof NSString *> *> *kindofStringsArrayArray; + NSArray<NSArray<NSString *> *> *stringsArrayArray; + kindofStringsArrayArray = stringsArrayArray; + stringsArrayArray = kindofStringsArrayArray; +} + +// --------------------------------------------------------------------------- +// __kindof + nullability +// --------------------------------------------------------------------------- + +void testNullability() { + // The base type being a pointer type tickles the bug. + extern __kindof id <NSCopying> _Nonnull getSomeCopyable(); + NSString *string = getSomeCopyable(); // no-warning + + void processCopyable(__typeof(getSomeCopyable()) string); + processCopyable(0); // expected-warning{{null passed to a callee that requires a non-null argument}} +} diff --git a/test/SemaObjC/objc2-merge-gc-attribue-decl.m b/test/SemaObjC/objc2-merge-gc-attribue-decl.m index 673a7417e384c..232f8dd794d6d 100644 --- a/test/SemaObjC/objc2-merge-gc-attribue-decl.m +++ b/test/SemaObjC/objc2-merge-gc-attribue-decl.m @@ -13,17 +13,17 @@ extern __strong id CFRunLoopGetMain(); extern __weak id WLoopGetMain(); // expected-note {{previous declaration is here}} extern id WLoopGetMain(); // expected-error {{conflicting types for 'WLoopGetMain'}} -extern id p3; // expected-note {{previous definition is here}} -extern __weak id p3; // expected-error {{redefinition of 'p3' with a different type}} +extern id p3; // expected-note {{previous declaration is here}} +extern __weak id p3; // expected-error {{redeclaration of 'p3' with a different type}} -extern void *p4; // expected-note {{previous definition is here}} -extern void * __strong p4; // expected-error {{redefinition of 'p4' with a different type}} +extern void *p4; // expected-note {{previous declaration is here}} +extern void * __strong p4; // expected-error {{redeclaration of 'p4' with a different type}} extern id p5; extern __strong id p5; -extern char* __strong p6; // expected-note {{previous definition is here}} -extern char* p6; // expected-error {{redefinition of 'p6' with a different type}} +extern char* __strong p6; // expected-note {{previous declaration is here}} +extern char* p6; // expected-error {{redeclaration of 'p6' with a different type}} -extern __strong char* p7; // expected-note {{previous definition is here}} -extern char* p7; // expected-error {{redefinition of 'p7' with a different type}} +extern __strong char* p7; // expected-note {{previous declaration is here}} +extern char* p7; // expected-error {{redeclaration of 'p7' with a different type}} diff --git a/test/SemaObjC/parameterized_classes.m b/test/SemaObjC/parameterized_classes.m new file mode 100644 index 0000000000000..644fe3a329af3 --- /dev/null +++ b/test/SemaObjC/parameterized_classes.m @@ -0,0 +1,357 @@ +// RUN: %clang_cc1 -fblocks %s -verify + +#if !__has_feature(objc_generics) +# error Compiler does not support Objective-C generics? +#endif + +#if !__has_feature(objc_generics_variance) +# error Compiler does not support co- and contr-variance? +#endif + +@protocol NSObject // expected-note{{'NSObject' declared here}} +@end + +@protocol NSCopying // expected-note{{'NSCopying' declared here}} +@end + +__attribute__((objc_root_class)) +@interface NSObject <NSObject> // expected-note{{'NSObject' defined here}} +@end + +@interface NSString : NSObject <NSCopying> +@end + +// -------------------------------------------------------------------------- +// Parsing parameterized classes. +// -------------------------------------------------------------------------- + +// Parse type parameters with a bound +@interface PC1<T, U : NSObject*> : NSObject // expected-note{{'PC1' declared here}} +// expected-note@-1{{type parameter 'T' declared here}} +// expected-note@-2{{type parameter 'U' declared here}} +// expected-note@-3{{type parameter 'U' declared here}} +@end + +// Parse a type parameter with a bound that terminates in '>>'. +@interface PC2<T : id<NSObject>> : NSObject +@end + +// Parse multiple type parameters. +@interface PC3<T, U : id> : NSObject +@end + +// Parse multiple type parameters--grammatically ambiguous with protocol refs. +@interface PC4<T, U, V> : NSObject // expected-note 2{{'PC4' declared here}} +@end + +// Parse a type parameter list without a superclass. +@interface PC5<T : id> +@end + +// Parse a type parameter with name conflicts. +@interface PC6<T, U, + T> : NSObject // expected-error{{redeclaration of type parameter 'T'}} +@end + +// Parse Objective-C protocol references. +@interface PC7<T> // expected-error{{cannot find protocol declaration for 'T'}} +@end + +// Parse both type parameters and protocol references. +@interface PC8<T> : NSObject <NSObject> +@end + +// Type parameters with improper bounds. +@interface PC9<T : int, // expected-error{{type bound 'int' for type parameter 'T' is not an Objective-C pointer type}} + U : NSString> : NSObject // expected-error{{missing '*' in type bound 'NSString' for type parameter 'U'}} +@end + +// -------------------------------------------------------------------------- +// Parsing parameterized forward declarations classes. +// -------------------------------------------------------------------------- + +// Okay: forward declaration without type parameters. +@class PC10; + +// Okay: forward declarations with type parameters. +@class PC10<T, U : NSObject *>, PC11<T : NSObject *, U : id>; // expected-note{{type parameter 'T' declared here}} + +// Okay: forward declaration without type parameters following ones +// with type parameters. +@class PC10, PC11; + +// Okay: definition of class with type parameters that was formerly +// declared with the same type parameters. +@interface PC10<T, U : NSObject *> : NSObject +@end + +// Mismatched parameters in declaration of @interface following @class. +@interface PC11<T, U> : NSObject // expected-error{{missing type bound 'NSObject *' for type parameter 'T' in @interface}} +@end + +@interface PC12<T : NSObject *> : NSObject // expected-note{{type parameter 'T' declared here}} +@end + +@class PC12; + +// Mismatched parameters in subsequent forward declarations. +@class PC13<T : NSObject *>; // expected-note{{type parameter 'T' declared here}} +@class PC13; +@class PC13<U>; // expected-error{{missing type bound 'NSObject *' for type parameter 'U' in @class}} + +// Mismatch parameters in declaration of @class following @interface. +@class PC12<T>; // expected-error{{missing type bound 'NSObject *' for type parameter 'T' in @class}} + +// Parameterized forward declaration a class that is not parameterized. +@class NSObject<T>; // expected-error{{forward declaration of non-parameterized class 'NSObject' cannot have type parameters}} +// expected-note@-1{{'NSObject' declared here}} + +// Parameterized forward declaration preceding the definition (that is +// not parameterized). +@class NSNumber<T : NSObject *>; // expected-note{{'NSNumber' declared here}} +@interface NSNumber : NSObject // expected-error{{class 'NSNumber' previously declared with type parameters}} +@end + +@class PC14; + +// Okay: definition of class with type parameters that was formerly +// declared without type parameters. +@interface PC14<T, U : NSObject *> : NSObject +@end + +// -------------------------------------------------------------------------- +// Parsing parameterized categories and extensions. +// -------------------------------------------------------------------------- + +// Inferring type bounds +@interface PC1<T, U> (Cat1) <NSObject> +@end + +// Matching type bounds +@interface PC1<T : id, U : NSObject *> (Cat2) <NSObject> +@end + +// Inferring type bounds +@interface PC1<T, U> () <NSObject> +@end + +// Matching type bounds +@interface PC1<T : id, U : NSObject *> () <NSObject> +@end + +// Missing type parameters. +@interface PC1<T> () // expected-error{{extension has too few type parameters (expected 2, have 1)}} +@end + +// Extra type parameters. +@interface PC1<T, U, V> (Cat3) // expected-error{{category has too many type parameters (expected 2, have 3)}} +@end + +// Mismatched bounds. +@interface PC1<T : NSObject *, // expected-error{{type bound 'NSObject *' for type parameter 'T' conflicts with implicit bound 'id'}} + X : id> () // expected-error{{type bound 'id' for type parameter 'X' conflicts with previous bound 'NSObject *'for type parameter 'U'}} +@end + +// Parameterized category/extension of non-parameterized class. +@interface NSObject<T> (Cat1) // expected-error{{category of non-parameterized class 'NSObject' cannot have type parameters}} +@end + +@interface NSObject<T> () // expected-error{{extension of non-parameterized class 'NSObject' cannot have type parameters}} +@end + +// -------------------------------------------------------------------------- +// @implementations cannot have type parameters +// -------------------------------------------------------------------------- +@implementation PC1<T : id> // expected-error{{@implementation cannot have type parameters}} +@end + +@implementation PC2<T> // expected-error{{@implementation declaration cannot be protocol qualified}} +@end + +@implementation PC1<T> (Cat1) // expected-error{{@implementation cannot have type parameters}} +@end + +@implementation PC1<T : id> (Cat2) // expected-error{{@implementation cannot have type parameters}} +@end + +// -------------------------------------------------------------------------- +// Interfaces involving type parameters +// -------------------------------------------------------------------------- +@interface PC20<T : id, U : NSObject *, V : NSString *> : NSObject { + T object; +} + +- (U)method:(V)param; +@end + +@interface PC20<T, U, V> (Cat1) +- (U)catMethod:(V)param; +@end + +@interface PC20<X, Y, Z>() +- (X)extMethod:(Y)param; +@end + +// -------------------------------------------------------------------------- +// Parsing type arguments. +// -------------------------------------------------------------------------- + +typedef NSString * ObjCStringRef; // expected-note{{'ObjCStringRef' declared here}} + +// Type arguments with a mix of identifiers and type-names. +typedef PC4<id, NSObject *, NSString *> typeArgs1; + +// Type arguments with only identifiers. +typedef PC4<id, id, id> typeArgs2; + +// Type arguments with only identifiers; one is ambiguous (resolved as +// types). +typedef PC4<NSObject, id, id> typeArgs3; // expected-error{{type argument 'NSObject' must be a pointer (requires a '*')}} + +// Type arguments with only identifiers; one is ambiguous (resolved as +// protocol qualifiers). +typedef PC4<NSObject, NSCopying> protocolQuals1; + +// Type arguments and protocol qualifiers. +typedef PC4<id, NSObject *, id><NSObject, NSCopying> typeArgsAndProtocolQuals1; + +// Type arguments and protocol qualifiers in the wrong order. +typedef PC4<NSObject, NSCopying><id, NSObject *, id> typeArgsAndProtocolQuals2; // expected-error{{protocol qualifiers must precede type arguments}} + +// Type arguments and protocol qualifiers (identifiers). +typedef PC4<id, NSObject, id><NSObject, NSCopying> typeArgsAndProtocolQuals3; // expected-error{{type argument 'NSObject' must be a pointer (requires a '*')}} + +// Typo correction: protocol bias. +typedef PC4<NSCopying, NSObjec> protocolQuals2; // expected-error{{cannot find protocol declaration for 'NSObjec'; did you mean 'NSObject'?}} + +// Typo correction: type bias. +typedef PC4<id, id, NSObjec> typeArgs4; // expected-error{{unknown class name 'NSObjec'; did you mean 'NSObject'?}} +// expected-error@-1{{type argument 'NSObject' must be a pointer (requires a '*')}} + +// Typo correction: bias set by correction itself to a protocol. +typedef PC4<NSObject, NSObject, NSCopyin> protocolQuals3; // expected-error{{cannot find protocol declaration for 'NSCopyin'; did you mean 'NSCopying'?}} + +// Typo correction: bias set by correction itself to a type. +typedef PC4<NSObject, NSObject, ObjCStringref> typeArgs5; // expected-error{{unknown type name 'ObjCStringref'; did you mean 'ObjCStringRef'?}} +// expected-error@-1{{type argument 'NSObject' must be a pointer (requires a '*')}} +// expected-error@-2{{type argument 'NSObject' must be a pointer (requires a '*')}} + +// Type/protocol conflict. +typedef PC4<NSCopying, ObjCStringRef> typeArgsProtocolQualsConflict1; // expected-error{{angle brackets contain both a type ('ObjCStringRef') and a protocol ('NSCopying')}} + +// Handling the '>>' in type argument lists. +typedef PC4<id<NSCopying>, NSObject *, id<NSObject>> typeArgs6; + +// -------------------------------------------------------------------------- +// Checking type arguments. +// -------------------------------------------------------------------------- + +@interface PC15<T : id, U : NSObject *, V : id<NSCopying>> : NSObject +// expected-note@-1{{type parameter 'V' declared here}} +// expected-note@-2{{type parameter 'V' declared here}} +// expected-note@-3{{type parameter 'U' declared here}} +@end + +typedef PC4<NSString *> tooFewTypeArgs1; // expected-error{{too few type arguments for class 'PC4' (have 1, expected 3)}} + +typedef PC4<NSString *, NSString *, NSString *, NSString *> tooManyTypeArgs1; // expected-error{{too many type arguments for class 'PC4' (have 4, expected 3)}} + +typedef PC15<int (^)(int, int), // block pointers as 'id' + NSString *, // subclass + NSString *> typeArgs7; // class that conforms to the protocol + +typedef PC15<NSObject *, NSObject *, id<NSCopying>> typeArgs8; + +typedef PC15<NSObject *, NSObject *, + NSObject *> typeArgs8b; // expected-error{{type argument 'NSObject *' does not satisfy the bound ('id<NSCopying>') of type parameter 'V'}} + +typedef PC15<id, + id, // expected-error{{type argument 'id' does not satisfy the bound ('NSObject *') of type parameter 'U'}} + id> typeArgs9; + +typedef PC15<id, NSObject *, + id> typeArgs10; // expected-error{{type argument 'id' does not satisfy the bound ('id<NSCopying>') of type parameter 'V'}} + +typedef PC15<id, + int (^)(int, int), // okay + id<NSCopying, NSObject>> typeArgs11; + +typedef PC15<id, NSString *, int (^)(int, int)> typeArgs12; // okay + +typedef NSObject<id, id> typeArgs13; // expected-error{{type arguments cannot be applied to non-parameterized class 'NSObject'}} + +typedef id<id, id> typeArgs14; // expected-error{{type arguments cannot be applied to non-class type 'id'}} + +typedef PC1<NSObject *, NSString *> typeArgs15; + +typedef PC1<NSObject *, NSString *><NSCopying> typeArgsAndProtocolQuals4; + +typedef typeArgs15<NSCopying> typeArgsAndProtocolQuals5; + +typedef typeArgs15<NSObject *, NSString *> typeArgs16; // expected-error{{type arguments cannot be applied to already-specialized class type 'typeArgs15' (aka 'PC1<NSObject *,NSString *>')}} + +typedef typeArgs15<NSObject> typeArgsAndProtocolQuals6; + +void testSpecializedTypePrinting() { + int *ip; + + ip = (typeArgs15*)0; // expected-warning{{'typeArgs15 *' (aka 'PC1<NSObject *,NSString *> *')}} + ip = (typeArgsAndProtocolQuals4*)0; // expected-warning{{'typeArgsAndProtocolQuals4 *' (aka 'PC1<NSObject *,NSString *><NSCopying> *')}} + ip = (typeArgsAndProtocolQuals5*)0; // expected-warning{{'typeArgsAndProtocolQuals5 *' (aka 'typeArgs15<NSCopying> *')}} + ip = (typeArgsAndProtocolQuals6)0; // expected-error{{used type 'typeArgsAndProtocolQuals6' (aka 'typeArgs15<NSObject>')}} + ip = (typeArgsAndProtocolQuals6*)0;// expected-warning{{'typeArgsAndProtocolQuals6 *' (aka 'typeArgs15<NSObject> *')}} +} + +// -------------------------------------------------------------------------- +// Specialized superclasses +// -------------------------------------------------------------------------- +@interface PC21<T : NSObject *> : PC1<T, T> +@end + +@interface PC22<T : NSObject *> : PC1<T> // expected-error{{too few type arguments for class 'PC1' (have 1, expected 2)}} +@end + +@interface PC23<T : NSObject *> : PC1<T, U> // expected-error{{unknown type name 'U'}} +@end + +@interface PC24<T> : PC1<T, T> // expected-error{{type argument 'T' (aka 'id') does not satisfy the bound ('NSObject *') of type parameter 'U'}} +@end + +@interface NSFoo : PC1<NSObject *, NSObject *> // okay +@end + +// -------------------------------------------------------------------------- +// Co- and contra-variance. +// -------------------------------------------------------------------------- +@class Variance1<T, U>; + +@class Variance1<__covariant T, __contravariant U>; + +@interface Variance1<__covariant T, __contravariant U> : NSObject // expected-note 2{{declared here}} +@end + +@interface Variance1<T, U> () // okay, inferred +@end + +@interface Variance1<T, U> (Cat1) // okay, inferred +@end + +@class Variance1<T, U>; // okay, inferred + +@interface Variance1<__covariant T, __contravariant U> () // okay, matches +@end + +@interface Variance1<__covariant T, __contravariant U> (Cat2) // okay, matches +@end + +@class Variance1<__covariant T, __contravariant U>; // okay, matches + +@interface Variance1<__contravariant X, // expected-error{{contravariant type parameter 'X' conflicts with previous covariant type parameter 'T'}} + __covariant Y> () // expected-error{{covariant type parameter 'Y' conflicts with previous contravariant type parameter 'U'}} +@end + +@class Variance2<__covariant T, __contravariant U>; // expected-note 2{{declared here}} + +@interface Variance2<__contravariant T, // expected-error{{contravariant type parameter 'T' conflicts with previous covariant type parameter 'T'}} + U> : NSObject // expected-error{{invariant type parameter 'U' conflicts with previous contravariant type parameter 'U'}} +@end diff --git a/test/SemaObjC/parameterized_classes_collection_literal.m b/test/SemaObjC/parameterized_classes_collection_literal.m new file mode 100644 index 0000000000000..472746e09db9e --- /dev/null +++ b/test/SemaObjC/parameterized_classes_collection_literal.m @@ -0,0 +1,52 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -x objective-c++ -fsyntax-only -verify %s + +#if __LP64__ || (TARGET_OS_EMBEDDED && !TARGET_OS_IPHONE) || TARGET_OS_WIN32 || NS_BUILD_32_LIKE_64 +typedef unsigned long NSUInteger; +#else +typedef unsigned int NSUInteger; +#endif + +@protocol NSObject +@end + +@protocol NSCopying +@end + +__attribute__((objc_root_class)) +@interface NSObject <NSObject> +@end + +@interface NSString : NSObject <NSCopying> +@end + +@interface NSNumber : NSObject <NSCopying> ++ (NSNumber *)numberWithInt:(int)value; +@end + +@interface NSArray<T> : NSObject <NSCopying> ++ (instancetype)arrayWithObjects:(const T [])objects count:(NSUInteger)cnt; +@end + +@interface NSDictionary<K, V> : NSObject <NSCopying> ++ (instancetype)dictionaryWithObjects:(const V [])objects forKeys:(const K [])keys count:(NSUInteger)cnt; +@end + +void testArrayLiteral(void) { + NSArray<NSString *> *array1 = @[@"hello", + @1, // expected-warning{{of type 'NSNumber *' is not compatible with array element type 'NSString *'}} + @"world", + @[@1, @2]]; // expected-warning{{of type 'NSArray *' is not compatible with array element type 'NSString *'}} + + NSArray<NSArray<NSString *> *> *array2 = @[@[@"hello", @"world"], + @"blah", // expected-warning{{object of type 'NSString *' is not compatible with array element type 'NSArray<NSString *> *'}} + @[@1]]; // expected-warning{{object of type 'NSNumber *' is not compatible with array element type 'NSString *'}} +} + +void testDictionaryLiteral(void) { + NSDictionary<NSString *, NSNumber *> *dict1 = @{ + @"hello" : @17, + @18 : @18, // expected-warning{{object of type 'NSNumber *' is not compatible with dictionary key type 'NSString *'}} + @"world" : @"blah" // expected-warning{{object of type 'NSString *' is not compatible with dictionary value type 'NSNumber *'}} + }; +} diff --git a/test/SemaObjC/parameterized_classes_subst.m b/test/SemaObjC/parameterized_classes_subst.m new file mode 100644 index 0000000000000..f90ee9093592c --- /dev/null +++ b/test/SemaObjC/parameterized_classes_subst.m @@ -0,0 +1,428 @@ +// 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. + +@protocol NSObject +@end + +__attribute__((objc_root_class)) +@interface NSObject <NSObject> ++ (instancetype)alloc; +- (instancetype)init; +@end + +@protocol NSCopying +@end + +@interface NSString : NSObject <NSCopying> +@end + +@interface NSMutableString : NSString +@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, + NSArray<__kindof NSString *> *kindofStringArray, + 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 *> *'}} + + ip = [[[NSViewController alloc] init] view]; // expected-warning{{from '__kindof NSView *'}} + [[[[NSViewController alloc] init] view] toggle]; + + NSMutableString *mutStr = kindofStringArray[0]; + NSNumber *number = kindofStringArray[0]; // expected-warning{{of type '__kindof NSString *'}} +} + +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 '__kindof id<NSCopying>'}} + + ip = [[NSViewController alloc] init].view; // expected-warning{{from '__kindof NSView *'}} +} + +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; +} + +@interface NSCovariant1<__covariant T> +@end + +@interface NSContravariant1<__contravariant T> +@end + +void test_variance(NSCovariant1<NSString *> *covariant1, + NSCovariant1<NSMutableString *> *covariant2, + NSCovariant1<NSString *(^)(void)> *covariant3, + NSCovariant1<NSMutableString *(^)(void)> *covariant4, + NSCovariant1<id> *covariant5, + NSCovariant1<id<NSCopying>> *covariant6, + NSContravariant1<NSString *> *contravariant1, + NSContravariant1<NSMutableString *> *contravariant2) { + covariant1 = covariant2; // okay + covariant2 = covariant1; // expected-warning{{incompatible pointer types assigning to 'NSCovariant1<NSMutableString *> *' from 'NSCovariant1<NSString *> *'}} + + covariant3 = covariant4; // okay + covariant4 = covariant3; // expected-warning{{incompatible pointer types assigning to 'NSCovariant1<NSMutableString *(^)(void)> *' from 'NSCovariant1<NSString *(^)(void)> *'}} + + covariant5 = covariant1; // okay + covariant1 = covariant5; // okay: id is promiscuous + + covariant5 = covariant3; // okay + covariant3 = covariant5; // okay + + contravariant1 = contravariant2; // expected-warning{{incompatible pointer types assigning to 'NSContravariant1<NSString *> *' from 'NSContravariant1<NSMutableString *> *'}} + contravariant2 = contravariant1; // okay +} + +// -------------------------------------------------------------------------- +// 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 *> *'}} + ip = cond ? mutStringArray : stringArray2; // expected-warning{{from 'NSArray<NSString *> *'}} + + ip = cond ? stringArray : mutArray; // expected-warning{{from 'NSArray *'}} + + ip = cond ? stringArray2 : mutArray; // expected-warning{{from 'NSArray *'}} + + ip = cond ? mutArray : stringArray; // expected-warning{{from 'NSArray *'}} + + ip = cond ? mutArray : stringArray2; // expected-warning{{from 'NSArray *'}} + + 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 + +// -------------------------------------------------------------------------- +// warning about likely protocol/class name typos. +// -------------------------------------------------------------------------- +typedef NSArray<NSObject> ArrayOfNSObjectWarning; // expected-warning{{parameterized class 'NSArray' already conforms to the protocols listed; did you forget a '*'?}} diff --git a/test/SemaObjC/protocol-archane.m b/test/SemaObjC/protocol-archane.m index 788edf276d7bf..f2f6025a5ad6f 100644 --- a/test/SemaObjC/protocol-archane.m +++ b/test/SemaObjC/protocol-archane.m @@ -40,3 +40,7 @@ Class <SomeProtocol> UnfortunateGCCExtension; - (void)crashWith:(<Broken>)a { // expected-warning {{protocol has no object type specified; defaults to qualified 'id'}} } @end + +typedef <SomeProtocol> id TwoTypeSpecs; // expected-warning{{no object type specified}} +// expected-error@-1{{typedef redefinition with different types ('id<SomeProtocol>' vs 'id')}} +// expected-error@-2{{expected ';' after top level declarator}} diff --git a/test/SemaObjC/protocol-warn.m b/test/SemaObjC/protocol-warn.m index 2d042380582e1..04df5031ab474 100644 --- a/test/SemaObjC/protocol-warn.m +++ b/test/SemaObjC/protocol-warn.m @@ -51,5 +51,5 @@ UIWebPDFView *getView() { UIWebBrowserView *browserView; UIWebPDFView *pdfView; - return pdfView ? pdfView : browserView; // expected-warning {{incompatible pointer types returning 'UIView<NSObject> *' from a function with result type 'UIWebPDFView *'}} + return pdfView ? pdfView : browserView; // expected-warning {{incompatible pointer types returning 'UIView *' from a function with result type 'UIWebPDFView *'}} } |