[clang] Implement lifetime analysis for lifetime_capture_by(X) (#115921)
[llvm-project.git] / clang / test / Modules / compare-objc-interface.m
blobcc3b5fe60b1f554673e4706ba70219b13ff955c7
1 // RUN: rm -rf %t
2 // RUN: split-file %s %t
4 // Build first header file
5 // RUN: echo "#define FIRST" >> %t/include/first.h
6 // RUN: cat %t/test.m        >> %t/include/first.h
7 // RUN: echo "#undef FIRST"  >> %t/include/first.h
9 // Build second header file
10 // RUN: echo "#define SECOND" >> %t/include/second.h
11 // RUN: cat %t/test.m         >> %t/include/second.h
12 // RUN: echo "#undef SECOND"  >> %t/include/second.h
14 // Test that each header can compile
15 // RUN: %clang_cc1 -fsyntax-only -x objective-c %t/include/first.h -fblocks -fobjc-arc
16 // RUN: %clang_cc1 -fsyntax-only -x objective-c %t/include/second.h -fblocks -fobjc-arc
18 // Run test
19 // RUN: %clang_cc1 -I%t/include -verify %t/test.m -fblocks -fobjc-arc \
20 // RUN:            -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/modules.cache
22 // Run the same test with second.h being modular
23 // RUN: cat %t/include/second.modulemap >> %t/include/module.modulemap
24 // RUN: %clang_cc1 -I%t/include -verify %t/test.m -fblocks -fobjc-arc -DTEST_MODULAR=1 \
25 // RUN:            -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/modules.cache
27 // Test that we don't accept different class definitions with the same name
28 // from multiple modules but detect mismatches and provide actionable
29 // diagnostic.
31 //--- include/common.h
32 #ifndef COMMON_H
33 #define COMMON_H
34 @interface NSObject @end
35 @protocol CommonProtocol @end
36 @protocol ExtraProtocol @end
37 #endif
39 //--- include/first-empty.h
40 //--- include/module.modulemap
41 module First {
42   module Empty {
43     header "first-empty.h"
44   }
45   module Hidden {
46     header "first.h"
47     export *
48   }
51 //--- include/second.modulemap
52 module Second {
53   header "second.h"
54   export *
57 //--- test.m
58 #if defined(FIRST) || defined(SECOND)
59 # include "common.h"
60 #endif
62 #if !defined(FIRST) && !defined(SECOND)
63 # include "first-empty.h"
64 # include "second.h"
65 #endif
67 #if defined(FIRST)
68 @class CompareForwardDeclaration1;
69 @interface CompareForwardDeclaration2: NSObject @end
70 #elif defined(SECOND)
71 @interface CompareForwardDeclaration1: NSObject @end
72 @class CompareForwardDeclaration2;
73 #else
74 CompareForwardDeclaration1 *compareForwardDeclaration1;
75 CompareForwardDeclaration2 *compareForwardDeclaration2;
76 #endif
78 #if defined(FIRST)
79 @interface CompareMatchingSuperclass: NSObject @end
81 @interface CompareSuperclassPresence1: NSObject @end
82 @interface CompareSuperclassPresence2 @end
84 @interface CompareDifferentSuperclass: NSObject @end
85 #elif defined(SECOND)
86 @interface CompareMatchingSuperclass: NSObject @end
88 @interface CompareSuperclassPresence1 @end
89 @interface CompareSuperclassPresence2: NSObject @end
91 @interface DifferentSuperclass: NSObject @end
92 @interface CompareDifferentSuperclass: DifferentSuperclass @end
93 #else
94 CompareMatchingSuperclass *compareMatchingSuperclass;
95 CompareSuperclassPresence1 *compareSuperclassPresence1;
96 // expected-error@first.h:* {{'CompareSuperclassPresence1' has different definitions in different modules; first difference is definition in module 'First.Hidden' found super class with type 'NSObject'}}
97 // expected-note-re@second.h:* {{but in {{'Second'|definition here}} found no super class}}
98 CompareSuperclassPresence2 *compareSuperclassPresence2;
99 // expected-error@first.h:* {{'CompareSuperclassPresence2' has different definitions in different modules; first difference is definition in module 'First.Hidden' found no super class}}
100 // expected-note-re@second.h:* {{but in {{'Second'|definition here}} found super class with type 'NSObject'}}
101 CompareDifferentSuperclass *compareDifferentSuperclass;
102 // expected-error@first.h:* {{'CompareDifferentSuperclass' has different definitions in different modules; first difference is definition in module 'First.Hidden' found super class with type 'NSObject'}}
103 // expected-note-re@second.h:* {{but in {{'Second'|definition here}} found super class with type 'DifferentSuperclass'}}
104 #endif
106 #if defined(FIRST)
107 @interface CompareMatchingConformingProtocols: NSObject<CommonProtocol> @end
108 @protocol ForwardProtocol;
109 @interface CompareMatchingConformingForwardProtocols: NSObject<ForwardProtocol> @end
111 @interface CompareProtocolPresence1: NSObject<CommonProtocol> @end
112 @interface CompareProtocolPresence2: NSObject @end
114 @interface CompareDifferentProtocols: NSObject<CommonProtocol> @end
115 @interface CompareProtocolOrder: NSObject<CommonProtocol, ExtraProtocol> @end
116 #elif defined(SECOND)
117 @interface CompareMatchingConformingProtocols: NSObject<CommonProtocol> @end
118 @protocol ForwardProtocol @end
119 @interface CompareMatchingConformingForwardProtocols: NSObject<ForwardProtocol> @end
121 @interface CompareProtocolPresence1: NSObject @end
122 @interface CompareProtocolPresence2: NSObject<CommonProtocol> @end
124 @interface CompareDifferentProtocols: NSObject<ExtraProtocol> @end
125 @interface CompareProtocolOrder: NSObject<ExtraProtocol, CommonProtocol> @end
126 #else
127 CompareMatchingConformingProtocols *compareMatchingConformingProtocols;
128 CompareMatchingConformingForwardProtocols *compareMatchingConformingForwardProtocols;
130 CompareProtocolPresence1 *compareProtocolPresence1;
131 // expected-error@first.h:* {{'CompareProtocolPresence1' has different definitions in different modules; first difference is definition in module 'First.Hidden' found 1 referenced protocol}}
132 // expected-note-re@second.h:* {{but in {{'Second'|definition here}} found 0 referenced protocols}}
133 CompareProtocolPresence2 *compareProtocolPresence2;
134 // expected-error@first.h:* {{'CompareProtocolPresence2' has different definitions in different modules; first difference is definition in module 'First.Hidden' found 0 referenced protocols}}
135 // expected-note-re@second.h:* {{but in {{'Second'|definition here}} found 1 referenced protocol}}
137 CompareDifferentProtocols *compareDifferentProtocols;
138 // expected-error@first.h:* {{'CompareDifferentProtocols' has different definitions in different modules; first difference is definition in module 'First.Hidden' found 1st referenced protocol with name 'CommonProtocol'}}
139 // expected-note-re@second.h:* {{but in {{'Second'|definition here}} found 1st referenced protocol with different name 'ExtraProtocol'}}
140 CompareProtocolOrder *compareProtocolOrder;
141 // expected-error@first.h:* {{'CompareProtocolOrder' has different definitions in different modules; first difference is definition in module 'First.Hidden' found 1st referenced protocol with name 'CommonProtocol'}}
142 // expected-note-re@second.h:* {{but in {{'Second'|definition here}} found 1st referenced protocol with different name 'ExtraProtocol'}}
143 #endif
145 #if defined(FIRST)
146 @interface CompareMatchingIVars: NSObject { int ivarName; } @end
148 @interface CompareIVarPresence1: NSObject @end
149 @interface CompareIVarPresence2: NSObject { int ivarPresence2; } @end
151 @interface CompareIVarName: NSObject { int ivarName; } @end
152 @interface CompareIVarType: NSObject { int ivarType; } @end
153 @interface CompareIVarOrder: NSObject {
154   int ivarNameInt;
155   float ivarNameFloat;
157 @end
159 @interface CompareIVarVisibilityExplicit: NSObject {
160 @public
161   int ivarVisibility;
163 @end
164 @interface CompareIVarVisibilityDefault: NSObject {
165   int ivarVisibilityDefault;
167 @end
168 #elif defined(SECOND)
169 @interface CompareMatchingIVars: NSObject { int ivarName; } @end
171 @interface CompareIVarPresence1: NSObject { int ivarPresence1; } @end
172 @interface CompareIVarPresence2: NSObject @end
174 @interface CompareIVarName: NSObject { int differentIvarName; } @end
175 @interface CompareIVarType: NSObject { float ivarType; } @end
176 @interface CompareIVarOrder: NSObject {
177   float ivarNameFloat;
178   int ivarNameInt;
180 @end
182 @interface CompareIVarVisibilityExplicit: NSObject {
183 @private
184   int ivarVisibility;
186 @end
187 @interface CompareIVarVisibilityDefault: NSObject {
188 @public
189   int ivarVisibilityDefault;
191 @end
192 #else
193 CompareMatchingIVars *compareMatchingIVars;
195 CompareIVarPresence1 *compareIVarPresence1;
196 #ifdef TEST_MODULAR
197 // expected-error@second.h:* {{'CompareIVarPresence1::ivarPresence1' from module 'Second' is not present in definition of 'CompareIVarPresence1' in module 'First.Hidden'}}
198 // expected-note@first.h:* {{definition has no member 'ivarPresence1'}}
199 #else
200 // expected-error@first.h:* {{'CompareIVarPresence1' has different definitions in different modules; first difference is definition in module 'First.Hidden' found end of class}}
201 // expected-note@second.h:* {{but in definition here found instance variable}}
202 #endif
203 CompareIVarPresence2 *compareIVarPresence2;
204 // expected-error@first.h:* {{'CompareIVarPresence2' has different definitions in different modules; first difference is definition in module 'First.Hidden' found instance variable}}
205 // expected-note-re@second.h:* {{but in {{'Second'|definition here}} found end of class}}
207 CompareIVarName *compareIVarName;
208 #ifdef TEST_MODULAR
209 // expected-error@second.h:* {{'CompareIVarName::differentIvarName' from module 'Second' is not present in definition of 'CompareIVarName' in module 'First.Hidden'}}
210 // expected-note@first.h:* {{definition has no member 'differentIvarName'}}
211 #else
212 // expected-error@first.h:* {{'CompareIVarName' has different definitions in different modules; first difference is definition in module 'First.Hidden' found field 'ivarName'}}
213 // expected-note@second.h:* {{but in definition here found field 'differentIvarName'}}
214 #endif
215 CompareIVarType *compareIVarType;
216 #ifdef TEST_MODULAR
217 // expected-error@second.h:* {{'CompareIVarType::ivarType' from module 'Second' is not present in definition of 'CompareIVarType' in module 'First.Hidden'}}
218 // expected-note@first.h:* {{declaration of 'ivarType' does not match}}
219 #else
220 // expected-error@first.h:* {{'CompareIVarType' has different definitions in different modules; first difference is definition in module 'First.Hidden' found field 'ivarType' with type 'int'}}
221 // expected-note@second.h:* {{but in definition here found field 'ivarType' with type 'float'}}
222 #endif
223 CompareIVarOrder *compareIVarOrder;
224 // expected-error@first.h:* {{'CompareIVarOrder' has different definitions in different modules; first difference is definition in module 'First.Hidden' found field 'ivarNameInt'}}
225 // expected-note-re@second.h:* {{but in {{'Second'|definition here}} found field 'ivarNameFloat'}}
227 CompareIVarVisibilityExplicit *compareIVarVisibilityExplicit;
228 // expected-error@first.h:* {{'CompareIVarVisibilityExplicit' has different definitions in different modules; first difference is definition in module 'First.Hidden' found instance variable 'ivarVisibility' access control is @public}}
229 // expected-note-re@second.h:* {{but in {{'Second'|definition here}} found instance variable 'ivarVisibility' access control is @private}}
230 CompareIVarVisibilityDefault *compareIVarVisibilityDefault;
231 // expected-error@first.h:* {{'CompareIVarVisibilityDefault' has different definitions in different modules; first difference is definition in module 'First.Hidden' found instance variable 'ivarVisibilityDefault' access control is @protected}}
232 // expected-note-re@second.h:* {{but in {{'Second'|definition here}} found instance variable 'ivarVisibilityDefault' access control is @public}}
233 #endif
235 #if defined(FIRST)
236 @interface CompareMatchingMethods: NSObject
237 - (float)matchingMethod:(int)arg;
238 @end
240 @interface CompareMethodPresence1: NSObject
241 - (void)presenceMethod1;
242 @end
243 @interface CompareMethodPresence2: NSObject
244 @end
246 @interface CompareMethodName: NSObject
247 - (void)methodNameA;
248 @end
250 @interface CompareMethodArgCount: NSObject
251 - (void)methodArgCount:(int)arg0 :(int)arg1;
252 @end
253 @interface CompareMethodArgName: NSObject
254 - (void)methodArgName:(int)argNameA;
255 @end
256 @interface CompareMethodArgType: NSObject
257 - (void)methodArgType:(int)argType;
258 @end
260 @interface CompareMethodReturnType: NSObject
261 - (int)methodReturnType;
262 @end
264 @interface CompareMethodOrder: NSObject
265 - (void)methodOrderFirst;
266 - (void)methodOrderSecond;
267 @end
269 @interface CompareMethodClassInstance: NSObject
270 + (void)methodClassInstance;
271 @end
272 #elif defined(SECOND)
273 @interface CompareMatchingMethods: NSObject
274 - (float)matchingMethod:(int)arg;
275 @end
277 @interface CompareMethodPresence1: NSObject
278 @end
279 @interface CompareMethodPresence2: NSObject
280 - (void)presenceMethod2;
281 @end
283 @interface CompareMethodName: NSObject
284 - (void)methodNameB;
285 @end
287 @interface CompareMethodArgCount: NSObject
288 - (void)methodArgCount:(int)arg0;
289 @end
290 @interface CompareMethodArgName: NSObject
291 - (void)methodArgName:(int)argNameB;
292 @end
293 @interface CompareMethodArgType: NSObject
294 - (void)methodArgType:(float)argType;
295 @end
297 @interface CompareMethodReturnType: NSObject
298 - (float)methodReturnType;
299 @end
301 @interface CompareMethodOrder: NSObject
302 - (void)methodOrderSecond;
303 - (void)methodOrderFirst;
304 @end
306 @interface CompareMethodClassInstance: NSObject
307 - (void)methodClassInstance;
308 @end
309 #else
310 CompareMatchingMethods *compareMatchingMethods;
311 CompareMethodPresence1 *compareMethodPresence1;
312 // expected-error@first.h:* {{'CompareMethodPresence1' has different definitions in different modules; first difference is definition in module 'First.Hidden' found method}}
313 // expected-note-re@second.h:* {{but in {{'Second'|definition here}} found end of class}}
314 CompareMethodPresence2 *compareMethodPresence2;
315 // expected-error@first.h:* {{'CompareMethodPresence2' has different definitions in different modules; first difference is definition in module 'First.Hidden' found end of class}}
316 // expected-note-re@second.h:* {{but in {{'Second'|definition here}} found method}}
317 CompareMethodName *compareMethodName;
318 // expected-error@first.h:* {{'CompareMethodName' has different definitions in different modules; first difference is definition in module 'First.Hidden' found method 'methodNameA'}}
319 // expected-note-re@second.h:* {{but in {{'Second'|definition here}} found different method 'methodNameB'}}
321 CompareMethodArgCount *compareMethodArgCount;
322 // expected-error@first.h:* {{'CompareMethodArgCount' has different definitions in different modules; first difference is definition in module 'First.Hidden' found method 'methodArgCount::' that has 2 parameters}}
323 // expected-note-re@second.h:* {{but in {{'Second'|definition here}} found method 'methodArgCount:' that has 1 parameter}}
324 CompareMethodArgName *compareMethodArgName;
325 // expected-error@first.h:* {{'CompareMethodArgName' has different definitions in different modules; first difference is definition in module 'First.Hidden' found method 'methodArgName:' with 1st parameter named 'argNameA'}}
326 // expected-note-re@second.h:* {{but in {{'Second'|definition here}} found method 'methodArgName:' with 1st parameter named 'argNameB'}}
327 CompareMethodArgType *compareMethodArgType;
328 // expected-error@first.h:* {{'CompareMethodArgType' has different definitions in different modules; first difference is definition in module 'First.Hidden' found method 'methodArgType:' with 1st parameter of type 'int'}}
329 // expected-note-re@second.h:* {{but in {{'Second'|definition here}} found method 'methodArgType:' with 1st parameter of type 'float'}}
331 CompareMethodReturnType *compareMethodReturnType;
332 // expected-error@first.h:* {{'CompareMethodReturnType' has different definitions in different modules; first difference is definition in module 'First.Hidden' found method 'methodReturnType' with return type 'int'}}
333 // expected-note-re@second.h:* {{but in {{'Second'|definition here}} found method 'methodReturnType' with different return type 'float'}}
335 CompareMethodOrder *compareMethodOrder;
336 // expected-error@first.h:* {{'CompareMethodOrder' has different definitions in different modules; first difference is definition in module 'First.Hidden' found method 'methodOrderFirst'}}
337 // expected-note-re@second.h:* {{but in {{'Second'|definition here}} found different method 'methodOrderSecond'}}
338 CompareMethodClassInstance *compareMethodClassInstance;
339 // expected-error@first.h:* {{'CompareMethodClassInstance' has different definitions in different modules; first difference is definition in module 'First.Hidden' found class method 'methodClassInstance'}}
340 // expected-note-re@second.h:* {{but in {{'Second'|definition here}} found method 'methodClassInstance' as instance method}}
341 #endif
343 #if defined(FIRST)
344 @interface CompareMatchingProperties: NSObject
345 @property int matchingPropName;
346 @end
348 @interface ComparePropertyPresence1: NSObject
349 @property int propPresence1;
350 @end
351 @interface ComparePropertyPresence2: NSObject
352 @end
354 @interface ComparePropertyName: NSObject
355 @property int propNameA;
356 @end
358 @interface ComparePropertyType: NSObject
359 @property int propType;
360 @end
362 @interface ComparePropertyOrder: NSObject
363 @property int propOrderX;
364 @property int propOrderY;
365 @end
367 @interface CompareMatchingPropertyAttributes: NSObject
368 @property (nonatomic, assign) int matchingProp;
369 @end
370 @interface ComparePropertyAttributes: NSObject
371 @property (readonly) int propAttributes;
372 @end
373 // Edge cases.
374 @interface CompareFirstImplAttribute: NSObject
375 @property int firstImplAttribute;
376 @end
377 @interface CompareLastImplAttribute: NSObject
378 @property (direct) int lastImplAttribute;
379 @end
380 #elif defined(SECOND)
381 @interface CompareMatchingProperties: NSObject
382 @property int matchingPropName;
383 @end
385 @interface ComparePropertyPresence1: NSObject
386 @end
387 @interface ComparePropertyPresence2: NSObject
388 @property int propPresence2;
389 @end
391 @interface ComparePropertyName: NSObject
392 @property int propNameB;
393 @end
395 @interface ComparePropertyType: NSObject
396 @property float propType;
397 @end
399 @interface ComparePropertyOrder: NSObject
400 @property int propOrderY;
401 @property int propOrderX;
402 @end
404 @interface CompareMatchingPropertyAttributes: NSObject
405 @property (assign, nonatomic) int matchingProp;
406 @end
407 @interface ComparePropertyAttributes: NSObject
408 @property (readwrite) int propAttributes;
409 @end
410 // Edge cases.
411 @interface CompareFirstImplAttribute: NSObject
412 @property (readonly) int firstImplAttribute;
413 @end
414 @interface CompareLastImplAttribute: NSObject
415 @property int lastImplAttribute;
416 @end
417 #else
418 CompareMatchingProperties *compareMatchingProperties;
419 ComparePropertyPresence1 *comparePropertyPresence1;
420 // expected-error@first.h:* {{'ComparePropertyPresence1' has different definitions in different modules; first difference is definition in module 'First.Hidden' found property}}
421 // expected-note-re@second.h:* {{but in {{'Second'|definition here}} found end of class}}
422 ComparePropertyPresence2 *comparePropertyPresence2;
423 // expected-error@first.h:* {{'ComparePropertyPresence2' has different definitions in different modules; first difference is definition in module 'First.Hidden' found end of class}}
424 // expected-note-re@second.h:* {{but in {{'Second'|definition here}} found property}}
426 ComparePropertyName *comparePropertyName;
427 // expected-error@first.h:* {{'ComparePropertyName' has different definitions in different modules; first difference is definition in module 'First.Hidden' found property 'propNameA'}}
428 // expected-note-re@second.h:* {{but in {{'Second'|definition here}} found property 'propNameB'}}
429 ComparePropertyType *comparePropertyType;
430 // expected-error@first.h:* {{'ComparePropertyType' has different definitions in different modules; first difference is definition in module 'First.Hidden' found property 'propType' with type 'int'}}
431 // expected-note-re@second.h:* {{but in {{'Second'|definition here}} found property 'propType' with type 'float'}}
432 ComparePropertyOrder *comparePropertyOrder;
433 // expected-error@first.h:* {{'ComparePropertyOrder' has different definitions in different modules; first difference is definition in module 'First.Hidden' found property 'propOrderX'}}
434 // expected-note-re@second.h:* {{but in {{'Second'|definition here}} found property 'propOrderY'}}
436 CompareMatchingPropertyAttributes *compareMatchingPropertyAttributes;
437 ComparePropertyAttributes *comparePropertyAttributes;
438 // expected-error@first.h:* {{'ComparePropertyAttributes' has different definitions in different modules; first difference is definition in module 'First.Hidden' found property 'propAttributes' with 'readonly' attribute}}
439 // expected-note-re@second.h:* {{but in {{'Second'|definition here}} found property 'propAttributes' with different 'readonly' attribute}}
440 CompareFirstImplAttribute *compareFirstImplAttribute;
441 // expected-error@first.h:* {{'CompareFirstImplAttribute' has different definitions in different modules; first difference is definition in module 'First.Hidden' found property 'firstImplAttribute' with default 'readonly' attribute}}
442 // expected-note-re@second.h:* {{but in {{'Second'|definition here}} found property 'firstImplAttribute' with different 'readonly' attribute}}
443 CompareLastImplAttribute *compareLastImplAttribute;
444 // expected-error@first.h:* {{'CompareLastImplAttribute' has different definitions in different modules; first difference is definition in module 'First.Hidden' found property 'lastImplAttribute' with 'direct' attribute}}
445 // expected-note-re@second.h:* {{but in {{'Second'|definition here}} found property 'lastImplAttribute' with different 'direct' attribute}}
446 #endif
448 #if defined(FIRST)
449 @interface CompareMatchingCategories: NSObject @end
450 @interface CompareMatchingCategories(Matching)
451 - (int)testMethod;
452 @end
454 @interface CompareMismatchingCategories1: NSObject @end
455 @interface CompareMismatchingCategories1(Category1)
456 - (void)presentMethod;
457 @end
458 @interface CompareMismatchingCategories2: NSObject @end
459 @interface CompareMismatchingCategories2(Category2)
460 @end
462 @interface CompareDifferentCategoryNames: NSObject @end
463 @interface CompareDifferentCategoryNames(CategoryFirst)
464 - (void)firstMethod:(int)x;
465 @end
466 #elif defined(SECOND)
467 @interface CompareMatchingCategories: NSObject @end
468 @interface CompareMatchingCategories(Matching)
469 - (int)testMethod;
470 @end
472 @interface CompareMismatchingCategories1: NSObject @end
473 @interface CompareMismatchingCategories1(Category1)
474 @end
475 @interface CompareMismatchingCategories2: NSObject @end
476 @interface CompareMismatchingCategories2(Category2)
477 - (void)presentMethod;
478 @end
480 @interface CompareDifferentCategoryNames: NSObject @end
481 @interface CompareDifferentCategoryNames(CategorySecond)
482 - (void)secondMethod;
483 @end
484 #else
485 CompareMatchingCategories *compareMatchingCategories; // no diagnostic
486 CompareMismatchingCategories1 *compareMismatchingCategories1;
487 #ifdef TEST_MODULAR
488 // expected-warning@second.h:* {{duplicate definition of category 'Category1' on interface 'CompareMismatchingCategories1'}}
489 // expected-note@first.h:* {{previous definition is here}}
490 #endif
491 CompareMismatchingCategories2 *compareMismatchingCategories2;
492 #ifdef TEST_MODULAR
493 // expected-warning@second.h:* {{duplicate definition of category 'Category2' on interface 'CompareMismatchingCategories2'}}
494 // expected-note@first.h:* {{previous definition is here}}
495 #endif
496 CompareDifferentCategoryNames *compareDifferentCategoryNames; // no diagnostic
497 #endif