1// RUN: %clang_cc1 -fsyntax-only -verify %s 2 3#if !__has_feature(objc_instancetype) 4# error Missing 'instancetype' feature macro. 5#endif 6 7@interface Root 8+ (instancetype)alloc; 9- (instancetype)init; // expected-note{{overridden method is part of the 'init' method family}} 10- (instancetype)self; // expected-note {{explicitly declared 'instancetype'}} 11- (Class)class; 12 13@property (assign) Root *selfProp; 14- (instancetype)selfProp; 15@end 16 17@protocol Proto1 18@optional 19- (instancetype)methodInProto1; 20@end 21 22@protocol Proto2 23@optional 24- (instancetype)methodInProto2; // expected-note{{overridden method returns an instance of its class type}} 25- (instancetype)otherMethodInProto2; // expected-note{{overridden method returns an instance of its class type}} 26@end 27 28@interface Subclass1 : Root // expected-note 4 {{receiver is instance of class declared here}} 29- (instancetype)initSubclass1; 30- (void)methodOnSubclass1; 31+ (instancetype)allocSubclass1; 32@end 33 34@interface Subclass2 : Root 35- (instancetype)initSubclass2; 36- (void)methodOnSubclass2; 37@end 38 39// Sanity check: the basic initialization pattern. 40void test_instancetype_alloc_init_simple() { 41 Root *r1 = [[Root alloc] init]; 42 Subclass1 *sc1 = [[Subclass1 alloc] init]; 43} 44 45// Test that message sends to instancetype methods have the right type. 46void test_instancetype_narrow_method_search() { 47 // instancetype on class methods 48 Subclass1 *sc1 = [[Subclass1 alloc] initSubclass2]; // expected-warning{{'Subclass1' may not respond to 'initSubclass2'}} 49 Subclass2 *sc2 = [[Subclass2 alloc] initSubclass2]; // okay 50 51 // instancetype on instance methods 52 [[[Subclass1 alloc] init] methodOnSubclass2]; // expected-warning{{'Subclass1' may not respond to 'methodOnSubclass2'}} 53 [[[Subclass2 alloc] init] methodOnSubclass2]; 54 55 // instancetype on class methods using protocols 56 typedef Subclass1<Proto1> SC1Proto1; 57 typedef Subclass1<Proto2> SC1Proto2; 58 [[SC1Proto1 alloc] methodInProto2]; // expected-warning{{method '-methodInProto2' not found (return type defaults to 'id')}} 59 [[SC1Proto2 alloc] methodInProto2]; 60 61 // instancetype on instance methods 62 Subclass1<Proto1> *sc1proto1 = 0; 63 [[sc1proto1 self] methodInProto2]; // expected-warning{{method '-methodInProto2' not found (return type defaults to 'id')}} 64 Subclass1<Proto2> *sc1proto2 = 0; 65 [[sc1proto2 self] methodInProto2]; 66 67 // Exact type checks 68 typeof([[Subclass1 alloc] init]) *ptr1 = (Subclass1 **)0; 69 typeof([[Subclass2 alloc] init]) *ptr2 = (Subclass2 **)0; 70 71 // Message sends to Class. 72 Subclass1<Proto1> *sc1proto1_2 = [[[sc1proto1 class] alloc] init]; 73 74 // Property access 75 [sc1proto1.self methodInProto2]; // expected-warning{{method '-methodInProto2' not found (return type defaults to 'id')}} 76 [sc1proto2.self methodInProto2]; 77 [Subclass1.alloc initSubclass2]; // expected-warning{{'Subclass1' may not respond to 'initSubclass2'}} 78 [Subclass2.alloc initSubclass2]; 79 80 [sc1proto1.selfProp methodInProto2]; // expected-warning{{method '-methodInProto2' not found (return type defaults to 'id')}} 81 [sc1proto2.selfProp methodInProto2]; 82} 83 84// Test that message sends to super methods have the right type. 85@interface Subsubclass1 : Subclass1 86- (instancetype)initSubclass1; 87+ (instancetype)allocSubclass1; 88 89- (void)onlyInSubsubclass1; 90@end 91 92@implementation Subsubclass1 93- (instancetype)initSubclass1 { 94 // Check based on method search. 95 [[super initSubclass1] methodOnSubclass2]; // expected-warning{{'Subsubclass1' may not respond to 'methodOnSubclass2'}} 96 [super.initSubclass1 methodOnSubclass2]; // expected-warning{{'Subsubclass1' may not respond to 'methodOnSubclass2'}} 97 98 self = [super init]; // common pattern 99 100 // Exact type check. 101 typeof([super initSubclass1]) *ptr1 = (Subsubclass1**)0; 102 103 return self; 104} 105 106+ (instancetype)allocSubclass1 { 107 // Check based on method search. 108 [[super allocSubclass1] methodOnSubclass2]; // expected-warning{{'Subsubclass1' may not respond to 'methodOnSubclass2'}} 109 110 // The ASTs don't model super property accesses well enough to get this right 111 [super.allocSubclass1 methodOnSubclass2]; // expected-warning{{'Subsubclass1' may not respond to 'methodOnSubclass2'}} 112 113 // Exact type check. 114 typeof([super allocSubclass1]) *ptr1 = (Subsubclass1**)0; 115 116 return [super allocSubclass1]; 117} 118 119- (void)onlyInSubsubclass1 {} 120@end 121 122// Check compatibility rules for inheritance of related return types. 123@class Subclass4; 124 125@interface Subclass3 <Proto1, Proto2> 126- (Subclass3 *)methodInProto1; 127- (Subclass4 *)methodInProto2; // expected-warning{{method is expected to return an instance of its class type 'Subclass3', but is declared to return 'Subclass4 *'}} 128@end 129 130@interface Subclass4 : Root 131+ (Subclass4 *)alloc; // okay 132- (Subclass3 *)init; // expected-warning{{method is expected to return an instance of its class type 'Subclass4', but is declared to return 'Subclass3 *'}} 133- (id)self; // expected-note{{overridden method is part of the 'self' method family}} 134- (instancetype)initOther; 135@end 136 137@protocol Proto3 <Proto1, Proto2> 138@optional 139- (id)methodInProto1; 140- (Subclass1 *)methodInProto2; 141- (int)otherMethodInProto2; // expected-warning{{protocol method is expected to return an instance of the implementing class, but is declared to return 'int'}} 142@end 143 144@implementation Subclass4 145+ (id)alloc { 146 return self; // FIXME: we accept this in ObjC++ but not ObjC? 147} 148 149- (Subclass3 *)init { return 0; } // don't complain: we lost the related return type 150 151- (Subclass3 *)self { return 0; } // expected-warning{{method is expected to return an instance of its class type 'Subclass4', but is declared to return 'Subclass3 *'}} 152 153- (Subclass4 *)initOther { return 0; } 154 155@end 156 157// Check that inherited related return types influence the types of 158// message sends. 159void test_instancetype_inherited() { 160 [[Subclass4 alloc] initSubclass1]; // expected-warning{{'Subclass4' may not respond to 'initSubclass1'}} 161 [[Subclass4 alloc] initOther]; 162} 163 164// Check that related return types tighten up the semantics of 165// Objective-C method implementations. 166@implementation Subclass2 167- (instancetype)initSubclass2 { // expected-note {{explicitly declared 'instancetype'}} 168 Subclass1 *sc1 = [[Subclass1 alloc] init]; 169 return sc1; // expected-error{{cannot initialize return object of type 'Subclass2 *' with an lvalue of type 'Subclass1 *'}} 170} 171- (void)methodOnSubclass2 {} 172- (id)self { 173 Subclass1 *sc1 = [[Subclass1 alloc] init]; 174 return sc1; // expected-error{{cannot initialize return object of type 'Subclass2 *' with an lvalue of type 'Subclass1 *'}} 175} 176@end 177 178@interface MyClass : Root 179+ (int)myClassMethod; 180@end 181 182@implementation MyClass 183+ (int)myClassMethod { return 0; } 184 185- (void)blah { 186 int i = [[MyClass self] myClassMethod]; 187} 188 189@end 190 191// rdar://12493140 192@protocol P4 193- (instancetype) foo; // expected-note {{current method is explicitly declared 'instancetype' and is expected to return an instance of its class type}} 194@end 195@interface A4 : Root <P4> 196- (instancetype) bar; // expected-note {{current method is explicitly declared 'instancetype' and is expected to return an instance of its class type}} 197- (instancetype) baz; // expected-note {{overridden method returns an instance of its class type}} expected-note {{previous definition is here}} 198@end 199@interface B4 : Root @end 200 201@implementation A4 { 202 B4 *_b; 203} 204- (id) foo { 205 return _b; // expected-error {{cannot initialize return object of type 'A4 *' with an lvalue of type 'B4 *'}} 206} 207- (id) bar { 208 return _b; // expected-error {{cannot initialize return object of type 'A4 *' with an lvalue of type 'B4 *'}} 209} 210 211// This is really just to ensure that we don't crash. 212// FIXME: only one diagnostic, please 213- (float) baz { // expected-warning {{method is expected to return an instance of its class type 'A4', but is declared to return 'float'}} expected-warning {{conflicting return type in implementation}} 214 return 0; 215} 216@end 217