mirror of
https://github.com/gnustep/libs-base.git
synced 2025-05-30 00:11:26 +00:00
Quick hack tool to compare class methods
This commit is contained in:
parent
c64c3d9923
commit
732fd2d2fb
2 changed files with 516 additions and 2 deletions
|
@ -69,9 +69,9 @@ MAN8_PAGES = gdomap.8
|
|||
|
||||
# The application to be compiled
|
||||
ifeq ($(add),yes)
|
||||
TOOL_NAME = autogsdoc cvtenc plmerge sfparse xmlparse
|
||||
TOOL_NAME = autogsdoc classes cvtenc plmerge sfparse xmlparse
|
||||
else
|
||||
TOOL_NAME = autogsdoc cvtenc gdnc gspath defaults pl plmerge plutil \
|
||||
TOOL_NAME = autogsdoc classes cvtenc gdnc gspath defaults pl plmerge plutil \
|
||||
plparse sfparse pldes plget plser pl2link xmlparse HTMLLinker
|
||||
# gdomap is currently not supported on Windows MSVC or Android (which
|
||||
# can be either "linux-android" or "linux-androideabi")
|
||||
|
@ -88,6 +88,7 @@ TEST_TOOL_NAME = locale_alias
|
|||
|
||||
# The source files to be compiled
|
||||
autogsdoc_OBJC_FILES = autogsdoc.m AGSParser.m AGSOutput.m AGSIndex.m AGSHtml.m
|
||||
classes_OBJC_FILES = classes.m
|
||||
cvtenc_OBJC_FILES = cvtenc.m
|
||||
gdomap_C_FILES = gdomap.c
|
||||
gdnc_OBJC_FILES = gdnc.m
|
||||
|
|
513
Tools/classes.m
Normal file
513
Tools/classes.m
Normal file
|
@ -0,0 +1,513 @@
|
|||
/* Crude tool to compare classes in different version of library code to
|
||||
* look for possible compatiblity issues.
|
||||
* Only for internal/test use at the momement.
|
||||
*/
|
||||
#import "Foundation/Foundation.h"
|
||||
#import "GNUstepBase/GSObjCRuntime.h"
|
||||
|
||||
static NSSet *
|
||||
publicClasses()
|
||||
{
|
||||
static NSSet *set = nil;
|
||||
|
||||
if (nil == set)
|
||||
{
|
||||
static char *base[] = {
|
||||
"NSAffineTransform",
|
||||
"NSAppleEventDescriptor",
|
||||
"NSAppleEventManager",
|
||||
"NSAppleScript",
|
||||
"NSArchiver",
|
||||
"NSArray",
|
||||
"NSAssertionHandler",
|
||||
"NSAttributedString",
|
||||
"NSAutoreleasePool",
|
||||
"NSBackgroundActivityScheduler",
|
||||
"NSBlockOperation",
|
||||
"NSBundle",
|
||||
"NSByteCountFormatter",
|
||||
"NSCache",
|
||||
"NSCachedURLResponse",
|
||||
"NSCalendar",
|
||||
"NSCalendarDate",
|
||||
"NSCharacterSet",
|
||||
"NSClassDescription",
|
||||
"NSCoder",
|
||||
"NSComparisonPredicate",
|
||||
"NSCompoundPredicate",
|
||||
"NSCondition",
|
||||
"NSConditionLock",
|
||||
"NSConnection",
|
||||
"NSCountedSet",
|
||||
"NSData",
|
||||
"NSDate",
|
||||
"NSDateComponents",
|
||||
"NSDateComponentsFormatter",
|
||||
"NSDateFormatter",
|
||||
"NSDateInterval",
|
||||
"NSDateIntervalFormatter",
|
||||
"NSDecimalNumber",
|
||||
"NSDecimalNumberHandler",
|
||||
"NSDeserializer",
|
||||
"NSDictionary",
|
||||
"NSDimension",
|
||||
"NSDirectoryEnumerator",
|
||||
"NSDistantObject",
|
||||
"NSDistributedLock",
|
||||
"NSDistributedNotificationCenter",
|
||||
"NSEnergyFormatter",
|
||||
"NSEnumerator",
|
||||
"NSError",
|
||||
"NSException",
|
||||
"NSExpression",
|
||||
"NSExtensionContext",
|
||||
"NSExtensionItem",
|
||||
"NSFileAccessIntent",
|
||||
"NSFileCoordinator",
|
||||
"NSFileHandle",
|
||||
"NSFileManager",
|
||||
"NSFileVersion",
|
||||
"NSFileWrapper",
|
||||
"NSFormatter",
|
||||
"NSGarbageCollector",
|
||||
"NSHTTPCookie",
|
||||
"NSHTTPCookieStorage",
|
||||
"NSHTTPURLResponse",
|
||||
"NSHashTable",
|
||||
"NSHost",
|
||||
"NSISO8601DateFormatter",
|
||||
"NSIndexPath",
|
||||
"NSIndexSet",
|
||||
"NSInputStream",
|
||||
"NSInvocation",
|
||||
"NSInvocationOperation",
|
||||
"NSItemProvider",
|
||||
"NSItemProviderReadingWriting",
|
||||
"NSJSONSerialization",
|
||||
"NSKeyedArchiver",
|
||||
"NSKeyedUnarchiver",
|
||||
"NSLengthFormatter",
|
||||
"NSLinguisticTagger",
|
||||
"NSLocale",
|
||||
"NSLock",
|
||||
"NSMapTable",
|
||||
"NSMassFormatter",
|
||||
"NSMeasurement",
|
||||
"NSMeasurementFormatter",
|
||||
"NSMessagePort",
|
||||
"NSMessagePortNameServer",
|
||||
"NSMetadataItem",
|
||||
"NSMetadataQuery",
|
||||
"NSMetadataQueryAttributeValueTuple",
|
||||
"NSMetadataQueryResultGroup",
|
||||
"NSMethodSignature",
|
||||
"NSMutableArray",
|
||||
"NSMutableAttributedString",
|
||||
"NSMutableCharacterSet",
|
||||
"NSMutableData",
|
||||
"NSMutableDictionary",
|
||||
"NSMutableIndexSet",
|
||||
"NSMutableOrderedSet",
|
||||
"NSMutableSet",
|
||||
"NSMutableString",
|
||||
"NSMutableURLRequest",
|
||||
"NSNetService",
|
||||
"NSNetServiceBrowser",
|
||||
"NSNotification",
|
||||
"NSNotificationCenter",
|
||||
"NSNotificationQueue",
|
||||
"NSNull",
|
||||
"NSNumber",
|
||||
"NSNumberFormatter",
|
||||
"NSObject",
|
||||
"NSObjectScripting",
|
||||
"NSOperation",
|
||||
"NSOperationQueue",
|
||||
"NSOrderedSet",
|
||||
"NSOrthography",
|
||||
"NSOutputStream",
|
||||
"NSPersonNameComponents",
|
||||
"NSPersonNameComponentsFormatter",
|
||||
"NSPipe",
|
||||
"NSPointerArray",
|
||||
"NSPointerFunctions",
|
||||
"NSPort",
|
||||
"NSPortCoder",
|
||||
"NSPortMessage",
|
||||
"NSPortNameServer",
|
||||
"NSPredicate",
|
||||
"NSProcessInfo",
|
||||
"NSProgress",
|
||||
"NSPropertyListSerialization",
|
||||
"NSProtocolChecker",
|
||||
"NSProxy",
|
||||
"NSRecursiveLock",
|
||||
"NSRegularExpression",
|
||||
"NSRunLoop",
|
||||
"NSScanner",
|
||||
"NSScriptClassDescription",
|
||||
"NSScriptCoercionHandler",
|
||||
"NSScriptCommand",
|
||||
"NSScriptCommandDescription",
|
||||
"NSScriptExecutionContext",
|
||||
"NSScriptKeyValueCoding",
|
||||
"NSScriptObjectSpecifiers",
|
||||
"NSScriptStandardSuiteCommands",
|
||||
"NSScriptSuiteRegistry",
|
||||
"NSSerializer",
|
||||
"NSSet",
|
||||
"NSSocketPort",
|
||||
"NSSocketPortNameServer",
|
||||
"NSSortDescriptor",
|
||||
"NSSpellServer",
|
||||
"NSStream",
|
||||
"NSString",
|
||||
"NSTask",
|
||||
"NSTextCheckingResult",
|
||||
"NSThread",
|
||||
"NSTimeZone",
|
||||
"NSTimeZoneDetail",
|
||||
"NSTimer",
|
||||
"NSURL",
|
||||
"NSURLAuthenticationChallenge",
|
||||
"NSURLCache",
|
||||
"NSURLComponents",
|
||||
"NSURLConnection",
|
||||
"NSURLCredential",
|
||||
"NSURLCredentialStorage",
|
||||
"NSURLDownload",
|
||||
"NSURLHandle",
|
||||
"NSURLProtectionSpace",
|
||||
"NSURLProtocol",
|
||||
"NSURLQueryItem",
|
||||
"NSURLRequest",
|
||||
"NSURLResponse",
|
||||
"NSURLSession",
|
||||
"NSURLSessionConfiguration",
|
||||
"NSURLSessionDataTask",
|
||||
"NSURLSessionDownloadTask",
|
||||
"NSURLSessionStreamTask",
|
||||
"NSURLSessionTask",
|
||||
"NSURLSessionUploadTask",
|
||||
"NSUUID",
|
||||
"NSUbiquitousKeyValueStore",
|
||||
"NSUnarchiver",
|
||||
"NSUndoManager",
|
||||
"NSUnit",
|
||||
"NSUnitAcceleration",
|
||||
"NSUnitAngle",
|
||||
"NSUnitArea",
|
||||
"NSUnitConcentrationMass",
|
||||
"NSUnitConverter",
|
||||
"NSUnitConverterLinear",
|
||||
"NSUnitDispersion",
|
||||
"NSUnitDuration",
|
||||
"NSUnitElectricCharge",
|
||||
"NSUnitElectricCurrent",
|
||||
"NSUnitElectricPotentialDifference",
|
||||
"NSUnitElectricResistance",
|
||||
"NSUnitEnergy",
|
||||
"NSUnitFrequency",
|
||||
"NSUnitFuelEfficiency",
|
||||
"NSUnitIlluminance",
|
||||
"NSUnitLength",
|
||||
"NSUnitMass",
|
||||
"NSUnitPower",
|
||||
"NSUnitPressure",
|
||||
"NSUnitSpeed",
|
||||
"NSUnitTemperature",
|
||||
"NSUnitVolume",
|
||||
"NSUserActivity",
|
||||
"NSUserDefaults",
|
||||
"NSUserNotification",
|
||||
"NSUserNotificationCenter",
|
||||
"NSUserScriptTask",
|
||||
"NSValue",
|
||||
"NSValueTransformer",
|
||||
"NSXMLDTD",
|
||||
"NSXMLDTDNode",
|
||||
"NSXMLDocument",
|
||||
"NSXMLElement",
|
||||
"NSXMLNode",
|
||||
"NSXMLParser",
|
||||
"NSXPCConnection",
|
||||
"NSXPCInterface",
|
||||
"NSXPCListener",
|
||||
"NSXPCListenerEndpoint"
|
||||
};
|
||||
unsigned count = sizeof(base)/sizeof(*base);
|
||||
unsigned index;
|
||||
NSMutableSet *m;
|
||||
|
||||
ENTER_POOL
|
||||
m = [NSMutableSet setWithCapacity: count];
|
||||
for (index = 0; index < count; index++)
|
||||
{
|
||||
[m addObject: [NSString stringWithUTF8String: base[index]]];
|
||||
}
|
||||
ASSIGNCOPY(set, m);
|
||||
LEAVE_POOL
|
||||
}
|
||||
return set;
|
||||
}
|
||||
|
||||
static BOOL
|
||||
findClassMethod(NSString *mName, NSString *cName, NSDictionary *all)
|
||||
{
|
||||
while (cName != nil)
|
||||
{
|
||||
NSDictionary *info = [all objectForKey: cName];
|
||||
|
||||
if ([[info objectForKey: @"classmethods"] containsObject: mName])
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
cName = [info objectForKey: @"superclass"];
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
static BOOL
|
||||
findInstanceMethod(NSString *mName, NSString *cName, NSDictionary *all)
|
||||
{
|
||||
while (cName != nil)
|
||||
{
|
||||
NSDictionary *info = [all objectForKey: cName];
|
||||
|
||||
if ([[info objectForKey: @"instancemethods"] containsObject: mName])
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
cName = [info objectForKey: @"superclass"];
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
static BOOL
|
||||
doCompare(NSString *name, NSDictionary *oinfo, NSDictionary *all)
|
||||
{
|
||||
NSDictionary *ninfo = [all objectForKey: name];
|
||||
NSEnumerator *e;
|
||||
id n;
|
||||
id o;
|
||||
BOOL ok = YES;
|
||||
|
||||
if (nil == ninfo)
|
||||
{
|
||||
NSLog(@"Class '%@' removed\n", name);
|
||||
return NO;
|
||||
}
|
||||
o = [oinfo objectForKey: @"superclass"];
|
||||
n = [ninfo objectForKey: @"superclass"];
|
||||
if (o != n && NO == [o isEqual: n])
|
||||
{
|
||||
NSLog(@"Class '%@' superclass changed from %@ to %@\n", name, o, n);
|
||||
ok = NO;
|
||||
}
|
||||
|
||||
e = [[oinfo objectForKey: @"classmethods"] objectEnumerator];
|
||||
while ((o = [e nextObject]) != nil)
|
||||
{
|
||||
if (NO == findClassMethod(o, name, all))
|
||||
{
|
||||
NSLog(@"Class '%@' class method '%@' removed\n", name, o);
|
||||
ok = NO;
|
||||
}
|
||||
}
|
||||
|
||||
e = [[oinfo objectForKey: @"instancemethods"] objectEnumerator];
|
||||
while ((o = [e nextObject]) != nil)
|
||||
{
|
||||
if (NO == findInstanceMethod(o, name, all))
|
||||
{
|
||||
NSLog(@"Class '%@' instance method '%@' removed\n", name, o);
|
||||
ok = NO;
|
||||
}
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
static void
|
||||
doMethods(Class class, NSMutableDictionary *info, BOOL instance)
|
||||
{
|
||||
NSMutableArray *ma = [NSMutableArray array];
|
||||
Method *methods;
|
||||
unsigned int count;
|
||||
|
||||
if (instance)
|
||||
{
|
||||
methods = class_copyMethodList(class, &count);
|
||||
}
|
||||
else
|
||||
{
|
||||
methods = class_copyMethodList(object_getClass(class), &count);
|
||||
}
|
||||
if (methods)
|
||||
{
|
||||
NSString *name;
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
SEL sel = method_getName(methods[i]);
|
||||
const char *n = sel_getName(sel);
|
||||
|
||||
if (0 == n || '_' == *n)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
name = [NSString stringWithUTF8String: n];
|
||||
if ([ma containsObject: name] == NO)
|
||||
{
|
||||
[ma addObject: name];
|
||||
}
|
||||
}
|
||||
free(methods);
|
||||
}
|
||||
|
||||
if ([ma count])
|
||||
{
|
||||
[ma sortUsingSelector: @selector(compare:)];
|
||||
if (instance)
|
||||
{
|
||||
[info setObject: ma forKey: @"instancemethods"];
|
||||
}
|
||||
else
|
||||
{
|
||||
[info setObject: ma forKey: @"classmethods"];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
ENTER_POOL
|
||||
NSDictionary *oldClasses;
|
||||
NSMutableDictionary *newClasses;
|
||||
// Protocol **protocols;
|
||||
NSString *signature;
|
||||
int classCount;
|
||||
NSDictionary *locale;
|
||||
NSString *name;
|
||||
Class class;
|
||||
NSSet *set;
|
||||
|
||||
locale = [[NSUserDefaults standardUserDefaults] dictionaryRepresentation];
|
||||
|
||||
oldClasses = [NSDictionary dictionaryWithContentsOfFile: @"OldClasses.plist"];
|
||||
|
||||
set = publicClasses();
|
||||
classCount = [set count];
|
||||
if (0 == classCount)
|
||||
{
|
||||
/* No expected classes ... try to get all classes instead.
|
||||
*/
|
||||
classCount = objc_getClassList(NULL, 0);
|
||||
set = nil;
|
||||
}
|
||||
if (classCount > 0)
|
||||
{
|
||||
Class buf[classCount];
|
||||
int ci;
|
||||
|
||||
if (set)
|
||||
{
|
||||
NSEnumerator *e = [set objectEnumerator];
|
||||
|
||||
ci = 0;
|
||||
while ((name = [e nextObject]) != nil)
|
||||
{
|
||||
class = NSClassFromString(name);
|
||||
if (Nil == class)
|
||||
{
|
||||
NSLog(@"Expected class '%@' not found.", name);
|
||||
}
|
||||
else
|
||||
{
|
||||
buf[ci++] = class;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ci = objc_getClassList(buf, classCount);
|
||||
NSCAssert(ci == classCount, NSInternalInconsistencyException);
|
||||
}
|
||||
classCount = ci;
|
||||
|
||||
newClasses = [NSMutableDictionary dictionaryWithCapacity: ci];
|
||||
for (ci = 0; ci < classCount; ci++)
|
||||
{
|
||||
Class superClass;
|
||||
NSMutableDictionary *classDescription;
|
||||
const char *n;
|
||||
|
||||
class = buf[ci];
|
||||
if (class_isMetaClass(class))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
n = class_getName(class);
|
||||
if (0 == n || '_' == *n)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
name = [NSString stringWithUTF8String: class_getName(class)];
|
||||
if (set && nil == [set member: name])
|
||||
{
|
||||
NSLog(@"Unexpected class '%@' ignored", name);
|
||||
continue;
|
||||
}
|
||||
|
||||
classDescription = [NSMutableDictionary dictionaryWithCapacity: 4];
|
||||
[newClasses setObject: classDescription forKey: name];
|
||||
|
||||
superClass = class_getSuperclass(class);
|
||||
if (superClass != Nil)
|
||||
{
|
||||
n = class_getName(superClass);
|
||||
name = [NSString stringWithUTF8String: n];
|
||||
[classDescription setObject: name forKey: @"superclass"];
|
||||
}
|
||||
|
||||
doMethods(class, classDescription, YES);
|
||||
doMethods(class, classDescription, NO);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NSLog(@"Failed to find any classes");
|
||||
exit(1);
|
||||
}
|
||||
signature = [newClasses descriptionWithLocale: locale indent: 0];
|
||||
[signature writeToFile: @"NewClasses.plist" atomically: NO];
|
||||
|
||||
if (oldClasses)
|
||||
{
|
||||
NSEnumerator *e = [oldClasses keyEnumerator];
|
||||
BOOL ok = YES;
|
||||
|
||||
while ((name = [e nextObject]) != nil)
|
||||
{
|
||||
NSDictionary *oinfo = [oldClasses objectForKey: name];
|
||||
|
||||
if (NO == doCompare(name, oinfo, newClasses))
|
||||
{
|
||||
ok = NO;
|
||||
}
|
||||
}
|
||||
if (ok)
|
||||
{
|
||||
NSLog(@"Old and new class signature match.");
|
||||
}
|
||||
else
|
||||
{
|
||||
NSLog(@"Old and new class signature differ.");
|
||||
}
|
||||
}
|
||||
|
||||
LEAVE_POOL
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue