In gcc/: 2010-10-17 Nicola Pero <nicola.pero@meta-innovation.com>
In gcc/: 2010-10-17 Nicola Pero <nicola.pero@meta-innovation.com> * doc/objc.texi (GNU Objective-C runtime API): New section. (Modern GNU Objective-C runtime API): New section. (Traditional GNU Objective-C runtime API): New section. (Executing code before main): Mention that this section is specific to the GNU Objective-C runtime. (Garbage Collection): Same. In gcc/testsuite/: 2010-10-17 Nicola Pero <nicola.pero@meta-innovation.com> * obj-c++.dg/gnu-api-2-class.mm: New. * obj-c++.dg/gnu-api-2-ivar.mm: New. * obj-c++.dg/gnu-api-2-method.mm: New. * obj-c++.dg/gnu-api-2-objc.mm: New. * obj-c++.dg/gnu-api-2-object.mm: New. * obj-c++.dg/gnu-api-2-property.mm: New. * obj-c++.dg/gnu-api-2-protocol.mm: New. * obj-c++.dg/gnu-api-2-sel.mm: New. In libobjc/: 2010-10-17 Nicola Pero <nicola.pero@meta-innovation.com> * objc/message.h: Moved initial includes outside of extern "C". * objc/runtime.h: Add extern "C" for Objective-C++. From-SVN: r165595
This commit is contained in:
parent
91b90ead33
commit
5b8b526e69
@ -1,3 +1,12 @@
|
||||
2010-10-17 Nicola Pero <nicola.pero@meta-innovation.com>
|
||||
|
||||
* doc/objc.texi (GNU Objective-C runtime API): New section.
|
||||
(Modern GNU Objective-C runtime API): New section.
|
||||
(Traditional GNU Objective-C runtime API): New section.
|
||||
(Executing code before main): Mention that this section is
|
||||
specific to the GNU Objective-C runtime.
|
||||
(Garbage Collection): Same.
|
||||
|
||||
2010-10-17 Uros Bizjak <ubizjak@gmail.com>
|
||||
|
||||
* c-parser.c (c_parser_for_statement): Move initialization of
|
||||
|
@ -9,10 +9,11 @@
|
||||
@chapter GNU Objective-C features
|
||||
|
||||
This document is meant to describe some of the GNU Objective-C
|
||||
features. It is not intended to teach you Objective-C, there are
|
||||
features. It is not intended to teach you Objective-C. There are
|
||||
several resources on the Internet that present the language.
|
||||
|
||||
@menu
|
||||
* GNU Objective-C runtime API::
|
||||
* Executing code before main::
|
||||
* Type encoding::
|
||||
* Garbage Collection::
|
||||
@ -23,9 +24,124 @@ several resources on the Internet that present the language.
|
||||
* Fast enumeration::
|
||||
@end menu
|
||||
|
||||
@c =========================================================================
|
||||
@node GNU Objective-C runtime API
|
||||
@section GNU Objective-C runtime API
|
||||
|
||||
This section is specific for the GNU Objective-C runtime. If you are
|
||||
using a different runtime, you can skip it.
|
||||
|
||||
The GNU Objective-C runtime provides an API that allows you to
|
||||
interact with the Objective-C runtime system, querying the live
|
||||
runtime structures and even manipulating them. This allows you for
|
||||
example to inspect and navigate classes, methods and protocols; to
|
||||
define new classes or new methods, and even to modify existing classes
|
||||
or protocols.
|
||||
|
||||
If you are using a ``Foundation'' library such as GNUstep-Base, this
|
||||
library will provide you with a rich set of functionality to do most
|
||||
of the inspection tasks, and you probably will only need direct access
|
||||
to the GNU Objective-C runtime API to define new classes or methods.
|
||||
|
||||
@menu
|
||||
* Modern GNU Objective-C runtime API::
|
||||
* Traditional GNU Objective-C runtime API::
|
||||
@end menu
|
||||
|
||||
@c =========================================================================
|
||||
@node Modern GNU Objective-C runtime API
|
||||
@subsection Modern GNU Objective-C runtime API
|
||||
|
||||
The GNU Objective-C runtime provides an API which is similar to the
|
||||
one provided by the ``Objective-C 2.0'' Apple/NeXT Objective-C
|
||||
runtime. The API is documented in the public header files of the GNU
|
||||
Objective-C runtime:
|
||||
|
||||
@itemize @bullet
|
||||
|
||||
@item
|
||||
@file{objc/objc.h}: this is the basic Objective-C header file,
|
||||
defining the basic Objective-C types such as @code{id}, @code{Class}
|
||||
and @code{BOOL}. You have to include this header to do almost
|
||||
anything with Objective-C.
|
||||
|
||||
@item
|
||||
@file{objc/runtime.h}: this header declares most of the public runtime
|
||||
API functions allowing you to inspect and manipulate the Objective-C
|
||||
runtime data structures. These functions are fairly standardized
|
||||
across Objective-C runtimes and are almost identical to the Apple/NeXT
|
||||
Objective-C runtime ones. It does not declare functions in some
|
||||
specialized areas (constructing and forwarding message invocations,
|
||||
threading) which are in the other headers below. You have to include
|
||||
@file{objc/objc.h} and @file{objc/runtime.h} to use any of the
|
||||
functions, such as @code{class_getName()}, declared in
|
||||
@file{objc/runtime.h}.
|
||||
|
||||
@item
|
||||
@file{objc/message.h}: this header declares public functions used to
|
||||
construct, deconstruct and forward message invocations. Because
|
||||
messaging is done in quite a different way on different runtimes,
|
||||
functions in this header are specific to the GNU Objective-C runtime
|
||||
implementation.
|
||||
|
||||
@item
|
||||
@file{objc/objc-exception.h}: this header declares some public
|
||||
functions related to Objective-C exceptions. For example functions in
|
||||
this header allow you to throw an Objective-C exception from plain
|
||||
C/C++ code.
|
||||
|
||||
@item
|
||||
@file{objc/objc-sync.h}: this header declares some public functions
|
||||
related to the Objective-C @code{@@synchronized()} syntax, allowing
|
||||
you to emulate an Objective-C @code{@@synchronized()} block in plain
|
||||
C/C++ code.
|
||||
|
||||
@item
|
||||
@file{objc/thr.h}: this header declares a public runtime API threading
|
||||
layer that is only provided by the GNU Objective-C runtime. It
|
||||
declares functions such as @code{objc_mutex_lock()}, which provide a
|
||||
platform-independent set of threading functions.
|
||||
|
||||
@end itemize
|
||||
|
||||
@c =========================================================================
|
||||
@node Traditional GNU Objective-C runtime API
|
||||
@subsection Traditional GNU Objective-C runtime API
|
||||
|
||||
The GNU Objective-C runtime used to provide a different API, which we
|
||||
call the ``traditional'' GNU Objective-C runtime API. Functions
|
||||
belonging to this API are easy to recognize because they use a
|
||||
different naming convention, such as @code{class_get_super_class()}
|
||||
(traditional API) instead of @code{class_getSuperclass()} (modern
|
||||
API). Software using this API includes the file
|
||||
@file{objc/objc-api.h} where it is declared.
|
||||
|
||||
The traditional API is deprecated but it is still supported in this
|
||||
release of the runtime; you can access it as usual by including
|
||||
@file{objc/objc-api.h}.
|
||||
|
||||
If you are using the traditional API you are urged to upgrade your
|
||||
software to use the modern API because the traditional API requires
|
||||
access to private runtime internals to do anything serious with it;
|
||||
for this reason, there is no guarantee that future releases of the GNU
|
||||
Objective-C runtime library will be able to provide a fully compatible
|
||||
@file{objc/objc-api.h} as the private runtime internals change. It is
|
||||
expected that the next release will hide a number of runtime internals
|
||||
making the traditional API nominally supported but fairly useless
|
||||
beyond very simple use cases.
|
||||
|
||||
Finally, you can not include both @file{objc/objc-api.h} and
|
||||
@file{objc/runtime.h} at the same time. The traditional and modern
|
||||
APIs unfortunately have some conflicting declarations (such as the one
|
||||
for @code{Method}) and can not be used at the same time.
|
||||
|
||||
@c =========================================================================
|
||||
@node Executing code before main
|
||||
@section @code{+load}: Executing code before main
|
||||
|
||||
This section is specific for the GNU Objective-C runtime. If you are
|
||||
using a different runtime, you can skip it.
|
||||
|
||||
The GNU Objective-C runtime provides a way that allows you to execute
|
||||
code before the execution of the program enters the @code{main}
|
||||
function. The code is executed on a per-class and a per-category basis,
|
||||
@ -480,6 +596,9 @@ of Objective-C methods.
|
||||
@node Garbage Collection
|
||||
@section Garbage Collection
|
||||
|
||||
This section is specific for the GNU Objective-C runtime. If you are
|
||||
using a different runtime, you can skip it.
|
||||
|
||||
Support for garbage collection with the GNU runtime has been added by
|
||||
using a powerful conservative garbage collector, known as the
|
||||
Boehm-Demers-Weiser conservative garbage collector.
|
||||
|
@ -1,3 +1,14 @@
|
||||
2010-10-17 Nicola Pero <nicola.pero@meta-innovation.com>
|
||||
|
||||
* obj-c++.dg/gnu-api-2-class.mm: New.
|
||||
* obj-c++.dg/gnu-api-2-ivar.mm: New.
|
||||
* obj-c++.dg/gnu-api-2-method.mm: New.
|
||||
* obj-c++.dg/gnu-api-2-objc.mm: New.
|
||||
* obj-c++.dg/gnu-api-2-object.mm: New.
|
||||
* obj-c++.dg/gnu-api-2-property.mm: New.
|
||||
* obj-c++.dg/gnu-api-2-protocol.mm: New.
|
||||
* obj-c++.dg/gnu-api-2-sel.mm: New.
|
||||
|
||||
2010-10-17 Iain Sandoe <iains@gcc.gnu.org>
|
||||
|
||||
* objc.dg/fsf-package-0.m: New.
|
||||
|
441
gcc/testsuite/obj-c++.dg/gnu-api-2-class.mm
Normal file
441
gcc/testsuite/obj-c++.dg/gnu-api-2-class.mm
Normal file
@ -0,0 +1,441 @@
|
||||
/* Test the Modern GNU Objective-C Runtime API.
|
||||
|
||||
This is test 'class', covering all functions starting with 'class'. */
|
||||
|
||||
/* { dg-do run } */
|
||||
/* { dg-skip-if "" { *-*-* } { "-fnext-runtime" } { "" } } */
|
||||
|
||||
/* To get the modern GNU Objective-C Runtime API, you include
|
||||
objc/runtime.h. */
|
||||
#include <objc/runtime.h>
|
||||
#include <stdlib.h>
|
||||
#include <iostream>
|
||||
#include <cstring>
|
||||
|
||||
@interface MyRootClass
|
||||
{ Class isa; }
|
||||
+ alloc;
|
||||
- init;
|
||||
@end
|
||||
|
||||
@implementation MyRootClass
|
||||
+ alloc { return class_createInstance (self, 0); }
|
||||
- init { return self; }
|
||||
@end
|
||||
|
||||
@protocol MyProtocol
|
||||
- (id) variable;
|
||||
@end
|
||||
|
||||
@protocol MySecondProtocol
|
||||
- (id) setVariable: (id)value;
|
||||
@end
|
||||
|
||||
@interface MySubClass : MyRootClass <MyProtocol>
|
||||
{ id variable_ivar; }
|
||||
- (void) setVariable: (id)value;
|
||||
- (id) variable;
|
||||
@end
|
||||
|
||||
@implementation MySubClass
|
||||
- (void) setVariable: (id)value { variable_ivar = value; }
|
||||
- (id) variable { return variable_ivar; }
|
||||
@end
|
||||
|
||||
@interface DifferentClass : MyRootClass
|
||||
- (id) myClass;
|
||||
- (id) self;
|
||||
@end
|
||||
|
||||
@implementation DifferentClass
|
||||
- (id) myClass { return object_getClass (self); }
|
||||
- (id) self { return self; }
|
||||
@end
|
||||
|
||||
@interface MySubClass (MySelf)
|
||||
- (id) mySelf;
|
||||
@end
|
||||
|
||||
int main ()
|
||||
{
|
||||
/* Functions are tested in alphabetical order. */
|
||||
|
||||
std::cout << "Testing class_addIvar ()...\n";
|
||||
{
|
||||
Class new_class = objc_allocateClassPair (objc_getClass ("MySubClass"), "MySubSubClass", 0);
|
||||
|
||||
if (new_class == Nil)
|
||||
abort ();
|
||||
|
||||
if (! class_addIvar (new_class, "variable2_ivar", sizeof (id),
|
||||
__alignof__ (id), @encode (id)))
|
||||
abort ();
|
||||
|
||||
if (! class_addIvar (new_class, "variable3_ivar", sizeof (unsigned char),
|
||||
__alignof__ (unsigned char), @encode (unsigned char)))
|
||||
abort ();
|
||||
|
||||
if (! class_addIvar (new_class, "variable4_ivar", sizeof (unsigned long),
|
||||
__alignof__ (unsigned long), @encode (unsigned long)))
|
||||
abort ();
|
||||
|
||||
objc_registerClassPair (new_class);
|
||||
|
||||
{
|
||||
MySubClass *o = [[objc_getClass ("MySubSubClass") alloc] init];
|
||||
Ivar variable2 = class_getInstanceVariable (objc_getClass ("MySubSubClass"), "variable2_ivar");
|
||||
Ivar variable3 = class_getInstanceVariable (objc_getClass ("MySubSubClass"), "variable3_ivar");
|
||||
Ivar variable4 = class_getInstanceVariable (objc_getClass ("MySubSubClass"), "variable4_ivar");
|
||||
|
||||
if (variable2 == NULL || variable3 == NULL || variable4 == NULL)
|
||||
abort ();
|
||||
|
||||
if (std::strcmp (ivar_getName (variable2), "variable2_ivar") != 0)
|
||||
abort ();
|
||||
|
||||
if (std::strcmp (ivar_getName (variable3), "variable3_ivar") != 0)
|
||||
abort ();
|
||||
|
||||
if (std::strcmp (ivar_getName (variable4), "variable4_ivar") != 0)
|
||||
abort ();
|
||||
|
||||
{
|
||||
unsigned char *var3 = (unsigned char *)((char *)o + ivar_getOffset (variable3));
|
||||
unsigned long *var4 = (unsigned long *)((char *)o + ivar_getOffset (variable4));
|
||||
|
||||
object_setIvar (o, variable2, new_class);
|
||||
*var3 = 230;
|
||||
*var4 = 89000L;
|
||||
|
||||
if (object_getIvar (o, variable2) != new_class)
|
||||
abort ();
|
||||
|
||||
if (*var3 != 230)
|
||||
abort ();
|
||||
|
||||
if (*var4 != 89000L)
|
||||
abort ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "Testing class_addMethod ()...\n";
|
||||
{
|
||||
Class new_class = objc_allocateClassPair (objc_getClass ("MyRootClass"), "MySubClass2", 0);
|
||||
Method method1 = class_getInstanceMethod (objc_getClass ("MySubClass"), @selector (setVariable:));
|
||||
Method method2 = class_getInstanceMethod (objc_getClass ("MySubClass"), @selector (variable));
|
||||
|
||||
if (new_class == Nil)
|
||||
abort ();
|
||||
|
||||
if (! class_addIvar (new_class, "variable_ivar", sizeof (id),
|
||||
__alignof__ (id), @encode (id)))
|
||||
abort ();
|
||||
|
||||
if (! class_addMethod (new_class, @selector (setVariable:), method_getImplementation (method1),
|
||||
method_getTypeEncoding (method1)))
|
||||
abort ();
|
||||
|
||||
if (! class_addMethod (new_class, @selector (variable), method_getImplementation (method2),
|
||||
method_getTypeEncoding (method2)))
|
||||
abort ();
|
||||
|
||||
objc_registerClassPair (new_class);
|
||||
|
||||
/* Now, MySubClass2 is basically the same as MySubClass! We'll
|
||||
use the variable and setVariable: methods on it. */
|
||||
{
|
||||
MySubClass *o = (MySubClass *)[[objc_getClass ("MySubClass2") alloc] init];
|
||||
|
||||
[o setVariable: o];
|
||||
|
||||
if ([o variable] != o)
|
||||
abort ();
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "Testing class_addProtocol ()...\n";
|
||||
{
|
||||
if (!class_addProtocol (objc_getClass ("MySubClass"), @protocol (MySecondProtocol)))
|
||||
abort ();
|
||||
|
||||
if (!class_conformsToProtocol (objc_getClass ("MySubClass"), @protocol (MyProtocol)))
|
||||
abort ();
|
||||
|
||||
if (!class_conformsToProtocol (objc_getClass ("MySubClass"), @protocol (MySecondProtocol)))
|
||||
abort ();
|
||||
}
|
||||
|
||||
std::cout << "Testing class_conformsToProtocol ()...\n";
|
||||
{
|
||||
if (class_conformsToProtocol (objc_getClass ("MyRootClass"), @protocol (MyProtocol)))
|
||||
abort ();
|
||||
|
||||
if (!class_conformsToProtocol (objc_getClass ("MySubClass"), @protocol (MyProtocol)))
|
||||
abort ();
|
||||
}
|
||||
|
||||
std::cout << "Testing class_copyIvarList ()...\n";
|
||||
{
|
||||
unsigned int count;
|
||||
Ivar * list = class_copyIvarList (objc_getClass ("MySubClass"), &count);
|
||||
|
||||
if (count != 1)
|
||||
abort ();
|
||||
|
||||
if (std::strcmp (ivar_getName (list[0]), "variable_ivar") != 0)
|
||||
abort ();
|
||||
|
||||
if (list[1] != NULL)
|
||||
abort ();
|
||||
}
|
||||
|
||||
std::cout << "Testing class_copyMethodList ()...\n";
|
||||
{
|
||||
unsigned int count;
|
||||
Method * list = class_copyMethodList (objc_getClass ("MySubClass"), &count);
|
||||
|
||||
if (count != 2)
|
||||
abort ();
|
||||
|
||||
if (! ((std::strcmp (sel_getName (method_getName (list[0])), "variable") == 0
|
||||
&& std::strcmp (sel_getName (method_getName (list[1])), "setVariable:") == 0)
|
||||
|| (std::strcmp (sel_getName (method_getName (list[0])), "setVariable:") == 0
|
||||
&& std::strcmp (sel_getName (method_getName (list[1])), "variable") == 0)))
|
||||
abort ();
|
||||
|
||||
if (list[2] != NULL)
|
||||
abort ();
|
||||
}
|
||||
|
||||
/* TODO: Test new ABI (when available). */
|
||||
std::cout << "Testing class_copyPropertyList ()...\n";
|
||||
{
|
||||
unsigned int count;
|
||||
Property * list = class_copyPropertyList (objc_getClass ("MySubClass"), &count);
|
||||
|
||||
if (count != 0 || list != NULL)
|
||||
abort ();
|
||||
}
|
||||
|
||||
std::cout << "Testing class_copyProtocolList ()...\n";
|
||||
{
|
||||
unsigned int count;
|
||||
Protocol ** list = class_copyProtocolList (objc_getClass ("MySubClass"), &count);
|
||||
|
||||
/* Remember that we added MySecondProtocol in the test above. */
|
||||
if (count != 2)
|
||||
abort ();
|
||||
|
||||
if (! ((std::strcmp (protocol_getName (list[0]), "MyProtocol") == 0
|
||||
&& std::strcmp (protocol_getName (list[1]), "MySecondProtocol") == 0)
|
||||
|| (std::strcmp (protocol_getName (list[0]), "MySecondProtocol") == 0
|
||||
&& std::strcmp (protocol_getName (list[1]), "MyProtocol") == 0)))
|
||||
abort ();
|
||||
|
||||
if (list[2] != NULL)
|
||||
abort ();
|
||||
}
|
||||
|
||||
std::cout << "Testing class_createInstance ()...\n";
|
||||
{
|
||||
MySubClass *object = [[MySubClass alloc] init];
|
||||
|
||||
[object setVariable: object];
|
||||
if ([object variable] != object)
|
||||
abort ();
|
||||
}
|
||||
|
||||
std::cout << "Testing class_getClassMethod ()...\n";
|
||||
{
|
||||
Method method = class_getClassMethod (objc_getClass ("MySubClass"),
|
||||
@selector(alloc));
|
||||
|
||||
if (method == NULL)
|
||||
abort ();
|
||||
|
||||
if (std::strcmp (sel_getName (method_getName (method)), "alloc") != 0)
|
||||
abort ();
|
||||
|
||||
if (class_getClassMethod (objc_getClass ("MySubClass"),
|
||||
@selector(variable)))
|
||||
abort ();
|
||||
}
|
||||
|
||||
std::cout << "Testing class_getClassVariable ()...\n";
|
||||
{
|
||||
if (class_getClassVariable (objc_getClass ("MySubClass"), "variable_ivar"))
|
||||
abort ();
|
||||
}
|
||||
|
||||
std::cout << "Testing class_getInstanceMethod ()...\n";
|
||||
{
|
||||
Method method = class_getInstanceMethod (objc_getClass ("MySubClass"),
|
||||
@selector(variable));
|
||||
|
||||
if (method == NULL)
|
||||
abort ();
|
||||
|
||||
if (std::strcmp (sel_getName (method_getName (method)), "variable") != 0)
|
||||
abort ();
|
||||
|
||||
if (class_getInstanceMethod (objc_getClass ("MySubClass"),
|
||||
@selector(alloc)))
|
||||
abort ();
|
||||
}
|
||||
|
||||
std::cout << "Testing class_getInstanceSize ()...\n";
|
||||
{
|
||||
if (class_getInstanceSize (objc_getClass ("MyRootClass")) != sizeof (struct objc_object))
|
||||
abort ();
|
||||
}
|
||||
|
||||
std::cout << "Testing class_getInstanceVariable ()...\n";
|
||||
{
|
||||
Ivar variable = class_getInstanceVariable (objc_getClass ("MySubClass"), "variable_ivar");
|
||||
|
||||
if (variable == NULL)
|
||||
abort ();
|
||||
|
||||
if (std::strcmp (ivar_getName (variable), "variable_ivar") != 0)
|
||||
abort ();
|
||||
|
||||
if (class_getInstanceVariable (objc_getClass ("MySubClass"), "variable_ivar_no"))
|
||||
abort ();
|
||||
}
|
||||
|
||||
std::cout << "Testing class_getIvarLayout ()...\n";
|
||||
{
|
||||
if (class_getIvarLayout (objc_getClass ("MyRootClass")) != NULL)
|
||||
abort ();
|
||||
}
|
||||
|
||||
std::cout << "Testing class_getMethodImplementation ()...\n";
|
||||
{
|
||||
MySubClass *object = [[MySubClass alloc] init];
|
||||
IMP imp = class_getMethodImplementation (objc_getClass ("MySubClass"),
|
||||
@selector(variable));
|
||||
|
||||
if (imp == NULL)
|
||||
abort ();
|
||||
|
||||
[object setVariable: object];
|
||||
|
||||
if ((*imp)(object, @selector(variable)) != object)
|
||||
abort ();
|
||||
}
|
||||
|
||||
/* This function does not exist with the GNU runtime. */
|
||||
/* std::cout << "Testing class_getMethodImplementation_stret ()...\n"; */
|
||||
|
||||
std::cout << "Testing class_getName ()...\n";
|
||||
{
|
||||
if (std::strcmp (class_getName (objc_getClass ("MyRootClass")),
|
||||
"MyRootClass") != 0)
|
||||
abort ();
|
||||
}
|
||||
|
||||
/* TODO: Test new ABI (when available). */
|
||||
std::cout << "Testing class_getProperty ()...\n";
|
||||
{
|
||||
if (class_getProperty (objc_getClass ("MyRootClass"), "property") != NULL)
|
||||
abort ();
|
||||
}
|
||||
|
||||
std::cout << "Testing class_getSuperclass ()...\n";
|
||||
{
|
||||
MySubClass *object = [[MySubClass alloc] init];
|
||||
if (class_getSuperclass (object_getClass (object)) != objc_getClass ("MyRootClass"))
|
||||
abort ();
|
||||
}
|
||||
|
||||
std::cout << "Testing class_getVersion ()...\n";
|
||||
{
|
||||
if (class_getVersion (objc_getClass ("MySubClass")) != 0)
|
||||
abort ();
|
||||
}
|
||||
|
||||
std::cout << "Testing class_getWeakIvarLayout ()...\n";
|
||||
{
|
||||
if (class_getWeakIvarLayout (objc_getClass ("MyRootClass")) != NULL)
|
||||
abort ();
|
||||
}
|
||||
|
||||
std::cout << "Testing class_isMetaClass ()...\n";
|
||||
{
|
||||
MySubClass *object = [[MySubClass alloc] init];
|
||||
if (class_isMetaClass (object_getClass (object))
|
||||
|| ! class_isMetaClass (object_getClass (object_getClass (object))))
|
||||
abort ();
|
||||
}
|
||||
|
||||
std::cout << "Testing class_replaceMethod ()...\n";
|
||||
{
|
||||
Method new_method = class_getInstanceMethod (objc_getClass ("DifferentClass"),
|
||||
@selector (myClass));
|
||||
Method old_method = class_getInstanceMethod (objc_getClass ("MySubClass"),
|
||||
@selector (variable));
|
||||
const char *new_types = method_getTypeEncoding (new_method);
|
||||
IMP new_imp = method_getImplementation (new_method);
|
||||
const char *old_types = method_getTypeEncoding (old_method);
|
||||
IMP old_imp = class_replaceMethod (objc_getClass ("MySubClass"), @selector (variable),
|
||||
method_getImplementation (new_method),
|
||||
method_getTypeEncoding (new_method));
|
||||
MySubClass *o = [[MySubClass alloc] init];
|
||||
|
||||
[o setVariable: o];
|
||||
|
||||
/* Try the new method implementation. */
|
||||
if ([o variable] != objc_getClass ("MySubClass"))
|
||||
abort ();
|
||||
|
||||
/* Put the original method back. */
|
||||
class_replaceMethod (objc_getClass ("MySubClass"), @selector (variable),
|
||||
old_imp, old_types);
|
||||
|
||||
/* Test it's back to what it was. */
|
||||
if ([o variable] != o)
|
||||
abort ();
|
||||
|
||||
{
|
||||
DifferentClass *o = [[DifferentClass alloc] init];
|
||||
|
||||
/* Finally, try adding a new method. */
|
||||
class_replaceMethod (objc_getClass ("DifferentClass"), @selector (mySelf),
|
||||
new_imp, new_types);
|
||||
|
||||
if ([(MySubClass*)o mySelf] != objc_getClass ("DifferentClass"))
|
||||
abort ();
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "Testing class_respondsToSelector ()...\n";
|
||||
{
|
||||
if (! class_respondsToSelector (objc_getClass ("MySubClass"), @selector(setVariable:)))
|
||||
abort ();
|
||||
|
||||
if (class_respondsToSelector (objc_getClass ("MyRootClass"), @selector(setVariable:)))
|
||||
abort ();
|
||||
}
|
||||
|
||||
/* This is not really implemented with the GNU runtime. */
|
||||
/* std::cout << "Testing class_setIvarLayout ()...\n"; */
|
||||
|
||||
std::cout << "Testing class_setVersion ()...\n";
|
||||
{
|
||||
class_setVersion (objc_getClass ("MySubClass"), 45);
|
||||
|
||||
if (class_getVersion (objc_getClass ("MySubClass")) != 45)
|
||||
abort ();
|
||||
|
||||
class_setVersion (objc_getClass ("MySubClass"), 46);
|
||||
|
||||
if (class_getVersion (objc_getClass ("MySubClass")) != 46)
|
||||
abort ();
|
||||
}
|
||||
|
||||
/* This is not really implemented with the GNU runtime. */
|
||||
/* std::cout << "Testing class_setWeakIvarLayout ()...\n"; */
|
||||
|
||||
return (0);
|
||||
}
|
80
gcc/testsuite/obj-c++.dg/gnu-api-2-ivar.mm
Normal file
80
gcc/testsuite/obj-c++.dg/gnu-api-2-ivar.mm
Normal file
@ -0,0 +1,80 @@
|
||||
/* Test the Modern GNU Objective-C Runtime API.
|
||||
|
||||
This is test 'ivar', covering all functions starting with 'ivar'. */
|
||||
|
||||
/* { dg-do run } */
|
||||
/* { dg-skip-if "" { *-*-* } { "-fnext-runtime" } { "" } } */
|
||||
|
||||
/* To get the modern GNU Objective-C Runtime API, you include
|
||||
objc/runtime.h. */
|
||||
#include <objc/runtime.h>
|
||||
#include <stdlib.h>
|
||||
#include <iostream>
|
||||
#include <cstring>
|
||||
|
||||
@interface MyRootClass
|
||||
{ Class isa; }
|
||||
+ alloc;
|
||||
- init;
|
||||
@end
|
||||
|
||||
@implementation MyRootClass
|
||||
+ alloc { return class_createInstance (self, 0); }
|
||||
- init { return self; }
|
||||
@end
|
||||
|
||||
@protocol MyProtocol
|
||||
- (id) variable;
|
||||
@end
|
||||
|
||||
@protocol MySecondProtocol
|
||||
- (id) setVariable: (id)value;
|
||||
@end
|
||||
|
||||
@interface MySubClass : MyRootClass <MyProtocol>
|
||||
{ id variable_ivar; }
|
||||
- (void) setVariable: (id)value;
|
||||
- (id) variable;
|
||||
@end
|
||||
|
||||
@implementation MySubClass
|
||||
- (void) setVariable: (id)value { variable_ivar = value; }
|
||||
- (id) variable { return variable_ivar; }
|
||||
@end
|
||||
|
||||
|
||||
int main ()
|
||||
{
|
||||
/* Functions are tested in alphabetical order. */
|
||||
|
||||
std::cout << "Testing ivar_getName () ...\n";
|
||||
{
|
||||
Ivar ivar = class_getInstanceVariable (objc_getClass ("MySubClass"),
|
||||
"variable_ivar");
|
||||
if (strcmp (ivar_getName (ivar), "variable_ivar") != 0)
|
||||
abort ();
|
||||
|
||||
ivar = class_getInstanceVariable (objc_getClass ("MySubClass"),
|
||||
"variable");
|
||||
if (ivar != 0)
|
||||
abort ();
|
||||
}
|
||||
|
||||
std::cout << "Testing ivar_getOffset () ...\n";
|
||||
{
|
||||
Ivar ivar = class_getInstanceVariable (objc_getClass ("MyRootClass"),
|
||||
"isa");
|
||||
if (ivar_getOffset (ivar) != 0)
|
||||
abort ();
|
||||
}
|
||||
|
||||
std::cout << "Testing ivar_getTypeEncoding () ...\n";
|
||||
{
|
||||
Ivar ivar = class_getInstanceVariable (objc_getClass ("MySubClass"),
|
||||
"variable_ivar");
|
||||
if (strcmp (ivar_getTypeEncoding (ivar), "@") != 0)
|
||||
abort ();
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
227
gcc/testsuite/obj-c++.dg/gnu-api-2-method.mm
Normal file
227
gcc/testsuite/obj-c++.dg/gnu-api-2-method.mm
Normal file
@ -0,0 +1,227 @@
|
||||
/* Test the Modern GNU Objective-C Runtime API.
|
||||
|
||||
This is test 'method', covering all functions starting with 'method'. */
|
||||
|
||||
/* { dg-do run } */
|
||||
/* { dg-skip-if "" { *-*-* } { "-fnext-runtime" } { "" } } */
|
||||
|
||||
/* To get the modern GNU Objective-C Runtime API, you include
|
||||
objc/runtime.h. */
|
||||
#include <objc/runtime.h>
|
||||
#include <stdlib.h>
|
||||
#include <iostream>
|
||||
#include <cstring>
|
||||
|
||||
@interface MyRootClass
|
||||
{ Class isa; }
|
||||
+ alloc;
|
||||
- init;
|
||||
@end
|
||||
|
||||
@implementation MyRootClass
|
||||
+ alloc { return class_createInstance (self, 0); }
|
||||
- init { return self; }
|
||||
@end
|
||||
|
||||
@protocol MyProtocol
|
||||
- (id) variable;
|
||||
@end
|
||||
|
||||
@protocol MySecondProtocol
|
||||
- (id) setVariable: (id)value;
|
||||
@end
|
||||
|
||||
@interface MySubClass : MyRootClass <MyProtocol>
|
||||
{ id variable_ivar; }
|
||||
- (void) setVariable: (id)value;
|
||||
- (id) variable;
|
||||
- (id) constant;
|
||||
@end
|
||||
|
||||
@implementation MySubClass
|
||||
- (void) setVariable: (id)value { variable_ivar = value; }
|
||||
- (id) variable { return variable_ivar; }
|
||||
- (id) constant { return nil; }
|
||||
@end
|
||||
|
||||
|
||||
int main ()
|
||||
{
|
||||
/* Functions are tested in alphabetical order. */
|
||||
|
||||
std::cout <<"Testing method_copyArgumentType () ...\n";
|
||||
{
|
||||
Method method = class_getInstanceMethod (objc_getClass ("MySubClass"),
|
||||
@selector (setVariable:));
|
||||
char *type = method_copyArgumentType (method, 2);
|
||||
|
||||
if (type == NULL || type[0] != '@')
|
||||
abort ();
|
||||
}
|
||||
|
||||
std::cout << "Testing method_copyReturnType () ...\n";
|
||||
{
|
||||
Method method = class_getClassMethod (objc_getClass ("MyRootClass"),
|
||||
@selector (alloc));
|
||||
char *type = method_copyReturnType (method);
|
||||
|
||||
/* Check that it returns an object. */
|
||||
if (type == NULL || type[0] != '@')
|
||||
abort ();
|
||||
}
|
||||
|
||||
std::cout << "Testing method_exchangeImplementations () ...\n";
|
||||
{
|
||||
Method method_a = class_getInstanceMethod (objc_getClass ("MySubClass"),
|
||||
@selector (variable));
|
||||
Method method_b = class_getInstanceMethod (objc_getClass ("MySubClass"),
|
||||
@selector (constant));
|
||||
MySubClass *object = [[MySubClass alloc] init];
|
||||
|
||||
/* Check that things work as expected before the swap. */
|
||||
[object setVariable: object];
|
||||
|
||||
if ([object variable] != object || [object constant] != nil)
|
||||
abort ();
|
||||
|
||||
/* Swap the methods. */
|
||||
method_exchangeImplementations (method_a, method_b);
|
||||
|
||||
/* Check that behaviour has changed. */
|
||||
if ([object variable] != nil || [object constant] != object)
|
||||
abort ();
|
||||
|
||||
/* Swap the methods again. */
|
||||
method_exchangeImplementations (method_a, method_b);
|
||||
|
||||
/* Check that behaviour is back to normal. */
|
||||
if ([object variable] != object || [object constant] != nil)
|
||||
abort ();
|
||||
}
|
||||
|
||||
std::cout << "Testing method_getArgumentType () ...\n";
|
||||
{
|
||||
Method method = class_getInstanceMethod (objc_getClass ("MyRootClass"),
|
||||
@selector (init));
|
||||
char type[16];
|
||||
|
||||
method_getArgumentType (method, 1, type, 16);
|
||||
|
||||
/* Check the second argument (_cmd), which should be a SEL. */
|
||||
if (type[0] != ':')
|
||||
abort ();
|
||||
}
|
||||
|
||||
std::cout << "Testing method_getDescription () ...\n";
|
||||
{
|
||||
Method method = class_getInstanceMethod (objc_getClass ("MySubClass"),
|
||||
@selector (variable));
|
||||
struct objc_method_description *description = method_getDescription (method);
|
||||
|
||||
if (std::strcmp (sel_getName (description->name), "variable") != 0)
|
||||
abort ();
|
||||
|
||||
if (method_getDescription (NULL) != NULL)
|
||||
abort ();
|
||||
}
|
||||
|
||||
std::cout << "Testing method_getImplementation () ...\n";
|
||||
{
|
||||
typedef void (*set_variable_function) (id receiver, SEL _cmd, id variable);
|
||||
Method method = class_getInstanceMethod (objc_getClass ("MySubClass"),
|
||||
@selector (setVariable:));
|
||||
set_variable_function imp;
|
||||
MySubClass *object = [[MySubClass alloc] init];
|
||||
|
||||
imp = (set_variable_function)(method_getImplementation (method));
|
||||
|
||||
(*imp)(object, @selector (setVariable:), object);
|
||||
|
||||
if ([object variable] != object)
|
||||
abort ();
|
||||
}
|
||||
|
||||
std::cout << "Testing method_getName () ...\n";
|
||||
{
|
||||
Method method = class_getInstanceMethod (objc_getClass ("MySubClass"),
|
||||
@selector (setVariable:));
|
||||
if (std::strcmp (sel_getName (method_getName (method)), "setVariable:") != 0)
|
||||
abort ();
|
||||
}
|
||||
|
||||
std::cout << "Testing method_getNumberOfArguments () ...\n";
|
||||
{
|
||||
Method method = class_getInstanceMethod (objc_getClass ("MySubClass"),
|
||||
@selector (setVariable:));
|
||||
if (method_getNumberOfArguments (method) != 3)
|
||||
abort ();
|
||||
|
||||
method = class_getInstanceMethod (objc_getClass ("MySubClass"),
|
||||
@selector (variable));
|
||||
if (method_getNumberOfArguments (method) != 2)
|
||||
abort ();
|
||||
}
|
||||
|
||||
std::cout << "Testing method_getTypeEncoding () ...\n";
|
||||
{
|
||||
Method method = class_getInstanceMethod (objc_getClass ("MySubClass"),
|
||||
@selector (setVariable:));
|
||||
const char *types = method_getTypeEncoding (method);
|
||||
|
||||
/* Check that method type string starts with 'v' (void) */
|
||||
if (types == NULL || types[0] != 'v')
|
||||
abort ();
|
||||
}
|
||||
|
||||
std::cout << "Testing method_getReturnType () ...\n";
|
||||
{
|
||||
Method method = class_getInstanceMethod (objc_getClass ("MySubClass"),
|
||||
@selector (setVariable:));
|
||||
char type[16];
|
||||
|
||||
method_getReturnType (method, type, 16);
|
||||
|
||||
if (type[0] != 'v')
|
||||
abort ();
|
||||
|
||||
method_getReturnType (NULL, type, 16);
|
||||
|
||||
if (type[0] != 0)
|
||||
abort ();
|
||||
}
|
||||
|
||||
std::cout << "Testing method_setImplementation () ...\n";
|
||||
{
|
||||
Method method_a = class_getInstanceMethod (objc_getClass ("MySubClass"),
|
||||
@selector (variable));
|
||||
Method method_b = class_getInstanceMethod (objc_getClass ("MySubClass"),
|
||||
@selector (constant));
|
||||
IMP original_imp_a = method_getImplementation (method_a);
|
||||
IMP original_imp_b = method_getImplementation (method_b);
|
||||
MySubClass *object = [[MySubClass alloc] init];
|
||||
|
||||
/* Check that things work as expected before the swap. */
|
||||
[object setVariable: object];
|
||||
|
||||
if ([object variable] != object || [object constant] != nil)
|
||||
abort ();
|
||||
|
||||
/* Have 'variable' use the same implementation as 'constant'. */
|
||||
if (method_setImplementation (method_a, original_imp_b) != original_imp_a)
|
||||
abort ();
|
||||
|
||||
/* Check that behaviour has changed. */
|
||||
if ([object variable] != nil || [object constant] != nil)
|
||||
abort ();
|
||||
|
||||
/* Put the original method back. */
|
||||
if (method_setImplementation (method_a, original_imp_a) != original_imp_b)
|
||||
abort ();
|
||||
|
||||
/* Check that behaviour is back to normal. */
|
||||
if ([object variable] != object || [object constant] != nil)
|
||||
abort ();
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
242
gcc/testsuite/obj-c++.dg/gnu-api-2-objc.mm
Normal file
242
gcc/testsuite/obj-c++.dg/gnu-api-2-objc.mm
Normal file
@ -0,0 +1,242 @@
|
||||
/* Test the Modern GNU Objective-C Runtime API.
|
||||
|
||||
This is test 'objc', covering all functions starting with 'objc'. */
|
||||
|
||||
/* { dg-do run } */
|
||||
/* { dg-skip-if "" { *-*-* } { "-fnext-runtime" } { "" } } */
|
||||
|
||||
/* To get the modern GNU Objective-C Runtime API, you include
|
||||
objc/runtime.h. */
|
||||
#include <objc/runtime.h>
|
||||
#include <stdlib.h>
|
||||
#include <iostream>
|
||||
#include <cstring>
|
||||
|
||||
@interface MyRootClass
|
||||
{ Class isa; }
|
||||
+ alloc;
|
||||
- init;
|
||||
@end
|
||||
|
||||
@implementation MyRootClass
|
||||
+ alloc { return class_createInstance (self, 0); }
|
||||
- init { return self; }
|
||||
@end
|
||||
|
||||
@protocol MyProtocol
|
||||
- (id) variable;
|
||||
@end
|
||||
|
||||
@protocol MySecondProtocol
|
||||
- (id) setVariable: (id)value;
|
||||
@end
|
||||
|
||||
@interface MySubClass : MyRootClass <MyProtocol>
|
||||
{ id variable_ivar; }
|
||||
- (void) setVariable: (id)value;
|
||||
- (id) variable;
|
||||
@end
|
||||
|
||||
@implementation MySubClass
|
||||
- (void) setVariable: (id)value { variable_ivar = value; }
|
||||
- (id) variable { return variable_ivar; }
|
||||
@end
|
||||
|
||||
|
||||
int main ()
|
||||
{
|
||||
/* Functions are tested in alphabetical order. */
|
||||
|
||||
std::cout << "Testing objc_allocateClassPair ()...\n";
|
||||
{
|
||||
Class new_root_class = objc_allocateClassPair (Nil, "MyNewRootClass", 0);
|
||||
Class new_class = objc_allocateClassPair (objc_getClass ("MyRootClass"), "MyNewSubClass", 0);
|
||||
|
||||
/* A new root class would obviously need at least an 'isa'
|
||||
instance variable. We don't add it so we never actually
|
||||
instantiate an instance of the class, which wouldn't work. */
|
||||
|
||||
objc_registerClassPair (new_root_class);
|
||||
objc_registerClassPair (new_class);
|
||||
|
||||
if (std::strcmp (class_getName (new_class), "MyNewSubClass") != 0)
|
||||
abort ();
|
||||
|
||||
if (class_getSuperclass (new_class) != objc_getClass ("MyRootClass"))
|
||||
abort ();
|
||||
|
||||
if (std::strcmp (class_getName (new_root_class), "MyNewRootClass") != 0)
|
||||
abort ();
|
||||
|
||||
if (class_getSuperclass (new_root_class) != Nil)
|
||||
abort ();
|
||||
|
||||
{
|
||||
MySubClass *o = [[objc_getClass ("MyNewSubClass") alloc] init];
|
||||
|
||||
if (object_getClass (o) != objc_getClass ("MyNewSubClass"))
|
||||
abort ();
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "Testing objc_copyProtocolList ()...\n";
|
||||
{
|
||||
/* Make sure both our two protocols are known to the runtime. */
|
||||
id my_protocol = @protocol (MyProtocol);
|
||||
id my_second_protocol = @protocol (MySecondProtocol);
|
||||
unsigned int count;
|
||||
Protocol ** list = objc_copyProtocolList (&count);
|
||||
|
||||
if (count != 2)
|
||||
abort ();
|
||||
|
||||
if (! ((std::strcmp (protocol_getName (list[0]), "MyProtocol") == 0
|
||||
&& std::strcmp (protocol_getName (list[1]), "MySecondProtocol") == 0)
|
||||
|| (std::strcmp (protocol_getName (list[0]), "MySecondProtocol") == 0
|
||||
&& std::strcmp (protocol_getName (list[1]), "MyProtocol") == 0)))
|
||||
abort ();
|
||||
|
||||
if (list[2] != NULL)
|
||||
abort ();
|
||||
}
|
||||
|
||||
std::cout << "Testing objc_disposeClassPair ()...\n";
|
||||
{
|
||||
Method method = class_getInstanceMethod (objc_getClass ("MySubClass"), @selector (setVariable:));
|
||||
Class new_class = objc_allocateClassPair (objc_getClass ("MyRootClass"), "MyNewSubClass", 0);
|
||||
|
||||
/* Add a bit of everything to the class to exercise undoing all these changes. */
|
||||
|
||||
/* Instance variable. */
|
||||
class_addIvar (new_class, "my_variable", sizeof (float), __alignof__ (float), @encode (float));
|
||||
|
||||
/* Instance method. */
|
||||
class_addMethod (new_class, @selector (setVariable:), method_getImplementation (method),
|
||||
method_getTypeEncoding (method));
|
||||
|
||||
/* Class method. */
|
||||
class_addMethod (object_getClass (new_class), @selector (setVariable:), method_getImplementation (method),
|
||||
method_getTypeEncoding (method));
|
||||
|
||||
/* Protocol. */
|
||||
class_addProtocol (new_class, @protocol (MyProtocol));
|
||||
|
||||
objc_disposeClassPair (new_class);
|
||||
}
|
||||
|
||||
/* This function currently does not exist with the GNU runtime. */
|
||||
/* std::cout << "Testing objc_duplicateClass ()...\n"; */
|
||||
|
||||
/* TODO - Test it when implemented in the GNU Runtime */
|
||||
/* std::cout << "Testing objc_getAssociatedObject ()...\n"; */
|
||||
|
||||
std::cout << "Testing objc_getClass ()...\n";
|
||||
{
|
||||
if (std::strcmp (class_getName (objc_getClass ("MySubClass")),
|
||||
"MySubClass") != 0)
|
||||
abort ();
|
||||
}
|
||||
|
||||
std::cout << "Testing objc_getClassList ()...\n";
|
||||
{
|
||||
Class *list;
|
||||
int i, count, other_count;
|
||||
count = objc_getClassList (NULL, 0);
|
||||
|
||||
/* count most likely will be 5, (MyRootClass, MySubClass,
|
||||
Protocol, Object, NXConstantString). */
|
||||
if (count < 3)
|
||||
abort ();
|
||||
|
||||
list = (Class *)(malloc (sizeof (Class) * count));
|
||||
other_count = objc_getClassList (list, count);
|
||||
|
||||
if (other_count != count)
|
||||
abort ();
|
||||
|
||||
/* Spot-check: search for class 'MyRootClass' in the list. */
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
if (std::strcmp (class_getName (list[i]), "MyRootClass") == 0)
|
||||
break;
|
||||
}
|
||||
if (i == count)
|
||||
abort ();
|
||||
|
||||
/* Spot-check: search for class 'MySubClass' in the list. */
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
if (std::strcmp (class_getName (list[i]), "MySubClass") == 0)
|
||||
break;
|
||||
}
|
||||
if (i == count)
|
||||
abort ();
|
||||
|
||||
/* Spot-check: search for class 'Protocol' in the list. */
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
if (std::strcmp (class_getName (list[i]), "Protocol") == 0)
|
||||
break;
|
||||
}
|
||||
if (i == count)
|
||||
abort ();
|
||||
}
|
||||
|
||||
/* This function does not exist with the GNU runtime. */
|
||||
/* std::cout << "Testing objc_getFutureClass ()...\n"; */
|
||||
|
||||
std::cout << "Testing objc_getMetaClass ()...\n";
|
||||
{
|
||||
if (! class_isMetaClass (objc_getMetaClass ("MyRootClass")))
|
||||
abort ();
|
||||
}
|
||||
|
||||
std::cout << "Testing objc_getProtocol ()...\n";
|
||||
{
|
||||
if (! protocol_isEqual (objc_getProtocol ("MyProtocol"), @protocol (MyProtocol)))
|
||||
abort ();
|
||||
}
|
||||
|
||||
std::cout << "Testing objc_getRequiredClass ()...\n";
|
||||
{
|
||||
if (std::strcmp (class_getName (objc_getRequiredClass ("MyRootClass")),
|
||||
"MyRootClass") != 0)
|
||||
abort ();
|
||||
}
|
||||
|
||||
std::cout << "Testing objc_lookupClass ()...\n";
|
||||
{
|
||||
if (std::strcmp (class_getName (objc_lookupClass ("MyRootClass")),
|
||||
"MyRootClass") != 0)
|
||||
abort ();
|
||||
}
|
||||
|
||||
/* This function does not exist with the GNU runtime. */
|
||||
/* std::cout << "Testing objc_setFutureClass ()...\n"; */
|
||||
|
||||
std::cout << "Testing objc_registerClassPair ()...\n";
|
||||
{
|
||||
Class new_class = objc_allocateClassPair (objc_getClass ("MySubClass"), "MySubSubClass", 0);
|
||||
|
||||
class_addProtocol (new_class, @protocol (MySecondProtocol));
|
||||
|
||||
objc_registerClassPair (new_class);
|
||||
|
||||
if (std::strcmp (class_getName (new_class), "MySubSubClass") != 0)
|
||||
abort ();
|
||||
|
||||
if (class_getSuperclass (new_class) != objc_getClass ("MySubClass"))
|
||||
abort ();
|
||||
|
||||
if (! class_conformsToProtocol (new_class, @protocol (MySecondProtocol)))
|
||||
abort ();
|
||||
}
|
||||
|
||||
/* TODO - Test it when implemented in the GNU Runtime */
|
||||
/* std::cout << "Testing objc_removeAssociatedObjects ()...\n"; */
|
||||
|
||||
/* TODO - Test it when implemented in the GNU Runtime */
|
||||
/* std::cout << "Testing objc_setAssociatedObject ()...\n"; */
|
||||
|
||||
return (0);
|
||||
}
|
161
gcc/testsuite/obj-c++.dg/gnu-api-2-object.mm
Normal file
161
gcc/testsuite/obj-c++.dg/gnu-api-2-object.mm
Normal file
@ -0,0 +1,161 @@
|
||||
/* Test the Modern GNU Objective-C Runtime API.
|
||||
|
||||
This is test 'object', covering all functions starting with 'object'. */
|
||||
|
||||
/* { dg-do run } */
|
||||
/* { dg-skip-if "" { *-*-* } { "-fnext-runtime" } { "" } } */
|
||||
|
||||
/* To get the modern GNU Objective-C Runtime API, you include
|
||||
objc/runtime.h. */
|
||||
#include <objc/runtime.h>
|
||||
#include <stdlib.h>
|
||||
#include <iostream>
|
||||
#include <cstring>
|
||||
|
||||
@interface MyRootClass
|
||||
{ Class isa; }
|
||||
+ alloc;
|
||||
- init;
|
||||
@end
|
||||
|
||||
@implementation MyRootClass
|
||||
+ alloc { return class_createInstance (self, 0); }
|
||||
- init { return self; }
|
||||
@end
|
||||
|
||||
@protocol MyProtocol
|
||||
- (id) variable;
|
||||
@end
|
||||
|
||||
@protocol MySecondProtocol
|
||||
- (id) setVariable: (id)value;
|
||||
@end
|
||||
|
||||
@interface MySubClass : MyRootClass <MyProtocol>
|
||||
{ id variable_ivar; }
|
||||
- (void) setVariable: (id)value;
|
||||
- (id) variable;
|
||||
@end
|
||||
|
||||
@implementation MySubClass
|
||||
- (void) setVariable: (id)value { variable_ivar = value; }
|
||||
- (id) variable { return variable_ivar; }
|
||||
@end
|
||||
|
||||
@interface MySubSubClass : MySubClass
|
||||
- (id) test;
|
||||
@end
|
||||
|
||||
@implementation MySubSubClass
|
||||
- (id) test { return self; }
|
||||
@end
|
||||
|
||||
|
||||
|
||||
int main ()
|
||||
{
|
||||
/* Functions are tested in alphabetical order. */
|
||||
|
||||
std::cout << "Testing object_copy () ...\n";
|
||||
{
|
||||
MySubClass *object_a = [[MySubClass alloc] init];
|
||||
MySubClass *object_b = object_copy (object_a, 0);
|
||||
|
||||
[object_b setVariable: object_a];
|
||||
if ([object_b variable] != object_a)
|
||||
abort ();
|
||||
}
|
||||
|
||||
std::cout << "Testing object_dispose () ...\n";
|
||||
{
|
||||
MySubClass *object = [[MySubClass alloc] init];
|
||||
|
||||
object_dispose (object);
|
||||
}
|
||||
|
||||
std::cout << "Testing object_getClass () ...\n";
|
||||
{
|
||||
MyRootClass *o = [[MySubClass alloc] init];
|
||||
|
||||
if (object_getClass (o) != objc_getClass ("MySubClass"))
|
||||
abort ();
|
||||
}
|
||||
|
||||
std::cout << "Testing object_getClassName () ...\n";
|
||||
{
|
||||
MyRootClass *o = [[MyRootClass alloc] init];
|
||||
|
||||
if (std::strcmp (object_getClassName (o), "MyRootClass") != 0)
|
||||
abort ();
|
||||
}
|
||||
|
||||
std::cout << "Testing object_getIndexedIvars () ...\n";
|
||||
{
|
||||
if (object_getIndexedIvars ([[MyRootClass alloc] init]) == NULL)
|
||||
abort ();
|
||||
}
|
||||
|
||||
std::cout << "Testing object_getInstanceVariable () ...\n";
|
||||
{
|
||||
MySubClass *o = [[MySubClass alloc] init];
|
||||
id value;
|
||||
|
||||
[o setVariable: o];
|
||||
|
||||
if (object_getInstanceVariable (o, "variable_ivar", (void **)&value) == NULL)
|
||||
abort ();
|
||||
|
||||
if (value != o)
|
||||
abort ();
|
||||
}
|
||||
|
||||
std::cout << "Testing object_getIvar () ...\n";
|
||||
{
|
||||
MySubClass *o = [[MySubClass alloc] init];
|
||||
Ivar ivar = class_getInstanceVariable (objc_getClass ("MySubClass"), "variable_ivar");
|
||||
|
||||
[o setVariable: o];
|
||||
|
||||
if (object_getIvar (o, ivar) != o)
|
||||
abort ();
|
||||
}
|
||||
|
||||
std::cout << "Testing object_setClass () ...\n";
|
||||
{
|
||||
MySubClass *o = [[MySubClass alloc] init];
|
||||
|
||||
object_setClass (o, objc_getClass ("MySubSubClass"));
|
||||
|
||||
if ([(MySubSubClass *)o test] != o)
|
||||
abort ();
|
||||
}
|
||||
|
||||
std::cout << "Testing object_setInstanceVariable () ...\n";
|
||||
{
|
||||
MySubClass *o = [[MySubClass alloc] init];
|
||||
|
||||
[o setVariable: nil];
|
||||
|
||||
if (object_setInstanceVariable (o, "variable_ivar", (void *)o) == NULL)
|
||||
abort ();
|
||||
|
||||
if ([o variable] != o)
|
||||
abort ();
|
||||
}
|
||||
|
||||
std::cout << "Testing object_setIvar () ...\n";
|
||||
{
|
||||
MySubClass *o = [[MySubClass alloc] init];
|
||||
MySubClass *value = [[MySubClass alloc] init];
|
||||
Ivar ivar = class_getInstanceVariable (objc_getClass ("MySubClass"), "variable_ivar");
|
||||
|
||||
[o setVariable: o];
|
||||
|
||||
object_setIvar (o, ivar, value);
|
||||
|
||||
if ([o variable] != value)
|
||||
abort ();
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
65
gcc/testsuite/obj-c++.dg/gnu-api-2-property.mm
Normal file
65
gcc/testsuite/obj-c++.dg/gnu-api-2-property.mm
Normal file
@ -0,0 +1,65 @@
|
||||
/* Test the Modern GNU Objective-C Runtime API.
|
||||
|
||||
This is test 'property', covering all functions starting with 'property'. */
|
||||
|
||||
/* { dg-do run } */
|
||||
/* { dg-skip-if "" { *-*-* } { "-fnext-runtime" } { "" } } */
|
||||
|
||||
/* To get the modern GNU Objective-C Runtime API, you include
|
||||
objc/runtime.h. */
|
||||
#include <objc/runtime.h>
|
||||
#include <stdlib.h>
|
||||
#include <iostream>
|
||||
#include <cstring>
|
||||
|
||||
@interface MyRootClass
|
||||
{ Class isa; }
|
||||
+ alloc;
|
||||
- init;
|
||||
@end
|
||||
|
||||
@implementation MyRootClass
|
||||
+ alloc { return class_createInstance (self, 0); }
|
||||
- init { return self; }
|
||||
@end
|
||||
|
||||
@protocol MyProtocol
|
||||
- (id) variable;
|
||||
@end
|
||||
|
||||
@protocol MySecondProtocol
|
||||
- (id) setVariable: (id)value;
|
||||
@end
|
||||
|
||||
@interface MySubClass : MyRootClass <MyProtocol>
|
||||
{ id variable_ivar; }
|
||||
- (void) setVariable: (id)value;
|
||||
- (id) variable;
|
||||
@end
|
||||
|
||||
@implementation MySubClass
|
||||
- (void) setVariable: (id)value { variable_ivar = value; }
|
||||
- (id) variable { return variable_ivar; }
|
||||
@end
|
||||
|
||||
|
||||
int main ()
|
||||
{
|
||||
/* Functions are tested in alphabetical order. */
|
||||
|
||||
/* TODO: Test new ABI (when available). */
|
||||
std::cout << "Testing property_getAttributes () ...\n";
|
||||
{
|
||||
if (property_getAttributes (NULL) != NULL)
|
||||
abort ();
|
||||
}
|
||||
|
||||
/* TODO: Test new ABI (when available). */
|
||||
std::cout << "Testing property_getName () ...\n";
|
||||
{
|
||||
if (property_getName (NULL) != NULL)
|
||||
abort ();
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
160
gcc/testsuite/obj-c++.dg/gnu-api-2-protocol.mm
Normal file
160
gcc/testsuite/obj-c++.dg/gnu-api-2-protocol.mm
Normal file
@ -0,0 +1,160 @@
|
||||
/* Test the Modern GNU Objective-C Runtime API.
|
||||
|
||||
This is test 'protocol', covering all functions starting with 'protocol'. */
|
||||
|
||||
/* { dg-do run } */
|
||||
/* { dg-skip-if "" { *-*-* } { "-fnext-runtime" } { "" } } */
|
||||
|
||||
/* To get the modern GNU Objective-C Runtime API, you include
|
||||
objc/runtime.h. */
|
||||
#include <objc/runtime.h>
|
||||
#include <stdlib.h>
|
||||
#include <iostream>
|
||||
#include <cstring>
|
||||
|
||||
@interface MyRootClass
|
||||
{ Class isa; }
|
||||
+ alloc;
|
||||
- init;
|
||||
@end
|
||||
|
||||
@implementation MyRootClass
|
||||
+ alloc { return class_createInstance (self, 0); }
|
||||
- init { return self; }
|
||||
@end
|
||||
|
||||
@protocol MyProtocol
|
||||
- (id) variable;
|
||||
@end
|
||||
|
||||
@protocol MySecondProtocol
|
||||
- (id) setVariable: (id)value;
|
||||
@end
|
||||
|
||||
@protocol MyThirdProtocol <MySecondProtocol>
|
||||
- (id) setAnotherVariable: (id)value;
|
||||
@end
|
||||
|
||||
@interface MySubClass : MyRootClass <MyProtocol>
|
||||
{ id variable_ivar; }
|
||||
- (void) setVariable: (id)value;
|
||||
- (id) variable;
|
||||
@end
|
||||
|
||||
@implementation MySubClass
|
||||
- (void) setVariable: (id)value { variable_ivar = value; }
|
||||
- (id) variable { return variable_ivar; }
|
||||
@end
|
||||
|
||||
|
||||
int main ()
|
||||
{
|
||||
/* Functions are tested in alphabetical order. */
|
||||
|
||||
std::cout << "Testing protocol_conformsToProtocol ()...\n";
|
||||
{
|
||||
if (!protocol_conformsToProtocol (@protocol (MyProtocol),
|
||||
@protocol (MyProtocol)))
|
||||
abort ();
|
||||
|
||||
if (!protocol_conformsToProtocol (@protocol (MyThirdProtocol),
|
||||
@protocol (MySecondProtocol)))
|
||||
abort ();
|
||||
|
||||
if (protocol_conformsToProtocol (@protocol (MyProtocol),
|
||||
@protocol (MySecondProtocol)))
|
||||
abort ();
|
||||
}
|
||||
|
||||
std::cout << "Testing protocol_copyMethodDescriptionList ()...\n";
|
||||
{
|
||||
unsigned int count;
|
||||
struct objc_method_description *list;
|
||||
|
||||
list = protocol_copyMethodDescriptionList (@protocol (MyThirdProtocol),
|
||||
YES, YES, &count);
|
||||
|
||||
if (count != 1)
|
||||
abort ();
|
||||
|
||||
if (std::strcmp (sel_getName (list[0].name), "setAnotherVariable:") != 0)
|
||||
abort ();
|
||||
|
||||
if (list[1].name != NULL && list[1].types != NULL)
|
||||
abort ();
|
||||
}
|
||||
|
||||
/* TODO: Test new ABI (when available). */
|
||||
std::cout << "Testing protocol_copyPropertyList ()...\n";
|
||||
{
|
||||
unsigned int count;
|
||||
Property *list;
|
||||
|
||||
list = protocol_copyPropertyList (@protocol (MyProtocol), &count);
|
||||
|
||||
if (count != 0 || list != NULL)
|
||||
abort ();
|
||||
}
|
||||
|
||||
std::cout << "Testing protocol_copyProtocolList ()...\n";
|
||||
{
|
||||
unsigned int count;
|
||||
Protocol **list;
|
||||
|
||||
list = protocol_copyProtocolList (@protocol (MyThirdProtocol), &count);
|
||||
|
||||
if (count != 1)
|
||||
abort ();
|
||||
|
||||
if (std::strcmp (protocol_getName (list[0]), "MySecondProtocol") != 0)
|
||||
abort ();
|
||||
|
||||
if (list[1] != NULL)
|
||||
abort ();
|
||||
}
|
||||
|
||||
std::cout << "Testing protocol_getMethodDescription ()...\n";
|
||||
{
|
||||
struct objc_method_description description;
|
||||
|
||||
description = protocol_getMethodDescription (@protocol (MySecondProtocol),
|
||||
@selector (setVariable:),
|
||||
YES, YES);
|
||||
if (description.name == NULL && description.types == NULL)
|
||||
abort ();
|
||||
|
||||
if (std::strcmp (sel_getName (description.name), "setVariable:") != 0)
|
||||
abort ();
|
||||
}
|
||||
|
||||
std::cout << "Testing protocol_getName ()...\n";
|
||||
{
|
||||
if (std::strcmp (protocol_getName (@protocol (MyProtocol)), "MyProtocol") != 0)
|
||||
abort ();
|
||||
}
|
||||
|
||||
/* TODO: Test new ABI (when available). */
|
||||
std::cout << "Testing protocol_getProperty ()...\n";
|
||||
{
|
||||
Property property;
|
||||
|
||||
property = protocol_getProperty (objc_getProtocol ("MyProtocol"), "someProperty",
|
||||
YES, YES);
|
||||
|
||||
if (property != NULL)
|
||||
abort ();
|
||||
}
|
||||
|
||||
std::cout << "Testing protocol_isEqual ()...\n";
|
||||
{
|
||||
if (!protocol_isEqual (@protocol (MyProtocol),
|
||||
@protocol (MyProtocol)))
|
||||
abort ();
|
||||
|
||||
if (!protocol_isEqual (@protocol (MyProtocol),
|
||||
objc_getProtocol ("MyProtocol")))
|
||||
abort ();
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
103
gcc/testsuite/obj-c++.dg/gnu-api-2-sel.mm
Normal file
103
gcc/testsuite/obj-c++.dg/gnu-api-2-sel.mm
Normal file
@ -0,0 +1,103 @@
|
||||
/* Test the Modern GNU Objective-C Runtime API.
|
||||
|
||||
This is test 'sel', covering all functions starting with 'sel'. */
|
||||
|
||||
/* { dg-do run } */
|
||||
/* { dg-skip-if "" { *-*-* } { "-fnext-runtime" } { "" } } */
|
||||
|
||||
/* To get the modern GNU Objective-C Runtime API, you include
|
||||
objc/runtime.h. */
|
||||
#include <objc/runtime.h>
|
||||
#include <stdlib.h>
|
||||
#include <iostream>
|
||||
#include <cstring>
|
||||
|
||||
@interface MyRootClass
|
||||
{ Class isa; }
|
||||
+ alloc;
|
||||
- init;
|
||||
@end
|
||||
|
||||
@implementation MyRootClass
|
||||
+ alloc { return class_createInstance (self, 0); }
|
||||
- init { return self; }
|
||||
@end
|
||||
|
||||
@protocol MyProtocol
|
||||
- (id) variable;
|
||||
@end
|
||||
|
||||
@protocol MySecondProtocol
|
||||
- (id) setVariable: (id)value;
|
||||
@end
|
||||
|
||||
@interface MySubClass : MyRootClass <MyProtocol>
|
||||
{ id variable_ivar; }
|
||||
- (void) setVariable: (id)value;
|
||||
- (id) variable;
|
||||
@end
|
||||
|
||||
@implementation MySubClass
|
||||
- (void) setVariable: (id)value { variable_ivar = value; }
|
||||
- (id) variable { return variable_ivar; }
|
||||
@end
|
||||
|
||||
|
||||
int main ()
|
||||
{
|
||||
/* Functions are tested in alphabetical order. */
|
||||
|
||||
std::cout << "Testing sel_getName () ...\n";
|
||||
{
|
||||
if (std::strcmp (sel_getName (@selector (variable)), "variable") != 0)
|
||||
abort ();
|
||||
|
||||
if (std::strcmp (sel_getName (NULL), "<null selector>") != 0)
|
||||
abort ();
|
||||
}
|
||||
|
||||
std::cout << "Testing sel_getType () ...\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)
|
||||
abort ();
|
||||
}
|
||||
|
||||
std::cout << "Testing sel_getUid () ...\n";
|
||||
{
|
||||
if (std::strcmp (sel_getName (sel_getUid ("myMethod")), "myMethod") != 0)
|
||||
abort ();
|
||||
}
|
||||
|
||||
std::cout << "Testing sel_isEqual () ...\n";
|
||||
{
|
||||
if (! sel_isEqual (@selector (setVariable:), @selector (setVariable:)))
|
||||
abort ();
|
||||
}
|
||||
|
||||
std::cout << "Testing sel_registerName () ...\n";
|
||||
{
|
||||
if (std::strcmp (sel_getName (sel_registerName ("myMethod")), "myMethod") != 0)
|
||||
abort ();
|
||||
}
|
||||
|
||||
std::cout << "Testing set_registerTypedName () ...\n";
|
||||
{
|
||||
const char *types = method_getTypeEncoding (class_getInstanceMethod
|
||||
(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)
|
||||
abort ();
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
@ -1,3 +1,8 @@
|
||||
2010-10-17 Nicola Pero <nicola.pero@meta-innovation.com>
|
||||
|
||||
* objc/message.h: Moved initial includes outside of extern "C".
|
||||
* objc/runtime.h: Add extern "C" for Objective-C++.
|
||||
|
||||
2010-10-17 Nicola Pero <nicola.pero@meta-innovation.com>
|
||||
|
||||
* init.c (objc_send_load): Do not wait for NXConstantString to be
|
||||
@ -6,7 +11,7 @@
|
||||
as is the case for almost all users.
|
||||
* linking.m (__objc_linking): Do not try to forcefully link in
|
||||
NXConstantString.
|
||||
|
||||
|
||||
2010-10-16 Nicola Pero <nicola.pero@meta-innovation.com>
|
||||
|
||||
* objc/runtime.h: Updated comments.
|
||||
|
@ -26,13 +26,13 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
||||
#ifndef __objc_message_INCLUDE_GNU
|
||||
#define __objc_message_INCLUDE_GNU
|
||||
|
||||
#include "objc.h"
|
||||
#include "objc-decls.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "objc.h"
|
||||
#include "objc-decls.h"
|
||||
|
||||
/* This file includes declarations of the messaging functions and
|
||||
types.
|
||||
*/
|
||||
|
@ -50,6 +50,10 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
||||
#include "objc.h"
|
||||
#include "objc-decls.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/* An 'Ivar' represents an instance variable. It holds information
|
||||
about the name, type and offset of the instance variable. */
|
||||
typedef struct objc_ivar *Ivar;
|
||||
@ -1042,4 +1046,8 @@ void objc_layout_structure_get_info (struct objc_struct_layout *layout,
|
||||
unsigned int *align,
|
||||
const char **type);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user