Home | History | Annotate | Download | only in mac
      1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #import "chrome/common/mac/objc_method_swizzle.h"
      6 
      7 #import "base/logging.h"
      8 
      9 namespace ObjcEvilDoers {
     10 
     11 Method GetImplementedInstanceMethod(Class aClass, SEL aSelector) {
     12   Method method = NULL;
     13   unsigned int methodCount = 0;
     14   Method* methodList = class_copyMethodList(aClass, &methodCount);
     15   if (methodList) {
     16     for (unsigned int i = 0; i < methodCount; ++i) {
     17       if (method_getName(methodList[i]) == aSelector) {
     18         method = methodList[i];
     19         break;
     20       }
     21     }
     22     free(methodList);
     23   }
     24   return method;
     25 }
     26 
     27 IMP SwizzleImplementedInstanceMethods(
     28     Class aClass, const SEL originalSelector, const SEL alternateSelector) {
     29   // The methods must both be implemented by the target class, not
     30   // inherited from a superclass.
     31   Method original = GetImplementedInstanceMethod(aClass, originalSelector);
     32   Method alternate = GetImplementedInstanceMethod(aClass, alternateSelector);
     33   DCHECK(original);
     34   DCHECK(alternate);
     35   if (!original || !alternate) {
     36     return NULL;
     37   }
     38 
     39   // The argument and return types must match exactly.
     40   const char* originalTypes = method_getTypeEncoding(original);
     41   const char* alternateTypes = method_getTypeEncoding(alternate);
     42   DCHECK(originalTypes);
     43   DCHECK(alternateTypes);
     44   DCHECK(0 == strcmp(originalTypes, alternateTypes));
     45   if (!originalTypes || !alternateTypes ||
     46       strcmp(originalTypes, alternateTypes)) {
     47     return NULL;
     48   }
     49 
     50   IMP ret = method_getImplementation(original);
     51   if (ret) {
     52     method_exchangeImplementations(original, alternate);
     53   }
     54   return ret;
     55 }
     56 
     57 }  // namespace ObjcEvilDoers
     58