/* TEST_BUILD_OUTPUT .*getMethod.m:\d+:\d+: warning: null passed to a callee that requires a non-null argument \[-Wnonnull\](\n.* note: expanded from macro 'testassert')? .*getMethod.m:\d+:\d+: warning: null passed to a callee that requires a non-null argument \[-Wnonnull\](\n.* note: expanded from macro 'testassert')? .*getMethod.m:\d+:\d+: warning: null passed to a callee that requires a non-null argument \[-Wnonnull\](\n.* note: expanded from macro 'testassert')? .*getMethod.m:\d+:\d+: warning: null passed to a callee that requires a non-null argument \[-Wnonnull\](\n.* note: expanded from macro 'testassert')? END */ #include "test.h" #include "testroot.i" #include #include static int state = 0; @interface Super : TestRoot @end @implementation Super +(void)classMethod { state = 1; } -(void)instanceMethod { state = 4; } +(void)classMethodSuperOnly { state = 3; } -(void)instanceMethodSuperOnly { state = 6; } @end @interface Sub : Super @end @implementation Sub +(void)classMethod { state = 2; } -(void)instanceMethod { state = 5; } @end typedef void (*imp_t)(id, SEL); int main() { Class Super_cls, Sub_cls; Class buf[10]; Method m; SEL sel; IMP imp; id bufobj = (__bridge_transfer id)(void*)buf; // don't use [Super class] to check laziness handing Super_cls = objc_getClass("Super"); Sub_cls = objc_getClass("Sub"); sel = sel_registerName("classMethod"); m = class_getClassMethod(Super_cls, sel); testassert(m); testassert(sel == method_getName(m)); imp = method_getImplementation(m); testassert(imp == class_getMethodImplementation(object_getClass(Super_cls), sel)); testassert(imp == object_getMethodImplementation(Super_cls, sel)); state = 0; (*(imp_t)imp)(Super_cls, sel); testassert(state == 1); sel = sel_registerName("classMethod"); m = class_getClassMethod(Sub_cls, sel); testassert(m); testassert(sel == method_getName(m)); imp = method_getImplementation(m); testassert(imp == class_getMethodImplementation(object_getClass(Sub_cls), sel)); testassert(imp == object_getMethodImplementation(Sub_cls, sel)); state = 0; (*(imp_t)imp)(Sub_cls, sel); testassert(state == 2); sel = sel_registerName("classMethodSuperOnly"); m = class_getClassMethod(Sub_cls, sel); testassert(m); testassert(sel == method_getName(m)); imp = method_getImplementation(m); testassert(imp == class_getMethodImplementation(object_getClass(Sub_cls), sel)); testassert(imp == object_getMethodImplementation(Sub_cls, sel)); state = 0; (*(imp_t)imp)(Sub_cls, sel); testassert(state == 3); sel = sel_registerName("instanceMethod"); m = class_getInstanceMethod(Super_cls, sel); testassert(m); testassert(sel == method_getName(m)); imp = method_getImplementation(m); testassert(imp == class_getMethodImplementation(Super_cls, sel)); buf[0] = Super_cls; testassert(imp == object_getMethodImplementation(bufobj, sel)); state = 0; (*(imp_t)imp)(bufobj, sel); testassert(state == 4); sel = sel_registerName("instanceMethod"); m = class_getInstanceMethod(Sub_cls, sel); testassert(m); testassert(sel == method_getName(m)); imp = method_getImplementation(m); testassert(imp == class_getMethodImplementation(Sub_cls, sel)); buf[0] = Sub_cls; testassert(imp == object_getMethodImplementation(bufobj, sel)); state = 0; (*(imp_t)imp)(bufobj, sel); testassert(state == 5); sel = sel_registerName("instanceMethodSuperOnly"); m = class_getInstanceMethod(Sub_cls, sel); testassert(m); testassert(sel == method_getName(m)); imp = method_getImplementation(m); testassert(imp == class_getMethodImplementation(Sub_cls, sel)); buf[0] = Sub_cls; testassert(imp == object_getMethodImplementation(bufobj, sel)); state = 0; (*(imp_t)imp)(bufobj, sel); testassert(state == 6); // check class_getClassMethod(cls) == class_getInstanceMethod(cls->isa) sel = sel_registerName("classMethod"); testassert(class_getClassMethod(Sub_cls, sel) == class_getInstanceMethod(object_getClass(Sub_cls), sel)); sel = sel_registerName("nonexistent"); testassert(! class_getInstanceMethod(Sub_cls, sel)); testassert(! class_getClassMethod(Sub_cls, sel)); testassert(class_getMethodImplementation(Sub_cls, sel) == (IMP)&_objc_msgForward); buf[0] = Sub_cls; testassert(object_getMethodImplementation(bufobj, sel) == (IMP)&_objc_msgForward); #if !__arm64__ testassert(class_getMethodImplementation_stret(Sub_cls, sel) == (IMP)&_objc_msgForward_stret); testassert(object_getMethodImplementation_stret(bufobj, sel) == (IMP)&_objc_msgForward_stret); #endif testassert(! class_getInstanceMethod(NULL, NULL)); testassert(! class_getInstanceMethod(NULL, sel)); testassert(! class_getInstanceMethod(Sub_cls, NULL)); testassert(! class_getClassMethod(NULL, NULL)); testassert(! class_getClassMethod(NULL, sel)); testassert(! class_getClassMethod(Sub_cls, NULL)); succeed(__FILE__); }