summaryrefslogtreecommitdiffstats
path: root/clang/test/SemaObjC
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2015-07-07 03:58:42 +0000
committerDouglas Gregor <dgregor@apple.com>2015-07-07 03:58:42 +0000
commitab209d83be5dadff4f17364a71f323b89e3c63f8 (patch)
tree5e97315685c9476095deef062e53e98e525d78e5 /clang/test/SemaObjC
parent10dc9d80cbb47675be0c6ea8481e12ec197e1637 (diff)
downloadbcm5719-llvm-ab209d83be5dadff4f17364a71f323b89e3c63f8.tar.gz
bcm5719-llvm-ab209d83be5dadff4f17364a71f323b89e3c63f8.zip
Implement the Objective-C __kindof type qualifier.
The __kindof type qualifier can be applied to Objective-C object (pointer) types to indicate id-like behavior, which includes implicit "downcasting" of __kindof types to subclasses and id-like message-send behavior. __kindof types provide better type bounds for substitutions into unspecified generic types, which preserves more type information. llvm-svn: 241548
Diffstat (limited to 'clang/test/SemaObjC')
-rw-r--r--clang/test/SemaObjC/kindof.m304
-rw-r--r--clang/test/SemaObjC/parameterized_classes_subst.m14
2 files changed, 317 insertions, 1 deletions
diff --git a/clang/test/SemaObjC/kindof.m b/clang/test/SemaObjC/kindof.m
new file mode 100644
index 00000000000..7f795c51481
--- /dev/null
+++ b/clang/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/clang/test/SemaObjC/parameterized_classes_subst.m b/clang/test/SemaObjC/parameterized_classes_subst.m
index 6804bdc7955..dc243069ca1 100644
--- a/clang/test/SemaObjC/parameterized_classes_subst.m
+++ b/clang/test/SemaObjC/parameterized_classes_subst.m
@@ -18,6 +18,9 @@ __attribute__((objc_root_class))
@interface NSString : NSObject <NSCopying>
@end
+@interface NSMutableString : NSString
+@end
+
@interface NSNumber : NSObject <NSCopying>
@end
@@ -144,6 +147,7 @@ void test_message_send_result(
NSMutableSet *mutSet,
MutableSetOfArrays *mutArraySet,
NSArray<NSString *> *stringArray,
+ NSArray<__kindof NSString *> *kindofStringArray,
void (^block)(void)) {
int *ip;
ip = [stringSet firstObject]; // expected-warning{{from 'NSString *'}}
@@ -171,6 +175,12 @@ void test_message_send_result(
[[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(
@@ -215,7 +225,9 @@ void test_property_read(
ip = mutSet.allObjects; // expected-warning{{from 'NSArray *'}}
ip = mutArraySet.allObjects; // expected-warning{{from 'NSArray *'}}
- ip = mutDict.someRandomKey; // expected-warning{{from 'id'}}
+ ip = mutDict.someRandomKey; // expected-warning{{from '__kindof id<NSCopying>'}}
+
+ ip = [[NSViewController alloc] init].view; // expected-warning{{from '__kindof NSView *'}}
}
void test_property_write(
OpenPOWER on IntegriCloud