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/browser/ui/cocoa/objc_method_swizzle.h"
6
7#import "base/logging.h"
8#import "base/memory/scoped_nsobject.h"
9#import "chrome/app/breakpad_mac.h"
10
11namespace ObjcEvilDoers {
12
13Method GetImplementedInstanceMethod(Class aClass, SEL aSelector) {
14  Method method = NULL;
15  unsigned int methodCount = 0;
16  Method* methodList = class_copyMethodList(aClass, &methodCount);
17  if (methodList) {
18    for (unsigned int i = 0; i < methodCount; ++i) {
19      if (method_getName(methodList[i]) == aSelector) {
20        method = methodList[i];
21        break;
22      }
23    }
24    free(methodList);
25  }
26  return method;
27}
28
29IMP SwizzleImplementedInstanceMethods(
30    Class aClass, const SEL originalSelector, const SEL alternateSelector) {
31  // The methods must both be implemented by the target class, not
32  // inherited from a superclass.
33  Method original = GetImplementedInstanceMethod(aClass, originalSelector);
34  Method alternate = GetImplementedInstanceMethod(aClass, alternateSelector);
35  DCHECK(original);
36  DCHECK(alternate);
37  if (!original || !alternate) {
38    return NULL;
39  }
40
41  // The argument and return types must match exactly.
42  const char* originalTypes = method_getTypeEncoding(original);
43  const char* alternateTypes = method_getTypeEncoding(alternate);
44  DCHECK(originalTypes);
45  DCHECK(alternateTypes);
46  DCHECK(0 == strcmp(originalTypes, alternateTypes));
47  if (!originalTypes || !alternateTypes ||
48      strcmp(originalTypes, alternateTypes)) {
49    return NULL;
50  }
51
52  IMP ret = method_getImplementation(original);
53  if (ret) {
54    method_exchangeImplementations(original, alternate);
55  }
56  return ret;
57}
58
59}  // namespace ObjcEvilDoers
60