Improve protocol tests and fix bugs.

Also add the new protocol_getProperties2 function.
main
David Chisnall 8 years ago
parent 8eb06a3b15
commit 0c9ee8b920

@ -4,26 +4,91 @@
#include <assert.h> #include <assert.h>
@protocol Test2 @end @protocol Test2 @end
@protocol Test3 @end
@protocol Test4 @end
void checkProtocolMethod(Protocol *p, SEL sel, BOOL isClass, BOOL isOptional)
{
struct objc_method_description d = protocol_getMethodDescription(p, sel, isClass, isOptional);
assert(sel_isEqual(d.name, sel));
assert(strcmp((d.types), "@:") == 0);
d = protocol_getMethodDescription(p, sel, !isClass, isOptional);
assert(d.name == NULL);
assert(d.types == NULL);
d = protocol_getMethodDescription(p, sel, isClass, !isOptional);
assert(d.name == NULL);
assert(d.types == NULL);
d = protocol_getMethodDescription(p, sel, !isClass, !isOptional);
assert(d.name == NULL);
assert(d.types == NULL);
}
int main(void) int main(void)
{ {
Protocol *force_reference = @protocol(Test2); Protocol *force_reference = @protocol(Test2);
Protocol *p = objc_allocateProtocol("Test"); Protocol *p = objc_allocateProtocol("Test");
protocol_addMethodDescription(p, @selector(someMethod), "@:", YES, NO); protocol_addMethodDescription(p, @selector(someClassMethod), "@:", YES, NO);
protocol_addMethodDescription(p, @selector(someOptionalClassMethod), "@:", YES, YES);
protocol_addMethodDescription(p, @selector(someMethod), "@:", NO, NO);
protocol_addMethodDescription(p, @selector(someOtherMethod), "@:", NO, NO);
protocol_addMethodDescription(p, @selector(someOptionalMethod), "@:", NO, YES);
assert(objc_getProtocol("Test2")); assert(objc_getProtocol("Test2"));
protocol_addProtocol(p, objc_getProtocol("Test2")); protocol_addProtocol(p, objc_getProtocol("Test2"));
objc_property_attribute_t attrs[] = { {"T", "@" }, {"V", "foo"} }; protocol_addProtocol(p, @protocol(Test3));
protocol_addProperty(p, "foo", attrs, 2, YES, YES);
// Check that this don't crash
protocol_addProtocol(p, NULL);
protocol_addProtocol(NULL, p);
protocol_addProtocol(NULL, NULL);
objc_property_attribute_t attrs[] = { {"T", "@" }, {"V", "optional"} };
protocol_addProperty(p, "optional", attrs, 2, NO, YES);
attrs[1].value = "required";
protocol_addProperty(p, "required", attrs, 2, YES, YES);
attrs[1].value = "required2";
protocol_addProperty(p, "required2", attrs, 2, YES, YES);
protocol_addProperty(p, "classOptional", attrs, 1, NO, NO);
protocol_addProperty(p, "classRequired", attrs, 1, YES, NO);
checkProtocolMethod(p, @selector(someClassMethod), YES, NO);
checkProtocolMethod(p, @selector(someOptionalClassMethod), YES, YES);
checkProtocolMethod(p, @selector(someMethod), NO, NO);
checkProtocolMethod(p, @selector(someOtherMethod), NO, NO);
checkProtocolMethod(p, @selector(someOptionalMethod), NO, YES);
objc_registerProtocol(p); objc_registerProtocol(p);
// Modifying protocols after they've been registered is not permitted.
protocol_addProtocol(p, @protocol(Test4));
protocol_addMethodDescription(p, @selector(someUnsupportedMethod), "@:", NO, NO);
protocol_addProperty(p, "classRequired2", attrs, 1, NO, NO);
Protocol *p1 = objc_getProtocol("Test"); Protocol *p1 = objc_getProtocol("Test");
assert(p == p1); assert(p == p1);
struct objc_method_description d = protocol_getMethodDescription(p1, @selector(someMethod), YES, NO);
assert(strcmp(sel_getName(d.name), "someMethod") == 0); checkProtocolMethod(p1, @selector(someClassMethod), YES, NO);
assert(strcmp((d.types), "@:") == 0); checkProtocolMethod(p1, @selector(someOptionalClassMethod), YES, YES);
checkProtocolMethod(p1, @selector(someMethod), NO, NO);
checkProtocolMethod(p1, @selector(someOtherMethod), NO, NO);
checkProtocolMethod(p1, @selector(someOptionalMethod), NO, YES);
// Added after the protocol was registered, shouldn't have been allowed.
struct objc_method_description d = protocol_getMethodDescription(p1, @selector(someUnsupportedMethod), NO, NO);
assert(d.name == NULL);
assert(d.types == NULL);
assert(protocol_conformsToProtocol(p1, objc_getProtocol("Test2"))); assert(protocol_conformsToProtocol(p1, objc_getProtocol("Test2")));
assert(protocol_conformsToProtocol(p1, objc_getProtocol("Test3")));
// Added after the protocol was registered, shouldn't have been allowed.
assert(!protocol_conformsToProtocol(p1, objc_getProtocol("Test4")));
unsigned int count; unsigned int count;
objc_property_t *props = protocol_copyPropertyList(p1, &count); protocol_copyPropertyList(p1, &count);
assert(count == 2);
protocol_copyPropertyList2(p1, &count, YES, YES);
assert(count == 2);
objc_property_t *props = protocol_copyPropertyList2(p1, &count, NO, YES);
assert(count == 1); assert(count == 1);
assert(strcmp("T@,Vfoo", property_getAttributes(*props)) == 0); assert(strcmp("T@,Voptional", property_getAttributes(*props)) == 0);
//objc_copyProtocolList
return 0; return 0;
} }

@ -715,12 +715,20 @@ struct objc_method_description *protocol_copyMethodDescriptionList(Protocol *p,
BOOL isRequiredMethod, BOOL isInstanceMethod, unsigned int *count); BOOL isRequiredMethod, BOOL isInstanceMethod, unsigned int *count);
/** /**
* Returns an array of property metadata values, with the number being stored * Returns an array of required instance properties, with the number being
* in the variable pointed to by the last argument. The caller is responsible * stored in the variable pointed to by the last argument. The caller is
* for freeing the returned array. * responsible for freeing the returned array.
*/ */
objc_property_t *protocol_copyPropertyList(Protocol *p, unsigned int *count); objc_property_t *protocol_copyPropertyList(Protocol *p, unsigned int *count);
/**
* Returns an array of properties specified by this class, with the number
* being stored in the variable pointed to by the last argument. The caller is
* responsible for freeing the returned array.
*/
objc_property_t *protocol_copyPropertyList2(Protocol *p, unsigned int *count,
BOOL isRequiredProperty, BOOL isInstanceProperty);
/** /**
* Returns an array of protocols that this protocol conforms to, with the * Returns an array of protocols that this protocol conforms to, with the
* number of protocols in the array being returned via the last argument. The * number of protocols in the array being returned via the last argument. The

@ -391,23 +391,28 @@ Protocol*__unsafe_unretained* protocol_copyProtocolList(Protocol *p, unsigned in
return out; return out;
} }
objc_property_t *protocol_copyPropertyList(Protocol *p, objc_property_t *protocol_copyPropertyList2(Protocol *p, unsigned int *outCount,
unsigned int *outCount) BOOL isRequiredProperty, BOOL isInstanceProperty)
{ {
struct objc_property_list *properties =
isInstanceProperty ?
(isRequiredProperty ? p->properties : p->optional_properties) :
(isRequiredProperty ? p->class_properties : p->optional_class_properties);
if (NULL == p) { return NULL; } if (NULL == p) { return NULL; }
if (!protocol_hasOptionalMethodsAndProperties(p)) // If it's an old protocol, it won't have any of the other options.
if (!isRequiredProperty && !isInstanceProperty &&
!protocol_hasOptionalMethodsAndProperties(p))
{ {
return NULL; return NULL;
} }
struct objc_property_list *properties = p->properties; if (properties == NULL)
unsigned int count = 0;
if (NULL != properties)
{ {
count = properties->count; return NULL;
} }
if (NULL != p->optional_properties) unsigned int count = 0;
for (struct objc_property_list *l=properties ; l!=NULL ; l=l->next)
{ {
count += p->optional_properties->count; count += properties->count;
} }
if (0 == count) if (0 == count)
{ {
@ -415,25 +420,23 @@ objc_property_t *protocol_copyPropertyList(Protocol *p,
} }
objc_property_t *list = calloc(sizeof(objc_property_t), count); objc_property_t *list = calloc(sizeof(objc_property_t), count);
unsigned int out = 0; unsigned int out = 0;
if (properties) for (struct objc_property_list *l=properties ; l!=NULL ; l=l->next)
{
for (int i=0 ; i<properties->count ; i++)
{
list[out++] = property_at_index(properties, i);
}
}
properties = p->optional_properties;
if (properties)
{ {
for (int i=0 ; i<properties->count ; i++) for (int i=0 ; i<l->count ; i++)
{ {
list[out++] = property_at_index(properties, i); list[out++] = property_at_index(l, i);
} }
} }
*outCount = count; *outCount = count;
return list; return list;
} }
objc_property_t *protocol_copyPropertyList(Protocol *p,
unsigned int *outCount)
{
return protocol_copyPropertyList2(p, outCount, YES, YES);
}
objc_property_t protocol_getProperty(Protocol *p, objc_property_t protocol_getProperty(Protocol *p,
const char *name, const char *name,
BOOL isRequiredProperty, BOOL isRequiredProperty,
@ -658,7 +661,6 @@ void protocol_addProtocol(Protocol *aProtocol, Protocol *addition)
aProtocol->protocol_list->count++; aProtocol->protocol_list->count++;
aProtocol->protocol_list = realloc(aProtocol->protocol_list, sizeof(struct objc_property_list) + aProtocol->protocol_list = realloc(aProtocol->protocol_list, sizeof(struct objc_property_list) +
aProtocol->protocol_list->count * sizeof(Protocol*)); aProtocol->protocol_list->count * sizeof(Protocol*));
aProtocol->protocol_list->count = 1;
} }
aProtocol->protocol_list->list[aProtocol->protocol_list->count-1] = (Protocol*)addition; aProtocol->protocol_list->list[aProtocol->protocol_list->count-1] = (Protocol*)addition;
} }
@ -672,15 +674,10 @@ void protocol_addProperty(Protocol *aProtocol,
if ((NULL == aProtocol) || (NULL == name)) { return; } if ((NULL == aProtocol) || (NULL == name)) { return; }
if (incompleteProtocolClass() != aProtocol->isa) { return; } if (incompleteProtocolClass() != aProtocol->isa) { return; }
if (!isInstanceProperty) { return; } if (!isInstanceProperty) { return; }
struct objc_property_list **listPtr; struct objc_property_list **listPtr =
if (isRequiredProperty) isInstanceProperty ?
{ (isRequiredProperty ? &aProtocol->properties : &aProtocol->optional_properties) :
listPtr = &aProtocol->properties; (isRequiredProperty ? &aProtocol->class_properties : &aProtocol->optional_class_properties);
}
else
{
listPtr = &aProtocol->optional_properties;
}
if (NULL == *listPtr) if (NULL == *listPtr)
{ {
*listPtr = calloc(1, sizeof(struct objc_property_list) + sizeof(struct objc_property)); *listPtr = calloc(1, sizeof(struct objc_property_list) + sizeof(struct objc_property));

Loading…
Cancel
Save