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 "CDTextClassDumpVisitor.h" |
| 7 |
| 8 #include <mach-o/arch.h> |
| 9 |
| 10 #import "NSArray-Extensions.h" |
| 11 #import "CDClassDump.h" |
| 12 #import "CDObjectiveC1Processor.h" |
| 13 #import "CDMachOFile.h" |
| 14 #import "CDOCProtocol.h" |
| 15 #import "CDLCDylib.h" |
| 16 #import "CDOCClass.h" |
| 17 #import "CDOCCategory.h" |
| 18 #import "CDSymbolReferences.h" |
| 19 #import "CDOCMethod.h" |
| 20 #import "CDOCProperty.h" |
| 21 #import "CDTypeFormatter.h" |
| 22 #import "CDTypeController.h" |
| 23 #import "CDVisitorPropertyState.h" |
| 24 |
| 25 static BOOL debug = NO; |
| 26 |
| 27 @implementation CDTextClassDumpVisitor |
| 28 |
| 29 - (id)init; |
| 30 { |
| 31 if ([super init] == nil) |
| 32 return nil; |
| 33 |
| 34 resultString = [[NSMutableString alloc] init]; |
| 35 symbolReferences = [[CDSymbolReferences alloc] init]; |
| 36 |
| 37 return self; |
| 38 } |
| 39 |
| 40 - (void)dealloc; |
| 41 { |
| 42 [resultString release]; |
| 43 [symbolReferences release]; |
| 44 |
| 45 [super dealloc]; |
| 46 } |
| 47 |
| 48 - (void)writeResultToStandardOutput; |
| 49 { |
| 50 NSData *data; |
| 51 |
| 52 data = [resultString dataUsingEncoding:NSUTF8StringEncoding]; |
| 53 [(NSFileHandle *)[NSFileHandle fileHandleWithStandardOutput] writeData:data]
; |
| 54 } |
| 55 |
| 56 - (void)willVisitClass:(CDOCClass *)aClass; |
| 57 { |
| 58 NSArray *protocols; |
| 59 |
| 60 if ([aClass isExported] == NO) |
| 61 [resultString appendString:@"// Not exported\n"]; |
| 62 |
| 63 [resultString appendFormat:@"@interface %@", [aClass name]]; |
| 64 if ([aClass superClassName] != nil) |
| 65 [resultString appendFormat:@" : %@", [aClass superClassName]]; |
| 66 |
| 67 protocols = [aClass protocols]; |
| 68 if ([protocols count] > 0) { |
| 69 [resultString appendFormat:@" <%@>", [[protocols arrayByMappingSelector:
@selector(name)] componentsJoinedByString:@", "]]; |
| 70 [symbolReferences addProtocolNamesFromArray:[protocols arrayByMappingSel
ector:@selector(name)]]; |
| 71 } |
| 72 |
| 73 [resultString appendString:@"\n"]; |
| 74 } |
| 75 |
| 76 - (void)didVisitClass:(CDOCClass *)aClass; |
| 77 { |
| 78 if ([aClass hasMethods]) |
| 79 [resultString appendString:@"\n"]; |
| 80 |
| 81 [resultString appendString:@"@end\n\n"]; |
| 82 } |
| 83 |
| 84 - (void)willVisitIvarsOfClass:(CDOCClass *)aClass; |
| 85 { |
| 86 [resultString appendString:@"{\n"]; |
| 87 } |
| 88 |
| 89 - (void)didVisitIvarsOfClass:(CDOCClass *)aClass; |
| 90 { |
| 91 [resultString appendString:@"}\n\n"]; |
| 92 } |
| 93 |
| 94 - (void)willVisitCategory:(CDOCCategory *)aCategory; |
| 95 { |
| 96 NSArray *protocols; |
| 97 |
| 98 [resultString appendFormat:@"@interface %@ (%@)", [aCategory className], [aC
ategory name]]; |
| 99 |
| 100 protocols = [aCategory protocols]; |
| 101 if ([protocols count] > 0) { |
| 102 [resultString appendFormat:@" <%@>", [[protocols arrayByMappingSelector:
@selector(name)] componentsJoinedByString:@", "]]; |
| 103 [symbolReferences addProtocolNamesFromArray:[protocols arrayByMappingSel
ector:@selector(name)]]; |
| 104 } |
| 105 |
| 106 [resultString appendString:@"\n"]; |
| 107 } |
| 108 |
| 109 - (void)didVisitCategory:(CDOCCategory *)aCategory; |
| 110 { |
| 111 [resultString appendString:@"@end\n\n"]; |
| 112 } |
| 113 |
| 114 - (void)willVisitProtocol:(CDOCProtocol *)aProtocol; |
| 115 { |
| 116 NSArray *protocols; |
| 117 |
| 118 [resultString appendFormat:@"@protocol %@", [aProtocol name]]; |
| 119 |
| 120 protocols = [aProtocol protocols]; |
| 121 if ([protocols count] > 0) { |
| 122 [resultString appendFormat:@" <%@>", [[protocols arrayByMappingSelector:
@selector(name)] componentsJoinedByString:@", "]]; |
| 123 [symbolReferences addProtocolNamesFromArray:[protocols arrayByMappingSel
ector:@selector(name)]]; |
| 124 } |
| 125 |
| 126 [resultString appendString:@"\n"]; |
| 127 } |
| 128 |
| 129 - (void)willVisitOptionalMethods; |
| 130 { |
| 131 [resultString appendString:@"\n@optional\n"]; |
| 132 } |
| 133 |
| 134 - (void)didVisitProtocol:(CDOCProtocol *)aProtocol; |
| 135 { |
| 136 [resultString appendString:@"@end\n\n"]; |
| 137 } |
| 138 |
| 139 - (void)visitClassMethod:(CDOCMethod *)aMethod; |
| 140 { |
| 141 [resultString appendString:@"+ "]; |
| 142 [aMethod appendToString:resultString typeController:[classDump typeControlle
r] symbolReferences:symbolReferences]; |
| 143 [resultString appendString:@"\n"]; |
| 144 } |
| 145 |
| 146 - (void)visitInstanceMethod:(CDOCMethod *)aMethod propertyState:(CDVisitorProper
tyState *)propertyState; |
| 147 { |
| 148 CDOCProperty *property; |
| 149 |
| 150 property = [propertyState propertyForAccessor:[aMethod name]]; |
| 151 if (property == nil) { |
| 152 //NSLog(@"No property for method: %@", [aMethod name]); |
| 153 [resultString appendString:@"- "]; |
| 154 [aMethod appendToString:resultString typeController:[classDump typeContr
oller] symbolReferences:symbolReferences]; |
| 155 [resultString appendString:@"\n"]; |
| 156 } else { |
| 157 if ([propertyState hasUsedProperty:property] == NO) { |
| 158 //NSLog(@"Emitting property %@ triggered by method %@", [property na
me], [aMethod name]); |
| 159 [self visitProperty:property]; |
| 160 [propertyState useProperty:property]; |
| 161 } else { |
| 162 //NSLog(@"Have already emitted property %@ triggered by method %@",
[property name], [aMethod name]); |
| 163 } |
| 164 } |
| 165 } |
| 166 |
| 167 - (void)visitIvar:(CDOCIvar *)anIvar; |
| 168 { |
| 169 [anIvar appendToString:resultString typeController:[classDump typeController
] symbolReferences:symbolReferences]; |
| 170 [resultString appendString:@"\n"]; |
| 171 } |
| 172 |
| 173 - (void)_visitProperty:(CDOCProperty *)aProperty parsedType:(CDType *)parsedType
attributes:(NSArray *)attrs; |
| 174 { |
| 175 NSMutableArray *alist, *unknownAttrs; |
| 176 NSString *backingVar = nil; |
| 177 NSString *formattedString; |
| 178 BOOL isWeak = NO; |
| 179 BOOL isDynamic = NO; |
| 180 |
| 181 alist = [[NSMutableArray alloc] init]; |
| 182 unknownAttrs = [[NSMutableArray alloc] init]; |
| 183 |
| 184 // objc_v2_encode_prop_attr() in gcc/objc/objc-act.c |
| 185 |
| 186 for (NSString *attr in attrs) { |
| 187 if ([attr hasPrefix:@"T"]) { |
| 188 if (debug) NSLog(@"Warning: Property attribute 'T' should occur only
occur at the beginning"); |
| 189 } else if ([attr hasPrefix:@"R"]) { |
| 190 [alist addObject:@"readonly"]; |
| 191 } else if ([attr hasPrefix:@"C"]) { |
| 192 [alist addObject:@"copy"]; |
| 193 } else if ([attr hasPrefix:@"&"]) { |
| 194 [alist addObject:@"retain"]; |
| 195 } else if ([attr hasPrefix:@"G"]) { |
| 196 [alist addObject:[NSString stringWithFormat:@"getter=%@", [attr subs
tringFromIndex:1]]]; |
| 197 } else if ([attr hasPrefix:@"S"]) { |
| 198 [alist addObject:[NSString stringWithFormat:@"setter=%@", [attr subs
tringFromIndex:1]]]; |
| 199 } else if ([attr hasPrefix:@"V"]) { |
| 200 backingVar = [attr substringFromIndex:1]; |
| 201 } else if ([attr hasPrefix:@"N"]) { |
| 202 [alist addObject:@"nonatomic"]; |
| 203 } else if ([attr hasPrefix:@"W"]) { |
| 204 // @property(assign) __weak NSObject *prop; |
| 205 // Only appears with GC. |
| 206 isWeak = YES; |
| 207 } else if ([attr hasPrefix:@"P"]) { |
| 208 // @property(assign) __strong NSObject *prop; |
| 209 // Only appears with GC. |
| 210 // This is the default. |
| 211 isWeak = NO; |
| 212 } else if ([attr hasPrefix:@"D"]) { |
| 213 // Dynamic property. Implementation supplied at runtime. |
| 214 // @property int prop; // @dynamic prop; |
| 215 isDynamic = YES; |
| 216 } else { |
| 217 if (debug) NSLog(@"Warning: Unknown property attribute '%@'", attr); |
| 218 [unknownAttrs addObject:attr]; |
| 219 } |
| 220 } |
| 221 |
| 222 if ([alist count] > 0) { |
| 223 [resultString appendFormat:@"@property(%@) ", [alist componentsJoinedByS
tring:@", "]]; |
| 224 } else { |
| 225 [resultString appendString:@"@property "]; |
| 226 } |
| 227 |
| 228 if (isWeak) |
| 229 [resultString appendString:@"__weak "]; |
| 230 |
| 231 formattedString = [[[classDump typeController] propertyTypeFormatter] format
Variable:[aProperty name] parsedType:parsedType symbolReferences:symbolReference
s]; |
| 232 [resultString appendFormat:@"%@;", formattedString]; |
| 233 |
| 234 if (isDynamic) { |
| 235 [resultString appendFormat:@" // @dynamic %@;", [aProperty name]]; |
| 236 } else if (backingVar != nil) { |
| 237 if ([backingVar isEqualToString:[aProperty name]]) { |
| 238 [resultString appendFormat:@" // @synthesize %@;", [aProperty name]]
; |
| 239 } else { |
| 240 [resultString appendFormat:@" // @synthesize %@=%@;", [aProperty nam
e], backingVar]; |
| 241 } |
| 242 } |
| 243 |
| 244 [resultString appendString:@"\n"]; |
| 245 if ([unknownAttrs count] > 0) { |
| 246 [resultString appendFormat:@"// Preceding property had unknown attribute
s: %@\n", [unknownAttrs componentsJoinedByString:@","]]; |
| 247 if ([[aProperty attributeString] length] > 80) { |
| 248 [resultString appendFormat:@"// Original attribute string (following
type): %@\n\n", [aProperty attributeStringAfterType]]; |
| 249 } else { |
| 250 [resultString appendFormat:@"// Original attribute string: %@\n\n",
[aProperty attributeString]]; |
| 251 } |
| 252 } |
| 253 |
| 254 [alist release]; |
| 255 [unknownAttrs release]; |
| 256 } |
| 257 |
| 258 - (void)visitProperty:(CDOCProperty *)aProperty; |
| 259 { |
| 260 CDType *parsedType; |
| 261 |
| 262 parsedType = [aProperty type]; |
| 263 if (parsedType == nil) { |
| 264 if ([[aProperty attributeString] hasPrefix:@"T"]) { |
| 265 [resultString appendFormat:@"// Error parsing type for property %@:\
n", [aProperty name]]; |
| 266 [resultString appendFormat:@"// Property attributes: %@\n\n", [aProp
erty attributeString]]; |
| 267 } else { |
| 268 [resultString appendFormat:@"// Error: Property attributes should be
gin with the type ('T') attribute, property name: %@\n", [aProperty name]]; |
| 269 [resultString appendFormat:@"// Property attributes: %@\n\n", [aProp
erty attributeString]]; |
| 270 } |
| 271 } else { |
| 272 [self _visitProperty:aProperty parsedType:parsedType attributes:[aProper
ty attributes]]; |
| 273 } |
| 274 } |
| 275 |
| 276 #define ADD_SPACE |
| 277 |
| 278 - (void)didVisitPropertiesOfClass:(CDOCClass *)aClass; |
| 279 { |
| 280 #ifdef ADD_SPACE |
| 281 if ([[aClass properties] count] > 0) |
| 282 [resultString appendString:@"\n"]; |
| 283 #endif |
| 284 } |
| 285 |
| 286 - (void)willVisitPropertiesOfCategory:(CDOCCategory *)aCategory; |
| 287 { |
| 288 #ifdef ADD_SPACE |
| 289 if ([[aCategory properties] count] > 0) |
| 290 [resultString appendString:@"\n"]; |
| 291 #endif |
| 292 } |
| 293 |
| 294 - (void)didVisitPropertiesOfCategory:(CDOCCategory *)aCategory; |
| 295 { |
| 296 #ifdef ADD_SPACE |
| 297 if ([[aCategory properties] count] > 0/* && [aCategory hasMethods]*/) |
| 298 [resultString appendString:@"\n"]; |
| 299 #endif |
| 300 } |
| 301 |
| 302 - (void)willVisitPropertiesOfProtocol:(CDOCProtocol *)aProtocol; |
| 303 { |
| 304 #ifdef ADD_SPACE |
| 305 if ([[aProtocol properties] count] > 0) |
| 306 [resultString appendString:@"\n"]; |
| 307 #endif |
| 308 } |
| 309 |
| 310 - (void)didVisitPropertiesOfProtocol:(CDOCProtocol *)aProtocol; |
| 311 { |
| 312 #ifdef ADD_SPACE |
| 313 if ([[aProtocol properties] count] > 0 /*&& [aProtocol hasMethods]*/) |
| 314 [resultString appendString:@"\n"]; |
| 315 #endif |
| 316 } |
| 317 |
| 318 - (void)visitRemainingProperties:(CDVisitorPropertyState *)propertyState; |
| 319 { |
| 320 NSArray *remaining = [propertyState remainingProperties]; |
| 321 |
| 322 if ([remaining count] > 0) { |
| 323 [resultString appendString:@"\n"]; |
| 324 [resultString appendFormat:@"// Remaining properties\n"]; |
| 325 //NSLog(@"Warning: remaining undeclared property count: %u", [remaining
count]); |
| 326 //NSLog(@"remaining: %@", remaining); |
| 327 for (CDOCProperty *property in remaining) |
| 328 [self visitProperty:property]; |
| 329 } |
| 330 } |
| 331 |
| 332 @end |
OLD | NEW |