Fix handling of properties that refer to an instance variable other than the

default.
main
theraven 13 years ago
parent 17b8ff43c9
commit abc1d44c9c

@ -0,0 +1,49 @@
#include <stdio.h>
#import <Foundation/NSObject.h>
#import <objc/runtime.h>
#include <assert.h>
@interface helloclass : NSObject {
@private int varName;
}
@property (readwrite,assign) int propName;
@end
@implementation helloclass
@synthesize propName = varName;
@end
int main()
{
unsigned int outCount, i;
objc_property_t *properties = class_copyPropertyList([helloclass class], &outCount);
assert(outCount == 1);
objc_property_t property = properties[0];
assert(strcmp(property_getName(property), "propName") == 0);
assert(strcmp(property_getAttributes(property), "Ti,VvarName") == 0);
free(properties);
Method* methods = class_copyMethodList([helloclass class], &outCount);
assert(outCount == 2);
free(methods);
objc_property_attribute_t a = { "V", "varName" };
assert(class_addProperty([helloclass class], "propName2", &a, 1));
properties = class_copyPropertyList([helloclass class], &outCount);
assert(outCount == 2);
int found = 0;
for (int i=0 ; i<2 ; i++)
{
property = properties[i];
fprintf(stderr, "Name: %s\n", property_getName(property));
fprintf(stderr, "Attrs: %s\n", property_getAttributes(property));
if (strcmp(property_getName(property), "propName2") == 0)
{
assert(strcmp(property_getAttributes(property), "VvarName") == 0);
found++;
}
}
assert(found == 1);
return 0;
}

@ -99,7 +99,16 @@ struct objc_property_list
}; };
/** /**
* Constructs a property description from a list of attributes. * Constructs a property description from a list of attributes, returning the
* instance variable name via the third parameter.
*/ */
PRIVATE struct objc_property propertyFromAttrs(const objc_property_attribute_t *attributes, PRIVATE struct objc_property propertyFromAttrs(const objc_property_attribute_t *attributes,
unsigned int attributeCount); unsigned int attributeCount,
const char **iVarName);
/**
* Constructs and installs a property attribute string from the property
* attributes and, optionally, an ivar string.
*/
PRIVATE const char *constructPropertyAttributes(objc_property_t property,
const char *iVarName);

@ -210,7 +210,7 @@ objc_property_t* class_copyPropertyList(Class cls, unsigned int *outCount)
{ {
for (int i=0 ; i<properties->count ; i++) for (int i=0 ; i<properties->count ; i++)
{ {
list[out] = &l->properties[i]; list[out++] = &l->properties[i];
} }
} }
return list; return list;
@ -238,6 +238,7 @@ PRIVATE size_t lengthOfTypeEncoding(const char *types);
static const char *property_getTypeEncoding(objc_property_t property) static const char *property_getTypeEncoding(objc_property_t property)
{ {
if (NULL == property) { return NULL; } if (NULL == property) { return NULL; }
if (NULL == property->getter_types) { return NULL; }
const char *name = property->getter_types; const char *name = property->getter_types;
if (name[0] == 0) if (name[0] == 0)
@ -256,19 +257,14 @@ static const char *property_getTypeEncoding(objc_property_t property)
return &property->getter_types[1]; return &property->getter_types[1];
} }
const char *property_getAttributes(objc_property_t property) PRIVATE const char *constructPropertyAttributes(objc_property_t property,
const char *iVarName)
{ {
if (NULL == property) { return NULL; }
const char *name = (char*)property->name; const char *name = (char*)property->name;
if (name[0] == 0)
{
return name + 2;
}
const char *typeEncoding = property_getTypeEncoding(property); const char *typeEncoding = property_getTypeEncoding(property);
size_t typeSize = strlen(typeEncoding); size_t typeSize = (NULL == typeEncoding) ? 0 : strlen(typeEncoding);
size_t nameSize = strlen(property->name); size_t nameSize = strlen(property->name);
size_t iVarNameSize = strlen(iVarName);
// Encoding is T{type},V{name}, so 4 bytes for the "T,V" that we always // 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. // need. We also need two bytes for the leading null and the length.
size_t encodingSize = typeSize + nameSize + 6; size_t encodingSize = typeSize + nameSize + 6;
@ -276,23 +272,35 @@ const char *property_getAttributes(objc_property_t property)
size_t i = 0; size_t i = 0;
// Flags that are a comma then a character // Flags that are a comma then a character
if ((property->attributes & OBJC_PR_readonly) == OBJC_PR_readonly) if ((property->attributes & OBJC_PR_readonly) == OBJC_PR_readonly)
{
if (i > 0)
{ {
flags[i++] = ','; flags[i++] = ',';
}
flags[i++] = 'R'; flags[i++] = 'R';
} }
if ((property->attributes & OBJC_PR_copy) == OBJC_PR_copy) if ((property->attributes & OBJC_PR_copy) == OBJC_PR_copy)
{
if (i > 0)
{ {
flags[i++] = ','; flags[i++] = ',';
}
flags[i++] = 'C'; flags[i++] = 'C';
} }
if ((property->attributes & OBJC_PR_retain) == OBJC_PR_retain) if ((property->attributes & OBJC_PR_retain) == OBJC_PR_retain)
{
if (i > 0)
{ {
flags[i++] = ','; flags[i++] = ',';
}
flags[i++] = '&'; flags[i++] = '&';
} }
if ((property->attributes & OBJC_PR_nonatomic) == OBJC_PR_nonatomic) if ((property->attributes & OBJC_PR_nonatomic) == OBJC_PR_nonatomic)
{
if (i > 0)
{ {
flags[i++] = ','; flags[i++] = ',';
}
flags[i++] = 'N'; flags[i++] = 'N';
} }
encodingSize += i; encodingSize += i;
@ -309,34 +317,61 @@ const char *property_getAttributes(objc_property_t property)
setterLength = strlen(property->setter_name); setterLength = strlen(property->setter_name);
encodingSize += 2 + setterLength; encodingSize += 2 + setterLength;
} }
if (NULL != iVarName)
{
encodingSize += 2 + iVarNameSize;
}
unsigned char *encoding = malloc(encodingSize); unsigned char *encoding = malloc(encodingSize);
// Set the leading 0 and the offset of the name // Set the leading 0 and the offset of the name
unsigned char *insert = encoding; unsigned char *insert = encoding;
*(insert++) = 0; *(insert++) = 0;
*(insert++) = 0; *(insert++) = 0;
// Set the type encoding // Set the type encoding
if (NULL != typeEncoding)
{
*(insert++) = 'T'; *(insert++) = 'T';
memcpy(insert, typeEncoding, typeSize); memcpy(insert, typeEncoding, typeSize);
insert += typeSize; insert += typeSize;
}
// Set the flags // Set the flags
memcpy(insert, flags, i); memcpy(insert, flags, i);
insert += i; insert += i;
if ((property->attributes & OBJC_PR_getter) == OBJC_PR_getter) if ((property->attributes & OBJC_PR_getter) == OBJC_PR_getter)
{
if (i > 0)
{ {
*(insert++) = ','; *(insert++) = ',';
}
i++;
*(insert++) = 'G'; *(insert++) = 'G';
memcpy(insert, property->getter_name, getterLength); memcpy(insert, property->getter_name, getterLength);
insert += getterLength; insert += getterLength;
} }
if ((property->attributes & OBJC_PR_setter) == OBJC_PR_setter) if ((property->attributes & OBJC_PR_setter) == OBJC_PR_setter)
{
if (i > 0)
{ {
*(insert++) = ','; *(insert++) = ',';
}
i++;
*(insert++) = 'S'; *(insert++) = 'S';
memcpy(insert, property->setter_name, setterLength); memcpy(insert, property->setter_name, setterLength);
insert += setterLength; insert += setterLength;
} }
if (i > 0)
{
*(insert++) = ','; *(insert++) = ',';
}
*(insert++) = 'V'; *(insert++) = 'V';
// If the instance variable name is the same as the property name, then we
// use the same string for both, otherwise we write the ivar name in the
// attributes string and then a null and then the name.
if (NULL != iVarName)
{
memcpy(insert, iVarName, iVarNameSize);
insert += iVarNameSize;
*(insert++) = '\0';
}
encoding[1] = (unsigned char)(uintptr_t)(insert - encoding); encoding[1] = (unsigned char)(uintptr_t)(insert - encoding);
memcpy(insert, property->name, nameSize); memcpy(insert, property->name, nameSize);
insert += nameSize; insert += nameSize;
@ -351,6 +386,19 @@ const char *property_getAttributes(objc_property_t property)
return (const char*)(encoding + 2); return (const char*)(encoding + 2);
} }
const char *property_getAttributes(objc_property_t property)
{
if (NULL == property) { return NULL; }
const char *name = (char*)property->name;
if (name[0] == 0)
{
return name + 2;
}
return constructPropertyAttributes(property, NULL);
}
objc_property_attribute_t *property_copyAttributeList(objc_property_t property, objc_property_attribute_t *property_copyAttributeList(objc_property_t property,
unsigned int *outCount) unsigned int *outCount)
{ {
@ -358,9 +406,13 @@ objc_property_attribute_t *property_copyAttributeList(objc_property_t property,
objc_property_attribute_t attrs[10]; objc_property_attribute_t attrs[10];
int count = 0; int count = 0;
const char *types = property_getTypeEncoding(property);
if (NULL != types)
{
attrs[count].name = "T"; attrs[count].name = "T";
attrs[count].value = property_getTypeEncoding(property); attrs[count].value = types;
count++; count++;
}
if ((property->attributes & OBJC_PR_copy) == OBJC_PR_copy) if ((property->attributes & OBJC_PR_copy) == OBJC_PR_copy)
{ {
attrs[count].name = "C"; attrs[count].name = "C";
@ -405,7 +457,8 @@ objc_property_attribute_t *property_copyAttributeList(objc_property_t property,
} }
PRIVATE struct objc_property propertyFromAttrs(const objc_property_attribute_t *attributes, PRIVATE struct objc_property propertyFromAttrs(const objc_property_attribute_t *attributes,
unsigned int attributeCount) unsigned int attributeCount,
const char **name)
{ {
struct objc_property p = { 0 }; struct objc_property p = { 0 };
for (unsigned int i=0 ; i<attributeCount ; i++) for (unsigned int i=0 ; i<attributeCount ; i++)
@ -434,7 +487,7 @@ PRIVATE struct objc_property propertyFromAttrs(const objc_property_attribute_t *
} }
case 'V': case 'V':
{ {
p.name = strdup(attributes[i].value); *name = attributes[i].value;
break; break;
} }
case 'C': case 'C':
@ -460,9 +513,19 @@ BOOL class_addProperty(Class cls,
unsigned int attributeCount) unsigned int attributeCount)
{ {
if ((Nil == cls) || (NULL == name) || (class_getProperty(cls, name) != 0)) { return NO; } if ((Nil == cls) || (NULL == name) || (class_getProperty(cls, name) != 0)) { return NO; }
struct objc_property p = propertyFromAttrs(attributes, attributeCount); const char *iVarname = NULL;
// If there is a name mismatch, the attributes are invalid. struct objc_property p = propertyFromAttrs(attributes, attributeCount, &iVarname);
if ((p.name != 0) && (strcmp(name, p.name) != 0)) { return NO; } // If the iVar name is not the same as the name, then we need to construct
// the attributes string now, otherwise we can construct it lazily.
if (iVarname)
{
p.name = name;
constructPropertyAttributes(&p, iVarname);
}
else
{
p.name = strdup(name);
}
struct objc_property_list *l = calloc(1, sizeof(struct objc_property_list) struct objc_property_list *l = calloc(1, sizeof(struct objc_property_list)
+ sizeof(struct objc_property)); + sizeof(struct objc_property));
@ -486,12 +549,16 @@ void class_replaceProperty(Class cls,
class_addProperty(cls, name, attributes, attributeCount); class_addProperty(cls, name, attributes, attributeCount);
return; return;
} }
struct objc_property p = propertyFromAttrs(attributes, attributeCount); const char *iVarname = name;
memcpy(old, &p, sizeof(struct objc_property)); struct objc_property p = propertyFromAttrs(attributes, attributeCount, &iVarname);
if (NULL == old->name) LOCK_RUNTIME_FOR_SCOPE();
// If the iVar name is not the same as the name, then we need to construct
// the attributes string now, otherwise we can construct it lazily.
if (iVarname != name)
{ {
old->name = name; constructPropertyAttributes(&p, iVarname);
} }
memcpy(old, &p, sizeof(struct objc_property));
} }
char *property_copyAttributeValue(objc_property_t property, char *property_copyAttributeValue(objc_property_t property,
const char *attributeName) const char *attributeName)
@ -501,7 +568,8 @@ char *property_copyAttributeValue(objc_property_t property,
{ {
case 'T': case 'T':
{ {
return strdup(property_getTypeEncoding(property)); const char *types = property_getTypeEncoding(property);
return (NULL == types) ? NULL : strdup(types);
} }
case 'V': case 'V':
{ {

@ -608,7 +608,12 @@ void protocol_addProperty(Protocol *aProtocol,
} }
struct objc_property_list *list = *listPtr; struct objc_property_list *list = *listPtr;
int index = list->count-1; int index = list->count-1;
struct objc_property p = propertyFromAttrs(attributes, attributeCount); const char *iVarName = NULL;
struct objc_property p = propertyFromAttrs(attributes, attributeCount, &iVarName);
if (iVarName)
{
constructPropertyAttributes(&p, iVarName);
}
p.name = strdup(name); p.name = strdup(name);
memcpy(&(list->properties[index]), &p, sizeof(p)); memcpy(&(list->properties[index]), &p, sizeof(p));
} }

Loading…
Cancel
Save