added iOS source code
[wl-app.git] / iOS / Pods / GoogleUtilities / GoogleUtilities / MethodSwizzler / GULSwizzler.m
diff --git a/iOS/Pods/GoogleUtilities/GoogleUtilities/MethodSwizzler/GULSwizzler.m b/iOS/Pods/GoogleUtilities/GoogleUtilities/MethodSwizzler/GULSwizzler.m
new file mode 100644 (file)
index 0000000..9839124
--- /dev/null
@@ -0,0 +1,185 @@
+// Copyright 2018 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#import "Private/GULSwizzler.h"
+
+#import <objc/runtime.h>
+
+#import <GoogleUtilities/GULLogger.h>
+#import "../Common/GULLoggerCodes.h"
+
+#ifdef GUL_UNSWIZZLING_ENABLED
+#import <GoogleUtilities/GULSwizzlingCache.h>
+// We need a private method for an assert.
+#import <GoogleUtilities/GULSwizzlingCache_Private.h>
+#endif
+
+static GULLoggerService kGULLoggerSwizzler = @"[GoogleUtilites/MethodSwizzler]";
+
+dispatch_queue_t GetGULSwizzlingQueue() {
+  static dispatch_queue_t queue;
+  static dispatch_once_t onceToken;
+  dispatch_once(&onceToken, ^{
+    queue = dispatch_queue_create("com.google.GULSwizzler", DISPATCH_QUEUE_SERIAL);
+  });
+  return queue;
+}
+
+@implementation GULSwizzler
+
++ (void)swizzleClass:(Class)aClass
+            selector:(SEL)selector
+     isClassSelector:(BOOL)isClassSelector
+           withBlock:(nullable id)block {
+  dispatch_sync(GetGULSwizzlingQueue(), ^{
+    NSAssert(selector, @"The selector cannot be NULL");
+    NSAssert(aClass, @"The class cannot be Nil");
+    Class resolvedClass = aClass;
+    Method method = nil;
+    if (isClassSelector) {
+      method = class_getClassMethod(aClass, selector);
+      resolvedClass = object_getClass(aClass);
+    } else {
+      method = class_getInstanceMethod(aClass, selector);
+    }
+    NSAssert(method, @"You're attempting to swizzle a method that doesn't exist. (%@, %@)",
+             NSStringFromClass(resolvedClass), NSStringFromSelector(selector));
+    IMP newImp = imp_implementationWithBlock(block);
+
+#ifdef GUL_UNSWIZZLING_ENABLED
+    IMP currentImp = class_getMethodImplementation(resolvedClass, selector);
+    [[GULSwizzlingCache sharedInstance] cacheCurrentIMP:currentImp
+                                              forNewIMP:newImp
+                                               forClass:resolvedClass
+                                           withSelector:selector];
+#endif
+
+    const char *typeEncoding = method_getTypeEncoding(method);
+    __unused IMP originalImpOfClass =
+        class_replaceMethod(resolvedClass, selector, newImp, typeEncoding);
+
+#ifdef GUL_UNSWIZZLING_ENABLED
+    // If !originalImpOfClass, then the IMP came from a superclass.
+    if (originalImpOfClass) {
+      if (originalImpOfClass !=
+          [[GULSwizzlingCache sharedInstance] originalIMPOfCurrentIMP:currentImp]) {
+        GULLogWarning(kGULLoggerSwizzler, NO,
+                      [NSString stringWithFormat:@"I-SWZ%06ld",
+                                                 (long)kGULSwizzlerMessageCodeMethodSwizzling000],
+                      @"Swizzling class: %@ SEL:%@ after it has been previously been swizzled.",
+                      NSStringFromClass(resolvedClass), NSStringFromSelector(selector));
+      }
+    }
+#endif
+  });
+}
+
++ (void)unswizzleClass:(Class)aClass selector:(SEL)selector isClassSelector:(BOOL)isClassSelector {
+#ifdef GUL_UNSWIZZLING_ENABLED
+  dispatch_sync(GetGULSwizzlingQueue(), ^{
+    NSAssert(aClass != nil && selector != nil, @"You cannot unswizzle a nil class or selector.");
+    Method method = nil;
+    Class resolvedClass = aClass;
+    if (isClassSelector) {
+      resolvedClass = object_getClass(aClass);
+      method = class_getClassMethod(aClass, selector);
+    } else {
+      method = class_getInstanceMethod(aClass, selector);
+    }
+    NSAssert(method, @"Couldn't find the method you're unswizzling in the runtime.");
+    IMP originalImp =
+        [[GULSwizzlingCache sharedInstance] cachedIMPForClass:resolvedClass withSelector:selector];
+    NSAssert(originalImp, @"This class/selector combination hasn't been swizzled");
+    IMP currentImp = method_setImplementation(method, originalImp);
+    BOOL didRemoveBlock = imp_removeBlock(currentImp);
+    NSAssert(didRemoveBlock, @"Wasn't able to remove the block of a swizzled IMP.");
+    [[GULSwizzlingCache sharedInstance] clearCacheForSwizzledIMP:currentImp
+                                                        selector:selector
+                                                          aClass:resolvedClass];
+  });
+#else
+  NSAssert(NO, @"Unswizzling is disabled.");
+#endif
+}
+
++ (nullable IMP)originalImplementationForClass:(Class)aClass
+                                      selector:(SEL)selector
+                               isClassSelector:(BOOL)isClassSelector {
+#ifdef GUL_UNSWIZZLING_ENABLED
+  __block IMP originalImp = nil;
+  dispatch_sync(GetGULSwizzlingQueue(), ^{
+    Class resolvedClass = isClassSelector ? object_getClass(aClass) : aClass;
+    originalImp =
+        [[GULSwizzlingCache sharedInstance] cachedIMPForClass:resolvedClass withSelector:selector];
+    NSAssert(originalImp, @"The IMP for this class/selector combo doesn't exist (%@, %@).",
+             NSStringFromClass(resolvedClass), NSStringFromSelector(selector));
+  });
+  return originalImp;
+#else
+  NSAssert(NO, @"Unswizzling is disabled and the original IMP is not cached.");
+  return nil;
+#endif
+}
+
++ (nullable IMP)currentImplementationForClass:(Class)aClass
+                                     selector:(SEL)selector
+                              isClassSelector:(BOOL)isClassSelector {
+  NSAssert(selector, @"The selector cannot be NULL");
+  NSAssert(aClass, @"The class cannot be Nil");
+  if (selector == NULL || aClass == nil) {
+    return nil;
+  }
+  __block IMP currentIMP = nil;
+  dispatch_sync(GetGULSwizzlingQueue(), ^{
+    Method method = nil;
+    if (isClassSelector) {
+      method = class_getClassMethod(aClass, selector);
+    } else {
+      method = class_getInstanceMethod(aClass, selector);
+    }
+    NSAssert(method, @"The Method for this class/selector combo doesn't exist (%@, %@).",
+             NSStringFromClass(aClass), NSStringFromSelector(selector));
+    if (method == nil) {
+      return;
+    }
+    currentIMP = method_getImplementation(method);
+    NSAssert(currentIMP, @"The IMP for this class/selector combo doesn't exist (%@, %@).",
+             NSStringFromClass(aClass), NSStringFromSelector(selector));
+  });
+  return currentIMP;
+}
+
++ (BOOL)selector:(SEL)selector existsInClass:(Class)aClass isClassSelector:(BOOL)isClassSelector {
+  Method method = isClassSelector ? class_getClassMethod(aClass, selector)
+                                  : class_getInstanceMethod(aClass, selector);
+  return method != nil;
+}
+
++ (NSArray<id> *)ivarObjectsForObject:(id)object {
+  NSMutableArray *array = [NSMutableArray array];
+  unsigned int count;
+  Ivar *vars = class_copyIvarList([object class], &count);
+  for (NSUInteger i = 0; i < count; i++) {
+    const char *typeEncoding = ivar_getTypeEncoding(vars[i]);
+    // Check to see if the ivar is an object.
+    if (strncmp(typeEncoding, "@", 1) == 0) {
+      id ivarObject = object_getIvar(object, vars[i]);
+      [array addObject:ivarObject];
+    }
+  }
+  free(vars);
+  return array;
+}
+
+@end