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 "CDTypeFormatter.h" |
| 7 |
| 8 #include <assert.h> |
| 9 #import "NSError-CDExtensions.h" |
| 10 #import "NSScanner-Extensions.h" |
| 11 #import "NSString-Extensions.h" |
| 12 #import "CDClassDump.h" // not ideal |
| 13 #import "CDMethodType.h" |
| 14 #import "CDSymbolReferences.h" |
| 15 #import "CDType.h" |
| 16 #import "CDTypeLexer.h" |
| 17 #import "CDTypeParser.h" |
| 18 #import "CDTypeController.h" |
| 19 |
| 20 static BOOL debug = NO; |
| 21 |
| 22 @implementation CDTypeFormatter |
| 23 |
| 24 - (id)init; |
| 25 { |
| 26 if ([super init] == nil) |
| 27 return nil; |
| 28 |
| 29 nonretained_typeController = nil; |
| 30 |
| 31 flags.shouldExpand = NO; |
| 32 flags.shouldAutoExpand = NO; |
| 33 flags.shouldShowLexing = debug; |
| 34 |
| 35 return self; |
| 36 } |
| 37 |
| 38 - (CDTypeController *)typeController; |
| 39 { |
| 40 return nonretained_typeController; |
| 41 } |
| 42 |
| 43 - (void)setTypeController:(CDTypeController *)newTypeController; |
| 44 { |
| 45 nonretained_typeController = newTypeController; |
| 46 } |
| 47 |
| 48 @synthesize baseLevel; |
| 49 |
| 50 - (BOOL)shouldExpand; |
| 51 { |
| 52 return flags.shouldExpand; |
| 53 } |
| 54 |
| 55 - (void)setShouldExpand:(BOOL)newFlag; |
| 56 { |
| 57 flags.shouldExpand = newFlag; |
| 58 } |
| 59 |
| 60 - (BOOL)shouldAutoExpand; |
| 61 { |
| 62 return flags.shouldAutoExpand; |
| 63 } |
| 64 |
| 65 - (void)setShouldAutoExpand:(BOOL)newFlag; |
| 66 { |
| 67 flags.shouldAutoExpand = newFlag; |
| 68 } |
| 69 |
| 70 - (BOOL)shouldShowLexing; |
| 71 { |
| 72 return flags.shouldShowLexing; |
| 73 } |
| 74 |
| 75 - (void)setShouldShowLexing:(BOOL)newFlag; |
| 76 { |
| 77 flags.shouldShowLexing = newFlag; |
| 78 } |
| 79 |
| 80 - (NSString *)_specialCaseVariable:(NSString *)name type:(NSString *)type; |
| 81 { |
| 82 if ([type isEqual:@"c"]) { |
| 83 if (name == nil) |
| 84 return @"BOOL"; |
| 85 else |
| 86 return [NSString stringWithFormat:@"BOOL %@", name]; |
| 87 #if 0 |
| 88 } else if ([type isEqual:@"b1"]) { |
| 89 if (name == nil) |
| 90 return @"BOOL :1"; |
| 91 else |
| 92 return [NSString stringWithFormat:@"BOOL %@:1", name]; |
| 93 #endif |
| 94 } |
| 95 |
| 96 return nil; |
| 97 } |
| 98 |
| 99 - (NSString *)_specialCaseVariable:(NSString *)name parsedType:(CDType *)type; |
| 100 { |
| 101 if ([type type] == 'c') { |
| 102 if (name == nil) |
| 103 return @"BOOL"; |
| 104 else |
| 105 return [NSString stringWithFormat:@"BOOL %@", name]; |
| 106 } |
| 107 |
| 108 return nil; |
| 109 } |
| 110 |
| 111 // TODO (2004-01-28): See if we can pass in the actual CDType. |
| 112 // TODO (2009-07-09): Now that we have the other method, see if we can use it in
stead. |
| 113 - (NSString *)formatVariable:(NSString *)name type:(NSString *)type symbolRefere
nces:(CDSymbolReferences *)symbolReferences; |
| 114 { |
| 115 NSString *specialCase; |
| 116 CDTypeParser *aParser; |
| 117 CDType *resultType; |
| 118 NSError *error; |
| 119 |
| 120 // Special cases: char -> BOOLs, 1 bit ints -> BOOL too? |
| 121 specialCase = [self _specialCaseVariable:name type:type]; |
| 122 if (specialCase != nil) { |
| 123 NSMutableString *resultString; |
| 124 |
| 125 resultString = [NSMutableString string]; |
| 126 [resultString appendString:[NSString spacesIndentedToLevel:baseLevel spa
cesPerLevel:4]]; |
| 127 [resultString appendString:specialCase]; |
| 128 |
| 129 return resultString; |
| 130 } |
| 131 |
| 132 aParser = [[CDTypeParser alloc] initWithType:type]; |
| 133 [[aParser lexer] setShouldShowLexing:flags.shouldShowLexing]; |
| 134 resultType = [aParser parseType:&error]; |
| 135 //NSLog(@"resultType: %p", resultType); |
| 136 |
| 137 if (resultType == nil) { |
| 138 NSLog(@"Couldn't parse type: %@", [error myExplanation]); |
| 139 [aParser release]; |
| 140 //NSLog(@"< %s", _cmd); |
| 141 return nil; |
| 142 } |
| 143 |
| 144 [aParser release]; |
| 145 |
| 146 return [self formatVariable:name parsedType:resultType symbolReferences:symb
olReferences]; |
| 147 } |
| 148 |
| 149 - (NSString *)formatVariable:(NSString *)name parsedType:(CDType *)type symbolRe
ferences:(CDSymbolReferences *)symbolReferences; |
| 150 { |
| 151 NSString *specialCase; |
| 152 NSMutableString *resultString; |
| 153 |
| 154 resultString = [NSMutableString string]; |
| 155 |
| 156 specialCase = [self _specialCaseVariable:name parsedType:type]; |
| 157 [resultString appendSpacesIndentedToLevel:baseLevel spacesPerLevel:4]; |
| 158 if (specialCase != nil) { |
| 159 [resultString appendString:specialCase]; |
| 160 } else { |
| 161 // TODO (2009-08-26): Ideally, just formatting a type shouldn't change i
t. These changes should be done before, but this is handy. |
| 162 [type setVariableName:name]; |
| 163 [type phase0RecursivelyFixStructureNames:NO]; // Nuke the $_ names |
| 164 [type phase3MergeWithTypeController:[self typeController]]; |
| 165 [resultString appendString:[type formattedString:nil formatter:self leve
l:0 symbolReferences:symbolReferences]]; |
| 166 } |
| 167 |
| 168 return resultString; |
| 169 } |
| 170 |
| 171 - (NSDictionary *)formattedTypesForMethodName:(NSString *)methodName type:(NSStr
ing *)type symbolReferences:(CDSymbolReferences *)symbolReferences; |
| 172 { |
| 173 CDTypeParser *aParser; |
| 174 NSArray *methodTypes; |
| 175 NSError *error; |
| 176 NSMutableDictionary *typeDict; |
| 177 NSMutableArray *parameterTypes; |
| 178 |
| 179 aParser = [[CDTypeParser alloc] initWithType:type]; |
| 180 methodTypes = [aParser parseMethodType:&error]; |
| 181 if (methodTypes == nil) |
| 182 NSLog(@"Warning: Parsing method types failed, %@", methodName); |
| 183 [aParser release]; |
| 184 |
| 185 if (methodTypes == nil || [methodTypes count] == 0) { |
| 186 return nil; |
| 187 } |
| 188 |
| 189 typeDict = [NSMutableDictionary dictionary]; |
| 190 { |
| 191 NSUInteger count, index; |
| 192 BOOL noMoreTypes; |
| 193 CDMethodType *aMethodType; |
| 194 NSScanner *scanner; |
| 195 NSString *specialCase; |
| 196 |
| 197 count = [methodTypes count]; |
| 198 index = 0; |
| 199 noMoreTypes = NO; |
| 200 |
| 201 aMethodType = [methodTypes objectAtIndex:index]; |
| 202 specialCase = [self _specialCaseVariable:nil type:[[aMethodType type] ba
reTypeString]]; |
| 203 if (specialCase != nil) { |
| 204 [typeDict setValue:specialCase forKey:@"return-type"]; |
| 205 } else { |
| 206 NSString *str; |
| 207 |
| 208 str = [[aMethodType type] formattedString:nil formatter:self level:0
symbolReferences:symbolReferences]; |
| 209 if (str != nil) |
| 210 [typeDict setValue:str forKey:@"return-type"]; |
| 211 } |
| 212 |
| 213 index += 3; |
| 214 |
| 215 parameterTypes = [NSMutableArray array]; |
| 216 [typeDict setValue:parameterTypes forKey:@"parametertypes"]; |
| 217 |
| 218 scanner = [[NSScanner alloc] initWithString:methodName]; |
| 219 while ([scanner isAtEnd] == NO) { |
| 220 NSString *str; |
| 221 |
| 222 // We can have unnamed parameters, ::: |
| 223 if ([scanner scanUpToString:@":" intoString:&str]) { |
| 224 //NSLog(@"str += '%@'", str); |
| 225 // int unnamedCount, unnamedIndex; |
| 226 // unnamedCount = [str length]; |
| 227 // for (unnamedIndex = 0; unnamedIndex < unnamedCou
nt; unnamedIndex++) |
| 228 // [parameterTypes addObject:[NSDictionary
dictionaryWithObjectsAndKeys:@"", @"type", @"", @"name", nil]]; |
| 229 } |
| 230 if ([scanner scanString:@":" intoString:NULL]) { |
| 231 NSString *typeString; |
| 232 |
| 233 if (index >= count) { |
| 234 noMoreTypes = YES; |
| 235 } else { |
| 236 NSMutableDictionary *parameter = [NSMutableDictionary dictio
nary]; |
| 237 |
| 238 aMethodType = [methodTypes objectAtIndex:index]; |
| 239 specialCase = [self _specialCaseVariable:nil type:[[aMethodT
ype type] bareTypeString]]; |
| 240 if (specialCase != nil) { |
| 241 [parameter setValue:specialCase forKey:@"type"]; |
| 242 } else { |
| 243 typeString = [[aMethodType type] formattedString:nil for
matter:self level:0 symbolReferences:symbolReferences]; |
| 244 [parameter setValue:typeString forKey:@"type"]; |
| 245 } |
| 246 //[parameter setValue:[NSString stringWithFormat:@"fp%@", [a
MethodType offset]] forKey:@"name"]; |
| 247 [parameter setValue:[NSString stringWithFormat:@"arg%u", ind
ex-2] forKey:@"name"]; |
| 248 [parameterTypes addObject:parameter]; |
| 249 index++; |
| 250 } |
| 251 } |
| 252 } |
| 253 |
| 254 [scanner release]; |
| 255 |
| 256 if (noMoreTypes) { |
| 257 NSLog(@" /* Error: Ran out of types for this method. */"); |
| 258 } |
| 259 } |
| 260 |
| 261 return typeDict; |
| 262 } |
| 263 |
| 264 - (NSString *)formatMethodName:(NSString *)methodName type:(NSString *)type symb
olReferences:(CDSymbolReferences *)symbolReferences; |
| 265 { |
| 266 CDTypeParser *aParser; |
| 267 NSArray *methodTypes; |
| 268 NSMutableString *resultString; |
| 269 NSError *error; |
| 270 |
| 271 aParser = [[CDTypeParser alloc] initWithType:type]; |
| 272 methodTypes = [aParser parseMethodType:&error]; |
| 273 if (methodTypes == nil) |
| 274 NSLog(@"Warning: Parsing method types failed, %@", methodName); |
| 275 [aParser release]; |
| 276 |
| 277 if (methodTypes == nil || [methodTypes count] == 0) { |
| 278 return nil; |
| 279 } |
| 280 |
| 281 resultString = [NSMutableString string]; |
| 282 { |
| 283 NSUInteger count, index; |
| 284 BOOL noMoreTypes; |
| 285 CDMethodType *aMethodType; |
| 286 NSScanner *scanner; |
| 287 NSString *specialCase; |
| 288 |
| 289 count = [methodTypes count]; |
| 290 index = 0; |
| 291 noMoreTypes = NO; |
| 292 |
| 293 aMethodType = [methodTypes objectAtIndex:index]; |
| 294 [resultString appendString:@"("]; |
| 295 specialCase = [self _specialCaseVariable:nil type:[[aMethodType type] ba
reTypeString]]; |
| 296 if (specialCase != nil) { |
| 297 [resultString appendString:specialCase]; |
| 298 } else { |
| 299 NSString *str; |
| 300 |
| 301 str = [[aMethodType type] formattedString:nil formatter:self level:0
symbolReferences:symbolReferences]; |
| 302 if (str != nil) |
| 303 [resultString appendFormat:@"%@", str]; |
| 304 } |
| 305 [resultString appendString:@")"]; |
| 306 |
| 307 index += 3; |
| 308 |
| 309 scanner = [[NSScanner alloc] initWithString:methodName]; |
| 310 while ([scanner isAtEnd] == NO) { |
| 311 NSString *str; |
| 312 |
| 313 // We can have unnamed paramenters, ::: |
| 314 if ([scanner scanUpToString:@":" intoString:&str]) { |
| 315 //NSLog(@"str += '%@'", str); |
| 316 [resultString appendString:str]; |
| 317 } |
| 318 if ([scanner scanString:@":" intoString:NULL]) { |
| 319 NSString *typeString; |
| 320 |
| 321 [resultString appendString:@":"]; |
| 322 if (index >= count) { |
| 323 noMoreTypes = YES; |
| 324 } else { |
| 325 NSString *ch; |
| 326 |
| 327 aMethodType = [methodTypes objectAtIndex:index]; |
| 328 specialCase = [self _specialCaseVariable:nil type:[[aMethodT
ype type] bareTypeString]]; |
| 329 if (specialCase != nil) { |
| 330 [resultString appendFormat:@"(%@)", specialCase]; |
| 331 } else { |
| 332 typeString = [[aMethodType type] formattedString:nil for
matter:self level:0 symbolReferences:symbolReferences]; |
| 333 //if ([[aMethodType type] isIDType] == NO) |
| 334 [resultString appendFormat:@"(%@)", typeString]; |
| 335 } |
| 336 //[resultString appendFormat:@"fp%@", [aMethodType offset]]; |
| 337 [resultString appendFormat:@"arg%u", index-2]; |
| 338 |
| 339 ch = [scanner peekCharacter]; |
| 340 // if next character is not ':' nor EOS then add space |
| 341 if (ch != nil && [ch isEqual:@":"] == NO) |
| 342 [resultString appendString:@" "]; |
| 343 index++; |
| 344 } |
| 345 } |
| 346 } |
| 347 |
| 348 [scanner release]; |
| 349 |
| 350 if (noMoreTypes) { |
| 351 [resultString appendString:@" /* Error: Ran out of types for this me
thod. */"]; |
| 352 } |
| 353 } |
| 354 |
| 355 return resultString; |
| 356 } |
| 357 |
| 358 // Called from CDType, which gets a formatter but not a type controller. |
| 359 - (CDType *)replacementForType:(CDType *)aType; |
| 360 { |
| 361 return [nonretained_typeController typeFormatter:self replacementForType:aTy
pe]; |
| 362 } |
| 363 |
| 364 // Called from CDType, which gets a formatter but not a type controller. |
| 365 - (NSString *)typedefNameForStruct:(CDType *)structType level:(NSUInteger)level; |
| 366 { |
| 367 return [nonretained_typeController typeFormatter:self typedefNameForStruct:s
tructType level:level]; |
| 368 } |
| 369 |
| 370 - (NSString *)description; |
| 371 { |
| 372 return [NSString stringWithFormat:@"<%@:%p> baseLevel: %u, shouldExpand: %u,
shouldAutoExpand: %u, shouldShowLexing: %u, tc: %p", |
| 373 NSStringFromClass([self class]), self, |
| 374 baseLevel, flags.shouldExpand, flags.shouldAutoExpand, flag
s.shouldShowLexing, nonretained_typeController]; |
| 375 } |
| 376 |
| 377 @end |
OLD | NEW |