OLD | NEW |
(Empty) | |
| 1 // -*- mode: ObjC -*- |
| 2 |
| 3 // This file is part of class-dump, a utility for examining the Objective-C seg
ment of Mach-O files. |
| 4 // Copyright (C) 1997-1998, 2000-2001, 2004-2010 Steve Nygard. |
| 5 |
| 6 #import "CDType.h" |
| 7 |
| 8 #import "NSArray-Extensions.h" |
| 9 #import "NSString-Extensions.h" |
| 10 #import "CDSymbolReferences.h" |
| 11 #import "CDTypeController.h" |
| 12 #import "CDTypeName.h" |
| 13 #import "CDTypeLexer.h" // For T_NAMED_OBJECT |
| 14 #import "CDTypeFormatter.h" |
| 15 #import "CDTypeParser.h" |
| 16 #import "NSError-CDExtensions.h" |
| 17 |
| 18 static BOOL debugMerge = NO; |
| 19 |
| 20 @implementation CDType |
| 21 |
| 22 - (id)init; |
| 23 { |
| 24 if ([super init] == nil) |
| 25 return nil; |
| 26 |
| 27 type = 0; // ?? |
| 28 protocols = nil; |
| 29 subtype = nil; |
| 30 typeName = nil; |
| 31 members = nil; |
| 32 variableName = nil; |
| 33 bitfieldSize = nil; |
| 34 arraySize = nil; |
| 35 |
| 36 return self; |
| 37 } |
| 38 |
| 39 - (id)initSimpleType:(int)aTypeCode; |
| 40 { |
| 41 if ([self init] == nil) |
| 42 return nil; |
| 43 |
| 44 if (aTypeCode == '*') { |
| 45 type = '^'; |
| 46 subtype = [[CDType alloc] initSimpleType:'c']; |
| 47 } else { |
| 48 type = aTypeCode; |
| 49 } |
| 50 |
| 51 return self; |
| 52 } |
| 53 |
| 54 - (id)initIDType:(CDTypeName *)aName; |
| 55 { |
| 56 if ([self init] == nil) |
| 57 return nil; |
| 58 |
| 59 if (aName != nil) { |
| 60 type = T_NAMED_OBJECT; |
| 61 typeName = [aName retain]; |
| 62 } else { |
| 63 type = '@'; |
| 64 } |
| 65 |
| 66 return self; |
| 67 } |
| 68 |
| 69 - (id)initIDTypeWithProtocols:(NSArray *)someProtocols; |
| 70 { |
| 71 if ([self init] == nil) |
| 72 return nil; |
| 73 |
| 74 type = '@'; |
| 75 protocols = [someProtocols retain]; |
| 76 |
| 77 return self; |
| 78 } |
| 79 |
| 80 - (id)initStructType:(CDTypeName *)aName members:(NSArray *)someMembers; |
| 81 { |
| 82 if ([self init] == nil) |
| 83 return nil; |
| 84 |
| 85 type = '{'; |
| 86 typeName = [aName retain]; |
| 87 members = [[NSMutableArray alloc] initWithArray:someMembers]; |
| 88 |
| 89 return self; |
| 90 } |
| 91 |
| 92 - (id)initUnionType:(CDTypeName *)aName members:(NSArray *)someMembers; |
| 93 { |
| 94 if ([self init] == nil) |
| 95 return nil; |
| 96 |
| 97 type = '('; |
| 98 typeName = [aName retain]; |
| 99 members = [[NSMutableArray alloc] initWithArray:someMembers]; |
| 100 |
| 101 return self; |
| 102 } |
| 103 |
| 104 - (id)initBitfieldType:(NSString *)aBitfieldSize; |
| 105 { |
| 106 if ([self init] == nil) |
| 107 return nil; |
| 108 |
| 109 type = 'b'; |
| 110 bitfieldSize = [aBitfieldSize retain]; |
| 111 |
| 112 return self; |
| 113 } |
| 114 |
| 115 - (id)initArrayType:(CDType *)aType count:(NSString *)aCount; |
| 116 { |
| 117 if ([self init] == nil) |
| 118 return nil; |
| 119 |
| 120 type = '['; |
| 121 arraySize = [aCount retain]; |
| 122 subtype = [aType retain]; |
| 123 |
| 124 return self; |
| 125 } |
| 126 |
| 127 - (id)initPointerType:(CDType *)aType; |
| 128 { |
| 129 if ([self init] == nil) |
| 130 return nil; |
| 131 |
| 132 type = '^'; |
| 133 subtype = [aType retain]; |
| 134 |
| 135 return self; |
| 136 } |
| 137 |
| 138 - (id)initModifier:(int)aModifier type:(CDType *)aType; |
| 139 { |
| 140 if ([self init] == nil) |
| 141 return nil; |
| 142 |
| 143 type = aModifier; |
| 144 subtype = [aType retain]; |
| 145 |
| 146 return self; |
| 147 } |
| 148 |
| 149 - (void)dealloc; |
| 150 { |
| 151 [protocols release]; |
| 152 [subtype release]; |
| 153 [typeName release]; |
| 154 [members release]; |
| 155 [variableName release]; |
| 156 [bitfieldSize release]; |
| 157 [arraySize release]; |
| 158 |
| 159 [super dealloc]; |
| 160 } |
| 161 |
| 162 @synthesize variableName; |
| 163 |
| 164 - (int)type; |
| 165 { |
| 166 return type; |
| 167 } |
| 168 |
| 169 - (BOOL)isIDType; |
| 170 { |
| 171 return type == '@' && typeName == nil; |
| 172 } |
| 173 |
| 174 - (BOOL)isNamedObject; |
| 175 { |
| 176 return type == T_NAMED_OBJECT; |
| 177 } |
| 178 |
| 179 - (BOOL)isTemplateType; |
| 180 { |
| 181 return [typeName isTemplateType]; |
| 182 } |
| 183 |
| 184 - (CDType *)subtype; |
| 185 { |
| 186 return subtype; |
| 187 } |
| 188 |
| 189 - (CDTypeName *)typeName; |
| 190 { |
| 191 return typeName; |
| 192 } |
| 193 |
| 194 - (NSArray *)members; |
| 195 { |
| 196 return members; |
| 197 } |
| 198 |
| 199 - (BOOL)isModifierType; |
| 200 { |
| 201 return type == 'r' || type == 'n' || type == 'N' || type == 'o' || type == '
O' || type == 'R' || type == 'V'; |
| 202 } |
| 203 |
| 204 - (int)typeIgnoringModifiers; |
| 205 { |
| 206 if ([self isModifierType] && subtype != nil) |
| 207 return [subtype typeIgnoringModifiers]; |
| 208 |
| 209 return type; |
| 210 } |
| 211 |
| 212 - (NSUInteger)structureDepth; |
| 213 { |
| 214 if (subtype != nil) |
| 215 return [subtype structureDepth]; |
| 216 |
| 217 if (type == '{' || type == '(') { |
| 218 NSUInteger maxDepth = 0; |
| 219 |
| 220 for (CDType *member in members) { |
| 221 if (maxDepth < [member structureDepth]) |
| 222 maxDepth = [member structureDepth]; |
| 223 } |
| 224 |
| 225 return maxDepth + 1; |
| 226 } |
| 227 |
| 228 return 0; |
| 229 } |
| 230 |
| 231 - (NSString *)description; |
| 232 { |
| 233 return [NSString stringWithFormat:@"[%@] type: %d('%c'), name: %@, subtype:
%@, bitfieldSize: %@, arraySize: %@, members: %@, variableName: %@", |
| 234 NSStringFromClass([self class]), type, type, typeName, subt
ype, bitfieldSize, arraySize, members, variableName]; |
| 235 } |
| 236 |
| 237 - (NSString *)formattedString:(NSString *)previousName formatter:(CDTypeFormatte
r *)typeFormatter level:(NSUInteger)level symbolReferences:(CDSymbolReferences *
)symbolReferences; |
| 238 { |
| 239 NSString *result, *currentName; |
| 240 NSString *baseType, *memberString; |
| 241 |
| 242 assert(variableName == nil || previousName == nil); |
| 243 if (variableName != nil) |
| 244 currentName = variableName; |
| 245 else |
| 246 currentName = previousName; |
| 247 |
| 248 switch (type) { |
| 249 case T_NAMED_OBJECT: |
| 250 assert(typeName != nil); |
| 251 [symbolReferences addClassName:[typeName name]]; |
| 252 if (currentName == nil) |
| 253 result = [NSString stringWithFormat:@"%@ *", typeName]; |
| 254 else |
| 255 result = [NSString stringWithFormat:@"%@ *%@", typeName, currentNa
me]; |
| 256 break; |
| 257 |
| 258 case '@': |
| 259 if (currentName == nil) { |
| 260 if (protocols == nil) |
| 261 result = @"id"; |
| 262 else |
| 263 result = [NSString stringWithFormat:@"id <%@>", [protocols com
ponentsJoinedByString:@", "]]; |
| 264 } else { |
| 265 if (protocols == nil) |
| 266 result = [NSString stringWithFormat:@"id %@", currentName]; |
| 267 else |
| 268 result = [NSString stringWithFormat:@"id <%@> %@", [protocols
componentsJoinedByString:@", "], currentName]; |
| 269 } |
| 270 break; |
| 271 |
| 272 case 'b': |
| 273 if (currentName == nil) { |
| 274 // This actually compiles! |
| 275 result = [NSString stringWithFormat:@"unsigned int :%@", bitfieldS
ize]; |
| 276 } else |
| 277 result = [NSString stringWithFormat:@"unsigned int %@:%@", current
Name, bitfieldSize]; |
| 278 break; |
| 279 |
| 280 case '[': |
| 281 if (currentName == nil) |
| 282 result = [NSString stringWithFormat:@"[%@]", arraySize]; |
| 283 else |
| 284 result = [NSString stringWithFormat:@"%@[%@]", currentName, arrayS
ize]; |
| 285 |
| 286 result = [subtype formattedString:result formatter:typeFormatter level
:level symbolReferences:symbolReferences]; |
| 287 break; |
| 288 |
| 289 case '(': |
| 290 baseType = nil; |
| 291 /*if (typeName == nil || [@"?" isEqual:[typeName description]])*/ { |
| 292 NSString *typedefName; |
| 293 |
| 294 typedefName = [typeFormatter typedefNameForStruct:self level:level
]; |
| 295 if (typedefName != nil) { |
| 296 baseType = typedefName; |
| 297 } |
| 298 } |
| 299 |
| 300 if (baseType == nil) { |
| 301 if (typeName == nil || [@"?" isEqual:[typeName description]]) |
| 302 baseType = @"union"; |
| 303 else |
| 304 baseType = [NSString stringWithFormat:@"union %@", typeName]; |
| 305 |
| 306 if (([typeFormatter shouldAutoExpand] && [[typeFormatter typeContr
oller] shouldExpandType:self] && [members count] > 0) |
| 307 || (level == 0 && [typeFormatter shouldExpand] && [members cou
nt] > 0)) |
| 308 memberString = [NSString stringWithFormat:@" {\n%@%@}", |
| 309 [self formattedStringForMembersAtLeve
l:level + 1 formatter:typeFormatter symbolReferences:symbolReferences], |
| 310 [NSString spacesIndentedToLevel:[type
Formatter baseLevel] + level spacesPerLevel:4]]; |
| 311 else |
| 312 memberString = @""; |
| 313 |
| 314 baseType = [baseType stringByAppendingString:memberString]; |
| 315 } |
| 316 |
| 317 if (currentName == nil /*|| [currentName hasPrefix:@"?"]*/) // Not sur
e about this |
| 318 result = baseType; |
| 319 else |
| 320 result = [NSString stringWithFormat:@"%@ %@", baseType, currentNam
e]; |
| 321 break; |
| 322 |
| 323 case '{': |
| 324 baseType = nil; |
| 325 /*if (typeName == nil || [@"?" isEqual:[typeName description]])*/ { |
| 326 NSString *typedefName; |
| 327 |
| 328 typedefName = [typeFormatter typedefNameForStruct:self level:level
]; |
| 329 if (typedefName != nil) { |
| 330 baseType = typedefName; |
| 331 } |
| 332 } |
| 333 if (baseType == nil) { |
| 334 if (typeName == nil || [@"?" isEqual:[typeName description]]) |
| 335 baseType = @"struct"; |
| 336 else |
| 337 baseType = [NSString stringWithFormat:@"struct %@", typeName]; |
| 338 |
| 339 if (([typeFormatter shouldAutoExpand] && [[typeFormatter typeContr
oller] shouldExpandType:self] && [members count] > 0) |
| 340 || (level == 0 && [typeFormatter shouldExpand] && [members cou
nt] > 0)) |
| 341 memberString = [NSString stringWithFormat:@" {\n%@%@}", |
| 342 [self formattedStringForMembersAtLeve
l:level + 1 formatter:typeFormatter symbolReferences:symbolReferences], |
| 343 [NSString spacesIndentedToLevel:[type
Formatter baseLevel] + level spacesPerLevel:4]]; |
| 344 else |
| 345 memberString = @""; |
| 346 |
| 347 baseType = [baseType stringByAppendingString:memberString]; |
| 348 } |
| 349 |
| 350 if (currentName == nil /*|| [currentName hasPrefix:@"?"]*/) // Not sur
e about this |
| 351 result = baseType; |
| 352 else |
| 353 result = [NSString stringWithFormat:@"%@ %@", baseType, currentNam
e]; |
| 354 break; |
| 355 |
| 356 case '^': |
| 357 if (currentName == nil) |
| 358 result = @"*"; |
| 359 else |
| 360 result = [@"*" stringByAppendingString:currentName]; |
| 361 |
| 362 if (subtype != nil && [subtype type] == '[') |
| 363 result = [NSString stringWithFormat:@"(%@)", result]; |
| 364 |
| 365 result = [subtype formattedString:result formatter:typeFormatter level
:level symbolReferences:symbolReferences]; |
| 366 break; |
| 367 |
| 368 case 'r': |
| 369 case 'n': |
| 370 case 'N': |
| 371 case 'o': |
| 372 case 'O': |
| 373 case 'R': |
| 374 case 'V': |
| 375 if (subtype == nil) { |
| 376 if (currentName == nil) |
| 377 result = [self formattedStringForSimpleType]; |
| 378 else |
| 379 result = [NSString stringWithFormat:@"%@ %@", [self formattedS
tringForSimpleType], currentName]; |
| 380 } else |
| 381 result = [NSString stringWithFormat:@"%@ %@", |
| 382 [self formattedStringForSimpleType], [subtype f
ormattedString:currentName formatter:typeFormatter level:level symbolReferences:
symbolReferences]]; |
| 383 break; |
| 384 |
| 385 default: |
| 386 if (currentName == nil) |
| 387 result = [self formattedStringForSimpleType]; |
| 388 else |
| 389 result = [NSString stringWithFormat:@"%@ %@", [self formattedStrin
gForSimpleType], currentName]; |
| 390 break; |
| 391 } |
| 392 |
| 393 return result; |
| 394 } |
| 395 |
| 396 - (NSString *)formattedStringForMembersAtLevel:(NSUInteger)level formatter:(CDTy
peFormatter *)typeFormatter symbolReferences:(CDSymbolReferences *)symbolReferen
ces; |
| 397 { |
| 398 NSMutableString *str; |
| 399 |
| 400 assert(type == '{' || type == '('); |
| 401 str = [NSMutableString string]; |
| 402 |
| 403 for (CDType *member in members) { |
| 404 [str appendString:[NSString spacesIndentedToLevel:[typeFormatter baseLev
el] + level spacesPerLevel:4]]; |
| 405 [str appendString:[member formattedString:nil |
| 406 formatter:typeFormatter |
| 407 level:level |
| 408 symbolReferences:symbolReferences]]; |
| 409 [str appendString:@";\n"]; |
| 410 } |
| 411 |
| 412 return str; |
| 413 } |
| 414 |
| 415 - (NSString *)formattedStringForSimpleType; |
| 416 { |
| 417 // Ugly but simple: |
| 418 switch (type) { |
| 419 case 'c': return @"char"; |
| 420 case 'i': return @"int"; |
| 421 case 's': return @"short"; |
| 422 case 'l': return @"long"; |
| 423 case 'q': return @"long long"; |
| 424 case 'C': return @"unsigned char"; |
| 425 case 'I': return @"unsigned int"; |
| 426 case 'S': return @"unsigned short"; |
| 427 case 'L': return @"unsigned long"; |
| 428 case 'Q': return @"unsigned long long"; |
| 429 case 'f': return @"float"; |
| 430 case 'd': return @"double"; |
| 431 case 'B': return @"_Bool"; /* C99 _Bool or C++ bool */ |
| 432 case 'v': return @"void"; |
| 433 case '*': return @"STR"; |
| 434 case '#': return @"Class"; |
| 435 case ':': return @"SEL"; |
| 436 case '%': return @"NXAtom"; |
| 437 case '?': return @"void"; |
| 438 //case '?': return @"UNKNOWN"; // For easier regression testing. |
| 439 case 'r': return @"const"; |
| 440 case 'n': return @"in"; |
| 441 case 'N': return @"inout"; |
| 442 case 'o': return @"out"; |
| 443 case 'O': return @"bycopy"; |
| 444 case 'R': return @"byref"; |
| 445 case 'V': return @"oneway"; |
| 446 default: |
| 447 break; |
| 448 } |
| 449 |
| 450 return nil; |
| 451 } |
| 452 |
| 453 - (NSString *)typeString; |
| 454 { |
| 455 return [self _typeStringWithVariableNamesToLevel:1e6 showObjectTypes:YES]; |
| 456 } |
| 457 |
| 458 - (NSString *)bareTypeString; |
| 459 { |
| 460 return [self _typeStringWithVariableNamesToLevel:0 showObjectTypes:YES]; |
| 461 } |
| 462 |
| 463 - (NSString *)reallyBareTypeString; |
| 464 { |
| 465 return [self _typeStringWithVariableNamesToLevel:0 showObjectTypes:NO]; |
| 466 } |
| 467 |
| 468 - (NSString *)keyTypeString; |
| 469 { |
| 470 // use variable names at top level |
| 471 return [self _typeStringWithVariableNamesToLevel:1 showObjectTypes:YES]; |
| 472 } |
| 473 |
| 474 - (NSString *)_typeStringWithVariableNamesToLevel:(NSUInteger)level showObjectTy
pes:(BOOL)shouldShowObjectTypes; |
| 475 { |
| 476 NSString *result; |
| 477 |
| 478 switch (type) { |
| 479 case T_NAMED_OBJECT: |
| 480 assert(typeName != nil); |
| 481 if (shouldShowObjectTypes) |
| 482 result = [NSString stringWithFormat:@"@\"%@\"", typeName]; |
| 483 else |
| 484 result = @"@"; |
| 485 break; |
| 486 |
| 487 case '@': |
| 488 result = @"@"; |
| 489 break; |
| 490 |
| 491 case 'b': |
| 492 result = [NSString stringWithFormat:@"b%@", bitfieldSize]; |
| 493 break; |
| 494 |
| 495 case '[': |
| 496 result = [NSString stringWithFormat:@"[%@%@]", arraySize, [subtype _ty
peStringWithVariableNamesToLevel:level showObjectTypes:shouldShowObjectTypes]]; |
| 497 break; |
| 498 |
| 499 case '(': |
| 500 if (typeName == nil) { |
| 501 return [NSString stringWithFormat:@"(%@)", [self _typeStringForMem
bersWithVariableNamesToLevel:level showObjectTypes:shouldShowObjectTypes]]; |
| 502 } else if ([members count] == 0) { |
| 503 return [NSString stringWithFormat:@"(%@)", typeName]; |
| 504 } else { |
| 505 return [NSString stringWithFormat:@"(%@=%@)", typeName, [self _typ
eStringForMembersWithVariableNamesToLevel:level showObjectTypes:shouldShowObject
Types]]; |
| 506 } |
| 507 break; |
| 508 |
| 509 case '{': |
| 510 if (typeName == nil) { |
| 511 return [NSString stringWithFormat:@"{%@}", [self _typeStringForMem
bersWithVariableNamesToLevel:level showObjectTypes:shouldShowObjectTypes]]; |
| 512 } else if ([members count] == 0) { |
| 513 return [NSString stringWithFormat:@"{%@}", typeName]; |
| 514 } else { |
| 515 return [NSString stringWithFormat:@"{%@=%@}", typeName, [self _typ
eStringForMembersWithVariableNamesToLevel:level showObjectTypes:shouldShowObject
Types]]; |
| 516 } |
| 517 break; |
| 518 |
| 519 case '^': |
| 520 result = [NSString stringWithFormat:@"^%@", [subtype _typeStringWithVa
riableNamesToLevel:level showObjectTypes:shouldShowObjectTypes]]; |
| 521 break; |
| 522 |
| 523 case 'r': |
| 524 case 'n': |
| 525 case 'N': |
| 526 case 'o': |
| 527 case 'O': |
| 528 case 'R': |
| 529 case 'V': |
| 530 result = [NSString stringWithFormat:@"%c%@", type, [subtype _typeStrin
gWithVariableNamesToLevel:level showObjectTypes:shouldShowObjectTypes]]; |
| 531 break; |
| 532 |
| 533 default: |
| 534 result = [NSString stringWithFormat:@"%c", type]; |
| 535 break; |
| 536 } |
| 537 |
| 538 return result; |
| 539 } |
| 540 |
| 541 - (NSString *)_typeStringForMembersWithVariableNamesToLevel:(NSInteger)level sho
wObjectTypes:(BOOL)shouldShowObjectTypes; |
| 542 { |
| 543 NSMutableString *str; |
| 544 |
| 545 assert(type == '{' || type == '('); |
| 546 str = [NSMutableString string]; |
| 547 |
| 548 for (CDType *aMember in members) { |
| 549 if ([aMember variableName] != nil && level > 0) |
| 550 [str appendFormat:@"\"%@\"", [aMember variableName]]; |
| 551 [str appendString:[aMember _typeStringWithVariableNamesToLevel:level - 1
showObjectTypes:shouldShowObjectTypes]]; |
| 552 } |
| 553 |
| 554 return str; |
| 555 } |
| 556 |
| 557 // TODO (2009-08-26): Looks like this doesn't compare the variable name. |
| 558 - (BOOL)isEqual:(CDType *)otherType; |
| 559 { |
| 560 return [[self typeString] isEqual:[otherType typeString]]; |
| 561 } |
| 562 |
| 563 // An easy deep copy. |
| 564 - (id)copyWithZone:(NSZone *)zone; |
| 565 { |
| 566 CDTypeParser *parser; |
| 567 NSError *error; |
| 568 NSString *str; |
| 569 CDType *copiedType; |
| 570 |
| 571 str = [self typeString]; |
| 572 NSParameterAssert(str != nil); |
| 573 |
| 574 parser = [[CDTypeParser alloc] initWithType:str]; |
| 575 copiedType = [[parser parseType:&error] retain]; |
| 576 if (copiedType == nil) |
| 577 NSLog(@"Warning: Parsing type in -[CDType copyWithZone:] failed, %@", st
r); |
| 578 [parser release]; |
| 579 |
| 580 NSParameterAssert([str isEqualToString:[copiedType typeString]]); |
| 581 |
| 582 [copiedType setVariableName:variableName]; |
| 583 |
| 584 return copiedType; |
| 585 } |
| 586 |
| 587 - (BOOL)canMergeWithType:(CDType *)otherType; |
| 588 { |
| 589 NSUInteger count, index; |
| 590 NSUInteger otherCount; |
| 591 NSArray *otherMembers; |
| 592 |
| 593 if ([self isIDType] && [otherType isNamedObject]) |
| 594 return YES; |
| 595 |
| 596 if ([self isNamedObject] && [otherType isIDType]) { |
| 597 return YES; |
| 598 } |
| 599 |
| 600 if ([self type] != [otherType type]) { |
| 601 if (debugMerge) { |
| 602 NSLog(@"--------------------"); |
| 603 NSLog(@"this: %@", [self typeString]); |
| 604 NSLog(@"other: %@", [otherType typeString]); |
| 605 NSLog(@"self isIDType? %u", [self isIDType]); |
| 606 NSLog(@"self isNamedObject? %u", [self isNamedObject]); |
| 607 NSLog(@"other isIDType? %u", [otherType isIDType]); |
| 608 NSLog(@"other isNamedObject? %u", [otherType isNamedObject]); |
| 609 } |
| 610 if (debugMerge) NSLog(@"%s, Can't merge because of type... %@ vs %@", _c
md, [self typeString], [otherType typeString]); |
| 611 return NO; |
| 612 } |
| 613 |
| 614 if (subtype != nil && [subtype canMergeWithType:[otherType subtype]] == NO)
{ |
| 615 if (debugMerge) NSLog(@"%s, Can't merge subtype", _cmd); |
| 616 return NO; |
| 617 } |
| 618 |
| 619 if (subtype == nil && [otherType subtype] != nil) { |
| 620 if (debugMerge) NSLog(@"%s, This subtype is nil, other isn't.", _cmd); |
| 621 return NO; |
| 622 } |
| 623 |
| 624 otherMembers = [otherType members]; |
| 625 count = [members count]; |
| 626 otherCount = [otherMembers count]; |
| 627 |
| 628 //NSLog(@"members: %p", members); |
| 629 //NSLog(@"otherMembers: %p", otherMembers); |
| 630 //NSLog(@"%s, count: %u, otherCount: %u", _cmd, count, otherCount); |
| 631 |
| 632 if (count != 0 && otherCount == 0) { |
| 633 if (debugMerge) NSLog(@"%s, count != 0 && otherCount is 0", _cmd); |
| 634 return NO; |
| 635 } |
| 636 |
| 637 if (count != 0 && count != otherCount) { |
| 638 if (debugMerge) NSLog(@"%s, count != 0 && count != otherCount", _cmd); |
| 639 return NO; |
| 640 } |
| 641 |
| 642 // count == 0 is ok: we just have a name in that case. |
| 643 if (count == otherCount) { |
| 644 for (index = 0; index < count; index++) { // Oooh |
| 645 CDType *thisMember, *otherMember; |
| 646 CDTypeName *thisTypeName, *otherTypeName; |
| 647 NSString *thisVariableName, *otherVariableName; |
| 648 |
| 649 thisMember = [members objectAtIndex:index]; |
| 650 otherMember = [otherMembers objectAtIndex:index]; |
| 651 |
| 652 thisTypeName = [thisMember typeName]; |
| 653 otherTypeName = [otherMember typeName]; |
| 654 thisVariableName = [thisMember variableName]; |
| 655 otherVariableName = [otherMember variableName]; |
| 656 |
| 657 // It seems to be okay if one of them didn't have a name |
| 658 if (thisTypeName != nil && otherTypeName != nil && [thisTypeName isE
qual:otherTypeName] == NO) { |
| 659 if (debugMerge) NSLog(@"%s, typeName mismatch on member %u", _cm
d, index); |
| 660 return NO; |
| 661 } |
| 662 |
| 663 if (thisVariableName != nil && otherVariableName != nil && [thisVari
ableName isEqual:otherVariableName] == NO) { |
| 664 if (debugMerge) NSLog(@"%s, variableName mismatch on member %u",
_cmd, index); |
| 665 return NO; |
| 666 } |
| 667 |
| 668 if ([thisMember canMergeWithType:otherMember] == NO) { |
| 669 if (debugMerge) NSLog(@"%s, Can't merge member %u", _cmd, index)
; |
| 670 return NO; |
| 671 } |
| 672 } |
| 673 } |
| 674 |
| 675 return YES; |
| 676 } |
| 677 |
| 678 // Merge struct/union member names. Should check using -canMergeWithType: first
. |
| 679 // Recursively merges, not just the top level. |
| 680 - (void)mergeWithType:(CDType *)otherType; |
| 681 { |
| 682 NSString *before, *after; |
| 683 |
| 684 before = [self typeString]; |
| 685 [self _recursivelyMergeWithType:otherType]; |
| 686 after = [self typeString]; |
| 687 if (debugMerge) { |
| 688 NSLog(@"----------------------------------------"); |
| 689 NSLog(@"%s", _cmd); |
| 690 NSLog(@"before: %@", before); |
| 691 NSLog(@" after: %@", after); |
| 692 NSLog(@"----------------------------------------"); |
| 693 } |
| 694 } |
| 695 |
| 696 - (void)_recursivelyMergeWithType:(CDType *)otherType; |
| 697 { |
| 698 NSUInteger count, index; |
| 699 NSUInteger otherCount; |
| 700 NSArray *otherMembers; |
| 701 |
| 702 if ([self isIDType] && [otherType isNamedObject]) { |
| 703 //NSLog(@"thisType: %@", [self typeString]); |
| 704 //NSLog(@"otherType: %@", [otherType typeString]); |
| 705 type = T_NAMED_OBJECT; |
| 706 typeName = [[otherType typeName] copy]; |
| 707 return; |
| 708 } |
| 709 |
| 710 if ([self isNamedObject] && [otherType isIDType]) { |
| 711 return; |
| 712 } |
| 713 |
| 714 if ([self type] != [otherType type]) { |
| 715 NSLog(@"Warning: Trying to merge different types in %s", _cmd); |
| 716 return; |
| 717 } |
| 718 |
| 719 [subtype _recursivelyMergeWithType:[otherType subtype]]; |
| 720 |
| 721 otherMembers = [otherType members]; |
| 722 count = [members count]; |
| 723 otherCount = [otherMembers count]; |
| 724 |
| 725 // The counts can be zero when we register structures that just have a name.
That happened while I was working on the |
| 726 // structure registration. |
| 727 if (otherCount == 0) { |
| 728 return; |
| 729 } else if (count == 0 && otherCount != 0) { |
| 730 NSParameterAssert(members != nil); |
| 731 [members removeAllObjects]; |
| 732 [members addObjectsFromArray:otherMembers]; |
| 733 //[self setMembers:otherMembers]; |
| 734 } else if (count != otherCount) { |
| 735 // Not so bad after all. Even kind of common. Consider _flags. |
| 736 NSLog(@"Warning: Types have different number of members. This is bad. (
%d vs %d)", count, otherCount); |
| 737 NSLog(@"%@ vs %@", [self typeString], [otherType typeString]); |
| 738 return; |
| 739 } |
| 740 |
| 741 //NSLog(@"****************************************"); |
| 742 for (index = 0; index < count; index++) { |
| 743 CDType *thisMember, *otherMember; |
| 744 CDTypeName *thisTypeName, *otherTypeName; |
| 745 NSString *thisVariableName, *otherVariableName; |
| 746 |
| 747 thisMember = [members objectAtIndex:index]; |
| 748 otherMember = [otherMembers objectAtIndex:index]; |
| 749 |
| 750 thisTypeName = [thisMember typeName]; |
| 751 otherTypeName = [otherMember typeName]; |
| 752 thisVariableName = [thisMember variableName]; |
| 753 otherVariableName = [otherMember variableName]; |
| 754 //NSLog(@"%d: type: %@ vs %@", index, thisTypeName, otherTypeName); |
| 755 //NSLog(@"%d: vari: %@ vs %@", index, thisVariableName, otherVariableNam
e); |
| 756 |
| 757 if ((thisTypeName == nil && otherTypeName != nil) || (thisTypeName != ni
l && otherTypeName == nil)) |
| 758 ; // It seems to be okay if one of them didn't have a name |
| 759 //NSLog(@"Warning: (1) type names don't match, %@ vs %@", thisTypeNa
me, otherTypeName); |
| 760 else if (thisTypeName != nil && [thisTypeName isEqual:otherTypeName] ==
NO) { |
| 761 NSLog(@"Warning: (2) type names don't match:\n\t%@ vs \n\t%@.", this
TypeName, otherTypeName); |
| 762 // In this case, we should skip the merge. |
| 763 } |
| 764 |
| 765 if (otherVariableName != nil) { |
| 766 if (thisVariableName == nil) |
| 767 [thisMember setVariableName:otherVariableName]; |
| 768 else if ([thisVariableName isEqual:otherVariableName] == NO) |
| 769 NSLog(@"Warning: Different variable names for same member..."); |
| 770 } |
| 771 |
| 772 [thisMember _recursivelyMergeWithType:otherMember]; |
| 773 } |
| 774 } |
| 775 |
| 776 - (void)generateMemberNames; |
| 777 { |
| 778 if (type == '{' || type == '(') { |
| 779 NSSet *usedNames; |
| 780 unsigned int number; |
| 781 NSString *name; |
| 782 |
| 783 usedNames = [[NSSet alloc] initWithArray:[members arrayByMappingSelector
:@selector(variableName)]]; |
| 784 |
| 785 number = 1; |
| 786 for (CDType *aMember in members) { |
| 787 [aMember generateMemberNames]; |
| 788 |
| 789 // Bitfields don't need a name. |
| 790 if ([aMember variableName] == nil && [aMember type] != 'b') { |
| 791 do { |
| 792 name = [NSString stringWithFormat:@"_field%u", number++]; |
| 793 } while ([usedNames containsObject:name]); |
| 794 [aMember setVariableName:name]; |
| 795 } |
| 796 } |
| 797 |
| 798 [usedNames release]; |
| 799 |
| 800 } |
| 801 |
| 802 [subtype generateMemberNames]; |
| 803 } |
| 804 |
| 805 // |
| 806 // Phase 0 |
| 807 // |
| 808 |
| 809 - (void)phase:(NSUInteger)phase registerTypesWithObject:(CDTypeController *)type
Controller usedInMethod:(BOOL)isUsedInMethod; |
| 810 { |
| 811 if (phase == 0) { |
| 812 [self phase0RegisterStructuresWithObject:typeController usedInMethod:isU
sedInMethod]; |
| 813 } |
| 814 } |
| 815 |
| 816 // Just top level structures |
| 817 - (void)phase0RegisterStructuresWithObject:(CDTypeController *)typeController us
edInMethod:(BOOL)isUsedInMethod; |
| 818 { |
| 819 // ^{ComponentInstanceRecord=} |
| 820 if (subtype != nil) |
| 821 [subtype phase0RegisterStructuresWithObject:typeController usedInMethod:
isUsedInMethod]; |
| 822 |
| 823 if ((type == '{' || type == '(') && [members count] > 0) { |
| 824 [typeController phase0RegisterStructure:self usedInMethod:isUsedInMethod
]; |
| 825 } |
| 826 } |
| 827 |
| 828 - (void)phase0RecursivelyFixStructureNames:(BOOL)flag; |
| 829 { |
| 830 [subtype phase0RecursivelyFixStructureNames:flag]; |
| 831 |
| 832 if ([[typeName name] hasPrefix:@"$"]) { |
| 833 if (flag) NSLog(@"%s, changing type name %@ to ?", _cmd, [typeName name]
); |
| 834 [typeName setName:@"?"]; |
| 835 } |
| 836 |
| 837 for (CDType *member in members) |
| 838 [member phase0RecursivelyFixStructureNames:flag]; |
| 839 } |
| 840 |
| 841 // |
| 842 // Phase 1 |
| 843 // |
| 844 |
| 845 // Recursively go through type, registering structs/unions. |
| 846 - (void)phase1RegisterStructuresWithObject:(CDTypeController *)typeController; |
| 847 { |
| 848 // ^{ComponentInstanceRecord=} |
| 849 if (subtype != nil) |
| 850 [subtype phase1RegisterStructuresWithObject:typeController]; |
| 851 |
| 852 if ((type == '{' || type == '(') && [members count] > 0) { |
| 853 [typeController phase1RegisterStructure:self]; |
| 854 for (CDType *member in members) |
| 855 [member phase1RegisterStructuresWithObject:typeController]; |
| 856 } |
| 857 } |
| 858 |
| 859 // |
| 860 // Phase 2 |
| 861 // |
| 862 |
| 863 // This wraps the recursive method, optionally logging if anything changed. |
| 864 - (void)phase2MergeWithTypeController:(CDTypeController *)typeController debug:(
BOOL)phase2Debug; |
| 865 { |
| 866 NSString *before, *after; |
| 867 |
| 868 before = [self typeString]; |
| 869 [self _phase2MergeWithTypeController:typeController debug:phase2Debug]; |
| 870 after = [self typeString]; |
| 871 if (phase2Debug && [before isEqualToString:after] == NO) { |
| 872 NSLog(@"----------------------------------------"); |
| 873 NSLog(@"%s, merge changed type", _cmd); |
| 874 NSLog(@"before: %@", before); |
| 875 NSLog(@" after: %@", after); |
| 876 } |
| 877 } |
| 878 |
| 879 // Recursive, bottom-up |
| 880 - (void)_phase2MergeWithTypeController:(CDTypeController *)typeController debug:
(BOOL)phase2Debug; |
| 881 { |
| 882 [subtype _phase2MergeWithTypeController:typeController debug:phase2Debug]; |
| 883 |
| 884 for (CDType *member in members) |
| 885 [member _phase2MergeWithTypeController:typeController debug:phase2Debug]
; |
| 886 |
| 887 if ((type == '{' || type == '(') && [members count] > 0) { |
| 888 CDType *phase2Type; |
| 889 |
| 890 phase2Type = [typeController phase2ReplacementForType:self]; |
| 891 if (phase2Type != nil) { |
| 892 // >0 members so we don't try replacing things like... {_xmlNode=^{_
xmlNode}} |
| 893 if ([members count] > 0 && [self canMergeWithType:phase2Type]) { |
| 894 [self mergeWithType:phase2Type]; |
| 895 } else { |
| 896 if (phase2Debug) { |
| 897 NSLog(@"Found phase2 type, but can't merge with it."); |
| 898 NSLog(@"this: %@", [self typeString]); |
| 899 NSLog(@"that: %@", [phase2Type typeString]); |
| 900 } |
| 901 } |
| 902 } |
| 903 } |
| 904 } |
| 905 |
| 906 // |
| 907 // Phase 3 |
| 908 // |
| 909 |
| 910 - (void)phase3RegisterWithTypeController:(CDTypeController *)typeController; |
| 911 { |
| 912 [subtype phase3RegisterWithTypeController:typeController]; |
| 913 |
| 914 if (type == '{' || type == '(') { |
| 915 [typeController phase3RegisterStructure:self /*count:1 usedInMethod:NO*/
]; |
| 916 } |
| 917 } |
| 918 |
| 919 - (void)phase3RegisterMembersWithTypeController:(CDTypeController *)typeControll
er; |
| 920 { |
| 921 //NSLog(@" > %s %@", _cmd, [self typeString]); |
| 922 for (CDType *member in members) { |
| 923 [member phase3RegisterWithTypeController:typeController]; |
| 924 } |
| 925 //NSLog(@"< %s", _cmd); |
| 926 } |
| 927 |
| 928 // Bottom-up |
| 929 - (void)phase3MergeWithTypeController:(CDTypeController *)typeController; |
| 930 { |
| 931 [subtype phase3MergeWithTypeController:typeController]; |
| 932 |
| 933 for (CDType *member in members) |
| 934 [member phase3MergeWithTypeController:typeController]; |
| 935 |
| 936 if ((type == '{' || type == '(') && [members count] > 0) { |
| 937 CDType *phase3Type; |
| 938 |
| 939 phase3Type = [typeController phase3ReplacementForType:self]; |
| 940 if (phase3Type != nil) { |
| 941 // >0 members so we don't try replacing things like... {_xmlNode=^{_
xmlNode}} |
| 942 if ([members count] > 0 && [self canMergeWithType:phase3Type]) { |
| 943 [self mergeWithType:phase3Type]; |
| 944 } else { |
| 945 if (0) { |
| 946 // This can happen in AU Lab, that struct has no members... |
| 947 NSLog(@"Found phase3 type, but can't merge with it."); |
| 948 NSLog(@"this: %@", [self typeString]); |
| 949 NSLog(@"that: %@", [phase3Type typeString]); |
| 950 } |
| 951 } |
| 952 } |
| 953 } |
| 954 } |
| 955 |
| 956 @end |
OLD | NEW |