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. |
40 | void 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. |
46 | void 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. |
159 | void 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 | |
218 | // PR27822 |
219 | @class NSString; |
220 | namespace pr27822 { } |
221 | @interface AXPlatformNodeCocoa |
222 | + (NSString*)nativeRoleFromAXRole:(pr27822::UndeclaredIdentifier)role; // expected-error {{expected a type}} |
223 | @end |
224 | |