Fix non-exported module warnings for superclasses

Reviewed By: mhorowitz

Differential Revision: D3841655

fbshipit-source-id: b855f9bef6c53a0964c59e1977e5eb23452edce3
This commit is contained in:
Pieter De Baets 2016-09-19 04:43:06 -07:00 committed by Facebook Github Bot 2
parent fd84447341
commit bd4cd6ea5d
3 changed files with 54 additions and 33 deletions

View File

@ -40,8 +40,6 @@ typedef NS_ENUM(NSUInteger, RCTBridgeFields) {
RCTBridgeFieldCallID, RCTBridgeFieldCallID,
}; };
RCT_EXTERN NSArray<Class> *RCTGetModuleClasses(void);
@implementation RCTBatchedBridge @implementation RCTBatchedBridge
{ {
BOOL _wasBatchActive; BOOL _wasBatchActive;
@ -265,38 +263,12 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithDelegate:(id<RCTBridgeDelegate>)dele
extraModules = self.moduleProvider(); extraModules = self.moduleProvider();
} }
#if RCT_DEBUG
static dispatch_once_t onceToken; static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{ dispatch_once(&onceToken, ^{
if (RCT_DEBUG && !RCTRunningInTestEnvironment()) { RCTVerifyAllModulesExported(extraModules);
// Check for unexported modules
Class *classes;
unsigned int classCount;
classes = objc_copyClassList(&classCount);
NSMutableSet *moduleClasses = [NSMutableSet new];
[moduleClasses addObjectsFromArray:RCTGetModuleClasses()];
[moduleClasses addObjectsFromArray:[extraModules valueForKeyPath:@"class"]];
for (unsigned int i = 0; i < classCount; i++)
{
Class cls = classes[i];
Class superclass = cls;
while (superclass)
{
if (class_conformsToProtocol(superclass, @protocol(RCTBridgeModule)))
{
if (![moduleClasses containsObject:cls] &&
![cls respondsToSelector:@selector(moduleName)]) {
RCTLogWarn(@"Class %@ was not exported. Did you forget to use "
"RCT_EXPORT_MODULE()?", cls);
}
break;
}
superclass = class_getSuperclass(superclass);
}
}
}
}); });
#endif
NSMutableArray<Class> *moduleClassesByID = [NSMutableArray new]; NSMutableArray<Class> *moduleClassesByID = [NSMutableArray new];
NSMutableArray<RCTModuleData *> *moduleDataByID = [NSMutableArray new]; NSMutableArray<RCTModuleData *> *moduleDataByID = [NSMutableArray new];

View File

@ -12,6 +12,12 @@
@class RCTModuleData; @class RCTModuleData;
@protocol RCTJavaScriptExecutor; @protocol RCTJavaScriptExecutor;
RCT_EXTERN NSArray<Class> *RCTGetModuleClasses(void);
#if RCT_DEBUG
RCT_EXTERN void RCTVerifyAllModulesExported(NSArray *extraModules);
#endif
@interface RCTBridge () @interface RCTBridge ()
// Private designated initializer // Private designated initializer

View File

@ -7,6 +7,7 @@
* of patent rights can be found in the PATENTS file in the same directory. * of patent rights can be found in the PATENTS file in the same directory.
*/ */
#import "RCTBridge.h"
#import "RCTBridge+Private.h" #import "RCTBridge+Private.h"
#import <objc/runtime.h> #import <objc/runtime.h>
@ -27,7 +28,6 @@ NSString *const RCTJavaScriptDidFailToLoadNotification = @"RCTJavaScriptDidFailT
NSString *const RCTDidInitializeModuleNotification = @"RCTDidInitializeModuleNotification"; NSString *const RCTDidInitializeModuleNotification = @"RCTDidInitializeModuleNotification";
static NSMutableArray<Class> *RCTModuleClasses; static NSMutableArray<Class> *RCTModuleClasses;
NSArray<Class> *RCTGetModuleClasses(void);
NSArray<Class> *RCTGetModuleClasses(void) NSArray<Class> *RCTGetModuleClasses(void)
{ {
return RCTModuleClasses; return RCTModuleClasses;
@ -58,7 +58,7 @@ void RCTRegisterModule(Class moduleClass)
*/ */
NSString *RCTBridgeModuleNameForClass(Class cls) NSString *RCTBridgeModuleNameForClass(Class cls)
{ {
#if RCT_DEV #if RCT_DEBUG
RCTAssert([cls conformsToProtocol:@protocol(RCTBridgeModule)], RCTAssert([cls conformsToProtocol:@protocol(RCTBridgeModule)],
@"Bridge module `%@` does not conform to RCTBridgeModule", cls); @"Bridge module `%@` does not conform to RCTBridgeModule", cls);
#endif #endif
@ -73,6 +73,49 @@ NSString *RCTBridgeModuleNameForClass(Class cls)
return name; return name;
} }
#if RCT_DEBUG
void RCTVerifyAllModulesExported(NSArray *extraModules)
{
// Check for unexported modules
unsigned int classCount;
Class *classes = objc_copyClassList(&classCount);
NSMutableSet *moduleClasses = [NSMutableSet new];
[moduleClasses addObjectsFromArray:RCTGetModuleClasses()];
[moduleClasses addObjectsFromArray:[extraModules valueForKeyPath:@"class"]];
for (unsigned int i = 0; i < classCount; i++) {
Class cls = classes[i];
Class superclass = cls;
while (superclass) {
if (class_conformsToProtocol(superclass, @protocol(RCTBridgeModule))) {
if ([moduleClasses containsObject:cls]) {
break;
}
// Verify it's not a super-class of one of our moduleClasses
BOOL isModuleSuperClass = NO;
for (Class moduleClass in moduleClasses) {
if ([moduleClass isSubclassOfClass:cls]) {
isModuleSuperClass = YES;
break;
}
}
if (isModuleSuperClass) {
break;
}
RCTLogWarn(@"Class %@ was not exported. Did you forget to use RCT_EXPORT_MODULE()?", cls);
break;
}
superclass = class_getSuperclass(superclass);
}
}
free(classes);
}
#endif
@implementation RCTBridge @implementation RCTBridge
{ {
NSURL *_delegateBundleURL; NSURL *_delegateBundleURL;