| Index: class-dump/src/CDTextClassDumpVisitor.m
|
| ===================================================================
|
| --- class-dump/src/CDTextClassDumpVisitor.m (revision 0)
|
| +++ class-dump/src/CDTextClassDumpVisitor.m (revision 0)
|
| @@ -0,0 +1,332 @@
|
| +// -*- 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 "CDTextClassDumpVisitor.h"
|
| +
|
| +#include <mach-o/arch.h>
|
| +
|
| +#import "NSArray-Extensions.h"
|
| +#import "CDClassDump.h"
|
| +#import "CDObjectiveC1Processor.h"
|
| +#import "CDMachOFile.h"
|
| +#import "CDOCProtocol.h"
|
| +#import "CDLCDylib.h"
|
| +#import "CDOCClass.h"
|
| +#import "CDOCCategory.h"
|
| +#import "CDSymbolReferences.h"
|
| +#import "CDOCMethod.h"
|
| +#import "CDOCProperty.h"
|
| +#import "CDTypeFormatter.h"
|
| +#import "CDTypeController.h"
|
| +#import "CDVisitorPropertyState.h"
|
| +
|
| +static BOOL debug = NO;
|
| +
|
| +@implementation CDTextClassDumpVisitor
|
| +
|
| +- (id)init;
|
| +{
|
| + if ([super init] == nil)
|
| + return nil;
|
| +
|
| + resultString = [[NSMutableString alloc] init];
|
| + symbolReferences = [[CDSymbolReferences alloc] init];
|
| +
|
| + return self;
|
| +}
|
| +
|
| +- (void)dealloc;
|
| +{
|
| + [resultString release];
|
| + [symbolReferences release];
|
| +
|
| + [super dealloc];
|
| +}
|
| +
|
| +- (void)writeResultToStandardOutput;
|
| +{
|
| + NSData *data;
|
| +
|
| + data = [resultString dataUsingEncoding:NSUTF8StringEncoding];
|
| + [(NSFileHandle *)[NSFileHandle fileHandleWithStandardOutput] writeData:data];
|
| +}
|
| +
|
| +- (void)willVisitClass:(CDOCClass *)aClass;
|
| +{
|
| + NSArray *protocols;
|
| +
|
| + if ([aClass isExported] == NO)
|
| + [resultString appendString:@"// Not exported\n"];
|
| +
|
| + [resultString appendFormat:@"@interface %@", [aClass name]];
|
| + if ([aClass superClassName] != nil)
|
| + [resultString appendFormat:@" : %@", [aClass superClassName]];
|
| +
|
| + protocols = [aClass protocols];
|
| + if ([protocols count] > 0) {
|
| + [resultString appendFormat:@" <%@>", [[protocols arrayByMappingSelector:@selector(name)] componentsJoinedByString:@", "]];
|
| + [symbolReferences addProtocolNamesFromArray:[protocols arrayByMappingSelector:@selector(name)]];
|
| + }
|
| +
|
| + [resultString appendString:@"\n"];
|
| +}
|
| +
|
| +- (void)didVisitClass:(CDOCClass *)aClass;
|
| +{
|
| + if ([aClass hasMethods])
|
| + [resultString appendString:@"\n"];
|
| +
|
| + [resultString appendString:@"@end\n\n"];
|
| +}
|
| +
|
| +- (void)willVisitIvarsOfClass:(CDOCClass *)aClass;
|
| +{
|
| + [resultString appendString:@"{\n"];
|
| +}
|
| +
|
| +- (void)didVisitIvarsOfClass:(CDOCClass *)aClass;
|
| +{
|
| + [resultString appendString:@"}\n\n"];
|
| +}
|
| +
|
| +- (void)willVisitCategory:(CDOCCategory *)aCategory;
|
| +{
|
| + NSArray *protocols;
|
| +
|
| + [resultString appendFormat:@"@interface %@ (%@)", [aCategory className], [aCategory name]];
|
| +
|
| + protocols = [aCategory protocols];
|
| + if ([protocols count] > 0) {
|
| + [resultString appendFormat:@" <%@>", [[protocols arrayByMappingSelector:@selector(name)] componentsJoinedByString:@", "]];
|
| + [symbolReferences addProtocolNamesFromArray:[protocols arrayByMappingSelector:@selector(name)]];
|
| + }
|
| +
|
| + [resultString appendString:@"\n"];
|
| +}
|
| +
|
| +- (void)didVisitCategory:(CDOCCategory *)aCategory;
|
| +{
|
| + [resultString appendString:@"@end\n\n"];
|
| +}
|
| +
|
| +- (void)willVisitProtocol:(CDOCProtocol *)aProtocol;
|
| +{
|
| + NSArray *protocols;
|
| +
|
| + [resultString appendFormat:@"@protocol %@", [aProtocol name]];
|
| +
|
| + protocols = [aProtocol protocols];
|
| + if ([protocols count] > 0) {
|
| + [resultString appendFormat:@" <%@>", [[protocols arrayByMappingSelector:@selector(name)] componentsJoinedByString:@", "]];
|
| + [symbolReferences addProtocolNamesFromArray:[protocols arrayByMappingSelector:@selector(name)]];
|
| + }
|
| +
|
| + [resultString appendString:@"\n"];
|
| +}
|
| +
|
| +- (void)willVisitOptionalMethods;
|
| +{
|
| + [resultString appendString:@"\n@optional\n"];
|
| +}
|
| +
|
| +- (void)didVisitProtocol:(CDOCProtocol *)aProtocol;
|
| +{
|
| + [resultString appendString:@"@end\n\n"];
|
| +}
|
| +
|
| +- (void)visitClassMethod:(CDOCMethod *)aMethod;
|
| +{
|
| + [resultString appendString:@"+ "];
|
| + [aMethod appendToString:resultString typeController:[classDump typeController] symbolReferences:symbolReferences];
|
| + [resultString appendString:@"\n"];
|
| +}
|
| +
|
| +- (void)visitInstanceMethod:(CDOCMethod *)aMethod propertyState:(CDVisitorPropertyState *)propertyState;
|
| +{
|
| + CDOCProperty *property;
|
| +
|
| + property = [propertyState propertyForAccessor:[aMethod name]];
|
| + if (property == nil) {
|
| + //NSLog(@"No property for method: %@", [aMethod name]);
|
| + [resultString appendString:@"- "];
|
| + [aMethod appendToString:resultString typeController:[classDump typeController] symbolReferences:symbolReferences];
|
| + [resultString appendString:@"\n"];
|
| + } else {
|
| + if ([propertyState hasUsedProperty:property] == NO) {
|
| + //NSLog(@"Emitting property %@ triggered by method %@", [property name], [aMethod name]);
|
| + [self visitProperty:property];
|
| + [propertyState useProperty:property];
|
| + } else {
|
| + //NSLog(@"Have already emitted property %@ triggered by method %@", [property name], [aMethod name]);
|
| + }
|
| + }
|
| +}
|
| +
|
| +- (void)visitIvar:(CDOCIvar *)anIvar;
|
| +{
|
| + [anIvar appendToString:resultString typeController:[classDump typeController] symbolReferences:symbolReferences];
|
| + [resultString appendString:@"\n"];
|
| +}
|
| +
|
| +- (void)_visitProperty:(CDOCProperty *)aProperty parsedType:(CDType *)parsedType attributes:(NSArray *)attrs;
|
| +{
|
| + NSMutableArray *alist, *unknownAttrs;
|
| + NSString *backingVar = nil;
|
| + NSString *formattedString;
|
| + BOOL isWeak = NO;
|
| + BOOL isDynamic = NO;
|
| +
|
| + alist = [[NSMutableArray alloc] init];
|
| + unknownAttrs = [[NSMutableArray alloc] init];
|
| +
|
| + // objc_v2_encode_prop_attr() in gcc/objc/objc-act.c
|
| +
|
| + for (NSString *attr in attrs) {
|
| + if ([attr hasPrefix:@"T"]) {
|
| + if (debug) NSLog(@"Warning: Property attribute 'T' should occur only occur at the beginning");
|
| + } else if ([attr hasPrefix:@"R"]) {
|
| + [alist addObject:@"readonly"];
|
| + } else if ([attr hasPrefix:@"C"]) {
|
| + [alist addObject:@"copy"];
|
| + } else if ([attr hasPrefix:@"&"]) {
|
| + [alist addObject:@"retain"];
|
| + } else if ([attr hasPrefix:@"G"]) {
|
| + [alist addObject:[NSString stringWithFormat:@"getter=%@", [attr substringFromIndex:1]]];
|
| + } else if ([attr hasPrefix:@"S"]) {
|
| + [alist addObject:[NSString stringWithFormat:@"setter=%@", [attr substringFromIndex:1]]];
|
| + } else if ([attr hasPrefix:@"V"]) {
|
| + backingVar = [attr substringFromIndex:1];
|
| + } else if ([attr hasPrefix:@"N"]) {
|
| + [alist addObject:@"nonatomic"];
|
| + } else if ([attr hasPrefix:@"W"]) {
|
| + // @property(assign) __weak NSObject *prop;
|
| + // Only appears with GC.
|
| + isWeak = YES;
|
| + } else if ([attr hasPrefix:@"P"]) {
|
| + // @property(assign) __strong NSObject *prop;
|
| + // Only appears with GC.
|
| + // This is the default.
|
| + isWeak = NO;
|
| + } else if ([attr hasPrefix:@"D"]) {
|
| + // Dynamic property. Implementation supplied at runtime.
|
| + // @property int prop; // @dynamic prop;
|
| + isDynamic = YES;
|
| + } else {
|
| + if (debug) NSLog(@"Warning: Unknown property attribute '%@'", attr);
|
| + [unknownAttrs addObject:attr];
|
| + }
|
| + }
|
| +
|
| + if ([alist count] > 0) {
|
| + [resultString appendFormat:@"@property(%@) ", [alist componentsJoinedByString:@", "]];
|
| + } else {
|
| + [resultString appendString:@"@property "];
|
| + }
|
| +
|
| + if (isWeak)
|
| + [resultString appendString:@"__weak "];
|
| +
|
| + formattedString = [[[classDump typeController] propertyTypeFormatter] formatVariable:[aProperty name] parsedType:parsedType symbolReferences:symbolReferences];
|
| + [resultString appendFormat:@"%@;", formattedString];
|
| +
|
| + if (isDynamic) {
|
| + [resultString appendFormat:@" // @dynamic %@;", [aProperty name]];
|
| + } else if (backingVar != nil) {
|
| + if ([backingVar isEqualToString:[aProperty name]]) {
|
| + [resultString appendFormat:@" // @synthesize %@;", [aProperty name]];
|
| + } else {
|
| + [resultString appendFormat:@" // @synthesize %@=%@;", [aProperty name], backingVar];
|
| + }
|
| + }
|
| +
|
| + [resultString appendString:@"\n"];
|
| + if ([unknownAttrs count] > 0) {
|
| + [resultString appendFormat:@"// Preceding property had unknown attributes: %@\n", [unknownAttrs componentsJoinedByString:@","]];
|
| + if ([[aProperty attributeString] length] > 80) {
|
| + [resultString appendFormat:@"// Original attribute string (following type): %@\n\n", [aProperty attributeStringAfterType]];
|
| + } else {
|
| + [resultString appendFormat:@"// Original attribute string: %@\n\n", [aProperty attributeString]];
|
| + }
|
| + }
|
| +
|
| + [alist release];
|
| + [unknownAttrs release];
|
| +}
|
| +
|
| +- (void)visitProperty:(CDOCProperty *)aProperty;
|
| +{
|
| + CDType *parsedType;
|
| +
|
| + parsedType = [aProperty type];
|
| + if (parsedType == nil) {
|
| + if ([[aProperty attributeString] hasPrefix:@"T"]) {
|
| + [resultString appendFormat:@"// Error parsing type for property %@:\n", [aProperty name]];
|
| + [resultString appendFormat:@"// Property attributes: %@\n\n", [aProperty attributeString]];
|
| + } else {
|
| + [resultString appendFormat:@"// Error: Property attributes should begin with the type ('T') attribute, property name: %@\n", [aProperty name]];
|
| + [resultString appendFormat:@"// Property attributes: %@\n\n", [aProperty attributeString]];
|
| + }
|
| + } else {
|
| + [self _visitProperty:aProperty parsedType:parsedType attributes:[aProperty attributes]];
|
| + }
|
| +}
|
| +
|
| +#define ADD_SPACE
|
| +
|
| +- (void)didVisitPropertiesOfClass:(CDOCClass *)aClass;
|
| +{
|
| +#ifdef ADD_SPACE
|
| + if ([[aClass properties] count] > 0)
|
| + [resultString appendString:@"\n"];
|
| +#endif
|
| +}
|
| +
|
| +- (void)willVisitPropertiesOfCategory:(CDOCCategory *)aCategory;
|
| +{
|
| +#ifdef ADD_SPACE
|
| + if ([[aCategory properties] count] > 0)
|
| + [resultString appendString:@"\n"];
|
| +#endif
|
| +}
|
| +
|
| +- (void)didVisitPropertiesOfCategory:(CDOCCategory *)aCategory;
|
| +{
|
| +#ifdef ADD_SPACE
|
| + if ([[aCategory properties] count] > 0/* && [aCategory hasMethods]*/)
|
| + [resultString appendString:@"\n"];
|
| +#endif
|
| +}
|
| +
|
| +- (void)willVisitPropertiesOfProtocol:(CDOCProtocol *)aProtocol;
|
| +{
|
| +#ifdef ADD_SPACE
|
| + if ([[aProtocol properties] count] > 0)
|
| + [resultString appendString:@"\n"];
|
| +#endif
|
| +}
|
| +
|
| +- (void)didVisitPropertiesOfProtocol:(CDOCProtocol *)aProtocol;
|
| +{
|
| +#ifdef ADD_SPACE
|
| + if ([[aProtocol properties] count] > 0 /*&& [aProtocol hasMethods]*/)
|
| + [resultString appendString:@"\n"];
|
| +#endif
|
| +}
|
| +
|
| +- (void)visitRemainingProperties:(CDVisitorPropertyState *)propertyState;
|
| +{
|
| + NSArray *remaining = [propertyState remainingProperties];
|
| +
|
| + if ([remaining count] > 0) {
|
| + [resultString appendString:@"\n"];
|
| + [resultString appendFormat:@"// Remaining properties\n"];
|
| + //NSLog(@"Warning: remaining undeclared property count: %u", [remaining count]);
|
| + //NSLog(@"remaining: %@", remaining);
|
| + for (CDOCProperty *property in remaining)
|
| + [self visitProperty:property];
|
| + }
|
| +}
|
| +
|
| +@end
|
|
|
| Property changes on: class-dump/src/CDTextClassDumpVisitor.m
|
| ___________________________________________________________________
|
| Added: svn:eol-style
|
| + LF
|
|
|
|
|