xref: /llvm-project/clang/test/Modules/compare-objc-interface.m (revision 2893d55f8f61edb2c253b960cab1107ea6c163c2)
1// RUN: rm -rf %t
2// RUN: split-file %s %t
3
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
8
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
13
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
17
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
21
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
26
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.
30
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
38
39//--- include/first-empty.h
40//--- include/module.modulemap
41module First {
42  module Empty {
43    header "first-empty.h"
44  }
45  module Hidden {
46    header "first.h"
47    export *
48  }
49}
50
51//--- include/second.modulemap
52module Second {
53  header "second.h"
54  export *
55}
56
57//--- test.m
58#if defined(FIRST) || defined(SECOND)
59# include "common.h"
60#endif
61
62#if !defined(FIRST) && !defined(SECOND)
63# include "first-empty.h"
64# include "second.h"
65#endif
66
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
74CompareForwardDeclaration1 *compareForwardDeclaration1;
75CompareForwardDeclaration2 *compareForwardDeclaration2;
76#endif
77
78#if defined(FIRST)
79@interface CompareMatchingSuperclass: NSObject @end
80
81@interface CompareSuperclassPresence1: NSObject @end
82@interface CompareSuperclassPresence2 @end
83
84@interface CompareDifferentSuperclass: NSObject @end
85#elif defined(SECOND)
86@interface CompareMatchingSuperclass: NSObject @end
87
88@interface CompareSuperclassPresence1 @end
89@interface CompareSuperclassPresence2: NSObject @end
90
91@interface DifferentSuperclass: NSObject @end
92@interface CompareDifferentSuperclass: DifferentSuperclass @end
93#else
94CompareMatchingSuperclass *compareMatchingSuperclass;
95CompareSuperclassPresence1 *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}}
98CompareSuperclassPresence2 *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'}}
101CompareDifferentSuperclass *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
105
106#if defined(FIRST)
107@interface CompareMatchingConformingProtocols: NSObject<CommonProtocol> @end
108@protocol ForwardProtocol;
109@interface CompareMatchingConformingForwardProtocols: NSObject<ForwardProtocol> @end
110
111@interface CompareProtocolPresence1: NSObject<CommonProtocol> @end
112@interface CompareProtocolPresence2: NSObject @end
113
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
120
121@interface CompareProtocolPresence1: NSObject @end
122@interface CompareProtocolPresence2: NSObject<CommonProtocol> @end
123
124@interface CompareDifferentProtocols: NSObject<ExtraProtocol> @end
125@interface CompareProtocolOrder: NSObject<ExtraProtocol, CommonProtocol> @end
126#else
127CompareMatchingConformingProtocols *compareMatchingConformingProtocols;
128CompareMatchingConformingForwardProtocols *compareMatchingConformingForwardProtocols;
129
130CompareProtocolPresence1 *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}}
133CompareProtocolPresence2 *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}}
136
137CompareDifferentProtocols *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'}}
140CompareProtocolOrder *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
144
145#if defined(FIRST)
146@interface CompareMatchingIVars: NSObject { int ivarName; } @end
147
148@interface CompareIVarPresence1: NSObject @end
149@interface CompareIVarPresence2: NSObject { int ivarPresence2; } @end
150
151@interface CompareIVarName: NSObject { int ivarName; } @end
152@interface CompareIVarType: NSObject { int ivarType; } @end
153@interface CompareIVarOrder: NSObject {
154  int ivarNameInt;
155  float ivarNameFloat;
156}
157@end
158
159@interface CompareIVarVisibilityExplicit: NSObject {
160@public
161  int ivarVisibility;
162}
163@end
164@interface CompareIVarVisibilityDefault: NSObject {
165  int ivarVisibilityDefault;
166}
167@end
168#elif defined(SECOND)
169@interface CompareMatchingIVars: NSObject { int ivarName; } @end
170
171@interface CompareIVarPresence1: NSObject { int ivarPresence1; } @end
172@interface CompareIVarPresence2: NSObject @end
173
174@interface CompareIVarName: NSObject { int differentIvarName; } @end
175@interface CompareIVarType: NSObject { float ivarType; } @end
176@interface CompareIVarOrder: NSObject {
177  float ivarNameFloat;
178  int ivarNameInt;
179}
180@end
181
182@interface CompareIVarVisibilityExplicit: NSObject {
183@private
184  int ivarVisibility;
185}
186@end
187@interface CompareIVarVisibilityDefault: NSObject {
188@public
189  int ivarVisibilityDefault;
190}
191@end
192#else
193CompareMatchingIVars *compareMatchingIVars;
194
195CompareIVarPresence1 *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
203CompareIVarPresence2 *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}}
206
207CompareIVarName *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
215CompareIVarType *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
223CompareIVarOrder *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'}}
226
227CompareIVarVisibilityExplicit *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}}
230CompareIVarVisibilityDefault *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
234
235#if defined(FIRST)
236@interface CompareMatchingMethods: NSObject
237- (float)matchingMethod:(int)arg;
238@end
239
240@interface CompareMethodPresence1: NSObject
241- (void)presenceMethod1;
242@end
243@interface CompareMethodPresence2: NSObject
244@end
245
246@interface CompareMethodName: NSObject
247- (void)methodNameA;
248@end
249
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
259
260@interface CompareMethodReturnType: NSObject
261- (int)methodReturnType;
262@end
263
264@interface CompareMethodOrder: NSObject
265- (void)methodOrderFirst;
266- (void)methodOrderSecond;
267@end
268
269@interface CompareMethodClassInstance: NSObject
270+ (void)methodClassInstance;
271@end
272#elif defined(SECOND)
273@interface CompareMatchingMethods: NSObject
274- (float)matchingMethod:(int)arg;
275@end
276
277@interface CompareMethodPresence1: NSObject
278@end
279@interface CompareMethodPresence2: NSObject
280- (void)presenceMethod2;
281@end
282
283@interface CompareMethodName: NSObject
284- (void)methodNameB;
285@end
286
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
296
297@interface CompareMethodReturnType: NSObject
298- (float)methodReturnType;
299@end
300
301@interface CompareMethodOrder: NSObject
302- (void)methodOrderSecond;
303- (void)methodOrderFirst;
304@end
305
306@interface CompareMethodClassInstance: NSObject
307- (void)methodClassInstance;
308@end
309#else
310CompareMatchingMethods *compareMatchingMethods;
311CompareMethodPresence1 *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}}
314CompareMethodPresence2 *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}}
317CompareMethodName *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'}}
320
321CompareMethodArgCount *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}}
324CompareMethodArgName *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'}}
327CompareMethodArgType *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'}}
330
331CompareMethodReturnType *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'}}
334
335CompareMethodOrder *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'}}
338CompareMethodClassInstance *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
342
343#if defined(FIRST)
344@interface CompareMatchingProperties: NSObject
345@property int matchingPropName;
346@end
347
348@interface ComparePropertyPresence1: NSObject
349@property int propPresence1;
350@end
351@interface ComparePropertyPresence2: NSObject
352@end
353
354@interface ComparePropertyName: NSObject
355@property int propNameA;
356@end
357
358@interface ComparePropertyType: NSObject
359@property int propType;
360@end
361
362@interface ComparePropertyOrder: NSObject
363@property int propOrderX;
364@property int propOrderY;
365@end
366
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
384
385@interface ComparePropertyPresence1: NSObject
386@end
387@interface ComparePropertyPresence2: NSObject
388@property int propPresence2;
389@end
390
391@interface ComparePropertyName: NSObject
392@property int propNameB;
393@end
394
395@interface ComparePropertyType: NSObject
396@property float propType;
397@end
398
399@interface ComparePropertyOrder: NSObject
400@property int propOrderY;
401@property int propOrderX;
402@end
403
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
418CompareMatchingProperties *compareMatchingProperties;
419ComparePropertyPresence1 *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}}
422ComparePropertyPresence2 *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}}
425
426ComparePropertyName *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'}}
429ComparePropertyType *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'}}
432ComparePropertyOrder *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'}}
435
436CompareMatchingPropertyAttributes *compareMatchingPropertyAttributes;
437ComparePropertyAttributes *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}}
440CompareFirstImplAttribute *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}}
443CompareLastImplAttribute *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
447
448#if defined(FIRST)
449@interface CompareMatchingCategories: NSObject @end
450@interface CompareMatchingCategories(Matching)
451- (int)testMethod;
452@end
453
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
461
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
471
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
479
480@interface CompareDifferentCategoryNames: NSObject @end
481@interface CompareDifferentCategoryNames(CategorySecond)
482- (void)secondMethod;
483@end
484#else
485CompareMatchingCategories *compareMatchingCategories; // no diagnostic
486CompareMismatchingCategories1 *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
491CompareMismatchingCategories2 *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
496CompareDifferentCategoryNames *compareDifferentCategoryNames; // no diagnostic
497#endif
498