mirror of
https://github.com/gnustep/libs-base.git
synced 2025-05-31 00:30:53 +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
|
# The application to be compiled
|
||||||
ifeq ($(add),yes)
|
ifeq ($(add),yes)
|
||||||
TOOL_NAME = autogsdoc cvtenc plmerge sfparse xmlparse
|
TOOL_NAME = autogsdoc classes cvtenc plmerge sfparse xmlparse
|
||||||
else
|
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
|
plparse sfparse pldes plget plser pl2link xmlparse HTMLLinker
|
||||||
# gdomap is currently not supported on Windows MSVC or Android (which
|
# gdomap is currently not supported on Windows MSVC or Android (which
|
||||||
# can be either "linux-android" or "linux-androideabi")
|
# can be either "linux-android" or "linux-androideabi")
|
||||||
|
@ -88,6 +88,7 @@ TEST_TOOL_NAME = locale_alias
|
||||||
|
|
||||||
# The source files to be compiled
|
# The source files to be compiled
|
||||||
autogsdoc_OBJC_FILES = autogsdoc.m AGSParser.m AGSOutput.m AGSIndex.m AGSHtml.m
|
autogsdoc_OBJC_FILES = autogsdoc.m AGSParser.m AGSOutput.m AGSIndex.m AGSHtml.m
|
||||||
|
classes_OBJC_FILES = classes.m
|
||||||
cvtenc_OBJC_FILES = cvtenc.m
|
cvtenc_OBJC_FILES = cvtenc.m
|
||||||
gdomap_C_FILES = gdomap.c
|
gdomap_C_FILES = gdomap.c
|
||||||
gdnc_OBJC_FILES = gdnc.m
|
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