---
 CMakeLists.txt                |   2 +-
 Test/CMakeLists.txt           |   3 +-
 Test/PropertyAttributeTest2.m | 641 ++++++++++++++++++++++++++++++++++++++++++
 properties.h                  |  94 ++++++-
 properties.m                  | 329 ++++++++++++++++++++++
 protocol.c                    |  30 +-
 6 files changed, 1085 insertions(+), 14 deletions(-)
 create mode 100644 Test/PropertyAttributeTest2.m

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 72ddc82..6b013a9 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -138,7 +138,7 @@ set(INCLUDE_DIRECTORY "objc" CACHE STRING
 if (${CMAKE_C_COMPILER_ID} MATCHES Clang*)
 	set(CMAKE_OBJC_FLAGS "${CMAKE_OBJC_FLAGS} -Wno-deprecated-objc-isa-usage -Wno-objc-root-class")
 	if (${CMAKE_C_COMPILER_VERSION} VERSION_GREATER 3.1)
-		set(CMAKE_OBJC_FLAGS "${CMAKE_OBJC_FLAGS} -fobjc-runtime=gnustep-1.7")
+		set(CMAKE_OBJC_FLAGS "${CMAKE_OBJC_FLAGS} -fobjc-runtime=gnustep-1.8")
 	endif ()
 	if (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "i686")
 		set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=i586")
diff --git a/Test/CMakeLists.txt b/Test/CMakeLists.txt
index 30e0751..9fdeea9 100644
--- a/Test/CMakeLists.txt
+++ b/Test/CMakeLists.txt
@@ -23,6 +23,7 @@ set(TESTS
 	ManyManySelectors.m
 	NestedExceptions.m
 	PropertyAttributeTest.m
+	PropertyAttributeTest2.m
 	PropertyIntrospectionTest.m
 	ProtocolCreation.m
 	RuntimeTest.m
@@ -36,7 +37,7 @@ function(addtest_flags TEST FLAGS TEST_SOURCE)
 	add_test(${TEST} ${TEST})
 	set_target_properties(${TEST} PROPERTIES
 		INCLUDE_DIRECTORIES "${CMAKE_SOURCE_DIR}"
-		COMPILE_FLAGS "-fobjc-runtime=gnustep-1.7 -fblocks ${FLAGS}"
+		COMPILE_FLAGS "-fobjc-runtime=gnustep-1.8 -fblocks ${FLAGS}"
 		LINKER_LANGUAGE C
 	)
 	set_property(TEST ${TEST} PROPERTY
diff --git a/Test/PropertyAttributeTest2.m b/Test/PropertyAttributeTest2.m
new file mode 100644
index 0000000..d7590d9
--- /dev/null
+++ b/Test/PropertyAttributeTest2.m
@@ -0,0 +1,641 @@
+#if __APPLE__
+#include <Foundation/Foundation.h>
+#include <objc/runtime.h>
+
+__attribute__((objc_root_class))
+@interface Test { id isa; }
+@end
+@implementation Test
++ (id)class { return self; }
++ (id)new
+{
+	return class_createInstance(self, 0);
+}
+- (void)dealloc
+{
+	object_dispose(self);
+}
+- (id)retain
+{
+	return self;
+}
+- (oneway void)release
+{
+}
+@end
+#else
+#include "Test.h"
+#endif
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+enum FooManChu { FOO, MAN, CHU };
+struct YorkshireTeaStruct { int pot; char lady; };
+typedef struct YorkshireTeaStruct YorkshireTeaStructType;
+union MoneyUnion { float alone; double down; };
+
+#ifndef __has_attribute
+#define __has_attribute(x)  0
+#endif
+
+#if __has_attribute(objc_root_class)
+__attribute__((objc_root_class))
+#endif
+@interface PropertyTest
+{
+@public
+	Class isa;
+	char charDefault;
+	double doubleDefault;
+	enum FooManChu enumDefault;
+	float floatDefault;
+	int intDefault;
+	long longDefault;
+	short shortDefault;
+	signed signedDefault;
+	struct YorkshireTeaStruct structDefault;
+	YorkshireTeaStructType typedefDefault;
+	union MoneyUnion unionDefault;
+	unsigned unsignedDefault;
+	int (*functionPointerDefault)(char *);
+	int *intPointer;
+	void *voidPointerDefault;
+	int intSynthEquals;
+	int intSetterGetter;
+	int intReadonly;
+	int intReadonlyGetter;
+	int intReadwrite;
+	int intAssign;
+	id idDefault;
+	id idRetain;
+	id idCopy;
+	id idWeak;
+	id idStrong;
+	int intNonatomic;
+	id idReadonlyCopyNonatomic;
+	id idReadonlyRetainNonatomic;
+	id idReadonlyWeakNonatomic;
+	id _idOther;
+}
+@property char charDefault;
+@property double doubleDefault;
+@property enum FooManChu enumDefault;
+@property float floatDefault;
+@property int intDefault;
+@property long longDefault;
+@property short shortDefault;
+@property signed signedDefault;
+@property struct YorkshireTeaStruct structDefault;
+@property YorkshireTeaStructType typedefDefault;
+@property union MoneyUnion unionDefault;
+@property unsigned unsignedDefault;
+@property int (*functionPointerDefault)(char *);
+@property int *intPointer;
+@property void *voidPointerDefault;
+@property(getter=intGetFoo, setter=intSetFoo:) int intSetterGetter;
+@property(readonly) int intReadonly;
+@property(getter=isIntReadOnlyGetter, readonly) int intReadonlyGetter;
+@property(readwrite) int intReadwrite;
+@property(assign) int intAssign;
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wobjc-property-no-attribute"
+@property id idDefault;
+#pragma GCC diagnostic pop
+@property(retain) id idRetain;
+@property(copy) id idCopy;
+@property(weak) id idWeak;
+@property(strong) id idStrong;
+@property(nonatomic) int intNonatomic;
+@property(nonatomic, readonly, copy) id idReadonlyCopyNonatomic;
+@property(nonatomic, readonly, retain) id idReadonlyRetainNonatomic;
+@property(nonatomic, readonly, weak) id idReadonlyWeakNonatomic;
+@property(retain) id idOther;
+@property(retain) id idDynamic;
+@property(retain, nonatomic, getter=dynamicGetterSetter, setter=setDynamicGetterSetter:) id idDynamicGetterSetter;
+@end
+
+@implementation PropertyTest
+@synthesize charDefault;
+@synthesize doubleDefault;
+@synthesize enumDefault;
+@synthesize floatDefault;
+@synthesize intDefault;
+@synthesize longDefault;
+@synthesize shortDefault;
+@synthesize signedDefault;
+@synthesize structDefault;
+@synthesize typedefDefault;
+@synthesize unionDefault;
+@synthesize unsignedDefault;
+@synthesize functionPointerDefault;
+@synthesize intPointer;
+@synthesize voidPointerDefault;
+@synthesize intSetterGetter;
+@synthesize intReadonly;
+@synthesize intReadonlyGetter;
+@synthesize intReadwrite;
+@synthesize intAssign;
+@synthesize idDefault;
+@synthesize idRetain;
+@synthesize idCopy;
+@synthesize idWeak;
+@synthesize idStrong;
+@synthesize intNonatomic;
+@synthesize idReadonlyCopyNonatomic;
+@synthesize idReadonlyRetainNonatomic;
+@synthesize idReadonlyWeakNonatomic;
+@synthesize idOther = _idOther;
+@dynamic idDynamic;
+@dynamic idDynamicGetterSetter;
+@end
+
+@protocol ProtocolTest
+@property char charDefault;
+@property double doubleDefault;
+@property enum FooManChu enumDefault;
+@property float floatDefault;
+@property int intDefault;
+@property long longDefault;
+@property short shortDefault;
+@property signed signedDefault;
+@property struct YorkshireTeaStruct structDefault;
+@property YorkshireTeaStructType typedefDefault;
+@property union MoneyUnion unionDefault;
+@property unsigned unsignedDefault;
+@property int (*functionPointerDefault)(char *);
+@property int *intPointer;
+@property void *voidPointerDefault;
+@property(getter=intGetFoo, setter=intSetFoo:) int intSetterGetter;
+@property(readonly) int intReadonly;
+@property(getter=isIntReadOnlyGetter, readonly) int intReadonlyGetter;
+@property(readwrite) int intReadwrite;
+@property(assign) int intAssign;
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wobjc-property-no-attribute"
+@property id idDefault;
+#pragma GCC diagnostic pop
+@property(retain) id idRetain;
+@property(copy) id idCopy;
+@property(weak) id idWeak;
+@property(strong) id idStrong;
+@property(nonatomic) int intNonatomic;
+@property(nonatomic, readonly, copy) id idReadonlyCopyNonatomic;
+@property(nonatomic, readonly, retain) id idReadonlyRetainNonatomic;
+@property(nonatomic, readonly, weak) id idReadonlyWeakNonatomic;
+@property(retain) id idOther;
+@property(retain) id idDynamic;
+@property(retain, nonatomic, getter=dynamicGetterSetter, setter=setDynamicGetterSetter:) id idDynamicGetterSetter;
+@end
+
+#if __has_attribute(objc_root_class)
+__attribute__((objc_root_class))
+#endif
+@interface PropertyProtocolTest <ProtocolTest>
+{
+	Class isa;
+	char charDefault;
+	double doubleDefault;
+	enum FooManChu enumDefault;
+	float floatDefault;
+	int intDefault;
+	long longDefault;
+	short shortDefault;
+	signed signedDefault;
+	struct YorkshireTeaStruct structDefault;
+	YorkshireTeaStructType typedefDefault;
+	union MoneyUnion unionDefault;
+	unsigned unsignedDefault;
+	int (*functionPointerDefault)(char *);
+	int *intPointer;
+	void *voidPointerDefault;
+	int intSynthEquals;
+	int intSetterGetter;
+	int intReadonly;
+	int intReadonlyGetter;
+	int intReadwrite;
+	int intAssign;
+	id idDefault;
+	id idRetain;
+	id idCopy;
+	id idWeak;
+	id idStrong;
+	int intNonatomic;
+	id idReadonlyCopyNonatomic;
+	id idReadonlyRetainNonatomic;
+	id idReadonlyWeakNonatomic;
+	id _idOther;
+}
+@end
+
+@implementation PropertyProtocolTest
+@synthesize charDefault;
+@synthesize doubleDefault;
+@synthesize enumDefault;
+@synthesize floatDefault;
+@synthesize intDefault;
+@synthesize longDefault;
+@synthesize shortDefault;
+@synthesize signedDefault;
+@synthesize structDefault;
+@synthesize typedefDefault;
+@synthesize unionDefault;
+@synthesize unsignedDefault;
+@synthesize functionPointerDefault;
+@synthesize intPointer;
+@synthesize voidPointerDefault;
+@synthesize intSetterGetter;
+@synthesize intReadonly;
+@synthesize intReadonlyGetter;
+@synthesize intReadwrite;
+@synthesize intAssign;
+@synthesize idDefault;
+@synthesize idRetain;
+@synthesize idCopy;
+@synthesize idWeak;
+@synthesize idStrong;
+@synthesize intNonatomic;
+@synthesize idReadonlyCopyNonatomic;
+@synthesize idReadonlyRetainNonatomic;
+@synthesize idReadonlyWeakNonatomic;
+@synthesize idOther = _idOther;
+@dynamic idDynamic;
+@dynamic idDynamicGetterSetter;
+@end
+
+#define ATTR(n, v)  (objc_property_attribute_t){(n), (v)}
+#define ATTRS(...)  (objc_property_attribute_t[]){ __VA_ARGS__ }, \
+						sizeof((objc_property_attribute_t[]){ __VA_ARGS__ }) / sizeof(objc_property_attribute_t)
+
+static void testPropertyForProperty(objc_property_t p,
+									const char *name,
+									const char *types,
+									objc_property_attribute_t* list,
+									unsigned int size)
+{
+	assert(0 != p);
+	assert(strcmp(name, property_getName(p)) == 0);
+	const char *attrs = property_getAttributes(p);
+	assert(0 != attrs);
+    printf("attributes for '%s': %s, should be: %s\n", name, attrs, types);
+	assert(strcmp(types, attrs) == 0);
+	unsigned int attrsCount = 0;
+	objc_property_attribute_t* attrsList = property_copyAttributeList(p, &attrsCount);
+	assert(0 != attrsList);
+    printf("attributes list size for '%s': %u, should be: %u\n", name, attrsCount, size);
+    assert(attrsCount == size);
+    for (unsigned int index=0; index<size; index++) {
+        int found = 0;
+        for (unsigned int attrsIndex=0; attrsIndex<attrsCount; attrsIndex++) {
+            if (strcmp(attrsList[attrsIndex].name, list[index].name) == 0) {
+                assert(strcmp(attrsList[attrsIndex].value, list[index].value) == 0);
+                found = 1;
+            }
+        }
+        assert(found);
+    }
+    for (unsigned int index=0; index<size; index++) {
+        const char* value = property_copyAttributeValue(p, list[index].name);
+        assert(0 != value);
+        assert(strcmp(value, list[index].value) == 0);
+    }
+}
+
+static void testPropertyForClass(Class testClass,
+								 const char *name,
+								 const char *types,
+								 objc_property_attribute_t* list,
+								 unsigned int size)
+{
+    testPropertyForProperty(class_getProperty(testClass, name), name, types, list, size);
+
+	static int addPropertyForClassIndex = 0;
+	char addPropertyName[32];
+	sprintf(addPropertyName, "addPropertyForClass%d", ++addPropertyForClassIndex);
+    assert(class_addProperty(testClass, addPropertyName, list, size));
+    testPropertyForProperty(class_getProperty(testClass, addPropertyName), addPropertyName, types, list, size);
+}
+
+static void testPropertyForProtocol(Protocol *testProto,
+									const char *name,
+									const char *types,
+									objc_property_attribute_t* list,
+									unsigned int size)
+{
+    testPropertyForProperty(protocol_getProperty(testProto, name, YES, YES), name, types, list, size);
+
+   	static int addPropertyForProtocolIndex = 0;
+	char addPropertyName[32];
+	sprintf(addPropertyName, "addPropertyForProtocol%d", ++addPropertyForProtocolIndex);
+    protocol_addProperty(testProto, addPropertyName, list, size, YES, YES);
+	assert(0 == protocol_getProperty(testProto, addPropertyName, YES, YES));
+}
+
+static void testProperty(const char *name, const char *types, objc_property_attribute_t* list, unsigned int size)
+{
+    testPropertyForProperty(class_getProperty(objc_getClass("PropertyTest"), name), name, types, list, size);
+    testPropertyForProperty(class_getProperty(objc_getClass("PropertyProtocolTest"), name), name, types, list, size);
+}
+
+static void testAddPropertyForClass(Class testClass)
+{
+    objc_property_attribute_t emptyType = { "T", "i" };
+    assert(!class_addProperty(testClass, NULL, &emptyType, 1));
+    class_replaceProperty(testClass, NULL, &emptyType, 1);
+
+    assert(class_addProperty(testClass, "addProperty1", ATTRS(ATTR("T", "@"))));
+	testPropertyForProperty(class_getProperty(testClass, "addProperty1"),
+							"addProperty1", "T@", ATTRS(ATTR("T", "@")));
+
+    assert(class_addProperty(testClass, "addProperty2", ATTRS(ATTR("T", "@"),
+															  ATTR("D", ""))));
+	testPropertyForProperty(class_getProperty(testClass, "addProperty2"),
+							"addProperty2", "T@,D", ATTRS(ATTR("T", "@"),
+														  ATTR("D", "")));
+
+    assert(class_addProperty(testClass, "addProperty3", ATTRS(ATTR("T", "@"),
+															  ATTR("D", ""),
+															  ATTR("V", "backingIvar"))));
+	testPropertyForProperty(class_getProperty(testClass, "addProperty3"),
+							"addProperty3", "T@,D,VbackingIvar", ATTRS(ATTR("T", "@"),
+																	   ATTR("D", ""),
+																	   ATTR("V", "backingIvar")));
+
+    assert(class_addProperty(testClass, "replaceProperty", ATTRS(ATTR("T", "@"))));
+	testPropertyForProperty(class_getProperty(testClass, "replaceProperty"),
+							"replaceProperty", "T@", ATTRS(ATTR("T", "@")));
+
+    assert(!class_addProperty(testClass, "replaceProperty", ATTRS(ATTR("T", "i"))));
+	testPropertyForProperty(class_getProperty(testClass, "replaceProperty"),
+							"replaceProperty", "T@", ATTRS(ATTR("T", "@")));
+
+    class_replaceProperty(testClass, "replaceProperty", ATTRS(ATTR("T", "i")));
+	testPropertyForProperty(class_getProperty(testClass, "replaceProperty"),
+							"replaceProperty", "Ti", ATTRS(ATTR("T", "i")));
+}
+
+static void testAddProperty()
+{
+    testAddPropertyForClass(objc_getClass("PropertyTest"));
+    testAddPropertyForClass(objc_getClass("PropertyProtocolTest"));
+}
+
+static void testAddPropertyForProtocol(Protocol *testProto)
+{
+    objc_property_attribute_t emptyType = { "T", "i" };
+    protocol_addProperty(testProto, NULL, &emptyType, 1, YES, YES);
+
+    protocol_addProperty(testProto, "addProperty1", ATTRS(ATTR("T", "@")), YES, YES);
+    protocol_addProperty(testProto, "addProperty2", ATTRS(ATTR("T", "@"),
+														  ATTR("D", "")), YES, YES);
+    protocol_addProperty(testProto, "addProperty3", ATTRS(ATTR("T", "@"),
+														  ATTR("D", ""),
+														  ATTR("V", "backingIvar")), YES, YES);
+
+	objc_registerProtocol(testProto);
+
+	testPropertyForProperty(protocol_getProperty(testProto, "addProperty1", YES, YES),
+							"addProperty1", "T@", ATTRS(ATTR("T", "@")));
+	testPropertyForProperty(protocol_getProperty(testProto, "addProperty2", YES, YES),
+							"addProperty2", "T@,D", ATTRS(ATTR("T", "@"),
+														  ATTR("D", "")));
+	testPropertyForProperty(protocol_getProperty(testProto, "addProperty3", YES, YES),
+							"addProperty3", "T@,D,VbackingIvar", ATTRS(ATTR("T", "@"),
+																	   ATTR("D", ""),
+																	   ATTR("V", "backingIvar")));
+}
+
+static int intDefault2Getter(id self, SEL _cmd) {
+    Ivar ivar = class_getInstanceVariable(objc_getClass("PropertyTest"), "intDefault");
+    return (int)object_getIvar(self, ivar);
+}
+
+static void intDefault2Setter(id self, SEL _cmd, int value) {
+    Ivar ivar = class_getInstanceVariable(objc_getClass("PropertyTest"), "intDefault");
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wint-to-pointer-cast"
+    object_setIvar(self, ivar, (id)value);
+#pragma GCC diagnostic pop
+}
+
+static struct YorkshireTeaStruct* structDefault2Getter(id self, SEL _cmd) {
+    Ivar ivar = class_getInstanceVariable(objc_getClass("PropertyTest"), "structDefault");
+    return (struct YorkshireTeaStruct*)object_getIvar(self, ivar);
+}
+
+void structDefault2Setter(id self, SEL _cmd, struct YorkshireTeaStruct* value) {
+    Ivar ivar = class_getInstanceVariable(objc_getClass("PropertyTest"), "structDefault");
+    object_setIvar(self, ivar, (id)value);
+}
+
+int main(void)
+{
+	testProperty("charDefault", "Tc,VcharDefault", ATTRS(ATTR("T", "c"), ATTR("V", "charDefault")));
+	testProperty("doubleDefault", "Td,VdoubleDefault", ATTRS(ATTR("T", "d"), ATTR("V", "doubleDefault")));
+	testProperty("enumDefault", "Ti,VenumDefault", ATTRS(ATTR("T", "i"), ATTR("V", "enumDefault")));
+	testProperty("floatDefault", "Tf,VfloatDefault", ATTRS(ATTR("T", "f"), ATTR("V", "floatDefault")));
+	testProperty("intDefault", "Ti,VintDefault", ATTRS(ATTR("T", "i"), ATTR("V", "intDefault")));
+	if (sizeof(long) == 4)
+	{
+		testProperty("longDefault", "Tl,VlongDefault", ATTRS(ATTR("T", "l"), ATTR("V", "longDefault")));
+	}
+	else
+	{
+		testProperty("longDefault", "Tq,VlongDefault", ATTRS(ATTR("T", "q"), ATTR("V", "longDefault")));
+	}
+	testProperty("shortDefault", "Ts,VshortDefault", ATTRS(ATTR("T", "s"), ATTR("V", "shortDefault")));
+	testProperty("signedDefault", "Ti,VsignedDefault", ATTRS(ATTR("T", "i"), ATTR("V", "signedDefault")));
+	testProperty("structDefault", "T{YorkshireTeaStruct=ic},VstructDefault", ATTRS(ATTR("T", "{YorkshireTeaStruct=ic}"),
+                                                                                   ATTR("V", "structDefault")));
+	testProperty("typedefDefault", "T{YorkshireTeaStruct=ic},VtypedefDefault", ATTRS(ATTR("T", "{YorkshireTeaStruct=ic}"),
+                                                                                     ATTR("V", "typedefDefault")));
+	testProperty("unionDefault", "T(MoneyUnion=fd),VunionDefault", ATTRS(ATTR("T", "(MoneyUnion=fd)"),
+                                                                         ATTR("V", "unionDefault")));
+	testProperty("unsignedDefault", "TI,VunsignedDefault", ATTRS(ATTR("T", "I"), ATTR("V", "unsignedDefault")));
+	testProperty("functionPointerDefault", "T^?,VfunctionPointerDefault", ATTRS(ATTR("T", "^?"), ATTR("V", "functionPointerDefault")));
+	testProperty("intPointer", "T^i,VintPointer", ATTRS(ATTR("T", "^i"), ATTR("V", "intPointer")));
+	testProperty("voidPointerDefault", "T^v,VvoidPointerDefault", ATTRS(ATTR("T", "^v"), ATTR("V", "voidPointerDefault")));
+	testProperty("intSetterGetter", "Ti,GintGetFoo,SintSetFoo:,VintSetterGetter", ATTRS(ATTR("T", "i"),
+                                                                                        ATTR("G", "intGetFoo"),
+                                                                                        ATTR("S", "intSetFoo:"),
+                                                                                        ATTR("V", "intSetterGetter")));
+	testProperty("intReadonly", "Ti,R,VintReadonly", ATTRS(ATTR("T", "i"),
+                                                           ATTR("R", ""),
+                                                           ATTR("V", "intReadonly")));
+	testProperty("intReadonlyGetter", "Ti,R,GisIntReadOnlyGetter,VintReadonlyGetter", ATTRS(ATTR("T", "i"),
+                                                                                            ATTR("R", ""),
+                                                                                            ATTR("G", "isIntReadOnlyGetter"),
+                                                                                            ATTR("V", "intReadonlyGetter")));
+	testProperty("intReadwrite", "Ti,VintReadwrite", ATTRS(ATTR("T", "i"), ATTR("V", "intReadwrite")));
+	testProperty("intAssign", "Ti,VintAssign", ATTRS(ATTR("T", "i"), ATTR("V", "intAssign")));
+	testProperty("idDefault", "T@,VidDefault", ATTRS(ATTR("T", "@"),
+                                                     ATTR("V", "idDefault")));
+	testProperty("idRetain", "T@,&,VidRetain", ATTRS(ATTR("T", "@"),
+                                                     ATTR("&", ""),
+                                                     ATTR("V", "idRetain")));
+	testProperty("idCopy", "T@,C,VidCopy", ATTRS(ATTR("T", "@"),
+                                                 ATTR("C", ""),
+                                                 ATTR("V", "idCopy")));
+	testProperty("idWeak", "T@,W,VidWeak", ATTRS(ATTR("T", "@"),
+                                                 ATTR("W", ""),
+                                                 ATTR("V", "idWeak")));
+	testProperty("idStrong", "T@,&,VidStrong", ATTRS(ATTR("T", "@"),
+                                                     ATTR("&", ""),
+                                                     ATTR("V", "idStrong")));
+	testProperty("intNonatomic", "Ti,N,VintNonatomic", ATTRS(ATTR("T", "i"),
+                                                             ATTR("N", ""),
+                                                             ATTR("V", "intNonatomic")));
+	testProperty("idReadonlyCopyNonatomic", "T@,R,N,VidReadonlyCopyNonatomic", ATTRS(ATTR("T", "@"),
+                                                                                     ATTR("R", ""),
+                                                                                     ATTR("N", ""),
+                                                                                     ATTR("V", "idReadonlyCopyNonatomic")));
+	testProperty("idReadonlyRetainNonatomic", "T@,R,N,VidReadonlyRetainNonatomic", ATTRS(ATTR("T", "@"),
+                                                                                         ATTR("R", ""),
+                                                                                         ATTR("N", ""),
+                                                                                         ATTR("V", "idReadonlyRetainNonatomic")));
+	testProperty("idReadonlyWeakNonatomic", "T@,R,N,VidReadonlyWeakNonatomic", ATTRS(ATTR("T", "@"),
+                                                                                     ATTR("R", ""),
+                                                                                     ATTR("N", ""),
+                                                                                     ATTR("V", "idReadonlyWeakNonatomic")));
+	testProperty("idOther", "T@,&,V_idOther", ATTRS(ATTR("T", "@"), ATTR("&", ""), ATTR("V", "_idOther")));
+	testProperty("idDynamic", "T@,&,D", ATTRS(ATTR("T", "@"), ATTR("&", ""), ATTR("D", "")));
+	testProperty("idDynamicGetterSetter", "T@,&,D,N,GdynamicGetterSetter,SsetDynamicGetterSetter:", ATTRS(ATTR("T", "@"),
+                                                                                                          ATTR("&", ""),
+                                                                                                          ATTR("D", ""),
+                                                                                                          ATTR("N", ""),
+                                                                                                          ATTR("G", "dynamicGetterSetter"),
+                                                                                                          ATTR("S", "setDynamicGetterSetter:")));
+
+    Protocol *testProto = objc_getProtocol("ProtocolTest");
+    testPropertyForProtocol(testProto, "charDefault", "Tc", ATTRS(ATTR("T", "c")));
+	testPropertyForProtocol(testProto, "doubleDefault", "Td", ATTRS(ATTR("T", "d")));
+	testPropertyForProtocol(testProto, "enumDefault", "Ti", ATTRS(ATTR("T", "i")));
+	testPropertyForProtocol(testProto, "floatDefault", "Tf", ATTRS(ATTR("T", "f")));
+	testPropertyForProtocol(testProto, "intDefault", "Ti", ATTRS(ATTR("T", "i")));
+	if (sizeof(long) == 4)
+	{
+		testPropertyForProtocol(testProto, "longDefault", "Tl", ATTRS(ATTR("T", "l")));
+	}
+	else
+	{
+		testPropertyForProtocol(testProto, "longDefault", "Tq", ATTRS(ATTR("T", "q")));
+	}
+	testPropertyForProtocol(testProto, "shortDefault", "Ts", ATTRS(ATTR("T", "s")));
+	testPropertyForProtocol(testProto, "signedDefault", "Ti", ATTRS(ATTR("T", "i")));
+	testPropertyForProtocol(testProto, "structDefault", "T{YorkshireTeaStruct=ic}", ATTRS(ATTR("T", "{YorkshireTeaStruct=ic}")));
+	testPropertyForProtocol(testProto, "typedefDefault", "T{YorkshireTeaStruct=ic}", ATTRS(ATTR("T", "{YorkshireTeaStruct=ic}")));
+	testPropertyForProtocol(testProto, "unionDefault", "T(MoneyUnion=fd)", ATTRS(ATTR("T", "(MoneyUnion=fd)")));
+	testPropertyForProtocol(testProto, "unsignedDefault", "TI", ATTRS(ATTR("T", "I")));
+	testPropertyForProtocol(testProto, "functionPointerDefault", "T^?", ATTRS(ATTR("T", "^?")));
+	testPropertyForProtocol(testProto, "intPointer", "T^i", ATTRS(ATTR("T", "^i")));
+	testPropertyForProtocol(testProto, "voidPointerDefault", "T^v", ATTRS(ATTR("T", "^v")));
+	testPropertyForProtocol(testProto, "intSetterGetter", "Ti,GintGetFoo,SintSetFoo:", ATTRS(ATTR("T", "i"),
+																							 ATTR("G", "intGetFoo"),
+																							 ATTR("S", "intSetFoo:")));
+	testPropertyForProtocol(testProto, "intReadonly", "Ti,R", ATTRS(ATTR("T", "i"),
+																	ATTR("R", "")));
+	testPropertyForProtocol(testProto, "intReadonlyGetter", "Ti,R,GisIntReadOnlyGetter", ATTRS(ATTR("T", "i"),
+																							   ATTR("R", ""),
+																							   ATTR("G", "isIntReadOnlyGetter")));
+	testPropertyForProtocol(testProto, "intReadwrite", "Ti", ATTRS(ATTR("T", "i")));
+	testPropertyForProtocol(testProto, "intAssign", "Ti", ATTRS(ATTR("T", "i")));
+	testPropertyForProtocol(testProto, "idDefault", "T@", ATTRS(ATTR("T", "@")));
+	testPropertyForProtocol(testProto, "idRetain", "T@,&", ATTRS(ATTR("T", "@"),
+																 ATTR("&", "")));
+	testPropertyForProtocol(testProto, "idCopy", "T@,C", ATTRS(ATTR("T", "@"),
+															   ATTR("C", "")));
+	testPropertyForProtocol(testProto, "idWeak", "T@,W", ATTRS(ATTR("T", "@"),
+															   ATTR("W", "")));
+	testPropertyForProtocol(testProto, "idStrong", "T@,&", ATTRS(ATTR("T", "@"),
+																 ATTR("&", "")));
+	testPropertyForProtocol(testProto, "intNonatomic", "Ti,N", ATTRS(ATTR("T", "i"),
+																	 ATTR("N", "")));
+	testPropertyForProtocol(testProto, "idReadonlyCopyNonatomic", "T@,R,N", ATTRS(ATTR("T", "@"),
+																				  ATTR("R", ""),
+																				  ATTR("N", "")));
+	testPropertyForProtocol(testProto, "idReadonlyRetainNonatomic", "T@,R,N", ATTRS(ATTR("T", "@"),
+																					ATTR("R", ""),
+																					ATTR("N", "")));
+	testPropertyForProtocol(testProto, "idReadonlyWeakNonatomic", "T@,R,N", ATTRS(ATTR("T", "@"),
+																				  ATTR("R", ""),
+																				  ATTR("N", "")));
+	testPropertyForProtocol(testProto, "idOther", "T@,&", ATTRS(ATTR("T", "@"), ATTR("&", "")));
+	testPropertyForProtocol(testProto, "idDynamic", "T@,&", ATTRS(ATTR("T", "@"), ATTR("&", "")));
+	testPropertyForProtocol(testProto, "idDynamicGetterSetter", "T@,&,N,GdynamicGetterSetter,SsetDynamicGetterSetter:", ATTRS(ATTR("T", "@"),
+																															  ATTR("&", ""),
+																															  ATTR("N", ""),
+																															  ATTR("G", "dynamicGetterSetter"),
+																															  ATTR("S", "setDynamicGetterSetter:")));
+    
+    testAddProperty();
+
+	Protocol *testAddProtocol = objc_allocateProtocol("TestAddProtocol");
+	assert(0 != testAddProtocol);
+    testAddPropertyForProtocol(testAddProtocol);
+
+    Class testClass = objc_getClass("PropertyTest");
+    objc_property_attribute_t intDefault2Attrs[] = { ATTR("T", "i"), ATTR("V", "intDefault") };
+    assert(class_addProperty(testClass, "intDefault2", intDefault2Attrs, 2));
+    assert(class_addMethod(testClass, @selector(intDefault2), (IMP)intDefault2Getter, "i@:"));
+    assert(class_addMethod(testClass, @selector(setIntDefault2:), (IMP)intDefault2Setter, "v@:i"));
+	testPropertyForClass(testClass, "intDefault2", "Ti,VintDefault", ATTRS(ATTR("T", "i"), ATTR("V", "intDefault")));
+    
+    objc_property_attribute_t structDefault2Attrs[] = { ATTR("T", "{YorkshireTeaStruct=ic}"),
+														ATTR("V", "structDefault") };
+    assert(class_addProperty(testClass, "structDefault2", structDefault2Attrs, 2));
+    assert(class_addMethod(testClass, @selector(structDefault2), (IMP)structDefault2Getter, "{YorkshireTeaStruct=ic}@:"));
+    assert(class_addMethod(testClass, @selector(setStructDefault2:), (IMP)structDefault2Setter, "v@:{YorkshireTeaStruct=ic}"));
+	testPropertyForClass(testClass, "structDefault2", "T{YorkshireTeaStruct=ic},VstructDefault", ATTRS(ATTR("T", "{YorkshireTeaStruct=ic}"),
+                                                                                                       ATTR("V", "structDefault")));
+    
+    PropertyTest* t = class_createInstance(testClass, 0);
+    object_setClass(t, testClass);
+    t.intDefault = 2;
+    assert(t.intDefault == 2);
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wobjc-method-access"
+    [t setIntDefault2:3];
+    assert((int)[t intDefault2] == 3);
+#pragma GCC diagnostic pop
+    assert(t.intDefault == 3);
+    
+    struct YorkshireTeaStruct struct1 = { 2, 'A' };
+    t.structDefault = struct1;
+    struct YorkshireTeaStruct readStruct = t.structDefault;
+    assert(memcmp(&struct1, &readStruct, sizeof(struct1)) == 0);
+    struct YorkshireTeaStruct struct2 = { 3, 'B' };
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wobjc-method-access"
+    [t setStructDefault2:struct2];
+    id readStruct2 = [t structDefault2];
+    assert(memcmp(&struct2, &readStruct2, sizeof(struct2)) == 0);
+#pragma GCC diagnostic pop
+    readStruct = t.structDefault;
+    assert(memcmp(&struct2, &readStruct, sizeof(struct2)) == 0);
+    
+    objc_property_attribute_t idRetainAttrs[] = { ATTR("T", "@"),
+												  ATTR("&", ""),
+												  ATTR("V", "_idOther") };
+    class_replaceProperty(testClass, "idRetain", idRetainAttrs, 3);
+	testPropertyForClass(testClass, "idRetain", "T@,&,V_idOther", ATTRS(ATTR("T", "@"),
+                                                                        ATTR("&", ""),
+                                                                        ATTR("V", "_idOther")));
+    id testValue = [Test new];
+    t.idRetain = testValue;
+    assert(t->idRetain == testValue);
+    assert(t->_idOther == nil);
+    
+#if __APPLE__
+	// why does this test fail with gnu runtime?
+    Method idRetainSetter = class_getInstanceMethod(testClass, @selector(setIdRetain:));
+    Method idOtherSetter = class_getInstanceMethod(testClass, @selector(setIdOther:));
+    method_setImplementation(idRetainSetter, method_getImplementation(idOtherSetter));
+    
+    id testValue2 = [Test new];
+    t.idRetain = testValue2;
+    assert(t->idRetain == testValue);
+    assert(t->_idOther == testValue2);
+#endif
+	return 0;
+}
diff --git a/properties.h b/properties.h
index 4f13a02..069e206 100644
--- a/properties.h
+++ b/properties.h
@@ -37,10 +37,98 @@ enum PropertyAttributeKind
 	/**
 	 * Property has setter.
 	 */
-	OBJC_PR_setter    = (1<<7)
+	OBJC_PR_setter    = (1<<7),
+	/**
+	 * Property is marked as atomic.
+	 */
+	OBJC_PR_atomic    = (1<<8),
+	/**
+	 * Property has weak semantics.
+	 */
+	OBJC_PR_weak      = (1<<9),
+	/**
+	 * Property has strong semantics.
+	 */
+	OBJC_PR_strong    = (1<<10),
+	/**
+	 * Property has unsafe unretained semantics.
+	 */
+	OBJC_PR_unsafe_unretained = (1<<11),
+	/**
+	 * Property is not synthesized.
+	 */
+	OBJC_PR_dynamic = (1<<12),
+	/**
+	 * Property was allocated by runtime.
+	 */
+	OBJC_PR_runtime_allocated = (1<<31)
+};
+
+#if __clang__ && __has_feature(objc_property_clean_abi)
+/**
+ * Structure used for property enumeration.
+ * Try to achieve MacOS X compatibility.
+ */
+struct objc_property
+{
+	/**
+	 * Name of this property.
+	 */
+	const char *name;
+	/**
+	 * Type encoding for this property.
+	 */
+	const char *type_encoding;
+	/**
+	 * Name of the getter for this property.  NULL if undefined.
+	 */
+	const char *getter_name;
+	/**
+	 * Name of the setter for this property.  NULL if undefined.
+	 */
+	const char *setter_name;
+	/**
+	 * Name of the ivar for this property.  NULL if undefined.
+	 */
+	const char *ivar_name;
+	/**
+	 * Attributes string for this property.  Return value for
+	 * property_getAttributes().
+	 */
+	const char *attrs_string;
+	/**
+	 * Attributes for this property.  Made by ORing together
+	 * PropertyAttributeKinds.
+	 */
+	unsigned int attributes;
 };
 
 /**
+ * List of property introspection data.
+ */
+struct objc_property_list
+{
+	/**
+	 * Number of properties in this array.
+	 */
+	int count;
+	/* 
+	 * The next property in a linked list.
+	 */
+	struct objc_property_list *next; 
+	/**
+	 * List of properties.
+	 */
+	struct objc_property properties[];
+};
+
+PRIVATE BOOL initPropertyFromAttributesList(struct objc_property *property,
+											const char *name,
+											const objc_property_attribute_t *attributes,
+											unsigned int attributesCount);
+
+#else /* __clang__ && __has_feature(objc_property_clean_abi) */
+/**
  * Structure used for property enumeration.  Note that property enumeration is
  * currently quite broken on OS X, so achieving full compatibility there is
  * impossible.  Instead, we strive to achieve compatibility with the
@@ -80,7 +168,7 @@ struct objc_property
 };
 
 /**
- * List of property inrospection data.
+ * List of property introspection data.
  */
 struct objc_property_list
 {
@@ -112,3 +200,5 @@ PRIVATE struct objc_property propertyFromAttrs(const objc_property_attribute_t *
  */
 PRIVATE const char *constructPropertyAttributes(objc_property_t property,
                                                 const char *iVarName);
+
+#endif /* __clang__ && __has_feature(objc_property_clean_abi) */
diff --git a/properties.m b/properties.m
index f26a2a4..2c28971 100644
--- a/properties.m
+++ b/properties.m
@@ -292,6 +292,333 @@ objc_property_t* class_copyPropertyList(Class cls, unsigned int *outCount)
 	return list;
 }
 
+#if __clang__ && __has_feature(objc_property_clean_abi)
+BOOL class_addProperty(Class cls,
+                       const char *name,
+                       const objc_property_attribute_t *attributes, 
+                       unsigned int attributesCount)
+{
+	if ((Nil == cls) || (NULL == name) || (class_getProperty(cls, name) != 0)) { return NO; }
+
+	struct objc_property p;
+	if (!initPropertyFromAttributesList(&p, name, attributes, attributesCount))
+	{
+		return NO;
+	}
+
+	struct objc_property_list *l = calloc(1, sizeof(struct objc_property_list)
+			+ sizeof(struct objc_property));
+	l->count = 1;
+	memcpy(&l->properties, &p, sizeof(struct objc_property));
+	LOCK_RUNTIME_FOR_SCOPE();
+	l->next = cls->properties;
+	cls->properties = l;
+	return YES;
+}
+
+void class_replaceProperty(Class cls,
+                           const char *name,
+                           const objc_property_attribute_t *attributes,
+                           unsigned int attributesCount)
+{
+	if ((Nil == cls) || (NULL == name)) { return; }
+	objc_property_t old = class_getProperty(cls, name);
+	if (NULL == old)
+	{
+		class_addProperty(cls, name, attributes, attributesCount);
+		return;
+	}
+	struct objc_property p;
+	if (!initPropertyFromAttributesList(&p, name, attributes, attributesCount))
+	{
+		return;
+	}
+	LOCK_RUNTIME_FOR_SCOPE();
+	if ((old->attributes & OBJC_PR_runtime_allocated) == OBJC_PR_runtime_allocated)
+	{
+		free((void *)old->name);
+		free((void *)old->attrs_string);
+		if (old->type_encoding != NULL)
+			free((void *)old->type_encoding);
+		if (old->getter_name != NULL)
+			free((void *)old->getter_name);
+		if (old->setter_name != NULL)
+			free((void *)old->setter_name);
+		if (old->ivar_name != NULL)
+			free((void *)old->ivar_name);
+	}
+	memcpy(old, &p, sizeof(p));
+}
+
+const char *property_getName(objc_property_t property)
+{
+	if (NULL == property) { return NULL; }
+
+	return property->name;
+}
+
+const char *property_getAttributes(objc_property_t property)
+{
+	if (NULL == property) { return NULL; }
+
+	return property->attrs_string;
+}
+
+objc_property_attribute_t *property_copyAttributeList(objc_property_t property,
+                                                      unsigned int *outCount)
+{
+	if (NULL == property) { return NULL; }
+	objc_property_attribute_t attrs[10];
+	int count = 0;
+
+	if (property->type_encoding != NULL)
+	{
+		attrs[count].name = "T";
+		attrs[count].value = property->type_encoding;
+		count++;
+	}
+	if ((property->attributes & OBJC_PR_readonly) == OBJC_PR_readonly)
+	{
+		attrs[count].name = "R";
+		attrs[count].value = "";
+		count++;
+	}
+	else
+	{
+		if ((property->attributes & OBJC_PR_retain) == OBJC_PR_retain
+			|| (property->attributes & OBJC_PR_strong) == OBJC_PR_strong)
+		{
+			attrs[count].name = "&";
+			attrs[count].value = "";
+			count++;
+		}
+		else if ((property->attributes & OBJC_PR_copy) == OBJC_PR_copy)
+		{
+			attrs[count].name = "C";
+			attrs[count].value = "";
+			count++;
+		}
+		else if ((property->attributes & OBJC_PR_weak) == OBJC_PR_weak)
+		{
+			attrs[count].name = "W";
+			attrs[count].value = "";
+			count++;
+		}
+	}
+	if ((property->attributes & OBJC_PR_dynamic) == OBJC_PR_dynamic)
+	{
+		attrs[count].name = "D";
+		attrs[count].value = "";
+		count++;
+	}
+	if ((property->attributes & OBJC_PR_nonatomic) == OBJC_PR_nonatomic)
+	{
+		attrs[count].name = "N";
+		attrs[count].value = "";
+		count++;
+	}
+	if ((property->attributes & OBJC_PR_getter) == OBJC_PR_getter)
+	{
+		attrs[count].name = "G";
+		attrs[count].value = property->getter_name;
+		count++;
+	}
+	if ((property->attributes & OBJC_PR_setter) == OBJC_PR_setter)
+	{
+		attrs[count].name = "S";
+		attrs[count].value = property->setter_name;
+		count++;
+	}
+	if (property->ivar_name != NULL)
+	{
+		attrs[count].name = "V";
+		attrs[count].value = property->ivar_name;
+		count++;
+	}
+
+	objc_property_attribute_t *propAttrs = calloc(sizeof(objc_property_attribute_t), count);
+	memcpy(propAttrs, attrs, count * sizeof(objc_property_attribute_t));
+	if (NULL != outCount)
+	{
+		*outCount = count;
+	}
+	return propAttrs;
+}
+
+char *property_copyAttributeValue(objc_property_t property,
+                                  const char *attributeName)
+{
+	if ((NULL == property) || (NULL == attributeName)) { return NULL; }
+	switch (attributeName[0])
+	{
+		case 'T':
+		{
+			return (NULL == property->type_encoding) ? NULL : strdup(property->type_encoding);
+		}
+		case 'V':
+		{
+			return (NULL == property->ivar_name) ? NULL : strdup(property->ivar_name);
+		}
+		case 'S':
+		{
+			return (NULL == property->setter_name) ? NULL : strdup(property->setter_name);
+		}
+		case 'G':
+		{
+			return (NULL == property->getter_name) ? NULL : strdup(property->getter_name);
+		}
+		case 'R':
+		{
+			return ((property->attributes & OBJC_PR_readonly) == OBJC_PR_readonly) ? strdup("") : 0;
+		}
+		case 'C':
+		{
+			return ((property->attributes & OBJC_PR_copy) == OBJC_PR_copy) ? strdup("") : 0;
+		}
+		case '&':
+		{
+			return ((property->attributes & OBJC_PR_retain) == OBJC_PR_retain
+				|| (property->attributes & OBJC_PR_strong) == OBJC_PR_strong) ? strdup("") : 0;
+		}
+		case 'W':
+		{
+			return ((property->attributes & OBJC_PR_weak) == OBJC_PR_weak) ? strdup("") : 0;
+		}
+		case 'N':
+		{
+			return ((property->attributes & OBJC_PR_nonatomic) == OBJC_PR_nonatomic) ? strdup("") : 0;
+		}
+		case 'D':
+		{
+			return ((property->attributes & OBJC_PR_dynamic) == OBJC_PR_dynamic) ? strdup("") : 0;
+		}
+	}
+	return 0;
+}
+
+/**
+ * Protocol's properties can not be dynamic nor should have a backing ivar.
+ * So use maybeDynamic only for categories or classes.
+ */
+BOOL initPropertyFromAttributesList(struct objc_property *p,
+									const char *name,
+								    const objc_property_attribute_t *attributes,
+								    unsigned int attributesCount)
+{
+	if (p == NULL || name == NULL) { return NO; }
+	memset(p, 0, sizeof(struct objc_property));
+	p->name = strdup(name);
+	p->attributes = OBJC_PR_runtime_allocated;
+
+	for (unsigned int i=0 ; i<attributesCount ; i++)
+	{
+		if (attributes[i].name == NULL)
+			continue;
+		
+		switch (attributes[i].name[0])
+		{
+			case 'T':
+				if (attributes[i].value != NULL)
+					p->type_encoding = strdup(attributes[i].value);
+				break;
+			case 'V':
+				if (attributes[i].value != NULL)
+					p->ivar_name = strdup(attributes[i].value);
+				break;
+			case 'S':
+				if (attributes[i].value != NULL)
+					p->setter_name = strdup(attributes[i].value);
+				break;
+			case 'G':
+				if (attributes[i].value != NULL)
+					p->getter_name = strdup(attributes[i].value);
+				break;
+			case 'R':
+				p->attributes |= OBJC_PR_readonly;
+				break;
+			case 'C':
+				p->attributes |= OBJC_PR_copy;
+				break;
+			case '&':
+				p->attributes |= OBJC_PR_retain;
+				break;
+			case 'W':
+				p->attributes |= OBJC_PR_weak;
+				break;
+			case 'N':
+				p->attributes |= OBJC_PR_nonatomic;
+				break;
+			case 'D':
+				p->attributes |= OBJC_PR_dynamic;
+				break;
+		}
+	}
+
+	p->attrs_string = (char *)malloc(32 +
+										((p->type_encoding) ? strlen(p->type_encoding) : 0) +
+										((p->getter_name) ? strlen(p->getter_name) : 0) +
+										((p->setter_name) ? strlen(p->setter_name) : 0) +
+										((p->ivar_name) ? strlen(p->ivar_name) : 0));
+	char *s = (char *)p->attrs_string;
+	if (p->type_encoding != NULL)
+	{
+		*s++ = 'T';
+		s = stpcpy(s, p->type_encoding);
+		*s++ = ',';
+	}
+	if ((p->attributes & OBJC_PR_readonly) == OBJC_PR_readonly)
+	{
+		s = stpcpy(s, "R,");
+	}
+	else
+	{
+		if ((p->attributes & OBJC_PR_retain) == OBJC_PR_retain
+			|| (p->attributes & OBJC_PR_strong) == OBJC_PR_strong)
+		{
+			s = stpcpy(s, "&,");
+		}
+		else if ((p->attributes & OBJC_PR_copy) == OBJC_PR_copy)
+		{
+			s = stpcpy(s, "C,");
+		}
+		else if ((p->attributes & OBJC_PR_weak) == OBJC_PR_weak)
+		{
+			s = stpcpy(s, "W,");
+		}
+	}
+	if ((p->attributes & OBJC_PR_dynamic) == OBJC_PR_dynamic)
+	{
+		s = stpcpy(s, "D,");
+	}
+	if ((p->attributes & OBJC_PR_nonatomic) == OBJC_PR_nonatomic)
+	{
+		s = stpcpy(s, "N,");
+	}
+	if (p->getter_name != NULL)
+	{
+		*s++ = 'G';
+		s = stpcpy(s, p->getter_name);
+		*s++ = ',';
+	}
+	if (p->setter_name != NULL)
+	{
+		*s++ = 'S';
+		s = stpcpy(s, p->setter_name);
+		*s++ = ',';
+	}
+	if (p->ivar_name != NULL)
+	{
+		*s++ = 'V';
+		s = stpcpy(s, p->ivar_name);
+		*s++ = ',';
+	}
+	// remove trailing ',' if any
+	if (s > p->attrs_string) s[-1] = '\0';
+
+	return YES;
+}
+
+#else /* __clang__ && __has_feature(objc_property_clean_abi) */
 const char *property_getName(objc_property_t property)
 {
 	if (NULL == property) { return NULL; }
@@ -678,3 +1005,5 @@ char *property_copyAttributeValue(objc_property_t property,
 	}
 	return 0;
 }
+
+#endif /* __clang__ && __has_feature(objc_property_clean_abi) */
diff --git a/protocol.c b/protocol.c
index 987463b..a5be2a4 100644
--- a/protocol.c
+++ b/protocol.c
@@ -516,6 +516,7 @@ void protocol_addMethodDescription(Protocol *aProtocol,
                                    BOOL isInstanceMethod)
 {
 	if ((NULL == aProtocol) || (NULL == name) || (NULL == types)) { return; }
+	LOCK_RUNTIME_FOR_SCOPE();
 	if (nil != aProtocol->isa) { return; }
 	Protocol2 *proto = (Protocol2*)aProtocol;
 	struct objc_method_description_list **listPtr;
@@ -560,6 +561,7 @@ void protocol_addMethodDescription(Protocol *aProtocol,
 void protocol_addProtocol(Protocol *aProtocol, Protocol *addition)
 {
 	if ((NULL == aProtocol) || (NULL == addition)) { return; }
+	LOCK_RUNTIME_FOR_SCOPE();
 	Protocol2 *proto = (Protocol2*)aProtocol;
 	if (NULL == proto->protocol_list)
 	{
@@ -578,13 +580,28 @@ void protocol_addProtocol(Protocol *aProtocol, Protocol *addition)
 void protocol_addProperty(Protocol *aProtocol,
                           const char *name,
                           const objc_property_attribute_t *attributes,
-                          unsigned int attributeCount,
+                          unsigned int attributesCount,
                           BOOL isRequiredProperty,
                           BOOL isInstanceProperty)
 {
-	if ((NULL == aProtocol) || (NULL == name)) { return; }
+	if ((NULL == aProtocol) || (NULL == name) || !isInstanceProperty) { return; }
+#if __clang__ && __has_feature(objc_property_clean_abi)
+	struct objc_property p;
+	if (!initPropertyFromAttributesList(&p, name, attributes, attributesCount))
+	{
+		return;
+	}
+#else /* __clang__ && __has_feature(objc_property_clean_abi) */
+	const char *iVarName = NULL;
+	struct objc_property p = propertyFromAttrs(attributes, attributesCount, &iVarName);
+	if (iVarName)
+	{
+		constructPropertyAttributes(&p, iVarName);
+	}
+	p.name = strdup(name);
+#endif /* __clang__ && __has_feature(objc_property_clean_abi) */
+	LOCK_RUNTIME_FOR_SCOPE();
 	if (nil != aProtocol->isa) { return; }
-	if (!isInstanceProperty) { return; }
 	Protocol2 *proto = (Protocol2*)aProtocol;
 	struct objc_property_list **listPtr;
 	if (isRequiredProperty)
@@ -608,13 +625,6 @@ void protocol_addProperty(Protocol *aProtocol,
 	}
 	struct objc_property_list *list = *listPtr;
 	int index = list->count-1;
-	const char *iVarName = NULL;
-	struct objc_property p = propertyFromAttrs(attributes, attributeCount, &iVarName);
-	if (iVarName)
-	{
-		constructPropertyAttributes(&p, iVarName);
-	}
-	p.name = strdup(name);
 	memcpy(&(list->properties[index]), &p, sizeof(p));
 }
 
_______________________________________________
Gnustep-dev mailing list
Gnustep-dev@gnu.org
https://lists.gnu.org/mailman/listinfo/gnustep-dev

Reply via email to