| Index: class-dump/src/CDType.m
|
| ===================================================================
|
| --- class-dump/src/CDType.m (revision 0)
|
| +++ class-dump/src/CDType.m (revision 0)
|
| @@ -0,0 +1,956 @@
|
| +// -*- mode: ObjC -*-
|
| +
|
| +// This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files.
|
| +// Copyright (C) 1997-1998, 2000-2001, 2004-2010 Steve Nygard.
|
| +
|
| +#import "CDType.h"
|
| +
|
| +#import "NSArray-Extensions.h"
|
| +#import "NSString-Extensions.h"
|
| +#import "CDSymbolReferences.h"
|
| +#import "CDTypeController.h"
|
| +#import "CDTypeName.h"
|
| +#import "CDTypeLexer.h" // For T_NAMED_OBJECT
|
| +#import "CDTypeFormatter.h"
|
| +#import "CDTypeParser.h"
|
| +#import "NSError-CDExtensions.h"
|
| +
|
| +static BOOL debugMerge = NO;
|
| +
|
| +@implementation CDType
|
| +
|
| +- (id)init;
|
| +{
|
| + if ([super init] == nil)
|
| + return nil;
|
| +
|
| + type = 0; // ??
|
| + protocols = nil;
|
| + subtype = nil;
|
| + typeName = nil;
|
| + members = nil;
|
| + variableName = nil;
|
| + bitfieldSize = nil;
|
| + arraySize = nil;
|
| +
|
| + return self;
|
| +}
|
| +
|
| +- (id)initSimpleType:(int)aTypeCode;
|
| +{
|
| + if ([self init] == nil)
|
| + return nil;
|
| +
|
| + if (aTypeCode == '*') {
|
| + type = '^';
|
| + subtype = [[CDType alloc] initSimpleType:'c'];
|
| + } else {
|
| + type = aTypeCode;
|
| + }
|
| +
|
| + return self;
|
| +}
|
| +
|
| +- (id)initIDType:(CDTypeName *)aName;
|
| +{
|
| + if ([self init] == nil)
|
| + return nil;
|
| +
|
| + if (aName != nil) {
|
| + type = T_NAMED_OBJECT;
|
| + typeName = [aName retain];
|
| + } else {
|
| + type = '@';
|
| + }
|
| +
|
| + return self;
|
| +}
|
| +
|
| +- (id)initIDTypeWithProtocols:(NSArray *)someProtocols;
|
| +{
|
| + if ([self init] == nil)
|
| + return nil;
|
| +
|
| + type = '@';
|
| + protocols = [someProtocols retain];
|
| +
|
| + return self;
|
| +}
|
| +
|
| +- (id)initStructType:(CDTypeName *)aName members:(NSArray *)someMembers;
|
| +{
|
| + if ([self init] == nil)
|
| + return nil;
|
| +
|
| + type = '{';
|
| + typeName = [aName retain];
|
| + members = [[NSMutableArray alloc] initWithArray:someMembers];
|
| +
|
| + return self;
|
| +}
|
| +
|
| +- (id)initUnionType:(CDTypeName *)aName members:(NSArray *)someMembers;
|
| +{
|
| + if ([self init] == nil)
|
| + return nil;
|
| +
|
| + type = '(';
|
| + typeName = [aName retain];
|
| + members = [[NSMutableArray alloc] initWithArray:someMembers];
|
| +
|
| + return self;
|
| +}
|
| +
|
| +- (id)initBitfieldType:(NSString *)aBitfieldSize;
|
| +{
|
| + if ([self init] == nil)
|
| + return nil;
|
| +
|
| + type = 'b';
|
| + bitfieldSize = [aBitfieldSize retain];
|
| +
|
| + return self;
|
| +}
|
| +
|
| +- (id)initArrayType:(CDType *)aType count:(NSString *)aCount;
|
| +{
|
| + if ([self init] == nil)
|
| + return nil;
|
| +
|
| + type = '[';
|
| + arraySize = [aCount retain];
|
| + subtype = [aType retain];
|
| +
|
| + return self;
|
| +}
|
| +
|
| +- (id)initPointerType:(CDType *)aType;
|
| +{
|
| + if ([self init] == nil)
|
| + return nil;
|
| +
|
| + type = '^';
|
| + subtype = [aType retain];
|
| +
|
| + return self;
|
| +}
|
| +
|
| +- (id)initModifier:(int)aModifier type:(CDType *)aType;
|
| +{
|
| + if ([self init] == nil)
|
| + return nil;
|
| +
|
| + type = aModifier;
|
| + subtype = [aType retain];
|
| +
|
| + return self;
|
| +}
|
| +
|
| +- (void)dealloc;
|
| +{
|
| + [protocols release];
|
| + [subtype release];
|
| + [typeName release];
|
| + [members release];
|
| + [variableName release];
|
| + [bitfieldSize release];
|
| + [arraySize release];
|
| +
|
| + [super dealloc];
|
| +}
|
| +
|
| +@synthesize variableName;
|
| +
|
| +- (int)type;
|
| +{
|
| + return type;
|
| +}
|
| +
|
| +- (BOOL)isIDType;
|
| +{
|
| + return type == '@' && typeName == nil;
|
| +}
|
| +
|
| +- (BOOL)isNamedObject;
|
| +{
|
| + return type == T_NAMED_OBJECT;
|
| +}
|
| +
|
| +- (BOOL)isTemplateType;
|
| +{
|
| + return [typeName isTemplateType];
|
| +}
|
| +
|
| +- (CDType *)subtype;
|
| +{
|
| + return subtype;
|
| +}
|
| +
|
| +- (CDTypeName *)typeName;
|
| +{
|
| + return typeName;
|
| +}
|
| +
|
| +- (NSArray *)members;
|
| +{
|
| + return members;
|
| +}
|
| +
|
| +- (BOOL)isModifierType;
|
| +{
|
| + return type == 'r' || type == 'n' || type == 'N' || type == 'o' || type == 'O' || type == 'R' || type == 'V';
|
| +}
|
| +
|
| +- (int)typeIgnoringModifiers;
|
| +{
|
| + if ([self isModifierType] && subtype != nil)
|
| + return [subtype typeIgnoringModifiers];
|
| +
|
| + return type;
|
| +}
|
| +
|
| +- (NSUInteger)structureDepth;
|
| +{
|
| + if (subtype != nil)
|
| + return [subtype structureDepth];
|
| +
|
| + if (type == '{' || type == '(') {
|
| + NSUInteger maxDepth = 0;
|
| +
|
| + for (CDType *member in members) {
|
| + if (maxDepth < [member structureDepth])
|
| + maxDepth = [member structureDepth];
|
| + }
|
| +
|
| + return maxDepth + 1;
|
| + }
|
| +
|
| + return 0;
|
| +}
|
| +
|
| +- (NSString *)description;
|
| +{
|
| + return [NSString stringWithFormat:@"[%@] type: %d('%c'), name: %@, subtype: %@, bitfieldSize: %@, arraySize: %@, members: %@, variableName: %@",
|
| + NSStringFromClass([self class]), type, type, typeName, subtype, bitfieldSize, arraySize, members, variableName];
|
| +}
|
| +
|
| +- (NSString *)formattedString:(NSString *)previousName formatter:(CDTypeFormatter *)typeFormatter level:(NSUInteger)level symbolReferences:(CDSymbolReferences *)symbolReferences;
|
| +{
|
| + NSString *result, *currentName;
|
| + NSString *baseType, *memberString;
|
| +
|
| + assert(variableName == nil || previousName == nil);
|
| + if (variableName != nil)
|
| + currentName = variableName;
|
| + else
|
| + currentName = previousName;
|
| +
|
| + switch (type) {
|
| + case T_NAMED_OBJECT:
|
| + assert(typeName != nil);
|
| + [symbolReferences addClassName:[typeName name]];
|
| + if (currentName == nil)
|
| + result = [NSString stringWithFormat:@"%@ *", typeName];
|
| + else
|
| + result = [NSString stringWithFormat:@"%@ *%@", typeName, currentName];
|
| + break;
|
| +
|
| + case '@':
|
| + if (currentName == nil) {
|
| + if (protocols == nil)
|
| + result = @"id";
|
| + else
|
| + result = [NSString stringWithFormat:@"id <%@>", [protocols componentsJoinedByString:@", "]];
|
| + } else {
|
| + if (protocols == nil)
|
| + result = [NSString stringWithFormat:@"id %@", currentName];
|
| + else
|
| + result = [NSString stringWithFormat:@"id <%@> %@", [protocols componentsJoinedByString:@", "], currentName];
|
| + }
|
| + break;
|
| +
|
| + case 'b':
|
| + if (currentName == nil) {
|
| + // This actually compiles!
|
| + result = [NSString stringWithFormat:@"unsigned int :%@", bitfieldSize];
|
| + } else
|
| + result = [NSString stringWithFormat:@"unsigned int %@:%@", currentName, bitfieldSize];
|
| + break;
|
| +
|
| + case '[':
|
| + if (currentName == nil)
|
| + result = [NSString stringWithFormat:@"[%@]", arraySize];
|
| + else
|
| + result = [NSString stringWithFormat:@"%@[%@]", currentName, arraySize];
|
| +
|
| + result = [subtype formattedString:result formatter:typeFormatter level:level symbolReferences:symbolReferences];
|
| + break;
|
| +
|
| + case '(':
|
| + baseType = nil;
|
| + /*if (typeName == nil || [@"?" isEqual:[typeName description]])*/ {
|
| + NSString *typedefName;
|
| +
|
| + typedefName = [typeFormatter typedefNameForStruct:self level:level];
|
| + if (typedefName != nil) {
|
| + baseType = typedefName;
|
| + }
|
| + }
|
| +
|
| + if (baseType == nil) {
|
| + if (typeName == nil || [@"?" isEqual:[typeName description]])
|
| + baseType = @"union";
|
| + else
|
| + baseType = [NSString stringWithFormat:@"union %@", typeName];
|
| +
|
| + if (([typeFormatter shouldAutoExpand] && [[typeFormatter typeController] shouldExpandType:self] && [members count] > 0)
|
| + || (level == 0 && [typeFormatter shouldExpand] && [members count] > 0))
|
| + memberString = [NSString stringWithFormat:@" {\n%@%@}",
|
| + [self formattedStringForMembersAtLevel:level + 1 formatter:typeFormatter symbolReferences:symbolReferences],
|
| + [NSString spacesIndentedToLevel:[typeFormatter baseLevel] + level spacesPerLevel:4]];
|
| + else
|
| + memberString = @"";
|
| +
|
| + baseType = [baseType stringByAppendingString:memberString];
|
| + }
|
| +
|
| + if (currentName == nil /*|| [currentName hasPrefix:@"?"]*/) // Not sure about this
|
| + result = baseType;
|
| + else
|
| + result = [NSString stringWithFormat:@"%@ %@", baseType, currentName];
|
| + break;
|
| +
|
| + case '{':
|
| + baseType = nil;
|
| + /*if (typeName == nil || [@"?" isEqual:[typeName description]])*/ {
|
| + NSString *typedefName;
|
| +
|
| + typedefName = [typeFormatter typedefNameForStruct:self level:level];
|
| + if (typedefName != nil) {
|
| + baseType = typedefName;
|
| + }
|
| + }
|
| + if (baseType == nil) {
|
| + if (typeName == nil || [@"?" isEqual:[typeName description]])
|
| + baseType = @"struct";
|
| + else
|
| + baseType = [NSString stringWithFormat:@"struct %@", typeName];
|
| +
|
| + if (([typeFormatter shouldAutoExpand] && [[typeFormatter typeController] shouldExpandType:self] && [members count] > 0)
|
| + || (level == 0 && [typeFormatter shouldExpand] && [members count] > 0))
|
| + memberString = [NSString stringWithFormat:@" {\n%@%@}",
|
| + [self formattedStringForMembersAtLevel:level + 1 formatter:typeFormatter symbolReferences:symbolReferences],
|
| + [NSString spacesIndentedToLevel:[typeFormatter baseLevel] + level spacesPerLevel:4]];
|
| + else
|
| + memberString = @"";
|
| +
|
| + baseType = [baseType stringByAppendingString:memberString];
|
| + }
|
| +
|
| + if (currentName == nil /*|| [currentName hasPrefix:@"?"]*/) // Not sure about this
|
| + result = baseType;
|
| + else
|
| + result = [NSString stringWithFormat:@"%@ %@", baseType, currentName];
|
| + break;
|
| +
|
| + case '^':
|
| + if (currentName == nil)
|
| + result = @"*";
|
| + else
|
| + result = [@"*" stringByAppendingString:currentName];
|
| +
|
| + if (subtype != nil && [subtype type] == '[')
|
| + result = [NSString stringWithFormat:@"(%@)", result];
|
| +
|
| + result = [subtype formattedString:result formatter:typeFormatter level:level symbolReferences:symbolReferences];
|
| + break;
|
| +
|
| + case 'r':
|
| + case 'n':
|
| + case 'N':
|
| + case 'o':
|
| + case 'O':
|
| + case 'R':
|
| + case 'V':
|
| + if (subtype == nil) {
|
| + if (currentName == nil)
|
| + result = [self formattedStringForSimpleType];
|
| + else
|
| + result = [NSString stringWithFormat:@"%@ %@", [self formattedStringForSimpleType], currentName];
|
| + } else
|
| + result = [NSString stringWithFormat:@"%@ %@",
|
| + [self formattedStringForSimpleType], [subtype formattedString:currentName formatter:typeFormatter level:level symbolReferences:symbolReferences]];
|
| + break;
|
| +
|
| + default:
|
| + if (currentName == nil)
|
| + result = [self formattedStringForSimpleType];
|
| + else
|
| + result = [NSString stringWithFormat:@"%@ %@", [self formattedStringForSimpleType], currentName];
|
| + break;
|
| + }
|
| +
|
| + return result;
|
| +}
|
| +
|
| +- (NSString *)formattedStringForMembersAtLevel:(NSUInteger)level formatter:(CDTypeFormatter *)typeFormatter symbolReferences:(CDSymbolReferences *)symbolReferences;
|
| +{
|
| + NSMutableString *str;
|
| +
|
| + assert(type == '{' || type == '(');
|
| + str = [NSMutableString string];
|
| +
|
| + for (CDType *member in members) {
|
| + [str appendString:[NSString spacesIndentedToLevel:[typeFormatter baseLevel] + level spacesPerLevel:4]];
|
| + [str appendString:[member formattedString:nil
|
| + formatter:typeFormatter
|
| + level:level
|
| + symbolReferences:symbolReferences]];
|
| + [str appendString:@";\n"];
|
| + }
|
| +
|
| + return str;
|
| +}
|
| +
|
| +- (NSString *)formattedStringForSimpleType;
|
| +{
|
| + // Ugly but simple:
|
| + switch (type) {
|
| + case 'c': return @"char";
|
| + case 'i': return @"int";
|
| + case 's': return @"short";
|
| + case 'l': return @"long";
|
| + case 'q': return @"long long";
|
| + case 'C': return @"unsigned char";
|
| + case 'I': return @"unsigned int";
|
| + case 'S': return @"unsigned short";
|
| + case 'L': return @"unsigned long";
|
| + case 'Q': return @"unsigned long long";
|
| + case 'f': return @"float";
|
| + case 'd': return @"double";
|
| + case 'B': return @"_Bool"; /* C99 _Bool or C++ bool */
|
| + case 'v': return @"void";
|
| + case '*': return @"STR";
|
| + case '#': return @"Class";
|
| + case ':': return @"SEL";
|
| + case '%': return @"NXAtom";
|
| + case '?': return @"void";
|
| + //case '?': return @"UNKNOWN"; // For easier regression testing.
|
| + case 'r': return @"const";
|
| + case 'n': return @"in";
|
| + case 'N': return @"inout";
|
| + case 'o': return @"out";
|
| + case 'O': return @"bycopy";
|
| + case 'R': return @"byref";
|
| + case 'V': return @"oneway";
|
| + default:
|
| + break;
|
| + }
|
| +
|
| + return nil;
|
| +}
|
| +
|
| +- (NSString *)typeString;
|
| +{
|
| + return [self _typeStringWithVariableNamesToLevel:1e6 showObjectTypes:YES];
|
| +}
|
| +
|
| +- (NSString *)bareTypeString;
|
| +{
|
| + return [self _typeStringWithVariableNamesToLevel:0 showObjectTypes:YES];
|
| +}
|
| +
|
| +- (NSString *)reallyBareTypeString;
|
| +{
|
| + return [self _typeStringWithVariableNamesToLevel:0 showObjectTypes:NO];
|
| +}
|
| +
|
| +- (NSString *)keyTypeString;
|
| +{
|
| + // use variable names at top level
|
| + return [self _typeStringWithVariableNamesToLevel:1 showObjectTypes:YES];
|
| +}
|
| +
|
| +- (NSString *)_typeStringWithVariableNamesToLevel:(NSUInteger)level showObjectTypes:(BOOL)shouldShowObjectTypes;
|
| +{
|
| + NSString *result;
|
| +
|
| + switch (type) {
|
| + case T_NAMED_OBJECT:
|
| + assert(typeName != nil);
|
| + if (shouldShowObjectTypes)
|
| + result = [NSString stringWithFormat:@"@\"%@\"", typeName];
|
| + else
|
| + result = @"@";
|
| + break;
|
| +
|
| + case '@':
|
| + result = @"@";
|
| + break;
|
| +
|
| + case 'b':
|
| + result = [NSString stringWithFormat:@"b%@", bitfieldSize];
|
| + break;
|
| +
|
| + case '[':
|
| + result = [NSString stringWithFormat:@"[%@%@]", arraySize, [subtype _typeStringWithVariableNamesToLevel:level showObjectTypes:shouldShowObjectTypes]];
|
| + break;
|
| +
|
| + case '(':
|
| + if (typeName == nil) {
|
| + return [NSString stringWithFormat:@"(%@)", [self _typeStringForMembersWithVariableNamesToLevel:level showObjectTypes:shouldShowObjectTypes]];
|
| + } else if ([members count] == 0) {
|
| + return [NSString stringWithFormat:@"(%@)", typeName];
|
| + } else {
|
| + return [NSString stringWithFormat:@"(%@=%@)", typeName, [self _typeStringForMembersWithVariableNamesToLevel:level showObjectTypes:shouldShowObjectTypes]];
|
| + }
|
| + break;
|
| +
|
| + case '{':
|
| + if (typeName == nil) {
|
| + return [NSString stringWithFormat:@"{%@}", [self _typeStringForMembersWithVariableNamesToLevel:level showObjectTypes:shouldShowObjectTypes]];
|
| + } else if ([members count] == 0) {
|
| + return [NSString stringWithFormat:@"{%@}", typeName];
|
| + } else {
|
| + return [NSString stringWithFormat:@"{%@=%@}", typeName, [self _typeStringForMembersWithVariableNamesToLevel:level showObjectTypes:shouldShowObjectTypes]];
|
| + }
|
| + break;
|
| +
|
| + case '^':
|
| + result = [NSString stringWithFormat:@"^%@", [subtype _typeStringWithVariableNamesToLevel:level showObjectTypes:shouldShowObjectTypes]];
|
| + break;
|
| +
|
| + case 'r':
|
| + case 'n':
|
| + case 'N':
|
| + case 'o':
|
| + case 'O':
|
| + case 'R':
|
| + case 'V':
|
| + result = [NSString stringWithFormat:@"%c%@", type, [subtype _typeStringWithVariableNamesToLevel:level showObjectTypes:shouldShowObjectTypes]];
|
| + break;
|
| +
|
| + default:
|
| + result = [NSString stringWithFormat:@"%c", type];
|
| + break;
|
| + }
|
| +
|
| + return result;
|
| +}
|
| +
|
| +- (NSString *)_typeStringForMembersWithVariableNamesToLevel:(NSInteger)level showObjectTypes:(BOOL)shouldShowObjectTypes;
|
| +{
|
| + NSMutableString *str;
|
| +
|
| + assert(type == '{' || type == '(');
|
| + str = [NSMutableString string];
|
| +
|
| + for (CDType *aMember in members) {
|
| + if ([aMember variableName] != nil && level > 0)
|
| + [str appendFormat:@"\"%@\"", [aMember variableName]];
|
| + [str appendString:[aMember _typeStringWithVariableNamesToLevel:level - 1 showObjectTypes:shouldShowObjectTypes]];
|
| + }
|
| +
|
| + return str;
|
| +}
|
| +
|
| +// TODO (2009-08-26): Looks like this doesn't compare the variable name.
|
| +- (BOOL)isEqual:(CDType *)otherType;
|
| +{
|
| + return [[self typeString] isEqual:[otherType typeString]];
|
| +}
|
| +
|
| +// An easy deep copy.
|
| +- (id)copyWithZone:(NSZone *)zone;
|
| +{
|
| + CDTypeParser *parser;
|
| + NSError *error;
|
| + NSString *str;
|
| + CDType *copiedType;
|
| +
|
| + str = [self typeString];
|
| + NSParameterAssert(str != nil);
|
| +
|
| + parser = [[CDTypeParser alloc] initWithType:str];
|
| + copiedType = [[parser parseType:&error] retain];
|
| + if (copiedType == nil)
|
| + NSLog(@"Warning: Parsing type in -[CDType copyWithZone:] failed, %@", str);
|
| + [parser release];
|
| +
|
| + NSParameterAssert([str isEqualToString:[copiedType typeString]]);
|
| +
|
| + [copiedType setVariableName:variableName];
|
| +
|
| + return copiedType;
|
| +}
|
| +
|
| +- (BOOL)canMergeWithType:(CDType *)otherType;
|
| +{
|
| + NSUInteger count, index;
|
| + NSUInteger otherCount;
|
| + NSArray *otherMembers;
|
| +
|
| + if ([self isIDType] && [otherType isNamedObject])
|
| + return YES;
|
| +
|
| + if ([self isNamedObject] && [otherType isIDType]) {
|
| + return YES;
|
| + }
|
| +
|
| + if ([self type] != [otherType type]) {
|
| + if (debugMerge) {
|
| + NSLog(@"--------------------");
|
| + NSLog(@"this: %@", [self typeString]);
|
| + NSLog(@"other: %@", [otherType typeString]);
|
| + NSLog(@"self isIDType? %u", [self isIDType]);
|
| + NSLog(@"self isNamedObject? %u", [self isNamedObject]);
|
| + NSLog(@"other isIDType? %u", [otherType isIDType]);
|
| + NSLog(@"other isNamedObject? %u", [otherType isNamedObject]);
|
| + }
|
| + if (debugMerge) NSLog(@"%s, Can't merge because of type... %@ vs %@", _cmd, [self typeString], [otherType typeString]);
|
| + return NO;
|
| + }
|
| +
|
| + if (subtype != nil && [subtype canMergeWithType:[otherType subtype]] == NO) {
|
| + if (debugMerge) NSLog(@"%s, Can't merge subtype", _cmd);
|
| + return NO;
|
| + }
|
| +
|
| + if (subtype == nil && [otherType subtype] != nil) {
|
| + if (debugMerge) NSLog(@"%s, This subtype is nil, other isn't.", _cmd);
|
| + return NO;
|
| + }
|
| +
|
| + otherMembers = [otherType members];
|
| + count = [members count];
|
| + otherCount = [otherMembers count];
|
| +
|
| + //NSLog(@"members: %p", members);
|
| + //NSLog(@"otherMembers: %p", otherMembers);
|
| + //NSLog(@"%s, count: %u, otherCount: %u", _cmd, count, otherCount);
|
| +
|
| + if (count != 0 && otherCount == 0) {
|
| + if (debugMerge) NSLog(@"%s, count != 0 && otherCount is 0", _cmd);
|
| + return NO;
|
| + }
|
| +
|
| + if (count != 0 && count != otherCount) {
|
| + if (debugMerge) NSLog(@"%s, count != 0 && count != otherCount", _cmd);
|
| + return NO;
|
| + }
|
| +
|
| + // count == 0 is ok: we just have a name in that case.
|
| + if (count == otherCount) {
|
| + for (index = 0; index < count; index++) { // Oooh
|
| + CDType *thisMember, *otherMember;
|
| + CDTypeName *thisTypeName, *otherTypeName;
|
| + NSString *thisVariableName, *otherVariableName;
|
| +
|
| + thisMember = [members objectAtIndex:index];
|
| + otherMember = [otherMembers objectAtIndex:index];
|
| +
|
| + thisTypeName = [thisMember typeName];
|
| + otherTypeName = [otherMember typeName];
|
| + thisVariableName = [thisMember variableName];
|
| + otherVariableName = [otherMember variableName];
|
| +
|
| + // It seems to be okay if one of them didn't have a name
|
| + if (thisTypeName != nil && otherTypeName != nil && [thisTypeName isEqual:otherTypeName] == NO) {
|
| + if (debugMerge) NSLog(@"%s, typeName mismatch on member %u", _cmd, index);
|
| + return NO;
|
| + }
|
| +
|
| + if (thisVariableName != nil && otherVariableName != nil && [thisVariableName isEqual:otherVariableName] == NO) {
|
| + if (debugMerge) NSLog(@"%s, variableName mismatch on member %u", _cmd, index);
|
| + return NO;
|
| + }
|
| +
|
| + if ([thisMember canMergeWithType:otherMember] == NO) {
|
| + if (debugMerge) NSLog(@"%s, Can't merge member %u", _cmd, index);
|
| + return NO;
|
| + }
|
| + }
|
| + }
|
| +
|
| + return YES;
|
| +}
|
| +
|
| +// Merge struct/union member names. Should check using -canMergeWithType: first.
|
| +// Recursively merges, not just the top level.
|
| +- (void)mergeWithType:(CDType *)otherType;
|
| +{
|
| + NSString *before, *after;
|
| +
|
| + before = [self typeString];
|
| + [self _recursivelyMergeWithType:otherType];
|
| + after = [self typeString];
|
| + if (debugMerge) {
|
| + NSLog(@"----------------------------------------");
|
| + NSLog(@"%s", _cmd);
|
| + NSLog(@"before: %@", before);
|
| + NSLog(@" after: %@", after);
|
| + NSLog(@"----------------------------------------");
|
| + }
|
| +}
|
| +
|
| +- (void)_recursivelyMergeWithType:(CDType *)otherType;
|
| +{
|
| + NSUInteger count, index;
|
| + NSUInteger otherCount;
|
| + NSArray *otherMembers;
|
| +
|
| + if ([self isIDType] && [otherType isNamedObject]) {
|
| + //NSLog(@"thisType: %@", [self typeString]);
|
| + //NSLog(@"otherType: %@", [otherType typeString]);
|
| + type = T_NAMED_OBJECT;
|
| + typeName = [[otherType typeName] copy];
|
| + return;
|
| + }
|
| +
|
| + if ([self isNamedObject] && [otherType isIDType]) {
|
| + return;
|
| + }
|
| +
|
| + if ([self type] != [otherType type]) {
|
| + NSLog(@"Warning: Trying to merge different types in %s", _cmd);
|
| + return;
|
| + }
|
| +
|
| + [subtype _recursivelyMergeWithType:[otherType subtype]];
|
| +
|
| + otherMembers = [otherType members];
|
| + count = [members count];
|
| + otherCount = [otherMembers count];
|
| +
|
| + // The counts can be zero when we register structures that just have a name. That happened while I was working on the
|
| + // structure registration.
|
| + if (otherCount == 0) {
|
| + return;
|
| + } else if (count == 0 && otherCount != 0) {
|
| + NSParameterAssert(members != nil);
|
| + [members removeAllObjects];
|
| + [members addObjectsFromArray:otherMembers];
|
| + //[self setMembers:otherMembers];
|
| + } else if (count != otherCount) {
|
| + // Not so bad after all. Even kind of common. Consider _flags.
|
| + NSLog(@"Warning: Types have different number of members. This is bad. (%d vs %d)", count, otherCount);
|
| + NSLog(@"%@ vs %@", [self typeString], [otherType typeString]);
|
| + return;
|
| + }
|
| +
|
| + //NSLog(@"****************************************");
|
| + for (index = 0; index < count; index++) {
|
| + CDType *thisMember, *otherMember;
|
| + CDTypeName *thisTypeName, *otherTypeName;
|
| + NSString *thisVariableName, *otherVariableName;
|
| +
|
| + thisMember = [members objectAtIndex:index];
|
| + otherMember = [otherMembers objectAtIndex:index];
|
| +
|
| + thisTypeName = [thisMember typeName];
|
| + otherTypeName = [otherMember typeName];
|
| + thisVariableName = [thisMember variableName];
|
| + otherVariableName = [otherMember variableName];
|
| + //NSLog(@"%d: type: %@ vs %@", index, thisTypeName, otherTypeName);
|
| + //NSLog(@"%d: vari: %@ vs %@", index, thisVariableName, otherVariableName);
|
| +
|
| + if ((thisTypeName == nil && otherTypeName != nil) || (thisTypeName != nil && otherTypeName == nil))
|
| + ; // It seems to be okay if one of them didn't have a name
|
| + //NSLog(@"Warning: (1) type names don't match, %@ vs %@", thisTypeName, otherTypeName);
|
| + else if (thisTypeName != nil && [thisTypeName isEqual:otherTypeName] == NO) {
|
| + NSLog(@"Warning: (2) type names don't match:\n\t%@ vs \n\t%@.", thisTypeName, otherTypeName);
|
| + // In this case, we should skip the merge.
|
| + }
|
| +
|
| + if (otherVariableName != nil) {
|
| + if (thisVariableName == nil)
|
| + [thisMember setVariableName:otherVariableName];
|
| + else if ([thisVariableName isEqual:otherVariableName] == NO)
|
| + NSLog(@"Warning: Different variable names for same member...");
|
| + }
|
| +
|
| + [thisMember _recursivelyMergeWithType:otherMember];
|
| + }
|
| +}
|
| +
|
| +- (void)generateMemberNames;
|
| +{
|
| + if (type == '{' || type == '(') {
|
| + NSSet *usedNames;
|
| + unsigned int number;
|
| + NSString *name;
|
| +
|
| + usedNames = [[NSSet alloc] initWithArray:[members arrayByMappingSelector:@selector(variableName)]];
|
| +
|
| + number = 1;
|
| + for (CDType *aMember in members) {
|
| + [aMember generateMemberNames];
|
| +
|
| + // Bitfields don't need a name.
|
| + if ([aMember variableName] == nil && [aMember type] != 'b') {
|
| + do {
|
| + name = [NSString stringWithFormat:@"_field%u", number++];
|
| + } while ([usedNames containsObject:name]);
|
| + [aMember setVariableName:name];
|
| + }
|
| + }
|
| +
|
| + [usedNames release];
|
| +
|
| + }
|
| +
|
| + [subtype generateMemberNames];
|
| +}
|
| +
|
| +//
|
| +// Phase 0
|
| +//
|
| +
|
| +- (void)phase:(NSUInteger)phase registerTypesWithObject:(CDTypeController *)typeController usedInMethod:(BOOL)isUsedInMethod;
|
| +{
|
| + if (phase == 0) {
|
| + [self phase0RegisterStructuresWithObject:typeController usedInMethod:isUsedInMethod];
|
| + }
|
| +}
|
| +
|
| +// Just top level structures
|
| +- (void)phase0RegisterStructuresWithObject:(CDTypeController *)typeController usedInMethod:(BOOL)isUsedInMethod;
|
| +{
|
| + // ^{ComponentInstanceRecord=}
|
| + if (subtype != nil)
|
| + [subtype phase0RegisterStructuresWithObject:typeController usedInMethod:isUsedInMethod];
|
| +
|
| + if ((type == '{' || type == '(') && [members count] > 0) {
|
| + [typeController phase0RegisterStructure:self usedInMethod:isUsedInMethod];
|
| + }
|
| +}
|
| +
|
| +- (void)phase0RecursivelyFixStructureNames:(BOOL)flag;
|
| +{
|
| + [subtype phase0RecursivelyFixStructureNames:flag];
|
| +
|
| + if ([[typeName name] hasPrefix:@"$"]) {
|
| + if (flag) NSLog(@"%s, changing type name %@ to ?", _cmd, [typeName name]);
|
| + [typeName setName:@"?"];
|
| + }
|
| +
|
| + for (CDType *member in members)
|
| + [member phase0RecursivelyFixStructureNames:flag];
|
| +}
|
| +
|
| +//
|
| +// Phase 1
|
| +//
|
| +
|
| +// Recursively go through type, registering structs/unions.
|
| +- (void)phase1RegisterStructuresWithObject:(CDTypeController *)typeController;
|
| +{
|
| + // ^{ComponentInstanceRecord=}
|
| + if (subtype != nil)
|
| + [subtype phase1RegisterStructuresWithObject:typeController];
|
| +
|
| + if ((type == '{' || type == '(') && [members count] > 0) {
|
| + [typeController phase1RegisterStructure:self];
|
| + for (CDType *member in members)
|
| + [member phase1RegisterStructuresWithObject:typeController];
|
| + }
|
| +}
|
| +
|
| +//
|
| +// Phase 2
|
| +//
|
| +
|
| +// This wraps the recursive method, optionally logging if anything changed.
|
| +- (void)phase2MergeWithTypeController:(CDTypeController *)typeController debug:(BOOL)phase2Debug;
|
| +{
|
| + NSString *before, *after;
|
| +
|
| + before = [self typeString];
|
| + [self _phase2MergeWithTypeController:typeController debug:phase2Debug];
|
| + after = [self typeString];
|
| + if (phase2Debug && [before isEqualToString:after] == NO) {
|
| + NSLog(@"----------------------------------------");
|
| + NSLog(@"%s, merge changed type", _cmd);
|
| + NSLog(@"before: %@", before);
|
| + NSLog(@" after: %@", after);
|
| + }
|
| +}
|
| +
|
| +// Recursive, bottom-up
|
| +- (void)_phase2MergeWithTypeController:(CDTypeController *)typeController debug:(BOOL)phase2Debug;
|
| +{
|
| + [subtype _phase2MergeWithTypeController:typeController debug:phase2Debug];
|
| +
|
| + for (CDType *member in members)
|
| + [member _phase2MergeWithTypeController:typeController debug:phase2Debug];
|
| +
|
| + if ((type == '{' || type == '(') && [members count] > 0) {
|
| + CDType *phase2Type;
|
| +
|
| + phase2Type = [typeController phase2ReplacementForType:self];
|
| + if (phase2Type != nil) {
|
| + // >0 members so we don't try replacing things like... {_xmlNode=^{_xmlNode}}
|
| + if ([members count] > 0 && [self canMergeWithType:phase2Type]) {
|
| + [self mergeWithType:phase2Type];
|
| + } else {
|
| + if (phase2Debug) {
|
| + NSLog(@"Found phase2 type, but can't merge with it.");
|
| + NSLog(@"this: %@", [self typeString]);
|
| + NSLog(@"that: %@", [phase2Type typeString]);
|
| + }
|
| + }
|
| + }
|
| + }
|
| +}
|
| +
|
| +//
|
| +// Phase 3
|
| +//
|
| +
|
| +- (void)phase3RegisterWithTypeController:(CDTypeController *)typeController;
|
| +{
|
| + [subtype phase3RegisterWithTypeController:typeController];
|
| +
|
| + if (type == '{' || type == '(') {
|
| + [typeController phase3RegisterStructure:self /*count:1 usedInMethod:NO*/];
|
| + }
|
| +}
|
| +
|
| +- (void)phase3RegisterMembersWithTypeController:(CDTypeController *)typeController;
|
| +{
|
| + //NSLog(@" > %s %@", _cmd, [self typeString]);
|
| + for (CDType *member in members) {
|
| + [member phase3RegisterWithTypeController:typeController];
|
| + }
|
| + //NSLog(@"< %s", _cmd);
|
| +}
|
| +
|
| +// Bottom-up
|
| +- (void)phase3MergeWithTypeController:(CDTypeController *)typeController;
|
| +{
|
| + [subtype phase3MergeWithTypeController:typeController];
|
| +
|
| + for (CDType *member in members)
|
| + [member phase3MergeWithTypeController:typeController];
|
| +
|
| + if ((type == '{' || type == '(') && [members count] > 0) {
|
| + CDType *phase3Type;
|
| +
|
| + phase3Type = [typeController phase3ReplacementForType:self];
|
| + if (phase3Type != nil) {
|
| + // >0 members so we don't try replacing things like... {_xmlNode=^{_xmlNode}}
|
| + if ([members count] > 0 && [self canMergeWithType:phase3Type]) {
|
| + [self mergeWithType:phase3Type];
|
| + } else {
|
| + if (0) {
|
| + // This can happen in AU Lab, that struct has no members...
|
| + NSLog(@"Found phase3 type, but can't merge with it.");
|
| + NSLog(@"this: %@", [self typeString]);
|
| + NSLog(@"that: %@", [phase3Type typeString]);
|
| + }
|
| + }
|
| + }
|
| + }
|
| +}
|
| +
|
| +@end
|
|
|
| Property changes on: class-dump/src/CDType.m
|
| ___________________________________________________________________
|
| Added: svn:eol-style
|
| + LF
|
|
|
|
|