diff --git a/encoding2.c b/encoding2.c index c20aac4..8fdcca7 100644 --- a/encoding2.c +++ b/encoding2.c @@ -5,6 +5,7 @@ #include "objc/runtime.h" #include "method_list.h" +#include "visibility.h" size_t objc_alignof_type (const char *type); @@ -38,7 +39,7 @@ const char *objc_skip_argspec(const char *type) return type; } -static size_t lengthOfTypeEncoding(const char *types) +PRIVATE size_t lengthOfTypeEncoding(const char *types) { const char *end = objc_skip_typespec(types); size_t length = end - types; diff --git a/objc/runtime.h b/objc/runtime.h index 5282066..38888b8 100644 --- a/objc/runtime.h +++ b/objc/runtime.h @@ -573,6 +573,14 @@ const char *object_getClassName(id obj); */ const char *property_getName(objc_property_t property); +/** + * Returns the attributes for the specified property. This is similar to an + * Objective-C type encoding, but contains some extra information. A full + * description of the format for this string may be found in Apple's + * Objective-C Runtime Programming Guide. + */ +const char *property_getAttributes(objc_property_t property); + /** * Testswhether a protocol conforms to another protocol. */ diff --git a/properties.h b/properties.h index aefb30c..64538b7 100644 --- a/properties.h +++ b/properties.h @@ -60,14 +60,6 @@ struct objc_property * Flag set if the property is synthesized. */ const char isSynthesized; - /** - * Name of the set method for this property. - */ - const char *setter_name; - /** - * Type encoding of the setter for this property. - */ - const char *setter_types; /** * Name of the getter for this property. */ @@ -76,6 +68,14 @@ struct objc_property * Type encoding for the get method for this property. */ const char *getter_types; + /** + * Name of the set method for this property. + */ + const char *setter_name; + /** + * Type encoding of the setter for this property. + */ + const char *setter_types; }; /** diff --git a/properties.m b/properties.m index 8dc87b3..960e9e9 100644 --- a/properties.m +++ b/properties.m @@ -199,5 +199,105 @@ objc_property_t* class_copyPropertyList(Class cls, unsigned int *outCount) const char *property_getName(objc_property_t property) { - return property->name; + if (NULL == property) { return NULL; } + + const char *name = property->name; + if (name[0] == 0) + { + name += name[1]; + } + return name; +} + +PRIVATE size_t lengthOfTypeEncoding(const char *types); + +const char *property_getAttributes(objc_property_t property) +{ + if (NULL == property) { return NULL; } + + char *name = (char*)property->name; + if (name[0] == 0) + { + return name + 2; + } + + size_t typeSize = lengthOfTypeEncoding(property->getter_types); + size_t nameSize = strlen(property->name); + // Encoding is T{type},V{name}, so 4 bytes for the "T,V" that we always + // need. We also need two bytes for the leading null and the length. + size_t encodingSize = typeSize + nameSize + 6; + char flags[16]; + size_t i = 0; + // Flags that are a comma then a character + if ((property->attributes & OBJC_PR_readonly) == OBJC_PR_readonly) + { + flags[i++] = ','; + flags[i++] = 'R'; + } + if ((property->attributes & OBJC_PR_copy) == OBJC_PR_copy) + { + flags[i++] = ','; + flags[i++] = 'C'; + } + if ((property->attributes & OBJC_PR_retain) == OBJC_PR_retain) + { + flags[i++] = ','; + flags[i++] = '&'; + } + if ((property->attributes & OBJC_PR_nonatomic) == OBJC_PR_nonatomic) + { + flags[i++] = ','; + flags[i++] = 'N'; + } + encodingSize += i; + flags[i] = '\0'; + size_t setterLength = 0; + size_t getterLength = 0; + if ((property->attributes & OBJC_PR_getter) == OBJC_PR_getter) + { + getterLength = strlen(property->getter_name); + encodingSize += 2 + getterLength; + } + if ((property->attributes & OBJC_PR_setter) == OBJC_PR_setter) + { + setterLength = strlen(property->setter_name); + encodingSize += 2 + setterLength; + } + name = malloc(encodingSize); + // Set the leading 0 and the offset of the name + char *insert = name; + *(insert++) = 0; + *(insert++) = 0; + // Set the type encoding + *(insert++) = 'T'; + memcpy(insert, property->getter_types, typeSize); + insert += typeSize; + // Set the flags + memcpy(insert, flags, i); + insert += i; + if ((property->attributes & OBJC_PR_getter) == OBJC_PR_getter) + { + *(insert++) = ','; + *(insert++) = 'G'; + memcpy(insert, property->getter_name, getterLength); + insert += getterLength; + } + if ((property->attributes & OBJC_PR_setter) == OBJC_PR_setter) + { + *(insert++) = ','; + *(insert++) = 'S'; + memcpy(insert, property->setter_name, setterLength); + insert += setterLength; + } + *(insert++) = ','; + *(insert++) = 'V'; + name[1] = (char)(uintptr_t)(insert - name); + memcpy(insert, property->name, nameSize); + insert += nameSize; + *insert = '\0'; + //FIXME: Don't leak if this is called simultaneously from two threads. + //Should be an atomic CAS + property->name = name; + return name + 2; } +