1#include "Test.h"
2#include <stdlib.h>
3#include <stdio.h>
4#include <string.h>
5#include <assert.h>
6#include <stdatomic.h>
7
8#pragma GCC diagnostic ignored "-Wobjc-property-no-attribute"
9
10// Clang < 3 doesn't exist usefully, so we can skip tests for it.  Clang 3.5
11// adds proper metadata for weak properties, earlier ones don't, so don't fail
12// the tests because of known compiler bugs.
13#ifndef __clang_minor__
14#define WEAK_ATTR ATTR("W", ""),
15#define WEAK_STR "W,"
16#elif (__clang_major__ < 4) && (__clang_minor__ < 5)
17#define WEAK_ATTR
18#define WEAK_STR
19#else
20#define WEAK_ATTR ATTR("W", ""),
21#define WEAK_STR "W,"
22#endif
23
24enum FooManChu { FOO, MAN, CHU };
25struct YorkshireTeaStruct { int pot; signed char lady; };
26typedef struct YorkshireTeaStruct YorkshireTeaStructType;
27union MoneyUnion { float alone; double down; };
28
29#ifndef __has_attribute
30#define __has_attribute(x)  0
31#endif
32
33#if __has_attribute(objc_root_class)
34__attribute__((objc_root_class))
35#endif
36@interface PropertyTest
37{
38@public
39	Class isa;
40	atomic_bool atomicBoolDefault;
41	signed char charDefault;
42	double doubleDefault;
43	enum FooManChu enumDefault;
44	float floatDefault;
45	int intDefault;
46	long longDefault;
47	short shortDefault;
48	signed signedDefault;
49	struct YorkshireTeaStruct structDefault;
50	YorkshireTeaStructType typedefDefault;
51	union MoneyUnion unionDefault;
52	unsigned unsignedDefault;
53	int (*functionPointerDefault)(char *);
54	int *intPointer;
55	void *voidPointerDefault;
56	int intSynthEquals;
57	int intSetterGetter;
58	int intReadonly;
59	int intReadonlyGetter;
60	int intReadwrite;
61	int intAssign;
62	__unsafe_unretained id idDefault;
63	id idRetain;
64	id idCopy;
65	__weak id idWeak;
66	id idStrong;
67	int intNonatomic;
68	id idReadonlyCopyNonatomic;
69	id idReadonlyRetainNonatomic;
70	__weak id idReadonlyWeakNonatomic;
71	id _idOther;
72}
73@property atomic_bool atomicBoolDefault;
74@property signed char charDefault;
75@property double doubleDefault;
76@property enum FooManChu enumDefault;
77@property float floatDefault;
78@property int intDefault;
79@property long longDefault;
80@property short shortDefault;
81@property signed signedDefault;
82@property struct YorkshireTeaStruct structDefault;
83@property YorkshireTeaStructType typedefDefault;
84@property union MoneyUnion unionDefault;
85@property unsigned unsignedDefault;
86@property int (*functionPointerDefault)(char *);
87@property int *intPointer;
88@property void *voidPointerDefault;
89@property(getter=intGetFoo, setter=intSetFoo:) int intSetterGetter;
90@property(readonly) int intReadonly;
91@property(getter=isIntReadOnlyGetter, readonly) int intReadonlyGetter;
92@property(readwrite) int intReadwrite;
93@property(assign) int intAssign;
94@property(unsafe_unretained) id idDefault;
95@property(retain) id idRetain;
96@property(copy) id idCopy;
97@property(weak) id idWeak;
98@property(strong) id idStrong;
99@property(nonatomic) int intNonatomic;
100@property(nonatomic, readonly, copy) id idReadonlyCopyNonatomic;
101@property(nonatomic, readonly, retain) id idReadonlyRetainNonatomic;
102@property(nonatomic, readonly, weak) id idReadonlyWeakNonatomic;
103@property(retain) id idOther;
104@property(retain) id idDynamic;
105@property(retain, nonatomic, getter=dynamicGetterSetter, setter=setDynamicGetterSetter:) id idDynamicGetterSetter;
106@end
107
108@interface PropertyTest (Informal)
109- (void)setStructDefault2: (struct YorkshireTeaStruct)tp;
110- (void)setIntDefault2: (int)i;
111- (struct YorkshireTeaStruct)structDefault2;
112- (int)intDefault2;
113@end
114
115
116@implementation PropertyTest
117@synthesize atomicBoolDefault;
118@synthesize charDefault;
119@synthesize doubleDefault;
120@synthesize enumDefault;
121@synthesize floatDefault;
122@synthesize intDefault;
123@synthesize longDefault;
124@synthesize shortDefault;
125@synthesize signedDefault;
126@synthesize structDefault;
127@synthesize typedefDefault;
128@synthesize unionDefault;
129@synthesize unsignedDefault;
130@synthesize functionPointerDefault;
131@synthesize intPointer;
132@synthesize voidPointerDefault;
133@synthesize intSetterGetter;
134@synthesize intReadonly;
135@synthesize intReadonlyGetter;
136@synthesize intReadwrite;
137@synthesize intAssign;
138@synthesize idDefault;
139@synthesize idRetain;
140@synthesize idCopy;
141@synthesize idWeak;
142@synthesize idStrong;
143@synthesize intNonatomic;
144@synthesize idReadonlyCopyNonatomic;
145@synthesize idReadonlyRetainNonatomic;
146@synthesize idReadonlyWeakNonatomic;
147@synthesize idOther = _idOther;
148@dynamic idDynamic;
149@dynamic idDynamicGetterSetter;
150- (void)_ARCCompliantRetainRelease {}
151@end
152
153@protocol ProtocolTest
154@property atomic_bool atomicBoolDefault;
155@property signed char charDefault;
156@property double doubleDefault;
157@property enum FooManChu enumDefault;
158@property float floatDefault;
159@property int intDefault;
160@property long longDefault;
161@property short shortDefault;
162@property signed signedDefault;
163@property struct YorkshireTeaStruct structDefault;
164@property YorkshireTeaStructType typedefDefault;
165@property union MoneyUnion unionDefault;
166@property unsigned unsignedDefault;
167@property int (*functionPointerDefault)(char *);
168@property int *intPointer;
169@property void *voidPointerDefault;
170@property(getter=intGetFoo, setter=intSetFoo:) int intSetterGetter;
171@property(readonly) int intReadonly;
172@property(getter=isIntReadOnlyGetter, readonly) int intReadonlyGetter;
173@property(readwrite) int intReadwrite;
174@property(assign) int intAssign;
175@property(unsafe_unretained) id idDefault;
176@property(retain) id idRetain;
177@property(copy) id idCopy;
178@property(weak) id idWeak;
179@property(strong) id idStrong;
180@property(nonatomic) int intNonatomic;
181@property(nonatomic, readonly, copy) id idReadonlyCopyNonatomic;
182@property(nonatomic, readonly, retain) id idReadonlyRetainNonatomic;
183@property(nonatomic, readonly, weak) id idReadonlyWeakNonatomic;
184@property(retain) id idOther;
185@property(retain) id idDynamic;
186@property(retain, nonatomic, getter=dynamicGetterSetter, setter=setDynamicGetterSetter:) id idDynamicGetterSetter;
187@end
188
189#if __has_attribute(objc_root_class)
190__attribute__((objc_root_class))
191#endif
192@interface PropertyProtocolTest <ProtocolTest>
193{
194	Class isa;
195	atomic_bool atomicBoolDefault;
196	signed char charDefault;
197	double doubleDefault;
198	enum FooManChu enumDefault;
199	float floatDefault;
200	int intDefault;
201	long longDefault;
202	short shortDefault;
203	signed signedDefault;
204	struct YorkshireTeaStruct structDefault;
205	YorkshireTeaStructType typedefDefault;
206	union MoneyUnion unionDefault;
207	unsigned unsignedDefault;
208	int (*functionPointerDefault)(char *);
209	int *intPointer;
210	void *voidPointerDefault;
211	int intSynthEquals;
212	int intSetterGetter;
213	int intReadonly;
214	int intReadonlyGetter;
215	int intReadwrite;
216	int intAssign;
217	__unsafe_unretained id idDefault;
218	id idRetain;
219	id idCopy;
220	__weak id idWeak;
221	id idStrong;
222	int intNonatomic;
223	id idReadonlyCopyNonatomic;
224	id idReadonlyRetainNonatomic;
225	__weak id idReadonlyWeakNonatomic;
226	id _idOther;
227}
228@end
229
230@implementation PropertyProtocolTest
231@synthesize atomicBoolDefault;
232@synthesize charDefault;
233@synthesize doubleDefault;
234@synthesize enumDefault;
235@synthesize floatDefault;
236@synthesize intDefault;
237@synthesize longDefault;
238@synthesize shortDefault;
239@synthesize signedDefault;
240@synthesize structDefault;
241@synthesize typedefDefault;
242@synthesize unionDefault;
243@synthesize unsignedDefault;
244@synthesize functionPointerDefault;
245@synthesize intPointer;
246@synthesize voidPointerDefault;
247@synthesize intSetterGetter;
248@synthesize intReadonly;
249@synthesize intReadonlyGetter;
250@synthesize intReadwrite;
251@synthesize intAssign;
252@synthesize idDefault;
253@synthesize idRetain;
254@synthesize idCopy;
255@synthesize idWeak;
256@synthesize idStrong;
257@synthesize intNonatomic;
258@synthesize idReadonlyCopyNonatomic;
259@synthesize idReadonlyRetainNonatomic;
260@synthesize idReadonlyWeakNonatomic;
261@synthesize idOther = _idOther;
262@dynamic idDynamic;
263@dynamic idDynamicGetterSetter;
264- (void)_ARCCompliantRetainRelease {}
265@end
266
267#define ATTR(n, v)  (objc_property_attribute_t){(n), (v)}
268#define ATTRS(...)  (objc_property_attribute_t[]){ __VA_ARGS__ }, \
269						sizeof((objc_property_attribute_t[]){ __VA_ARGS__ }) / sizeof(objc_property_attribute_t)
270#define OPT_ASSERT(stmt) if (abort) { \
271	assert(stmt);\
272} else { \
273	if (!(stmt)) { return NO; } \
274}
275
276static BOOL testPropertyForProperty_alt(objc_property_t p,
277									const char *name,
278									const char *types,
279									objc_property_attribute_t* list,
280									unsigned int size, BOOL abort)
281{
282	OPT_ASSERT(0 != p);
283	OPT_ASSERT(strcmp(name, property_getName(p)) == 0);
284	const char *attrs = property_getAttributes(p);
285	OPT_ASSERT(0 != attrs);
286	OPT_ASSERT(strcmp(types, attrs) == 0);
287	unsigned int attrsCount = 0;
288	objc_property_attribute_t *attrsList = property_copyAttributeList(p, &attrsCount);
289	OPT_ASSERT(0 != attrsList);
290        OPT_ASSERT(attrsCount == size);
291    for (unsigned int index=0; index<size; index++) {
292        int found = 0;
293        for (unsigned int attrsIndex=0; attrsIndex<attrsCount; attrsIndex++) {
294            if (strcmp(attrsList[attrsIndex].name, list[index].name) == 0) {
295                OPT_ASSERT(strcmp(attrsList[attrsIndex].value, list[index].value) == 0);
296                found = 1;
297            }
298        }
299        OPT_ASSERT(found);
300    }
301	free(attrsList);
302	attrsList = property_copyAttributeList(p, NULL);
303	OPT_ASSERT(0 != attrsList);
304	objc_property_attribute_t *ra;
305	for (attrsCount = 0, ra = attrsList; (ra->name != NULL) && (attrsCount < size); attrsCount++, ra++) {}
306    OPT_ASSERT(attrsCount == size);
307	free(attrsList);
308    for (unsigned int index=0; index<size; index++) {
309        const char* value = property_copyAttributeValue(p, list[index].name);
310        OPT_ASSERT(0 != value);
311        OPT_ASSERT(strcmp(value, list[index].value) == 0);
312    }
313    return YES;
314}
315
316
317static void testPropertyForProperty(objc_property_t p,
318									const char *name,
319									const char *types,
320									objc_property_attribute_t* list,
321									unsigned int size)
322{
323	testPropertyForProperty_alt(p, name, types, list, size, YES);
324}
325
326static void testPropertyForClass(Class testClass,
327								 const char *name,
328								 const char *types,
329								 objc_property_attribute_t* list,
330								 unsigned int size)
331{
332    testPropertyForProperty(class_getProperty(testClass, name), name, types, list, size);
333
334	static int addPropertyForClassIndex = 0;
335	char addPropertyName[32];
336	sprintf(addPropertyName, "addPropertyForClass%d", ++addPropertyForClassIndex);
337    assert(class_addProperty(testClass, addPropertyName, list, size));
338    testPropertyForProperty(class_getProperty(testClass, addPropertyName), addPropertyName, types, list, size);
339}
340
341static BOOL testPropertyForProtocol_alt(Protocol *testProto,
342									const char *name,
343									const char *types,
344									objc_property_attribute_t* list,
345									unsigned int size, BOOL abort)
346{
347    if (!testPropertyForProperty_alt(protocol_getProperty(testProto, name, YES, YES), name, types, list, size, abort))
348	{
349			return NO;
350	}
351
352   	static int addPropertyForProtocolIndex = 0;
353	char addPropertyName[32];
354	sprintf(addPropertyName, "addPropertyForProtocol%d", ++addPropertyForProtocolIndex);
355	protocol_addProperty(testProto, addPropertyName, list, size, YES, YES);
356	OPT_ASSERT(0 == protocol_getProperty(testProto, addPropertyName, YES, YES));
357	return YES;
358}
359
360static void testPropertyForProtocol(Protocol *testProto,
361									const char *name,
362									const char *types,
363									objc_property_attribute_t* list,
364									unsigned int size)
365{
366		testPropertyForProtocol_alt(testProto, name, types, list, size, YES);
367}
368
369static BOOL testProperty_alt(const char *name, const char *types, objc_property_attribute_t* list, unsigned int size, BOOL abort)
370{
371    return testPropertyForProperty_alt(class_getProperty(objc_getClass("PropertyTest"), name), name, types, list, size, abort)
372	    && testPropertyForProperty_alt(class_getProperty(objc_getClass("PropertyProtocolTest"), name), name, types, list, size, abort);
373}
374
375static void testProperty(const char *name, const char *types, objc_property_attribute_t* list, unsigned int size)
376{
377  testProperty_alt(name, types, list, size, YES);
378}
379
380static void testAddPropertyForClass(Class testClass)
381{
382    objc_property_attribute_t emptyType = { "T", "i" };
383    assert(!class_addProperty(testClass, NULL, &emptyType, 1));
384    class_replaceProperty(testClass, NULL, &emptyType, 1);
385
386    assert(class_addProperty(testClass, "addProperty1", ATTRS(ATTR("T", "@"))));
387	testPropertyForProperty(class_getProperty(testClass, "addProperty1"),
388							"addProperty1", "T@", ATTRS(ATTR("T", "@")));
389
390    assert(class_addProperty(testClass, "addProperty2", ATTRS(ATTR("T", "@"),
391															  ATTR("D", ""))));
392	testPropertyForProperty(class_getProperty(testClass, "addProperty2"),
393							"addProperty2", "T@,D", ATTRS(ATTR("T", "@"),
394														  ATTR("D", "")));
395
396    assert(class_addProperty(testClass, "addProperty3", ATTRS(ATTR("T", "@"),
397															  ATTR("D", ""),
398															  ATTR("V", "backingIvar"))));
399	testPropertyForProperty(class_getProperty(testClass, "addProperty3"),
400							"addProperty3", "T@,D,VbackingIvar", ATTRS(ATTR("T", "@"),
401																	   ATTR("D", ""),
402																	   ATTR("V", "backingIvar")));
403
404    assert(class_addProperty(testClass, "addProperty4", ATTRS(ATTR("T", "@"),
405															  ATTR("R", ""),
406															  ATTR("&", ""),
407															  ATTR("C", ""),
408															  WEAK_ATTR
409															  ATTR("D", ""),
410															  ATTR("V", "backingIvar"))));
411	testPropertyForProperty(class_getProperty(testClass, "addProperty4"),
412							"addProperty4", "T@,R,&,C," WEAK_STR "D,VbackingIvar", ATTRS(ATTR("T", "@"),
413																			   ATTR("R", ""),
414																			   ATTR("&", ""),
415																			   ATTR("C", ""),
416																			   WEAK_ATTR
417																			   ATTR("D", ""),
418																			   ATTR("V", "backingIvar")));
419
420    assert(class_addProperty(testClass, "addProperty5", ATTRS(ATTR("T", "@"),
421															  ATTR("D", ""),
422															  WEAK_ATTR
423															  ATTR("C", ""),
424															  ATTR("&", ""),
425															  ATTR("R", ""),
426															  ATTR("V", "backingIvar"))));
427	// The only concession to MacOS X is that we reorder the attributes string
428	if (!testPropertyForProperty_alt(class_getProperty(testClass, "addProperty5"),
429							"addProperty5", "T@,D," WEAK_STR "C,&,R,VbackingIvar", ATTRS(ATTR("T", "@"),
430																			   ATTR("D", ""),
431																			   WEAK_ATTR
432																			   ATTR("C", ""),
433																			   ATTR("&", ""),
434																			   ATTR("R", ""),
435																			   ATTR("V", "backingIvar")), NO))
436	{
437		testPropertyForProperty(class_getProperty(testClass, "addProperty5"),
438								"addProperty5", "T@,R,&,C," WEAK_STR "D,VbackingIvar", ATTRS(ATTR("T", "@"),
439																				   ATTR("R", ""),
440																				   ATTR("&", ""),
441																				   ATTR("C", ""),
442																				   WEAK_ATTR
443																				   ATTR("D", ""),
444																				   ATTR("V", "backingIvar")));
445	}
446
447    assert(class_addProperty(testClass, "replaceProperty", ATTRS(ATTR("T", "@"))));
448	testPropertyForProperty(class_getProperty(testClass, "replaceProperty"),
449							"replaceProperty", "T@", ATTRS(ATTR("T", "@")));
450
451    assert(!class_addProperty(testClass, "replaceProperty", ATTRS(ATTR("T", "i"))));
452	testPropertyForProperty(class_getProperty(testClass, "replaceProperty"),
453							"replaceProperty", "T@", ATTRS(ATTR("T", "@")));
454
455    class_replaceProperty(testClass, "replaceProperty", ATTRS(ATTR("T", "i")));
456	testPropertyForProperty(class_getProperty(testClass, "replaceProperty"),
457							"replaceProperty", "Ti", ATTRS(ATTR("T", "i")));
458}
459
460static void testAddProperty()
461{
462    testAddPropertyForClass(objc_getClass("PropertyTest"));
463    testAddPropertyForClass(objc_getClass("PropertyProtocolTest"));
464}
465
466static void testAddPropertyForProtocol(Protocol *testProto)
467{
468    objc_property_attribute_t emptyType = { "T", "i" };
469    protocol_addProperty(testProto, NULL, &emptyType, 1, YES, YES);
470
471    protocol_addProperty(testProto, "addProperty1", ATTRS(ATTR("T", "@")), YES, YES);
472    protocol_addProperty(testProto, "addProperty2", ATTRS(ATTR("T", "@"),
473														  ATTR("D", "")), YES, YES);
474    protocol_addProperty(testProto, "addProperty3", ATTRS(ATTR("T", "@"),
475														  ATTR("D", ""),
476														  ATTR("V", "backingIvar")), YES, YES);
477
478	objc_registerProtocol(testProto);
479
480	testPropertyForProperty(protocol_getProperty(testProto, "addProperty1", YES, YES),
481							"addProperty1", "T@", ATTRS(ATTR("T", "@")));
482	testPropertyForProperty(protocol_getProperty(testProto, "addProperty2", YES, YES),
483							"addProperty2", "T@,D", ATTRS(ATTR("T", "@"),
484														  ATTR("D", "")));
485	testPropertyForProperty(protocol_getProperty(testProto, "addProperty3", YES, YES),
486							"addProperty3", "T@,D,VbackingIvar", ATTRS(ATTR("T", "@"),
487																	   ATTR("D", ""),
488																	   ATTR("V", "backingIvar")));
489}
490
491static int intDefault2Getter(id self, SEL _cmd) {
492    Ivar ivar = class_getInstanceVariable(objc_getClass("PropertyTest"), "intDefault");
493    return (int)object_getIvar(self, ivar);
494}
495
496static void intDefault2Setter(id self, SEL _cmd, int value) {
497    Ivar ivar = class_getInstanceVariable(objc_getClass("PropertyTest"), "intDefault");
498    object_setIvar(self, ivar, (__bridge id)(void*)(intptr_t)value);
499}
500
501static struct YorkshireTeaStruct structDefault2Getter(id self, SEL _cmd) {
502    struct YorkshireTeaStruct *s;
503    object_getInstanceVariable(self, "structDefault", (void**)&s);
504    return *s;
505}
506
507void structDefault2Setter(id self, SEL _cmd, struct YorkshireTeaStruct value) {
508    object_setInstanceVariable(self, "structDefault", &value);
509}
510
511int main(void)
512{
513	testProperty("atomicBoolDefault", "TAB,VatomicBoolDefault", ATTRS(ATTR("T", "AB"), ATTR("V", "atomicBoolDefault")));
514	testProperty("charDefault", "Tc,VcharDefault", ATTRS(ATTR("T", "c"), ATTR("V", "charDefault")));
515	testProperty("doubleDefault", "Td,VdoubleDefault", ATTRS(ATTR("T", "d"), ATTR("V", "doubleDefault")));
516	testProperty("enumDefault", "Ti,VenumDefault", ATTRS(ATTR("T", "i"), ATTR("V", "enumDefault")));
517	testProperty("floatDefault", "Tf,VfloatDefault", ATTRS(ATTR("T", "f"), ATTR("V", "floatDefault")));
518	testProperty("intDefault", "Ti,VintDefault", ATTRS(ATTR("T", "i"), ATTR("V", "intDefault")));
519	if (sizeof(long) == 4)
520	{
521		testProperty("longDefault", "Tl,VlongDefault", ATTRS(ATTR("T", "l"), ATTR("V", "longDefault")));
522	}
523	else
524	{
525		testProperty("longDefault", "Tq,VlongDefault", ATTRS(ATTR("T", "q"), ATTR("V", "longDefault")));
526	}
527	testProperty("shortDefault", "Ts,VshortDefault", ATTRS(ATTR("T", "s"), ATTR("V", "shortDefault")));
528	testProperty("signedDefault", "Ti,VsignedDefault", ATTRS(ATTR("T", "i"), ATTR("V", "signedDefault")));
529	testProperty("structDefault", "T{YorkshireTeaStruct=ic},VstructDefault", ATTRS(ATTR("T", "{YorkshireTeaStruct=ic}"),
530                                                                                   ATTR("V", "structDefault")));
531	testProperty("typedefDefault", "T{YorkshireTeaStruct=ic},VtypedefDefault", ATTRS(ATTR("T", "{YorkshireTeaStruct=ic}"),
532                                                                                     ATTR("V", "typedefDefault")));
533	testProperty("unionDefault", "T(MoneyUnion=fd),VunionDefault", ATTRS(ATTR("T", "(MoneyUnion=fd)"),
534                                                                         ATTR("V", "unionDefault")));
535	testProperty("unsignedDefault", "TI,VunsignedDefault", ATTRS(ATTR("T", "I"), ATTR("V", "unsignedDefault")));
536	testProperty("functionPointerDefault", "T^?,VfunctionPointerDefault", ATTRS(ATTR("T", "^?"), ATTR("V", "functionPointerDefault")));
537	testProperty("intPointer", "T^i,VintPointer", ATTRS(ATTR("T", "^i"), ATTR("V", "intPointer")));
538	testProperty("voidPointerDefault", "T^v,VvoidPointerDefault", ATTRS(ATTR("T", "^v"), ATTR("V", "voidPointerDefault")));
539	testProperty("intSetterGetter", "Ti,GintGetFoo,SintSetFoo:,VintSetterGetter", ATTRS(ATTR("T", "i"),
540                                                                                        ATTR("G", "intGetFoo"),
541                                                                                        ATTR("S", "intSetFoo:"),
542                                                                                        ATTR("V", "intSetterGetter")));
543	testProperty("intReadonly", "Ti,R,VintReadonly", ATTRS(ATTR("T", "i"),
544                                                           ATTR("R", ""),
545                                                           ATTR("V", "intReadonly")));
546	testProperty("intReadonlyGetter", "Ti,R,GisIntReadOnlyGetter,VintReadonlyGetter", ATTRS(ATTR("T", "i"),
547                                                                                            ATTR("R", ""),
548                                                                                            ATTR("G", "isIntReadOnlyGetter"),
549                                                                                            ATTR("V", "intReadonlyGetter")));
550	testProperty("intReadwrite", "Ti,VintReadwrite", ATTRS(ATTR("T", "i"), ATTR("V", "intReadwrite")));
551	testProperty("intAssign", "Ti,VintAssign", ATTRS(ATTR("T", "i"), ATTR("V", "intAssign")));
552	testProperty("idDefault", "T@,VidDefault", ATTRS(ATTR("T", "@"),
553                                                     ATTR("V", "idDefault")));
554	testProperty("idRetain", "T@,&,VidRetain", ATTRS(ATTR("T", "@"),
555                                                     ATTR("&", ""),
556                                                     ATTR("V", "idRetain")));
557	testProperty("idCopy", "T@,C,VidCopy", ATTRS(ATTR("T", "@"),
558                                                 ATTR("C", ""),
559                                                 ATTR("V", "idCopy")));
560	testProperty("idWeak", "T@,W,VidWeak", ATTRS(ATTR("T", "@"),
561                                                 ATTR("W", ""),
562                                                 ATTR("V", "idWeak")));
563	testProperty("idStrong", "T@,&,VidStrong", ATTRS(ATTR("T", "@"),
564                                                     ATTR("&", ""),
565                                                     ATTR("V", "idStrong")));
566	testProperty("intNonatomic", "Ti,N,VintNonatomic", ATTRS(ATTR("T", "i"),
567                                                             ATTR("N", ""),
568                                                             ATTR("V", "intNonatomic")));
569	testProperty("idReadonlyCopyNonatomic", "T@,R,C,N,VidReadonlyCopyNonatomic", ATTRS(ATTR("T", "@"),
570                                                                                     ATTR("C", ""),
571                                                                                     ATTR("R", ""),
572                                                                                     ATTR("N", ""),
573                                                                                     ATTR("V", "idReadonlyCopyNonatomic")));
574	testProperty("idReadonlyRetainNonatomic", "T@,R,&,N,VidReadonlyRetainNonatomic", ATTRS(ATTR("T", "@"),
575                                                                                         ATTR("R", ""),
576                                                                                         ATTR("&", ""),
577                                                                                         ATTR("N", ""),
578                                                                                         ATTR("V", "idReadonlyRetainNonatomic")));
579	/**
580	 * The weak attribute was not present for earlier versions of clang, so we test
581	 * for all variants that the compiler may produce.
582	 */
583	if (!testProperty_alt("idReadonlyWeakNonatomic", "T@,R," WEAK_STR "N,VidReadonlyWeakNonatomic", ATTRS(ATTR("T", "@"),
584                                                                                     ATTR("R", ""),
585                                                                                     ATTR("N", ""),
586                                                                                     ATTR("V", "idReadonlyWeakNonatomic")), NO))
587	  {
588	    testProperty("idReadonlyWeakNonatomic", "T@,R," WEAK_STR "N,VidReadonlyWeakNonatomic", ATTRS(ATTR("T", "@"),
589                                                                                     ATTR("R", ""),
590                                                                                     WEAK_ATTR
591                                                                                     ATTR("N", ""),
592                                                                                     ATTR("V", "idReadonlyWeakNonatomic")));
593	  }
594	testProperty("idOther", "T@,&,V_idOther", ATTRS(ATTR("T", "@"), ATTR("&", ""), ATTR("V", "_idOther")));
595	testProperty("idDynamic", "T@,&,D", ATTRS(ATTR("T", "@"), ATTR("&", ""), ATTR("D", "")));
596	testProperty("idDynamicGetterSetter", "T@,&,D,N,GdynamicGetterSetter,SsetDynamicGetterSetter:", ATTRS(ATTR("T", "@"),
597                                                                                                          ATTR("&", ""),
598                                                                                                          ATTR("D", ""),
599                                                                                                          ATTR("N", ""),
600                                                                                                          ATTR("G", "dynamicGetterSetter"),
601                                                                                                          ATTR("S", "setDynamicGetterSetter:")));
602
603	Protocol *testProto = objc_getProtocol("ProtocolTest");
604	testPropertyForProtocol(testProto, "atomicBoolDefault", "TAB", ATTRS(ATTR("T", "AB")));
605	testPropertyForProtocol(testProto, "charDefault", "Tc", ATTRS(ATTR("T", "c")));
606	testPropertyForProtocol(testProto, "doubleDefault", "Td", ATTRS(ATTR("T", "d")));
607	testPropertyForProtocol(testProto, "enumDefault", "Ti", ATTRS(ATTR("T", "i")));
608	testPropertyForProtocol(testProto, "floatDefault", "Tf", ATTRS(ATTR("T", "f")));
609	testPropertyForProtocol(testProto, "intDefault", "Ti", ATTRS(ATTR("T", "i")));
610	if (sizeof(long) == 4)
611	{
612		testPropertyForProtocol(testProto, "longDefault", "Tl", ATTRS(ATTR("T", "l")));
613	}
614	else
615	{
616		testPropertyForProtocol(testProto, "longDefault", "Tq", ATTRS(ATTR("T", "q")));
617	}
618	testPropertyForProtocol(testProto, "shortDefault", "Ts", ATTRS(ATTR("T", "s")));
619	testPropertyForProtocol(testProto, "signedDefault", "Ti", ATTRS(ATTR("T", "i")));
620	testPropertyForProtocol(testProto, "structDefault", "T{YorkshireTeaStruct=ic}", ATTRS(ATTR("T", "{YorkshireTeaStruct=ic}")));
621	testPropertyForProtocol(testProto, "typedefDefault", "T{YorkshireTeaStruct=ic}", ATTRS(ATTR("T", "{YorkshireTeaStruct=ic}")));
622	testPropertyForProtocol(testProto, "unionDefault", "T(MoneyUnion=fd)", ATTRS(ATTR("T", "(MoneyUnion=fd)")));
623	testPropertyForProtocol(testProto, "unsignedDefault", "TI", ATTRS(ATTR("T", "I")));
624	testPropertyForProtocol(testProto, "functionPointerDefault", "T^?", ATTRS(ATTR("T", "^?")));
625	testPropertyForProtocol(testProto, "intPointer", "T^i", ATTRS(ATTR("T", "^i")));
626	testPropertyForProtocol(testProto, "voidPointerDefault", "T^v", ATTRS(ATTR("T", "^v")));
627	testPropertyForProtocol(testProto, "intSetterGetter", "Ti,GintGetFoo,SintSetFoo:", ATTRS(ATTR("T", "i"),
628																							 ATTR("G", "intGetFoo"),
629																							 ATTR("S", "intSetFoo:")));
630	testPropertyForProtocol(testProto, "intReadonly", "Ti,R", ATTRS(ATTR("T", "i"),
631																	ATTR("R", "")));
632	testPropertyForProtocol(testProto, "intReadonlyGetter", "Ti,R,GisIntReadOnlyGetter", ATTRS(ATTR("T", "i"),
633																							   ATTR("R", ""),
634																							   ATTR("G", "isIntReadOnlyGetter")));
635	testPropertyForProtocol(testProto, "intReadwrite", "Ti", ATTRS(ATTR("T", "i")));
636	testPropertyForProtocol(testProto, "intAssign", "Ti", ATTRS(ATTR("T", "i")));
637	testPropertyForProtocol(testProto, "idDefault", "T@", ATTRS(ATTR("T", "@")));
638	testPropertyForProtocol(testProto, "idRetain", "T@,&", ATTRS(ATTR("T", "@"),
639																 ATTR("&", "")));
640	testPropertyForProtocol(testProto, "idCopy", "T@,C", ATTRS(ATTR("T", "@"),
641															   ATTR("C", "")));
642	testPropertyForProtocol(testProto, "idWeak", "T@,W", ATTRS(ATTR("T", "@"),
643															   ATTR("W", "")));
644	testPropertyForProtocol(testProto, "idStrong", "T@,&", ATTRS(ATTR("T", "@"),
645																 ATTR("&", "")));
646	testPropertyForProtocol(testProto, "intNonatomic", "Ti,N", ATTRS(ATTR("T", "i"),
647																	 ATTR("N", "")));
648	testPropertyForProtocol(testProto, "idReadonlyCopyNonatomic", "T@,R,C,N", ATTRS(ATTR("T", "@"),
649																				  ATTR("R", ""),
650																				  ATTR("C", ""),
651																				  ATTR("N", "")));
652	testPropertyForProtocol(testProto, "idReadonlyRetainNonatomic", "T@,R,&,N", ATTRS(ATTR("T", "@"),
653																					ATTR("R", ""),
654																					ATTR("&", ""),
655																					ATTR("N", "")));
656	/*
657	 * Again, different clang versions emit slightly different property declarations.
658	 */
659	if (!testPropertyForProtocol_alt(testProto, "idReadonlyWeakNonatomic", "T@,R," WEAK_STR "N", ATTRS(ATTR("T", "@"),
660																				  ATTR("R", ""),
661																				  WEAK_ATTR
662																				  ATTR("N", "")), NO))
663	{
664
665	   testPropertyForProtocol(testProto, "idReadonlyWeakNonatomic", "T@,R,N", ATTRS(ATTR("T", "@"),
666																				  ATTR("R", ""),
667																				  ATTR("N", "")));
668	}
669	testPropertyForProtocol(testProto, "idOther", "T@,&", ATTRS(ATTR("T", "@"), ATTR("&", "")));
670	testPropertyForProtocol(testProto, "idDynamic", "T@,&", ATTRS(ATTR("T", "@"), ATTR("&", "")));
671	testPropertyForProtocol(testProto, "idDynamicGetterSetter", "T@,&,N,GdynamicGetterSetter,SsetDynamicGetterSetter:", ATTRS(ATTR("T", "@"),
672																															  ATTR("&", ""),
673																															  ATTR("N", ""),
674																															  ATTR("G", "dynamicGetterSetter"),
675																															  ATTR("S", "setDynamicGetterSetter:")));
676
677    testAddProperty();
678
679	Protocol *testAddProtocol = objc_allocateProtocol("TestAddProtocol");
680	assert(0 != testAddProtocol);
681    testAddPropertyForProtocol(testAddProtocol);
682
683    Class testClass = objc_getClass("PropertyTest");
684    objc_property_attribute_t intDefault2Attrs[] = { ATTR("T", "i"), ATTR("V", "intDefault") };
685    assert(class_addProperty(testClass, "intDefault2", intDefault2Attrs, 2));
686    assert(class_addMethod(testClass, @selector(intDefault2), (IMP)intDefault2Getter, "i@:"));
687    assert(class_addMethod(testClass, @selector(setIntDefault2:), (IMP)intDefault2Setter, "v@:i"));
688	testPropertyForClass(testClass, "intDefault2", "Ti,VintDefault", ATTRS(ATTR("T", "i"), ATTR("V", "intDefault")));
689
690    objc_property_attribute_t structDefault2Attrs[] = { ATTR("T", "{YorkshireTeaStruct=ic}"),
691														ATTR("V", "structDefault") };
692    assert(class_addProperty(testClass, "structDefault2", structDefault2Attrs, 2));
693    assert(class_addMethod(testClass, @selector(structDefault2), (IMP)structDefault2Getter, "{YorkshireTeaStruct=ic}@:"));
694    assert(class_addMethod(testClass, @selector(setStructDefault2:), (IMP)structDefault2Setter, "v@:{YorkshireTeaStruct=ic}"));
695	testPropertyForClass(testClass, "structDefault2", "T{YorkshireTeaStruct=ic},VstructDefault", ATTRS(ATTR("T", "{YorkshireTeaStruct=ic}"),
696                                                                                                       ATTR("V", "structDefault")));
697
698    PropertyTest* t = class_createInstance(testClass, 0);
699    assert(t != nil);
700    object_setClass(t, testClass);
701    t.intDefault = 2;
702    assert(t.intDefault == 2);
703    [t setIntDefault2:3];
704    assert((int)[t intDefault2] == 3);
705    assert(t.intDefault == 3);
706
707    struct YorkshireTeaStruct struct1 = { 2, 'A' };
708    t.structDefault = struct1;
709    struct YorkshireTeaStruct readStruct = t.structDefault;
710    assert(memcmp(&struct1, &readStruct, sizeof(struct1)) == 0);
711    struct YorkshireTeaStruct struct2 = { 3, 'B' };
712    [t setStructDefault2:struct2];
713    struct YorkshireTeaStruct readStruct2 = [t structDefault2];
714    assert(memcmp(&struct2, &readStruct2, sizeof(struct2)) == 0);
715    readStruct = t.structDefault;
716    assert(memcmp(&struct2, &readStruct, sizeof(struct2)) == 0);
717
718    objc_property_attribute_t idRetainAttrs[] = { ATTR("T", "@"),
719												  ATTR("&", ""),
720												  ATTR("V", "_idOther") };
721    class_replaceProperty(testClass, "idRetain", idRetainAttrs, 3);
722	testPropertyForClass(testClass, "idRetain", "T@,&,V_idOther", ATTRS(ATTR("T", "@"),
723                                                                        ATTR("&", ""),
724                                                                        ATTR("V", "_idOther")));
725    id testValue = [Test new];
726    t.idRetain = testValue;
727    assert(t->idRetain == testValue);
728    assert(t->_idOther == nil);
729
730    Method idRetainSetter = class_getInstanceMethod(testClass, @selector(setIdRetain:));
731    Method idOtherSetter = class_getInstanceMethod(testClass, @selector(setIdOther:));
732    method_setImplementation(idRetainSetter, method_getImplementation(idOtherSetter));
733    idRetainSetter = class_getInstanceMethod(testClass, @selector(setIdRetain:));
734
735    id testValue2 = [Test new];
736    t.idRetain = testValue2;
737    assert(t->idRetain == testValue);
738    assert(t->_idOther == testValue2);
739	return 0;
740}
741