From 5750872c618185a2f1161d24510ad2be8669338a Mon Sep 17 00:00:00 2001 From: Nicola Pero Date: Fri, 24 Dec 2010 17:00:19 +0000 Subject: [PATCH] In libobjc/: 2010-12-24 Nicola Pero In libobjc/: 2010-12-24 Nicola Pero * objc/runtime.h (sel_getType): Renamed to sel_getTypeEncoding to be consistent with method_getTypeEncoding and ivar_getTypeEncoding. (sel_copyTypedSelectorList, sel_getTypedSelector): New. * selector.c (sel_getType): Renamed to sel_getTypeEncoding. (sel_copyTypedSelectorList, sel_getTypedSelector): New. (sel_get_type): Updated call to sel_getType. In gcc/testsuite/: 2010-12-24 Nicola Pero * objc.dg/gnu-api-2-sel.m: Updated for renaming of sel_getType to sel_getTypeEncoding. Test that sel_getTypeEncoding returns NULL when called with a NULL argument. Added test for sel_copyTypedSelectorList and sel_getTypedSelector. * obj-c++.dg/gnu-api-2-sel.mm: Same changes. From-SVN: r168229 --- gcc/testsuite/ChangeLog | 8 ++ gcc/testsuite/obj-c++.dg/gnu-api-2-sel.mm | 70 +++++++++++++++- gcc/testsuite/objc.dg/gnu-api-2-sel.m | 68 +++++++++++++++- libobjc/ChangeLog | 10 +++ libobjc/objc/runtime.h | 45 ++++++++++- libobjc/selector.c | 99 ++++++++++++++++++++++- 6 files changed, 285 insertions(+), 15 deletions(-) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 87bc46f01f06..0140ced82d4f 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,11 @@ +2010-12-24 Nicola Pero + + * objc.dg/gnu-api-2-sel.m: Updated for renaming of sel_getType to + sel_getTypeEncoding. Test that sel_getTypeEncoding returns NULL + when called with a NULL argument. Added test for + sel_copyTypedSelectorList and sel_getTypedSelector. + * obj-c++.dg/gnu-api-2-sel.mm: Same changes. + 2010-12-24 Eric Botcazou * gnat.dg/opt13_pkg.ad[sb]: Fix line ending. diff --git a/gcc/testsuite/obj-c++.dg/gnu-api-2-sel.mm b/gcc/testsuite/obj-c++.dg/gnu-api-2-sel.mm index 66cf0725c79c..956ba29ca838 100644 --- a/gcc/testsuite/obj-c++.dg/gnu-api-2-sel.mm +++ b/gcc/testsuite/obj-c++.dg/gnu-api-2-sel.mm @@ -35,11 +35,13 @@ { id variable_ivar; } - (void) setVariable: (id)value; - (id) variable; +- (void) method; @end @implementation MySubClass - (void) setVariable: (id)value { variable_ivar = value; } - (id) variable { return variable_ivar; } +- (void) method { return; } @end @@ -47,6 +49,30 @@ int main () { /* Functions are tested in alphabetical order. */ + std::cout << "Testing sel_copyTypedSelectorList ()...\n"; + { + unsigned int count; + SEL * list = sel_copyTypedSelectorList ("method", &count); + + /* There should only be two, since 'method' is referenced twice, + once with types and once without (in this very test). */ + if (count != 2) + abort (); + + /* Check that both selectors are not-NULL, and have the correct + name. We use @selector() here, which wouldn't really be + needed, just to register a second, untyped selector with name + 'method'. */ + if (std::strcmp (sel_getName (list[0]), sel_getName (@selector (method))) != 0) + abort (); + + if (std::strcmp (sel_getName (list[1]), sel_getName (@selector (method))) != 0) + abort (); + + if (list[2] != NULL) + abort (); + } + std::cout << "Testing sel_getName () ...\n"; { if (std::strcmp (sel_getName (@selector (variable)), "variable") != 0) @@ -56,14 +82,50 @@ int main () abort (); } - std::cout << "Testing sel_getType () ...\n"; + std::cout << "Testing sel_getTypeEncoding () ...\n"; { /* Get a selector from a real class, so it has interesting types. */ Method method = class_getInstanceMethod (objc_getClass ("MySubClass"), @selector (variable)); - if (std::strcmp (sel_getType (method_getName (method)), method_getTypeEncoding (method)) != 0) + if (std::strcmp (sel_getTypeEncoding (method_getName (method)), + method_getTypeEncoding (method)) != 0) + abort (); + + if (sel_getTypeEncoding (NULL) != NULL) + abort (); + } + + std::cout << "Testing sel_getTypedSelector () ...\n"; + { + /* First try with a selector where we know that a typed one has + been registered. */ + SEL selector = sel_getTypedSelector ("variable"); + + if (selector == NULL) + abort (); + + if (sel_getTypeEncoding (selector) == NULL) + abort (); + + /* Now try a selector which was never registered. */ + selector = sel_getTypedSelector ("not_registered"); + + if (selector != NULL) + abort (); + + /* Now try registering a selector with no types. The following + line is just a way to have an unused '@selector()' expression + without the compiler complaining. */ + if (@selector (registered_with_no_types) == NULL) + abort (); + + /* Try getting it. Nothing should be returned because it is + untyped. */ + selector = sel_getTypedSelector ("registered_with_no_types"); + + if (selector != NULL) abort (); } @@ -91,11 +153,11 @@ int main () (objc_getClass ("MySubClass"), @selector (variable))); SEL selector = sel_registerTypedName ("aMethod", types); - + if (std::strcmp (sel_getName (selector), "aMethod") != 0) abort (); - if (std::strcmp (sel_getType (selector), types) != 0) + if (std::strcmp (sel_getTypeEncoding (selector), types) != 0) abort (); } diff --git a/gcc/testsuite/objc.dg/gnu-api-2-sel.m b/gcc/testsuite/objc.dg/gnu-api-2-sel.m index e710083232d2..db2dcd3ec28b 100644 --- a/gcc/testsuite/objc.dg/gnu-api-2-sel.m +++ b/gcc/testsuite/objc.dg/gnu-api-2-sel.m @@ -35,11 +35,13 @@ { id variable_ivar; } - (void) setVariable: (id)value; - (id) variable; +- (void) method; @end @implementation MySubClass - (void) setVariable: (id)value { variable_ivar = value; } - (id) variable { return variable_ivar; } +- (void) method { return; } @end @@ -47,6 +49,30 @@ int main(int argc, void **args) { /* Functions are tested in alphabetical order. */ + printf ("Testing sel_copyTypedSelectorList ()...\n"); + { + unsigned int count; + SEL * list = sel_copyTypedSelectorList ("method", &count); + + /* There should only be two, since 'method' is referenced twice, + once with types and once without (in this very test). */ + if (count != 2) + abort (); + + /* Check that both selectors are not-NULL, and have the correct + name. We use @selector() here, which wouldn't really be + needed, just to register a second, untyped selector with name + 'method'. */ + if (strcmp (sel_getName (list[0]), sel_getName (@selector (method))) != 0) + abort (); + + if (strcmp (sel_getName (list[1]), sel_getName (@selector (method))) != 0) + abort (); + + if (list[2] != NULL) + abort (); + } + printf ("Testing sel_getName () ...\n"); { if (strcmp (sel_getName (@selector (variable)), "variable") != 0) @@ -56,14 +82,50 @@ int main(int argc, void **args) abort (); } - printf ("Testing sel_getType () ...\n"); + printf ("Testing sel_getTypeEncoding () ...\n"); { /* Get a selector from a real class, so it has interesting types. */ Method method = class_getInstanceMethod (objc_getClass ("MySubClass"), @selector (variable)); - if (strcmp (sel_getType (method_getName (method)), method_getTypeEncoding (method)) != 0) + if (strcmp (sel_getTypeEncoding (method_getName (method)), + method_getTypeEncoding (method)) != 0) + abort (); + + if (sel_getTypeEncoding (NULL) != NULL) + abort (); + } + + printf ("Testing sel_getTypedSelector () ...\n"); + { + /* First try with a selector where we know that a typed one has + been registered. */ + SEL selector = sel_getTypedSelector ("variable"); + + if (selector == NULL) + abort (); + + if (sel_getTypeEncoding (selector) == NULL) + abort (); + + /* Now try a selector which was never registered. */ + selector = sel_getTypedSelector ("not_registered"); + + if (selector != NULL) + abort (); + + /* Now try registering a selector with no types. The following + line is just a way to have an unused '@selector()' expression + without the compiler complaining. */ + if (@selector (registered_with_no_types) == NULL) + abort (); + + /* Try getting it. Nothing should be returned because it is + untyped. */ + selector = sel_getTypedSelector ("registered_with_no_types"); + + if (selector != NULL) abort (); } @@ -95,7 +157,7 @@ int main(int argc, void **args) if (strcmp (sel_getName (selector), "aMethod") != 0) abort (); - if (strcmp (sel_getType (selector), types) != 0) + if (strcmp (sel_getTypeEncoding (selector), types) != 0) abort (); } diff --git a/libobjc/ChangeLog b/libobjc/ChangeLog index 78112bdecfe1..e028b58fc234 100644 --- a/libobjc/ChangeLog +++ b/libobjc/ChangeLog @@ -1,3 +1,13 @@ +2010-12-24 Nicola Pero + + * objc/runtime.h (sel_getType): Renamed to sel_getTypeEncoding to + be consistent with method_getTypeEncoding and + ivar_getTypeEncoding. + (sel_copyTypedSelectorList, sel_getTypedSelector): New. + * selector.c (sel_getType): Renamed to sel_getTypeEncoding. + (sel_copyTypedSelectorList, sel_getTypedSelector): New. + (sel_get_type): Updated call to sel_getType. + 2010-12-24 Nicola Pero * objc/runtime.h (class_conformsToProtocol, diff --git a/libobjc/objc/runtime.h b/libobjc/objc/runtime.h index 7ad46dcc6fd0..18fc8726dc42 100644 --- a/libobjc/objc/runtime.h +++ b/libobjc/objc/runtime.h @@ -175,12 +175,13 @@ object_getClass (id object) "". */ objc_EXPORT const char *sel_getName (SEL selector); -/* Return the type of a given selector. +/* Return the type of a given selector. Return NULL if selector is + NULL. Compatibility Note: the Apple/NeXT runtime has untyped selectors, so it does not have this function, which is specific to the GNU Runtime. */ -objc_EXPORT const char *sel_getType (SEL selector); +objc_EXPORT const char *sel_getTypeEncoding (SEL selector); /* This is the same as sel_registerName (). Please use sel_registerName () instead. */ @@ -188,11 +189,16 @@ objc_EXPORT SEL sel_getUid (const char *name); /* Register a selector with a given name (but unspecified types). If you know the types, it is better to call sel_registerTypedName(). - If a selector with this name already exists, it is returned. */ + If a selector with this name and no types already exists, it is + returned. Note that this function should really be called + 'objc_registerSelector'. */ objc_EXPORT SEL sel_registerName (const char *name); /* Register a selector with a given name and types. If a selector - with this name and types already exists, it is returned. + with this name and types already exists, it is returned. Note that + this function should really be called 'objc_registerTypedSelector', + and it's called 'sel_registerTypedName' only for consistency with + 'sel_registerName'. Compatibility Note: the Apple/NeXT runtime has untyped selectors, so it does not have this function, which is specific to the GNU @@ -203,6 +209,37 @@ objc_EXPORT SEL sel_registerTypedName (const char *name, const char *type); if not. */ objc_EXPORT BOOL sel_isEqual (SEL first_selector, SEL second_selector); +/* Return all the selectors with the supplied name. In the GNU + runtime, selectors are typed and there may be multiple selectors + with the same name but a different type. The return value of the + function is a pointer to an area, allocated with malloc(), that + contains all the selectors with the supplier name known to the + runtime. The list is terminated by NULL. Optionally, if you pass + a non-NULL 'numberOfReturnedSelectors' pointer, the unsigned int + that it points to will be filled with the number of selectors + returned. + + Compatibility Note: the Apple/NeXT runtime has untyped selectors, + so it does not have this function, which is specific to the GNU + Runtime. */ +objc_EXPORT SEL * sel_copyTypedSelectorList (const char *name, + unsigned int *numberOfReturnedSelectors); + +/* Return a selector with name 'name' and a non-zero type encoding, if + any such selector is registered with the runtime. If there is no + such selector, NULL is returned. + + This is useful if you have the name of the selector, and would + really like to get a selector for it that includes the type + encoding. Unfortunately, if the program contains multiple selector + with the same name but different types, sel_getTypedSelector + returns a random one of them, which may not be the right one. + + Compatibility Note: the Apple/NeXT runtime has untyped selectors, + so it does not have this function, which is specific to the GNU + Runtime. */ +objc_EXPORT SEL sel_getTypedSelector (const char *name); + /** Implementation: the following functions are in objects.c. */ diff --git a/libobjc/selector.c b/libobjc/selector.c index 4fd213ba9196..f8a7f14fdb16 100644 --- a/libobjc/selector.c +++ b/libobjc/selector.c @@ -31,6 +31,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #include "objc-private/runtime.h" #include "objc-private/sarray.h" #include "objc-private/selector.h" +#include /* For malloc. */ /* Initial selector hash table size. Value doesn't matter much. */ #define SELECTOR_HASH_SIZE 128 @@ -250,7 +251,11 @@ sel_types_match (const char *t1, const char *t2) return NO; } -/* Return selector representing name. */ +/* Return selector representing name. In the Modern API, you'd + normally use sel_registerTypedName() for this, which does the same + but would register the selector with the runtime if not registered + yet (if you only want to check for selectors without registering, + use sel_copyTypedSelectorList()). */ SEL sel_get_typed_uid (const char *name, const char *types) { @@ -290,7 +295,8 @@ sel_get_typed_uid (const char *name, const char *types) } /* Return selector representing name; prefer a selector with non-NULL - type. */ + type. In the Modern API, sel_getTypedSelector() is similar but + returns NULL if a typed selector couldn't be found. */ SEL sel_get_any_typed_uid (const char *name) { @@ -347,6 +353,91 @@ sel_get_any_uid (const char *name) return (SEL) l->head; } +SEL +sel_getTypedSelector (const char *name) +{ + sidx i; + objc_mutex_lock (__objc_runtime_mutex); + + /* Look for a typed selector. */ + i = (sidx) objc_hash_value_for_key (__objc_selector_hash, name); + if (i != 0) + { + struct objc_list *l; + + for (l = (struct objc_list *) sarray_get_safe (__objc_selector_array, i); + l; l = l->tail) + { + SEL s = (SEL) l->head; + if (s->sel_types) + { + objc_mutex_unlock (__objc_runtime_mutex); + return s; + } + } + } + + /* No typed selector found. Return NULL. */ + objc_mutex_unlock (__objc_runtime_mutex); + return 0; +} + +SEL * +sel_copyTypedSelectorList (const char *name, unsigned int *numberOfReturnedSelectors) +{ + unsigned int count = 0; + SEL *returnValue = NULL; + sidx i; + + if (name == NULL) + { + if (numberOfReturnedSelectors) + *numberOfReturnedSelectors = 0; + return NULL; + } + + objc_mutex_lock (__objc_runtime_mutex); + + /* Count how many selectors we have. */ + i = (sidx) objc_hash_value_for_key (__objc_selector_hash, name); + if (i != 0) + { + struct objc_list *selector_list = NULL; + selector_list = (struct objc_list *) sarray_get_safe (__objc_selector_array, i); + + /* Count how many selectors we have. */ + { + struct objc_list *l; + for (l = selector_list; l; l = l->tail) + count++; + } + + if (count != 0) + { + /* Allocate enough memory to hold them. */ + returnValue = (SEL *)(malloc (sizeof (SEL) * (count + 1))); + + /* Copy the selectors. */ + { + unsigned int j; + for (j = 0; j < count; j++) + { + returnValue[j] = (SEL)(selector_list->head); + selector_list = selector_list->tail; + } + returnValue[j] = NULL; + } + } + } + + objc_mutex_unlock (__objc_runtime_mutex); + + if (numberOfReturnedSelectors) + *numberOfReturnedSelectors = count; + + return returnValue; +} + /* Get the name of a selector. If the selector is unknown, the empty string "" is returned. */ const char *sel_getName (SEL selector) @@ -382,7 +473,7 @@ sel_is_mapped (SEL selector) return ((idx > 0) && (idx <= __objc_selector_max_index)); } -const char *sel_getType (SEL selector) +const char *sel_getTypeEncoding (SEL selector) { if (selector) return selector->sel_types; @@ -393,7 +484,7 @@ const char *sel_getType (SEL selector) /* Traditional GNU Objective-C Runtime API. */ const char *sel_get_type (SEL selector) { - return sel_getType (selector); + return sel_getTypeEncoding (selector); } /* The uninstalled dispatch table. */ -- 2.43.5