Add warning message to `isKindOfClass:`.

If the class object doesn't belong to the process of the callee object, the result will always be `NO`. For now, we print warning for this case, so developer may have chance to notice this if this is not the desired result.

PiperOrigin-RevId: 315752083
diff --git a/Service/Sources/EDOObject.m b/Service/Sources/EDOObject.m
index 5396c3e..16589d5 100644
--- a/Service/Sources/EDOObject.m
+++ b/Service/Sources/EDOObject.m
@@ -35,6 +35,9 @@
 static NSString *const kEDOObjectCoderClassNameKey = @"edoClassName";
 static NSString *const kEDOObjectCoderProcessUUIDKey = @"edoProcessUUID";
 
+/** Returns the boolean idicating if the two objects are from the same process. */
+static BOOL IsFromSameProcess(id object1, id object2);
+
 @interface EDOObject ()
 /** The port to connect to the local socket. */
 @property(readonly) EDOServicePort *servicePort;
@@ -171,8 +174,7 @@
   if (self == object) {
     return YES;
   }
-  if ([object class] == [EDOObject class] &&
-      [self.processUUID isEqual:((EDOObject *)object).processUUID]) {
+  if (IsFromSameProcess(self, object)) {
     BOOL returnValue = NO;
     NSMethodSignature *methodSignature = [NSMethodSignature methodSignatureForSelector:_cmd];
     NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSignature];
@@ -186,6 +188,27 @@
   return NO;
 }
 
+- (BOOL)isKindOfClass:(Class)aClass {
+  if (!IsFromSameProcess(self, aClass)) {
+    NSLog(@"EDO WARNING: %@'s class is being compared via isKindOfClass: with the class that "
+          @"doesn't belong to the process of the callee object. It will always return NO. To "
+          @"expect isKindOfClass: to return YES, please use a class object that is fetched by "
+          @"EDOClientService::classObjectWithName:hostPort:.",
+          self.className);
+    return NO;
+  }
+
+  NSMethodSignature *methodSignature = [NSMethodSignature methodSignatureForSelector:_cmd];
+  NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSignature];
+  invocation.target = self;
+  invocation.selector = _cmd;
+  [invocation setArgument:&aClass atIndex:2];
+  [self forwardInvocation:invocation];
+  BOOL returnValue = NO;
+  [invocation getReturnValue:&returnValue];
+  return returnValue;
+}
+
 - (NSUInteger)hash {
   NSUInteger remoteHash = 0;
   NSMethodSignature *methodSignature = [NSMethodSignature methodSignatureForSelector:_cmd];
@@ -331,3 +354,10 @@
 }
 
 @end
+
+static BOOL IsFromSameProcess(id object1, id object2) {
+  Class edoClass = [EDOObject class];
+  return ([object1 class] != edoClass && [object2 class] != edoClass) ||
+         ([object1 class] == edoClass && [object2 class] == edoClass &&
+          [((EDOObject *)object1).processUUID isEqual:((EDOObject *)object2).processUUID]);
+}
diff --git a/Service/Tests/FunctionalTests/EDOServiceUITest.m b/Service/Tests/FunctionalTests/EDOServiceUITest.m
index f0e0149..838dbf9 100644
--- a/Service/Tests/FunctionalTests/EDOServiceUITest.m
+++ b/Service/Tests/FunctionalTests/EDOServiceUITest.m
@@ -18,6 +18,7 @@
 
 #include <objc/runtime.h>
 
+#import "Channel/Sources/EDOHostPort.h"
 #import "Channel/Sources/EDOSocket.h"
 #import "Channel/Sources/EDOSocketChannel.h"
 #import "Service/Sources/EDOClientService.h"
@@ -328,6 +329,26 @@
   free(methods);
 }
 
+/**
+ *  Verifies `isKindOfClass:` returns true only if the class object belongs to the callee process.
+ */
+- (void)testIsKindOfClassOnlyResolvesInSameProcess {
+  [self launchApplicationWithPort:EDOTEST_APP_SERVICE_PORT initValue:5];
+  // Create a local service so it can wrap and deref the any returned EDOObjects.
+  EDOHostService *service = [EDOHostService serviceWithPort:2234
+                                                 rootObject:[[EDOTestDummyInTest alloc] init]
+                                                      queue:dispatch_get_main_queue()];
+  EDOTestDummy *remoteDummy = [EDOClientService rootObjectWithPort:EDOTEST_APP_SERVICE_PORT];
+  NSArray<NSNumber *> *remoteArray = [remoteDummy returnArray];
+
+  EDOHostPort *hostPort = [EDOHostPort hostPortWithLocalPort:EDOTEST_APP_SERVICE_PORT];
+  Class remoteArrayClass = [EDOClientService classObjectWithName:@"NSArray" hostPort:hostPort];
+  XCTAssertTrue([remoteArray isKindOfClass:remoteArrayClass]);
+  XCTAssertFalse([remoteArray isKindOfClass:[NSArray class]]);
+
+  [service invalidate];
+}
+
 - (void)testRemoteObjectCopy {
   [self launchApplicationWithPort:EDOTEST_APP_SERVICE_PORT initValue:5];
   EDOTestDummy *dummy = [EDOClientService rootObjectWithPort:EDOTEST_APP_SERVICE_PORT];