Skip to content

Commit 761facd

Browse files
committed
Initial commit
0 parents  commit 761facd

14 files changed

+1454
-0
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
build/

LICENSE

Lines changed: 675 additions & 0 deletions
Large diffs are not rendered by default.

README.md

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
`objc-class-tree` can print a nice tree of Objective-C classes.
2+
3+
By default, it will print a huge tree of all the classes loaded in its own binary:
4+
5+
```
6+
$ objc-class-tree | head -30
7+
NSProxy
8+
_NSZombie_
9+
__NSMessageBuilder
10+
__NSGenericDeallocHandler
11+
Object
12+
NSObject
13+
├── OCTMethod
14+
├── OCTTreeFormatter
15+
├── NSURLDownload
16+
├── NSXPCInterface
17+
├── NSAppleEventDescriptor
18+
├── NSFileWrapper
19+
│   ├── NSFileWrapperLink
20+
│   ├── NSFileWrapperDirectory
21+
│   └── NSFileWrapperFile
22+
├── NSURLSessionConfiguration
23+
├── NSSpellEngine
24+
├── NSXMLParser
25+
├── NSXMLNode
26+
│   ├── NSXMLElement
27+
│   ├── NSXMLDTDNode
28+
│   ├── NSXMLDTD
29+
│   └── NSXMLDocument
30+
├── NSValueTransformer
31+
│   └── _NSSharedValueTransformer
32+
│      ├── _NSUnarchiveFromDataTransformer
33+
│      ├── _NSKeyedUnarchiveFromDataTransformer
34+
│      └── _NSNegateBooleanTransformer
35+
│         ├── _NSIsNotNilTransformer
36+
│         └── _NSIsNilTransformer
37+
$ objc-class-tree | wc -l
38+
401
39+
```
40+
41+
You can limit its output to a handful of class trees by using the `--root-class` option:
42+
43+
```
44+
$ objc-class-tree --root-class NSArray --root-class NSXMLNode
45+
NSArray
46+
├── NSKeyValueArray
47+
├── __NSOrderedSetArrayProxy
48+
├── __NSArrayI
49+
└── NSMutableArray
50+
   ├── NSKeyValueMutableArray
51+
   │   ├── NSKeyValueNotifyingMutableArray
52+
   │   ├── NSKeyValueIvarMutableArray
53+
   │   ├── NSKeyValueFastMutableArray
54+
   │   │   ├── NSKeyValueFastMutableArray2
55+
   │   │   └── NSKeyValueFastMutableArray1
56+
   │   └── NSKeyValueSlowMutableArray
57+
   ├── __NSPlaceholderArray
58+
   └── __NSCFArray
59+
NSXMLNode
60+
├── NSXMLElement
61+
├── NSXMLDTDNode
62+
├── NSXMLDTD
63+
└── NSXMLDocument
64+
```
65+
66+
You can ask it to output implemented methods:
67+
68+
```
69+
$ objc-class-tree --root-class NSURLResponse --methods
70+
NSURLResponse
71+
├── - init
72+
├── - dealloc
73+
├── - copyWithZone:
74+
├── - initWithCoder:
75+
├── - encodeWithCoder:
76+
├── - URL
77+
├── - _CFURLResponse
78+
├── - _initWithCFURLResponse:
79+
├── - initWithURL:MIMEType:expectedContentLength:textEncodingName:
80+
├── - suggestedFilename
81+
├── - expectedContentLength
82+
├── - textEncodingName
83+
├── - MIMEType
84+
├── + _responseWithCFURLResponse:
85+
└── NSHTTPURLResponse
86+
   ├── - initWithCoder:
87+
   ├── - statusCode
88+
   ├── - _initWithCFURLResponse:
89+
   ├── - initWithURL:statusCode:HTTPVersion:headerFields:
90+
   ├── - initWithURL:statusCode:headerFields:requestTime:
91+
   ├── - _peerTrust
92+
   ├── - _setPeerTrust:
93+
   ├── - _clientCertificateState
94+
   ├── - _clientCertificateChain
95+
   ├── - _peerCertificateChain
96+
   ├── - allHeaderFields
97+
   ├── + supportsSecureCoding
98+
   ├── + isErrorStatusCode:
99+
   └── + localizedStringForStatusCode:
100+
```
101+
102+
It can also display protocols and which libraries the classes come from:
103+
104+
```
105+
$ objc-class-tree --root-class NSString --protocols --library-names
106+
NSString <NSCopying, NSMutableCopying, NSSecureCoding> (Foundation)
107+
├── NSSimpleCString (Foundation)
108+
│   └── NSConstantString (Foundation)
109+
├── NSPathStore2 (Foundation)
110+
├── NSLocalizableString <NSCoding, NSCopying> (Foundation)
111+
├── NSPlaceholderString (Foundation)
112+
└── NSMutableString (Foundation)
113+
   ├── NSPlaceholderMutableString (Foundation)
114+
   ├── NSMutableStringProxyForMutableAttributedString (Foundation)
115+
   └── __NSCFString (CoreFoundation)
116+
      └── __NSCFConstantString (CoreFoundation)
117+
```
118+
119+
See `main.m` for more supported options.
120+
121+
# Building
122+
123+
Build using Meson as usual:
124+
125+
```sh
126+
$ meson build
127+
$ cd build
128+
$ ninja build
129+
# optionally
130+
$ sudo ninja install
131+
```
132+
133+
# License
134+
135+
objc-class-tree is free software, available under the GNU General Public License version 3 or
136+
later.

meson.build

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
project('objc-class-tree', 'objc', version : '0.1')
2+
3+
subdir('src')

src/OCTClass.h

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/* objc-class-tree
2+
*
3+
* Copyright © 2019 Sergey Bugaev <bugaevc@gmail.com>
4+
*
5+
* This program is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU General Public License as published by
7+
* the Free Software Foundation, either version 3 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU General Public License
16+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
17+
*/
18+
19+
#import <objc/runtime.h>
20+
#import <Foundation/Foundation.h>
21+
22+
@interface OCTClass: NSObject <NSCopying> {
23+
Class _class;
24+
NSMutableArray *_subclasses;
25+
}
26+
27+
+ (NSArray *) rootClasses;
28+
29+
- (Class) rawClass;
30+
31+
- (NSString *) name;
32+
- (NSArray *) subclasses;
33+
34+
- (NSString *) libraryName;
35+
- (NSArray *) protocolNames;
36+
- (NSArray *) methods;
37+
38+
@end

src/OCTClass.m

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
/* objc-class-tree
2+
*
3+
* Copyright © 2019 Sergey Bugaev <bugaevc@gmail.com>
4+
*
5+
* This program is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU General Public License as published by
7+
* the Free Software Foundation, either version 3 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU General Public License
16+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
17+
*/
18+
19+
#import <objc/runtime.h>
20+
#import <Foundation/Foundation.h>
21+
#import "OCTClass.h"
22+
#import "OCTMethod.h"
23+
24+
@implementation OCTClass
25+
26+
+ (instancetype) classWithRawClass: (Class) class {
27+
OCTClass *res = [OCTClass new];
28+
res->_class = class;
29+
res->_subclasses = [NSMutableArray new];
30+
return [res autorelease];
31+
}
32+
33+
- (void) dealloc {
34+
[_subclasses release];
35+
[super dealloc];
36+
}
37+
38+
+ (NSArray *) rootClasses {
39+
NSMutableArray *rootClasses = [NSMutableArray new];
40+
NSUInteger allClassesCnt = objc_getClassList(NULL, 0);
41+
Class *allClasses = malloc(sizeof(Class) * allClassesCnt);
42+
objc_getClassList(allClasses, allClassesCnt);
43+
44+
NSMutableSet *classes = [NSMutableSet new];
45+
OCTClass *(^intern)(Class rawClass) = ^OCTClass *(Class rawClass) {
46+
OCTClass *class = [OCTClass classWithRawClass: rawClass];
47+
[classes addObject: class];
48+
return [classes member: class];
49+
};
50+
51+
for (NSUInteger i = 0; i < allClassesCnt; i++) {
52+
Class rawClass = allClasses[i];
53+
Class rawSuperclass = class_getSuperclass(rawClass);
54+
OCTClass *class = intern(rawClass);
55+
56+
if (rawSuperclass == Nil) {
57+
[rootClasses addObject: class];
58+
} else {
59+
OCTClass *superclass = intern(rawSuperclass);
60+
[superclass->_subclasses addObject: class];
61+
}
62+
}
63+
64+
[classes release];
65+
free(allClasses);
66+
return [rootClasses autorelease];
67+
}
68+
69+
- (NSArray *) subclasses {
70+
return _subclasses;
71+
}
72+
73+
- (BOOL) isEqual: (id) object {
74+
if (![object isMemberOfClass: [OCTClass class]]) {
75+
return NO;
76+
}
77+
OCTClass *other = (OCTClass *) object;
78+
return _class == other->_class;
79+
}
80+
81+
- (NSUInteger) hash {
82+
return (NSUInteger) _class;
83+
}
84+
85+
- (id) copyWithZone: (NSZone *) zone {
86+
OCTClass *res = [OCTClass new];
87+
res->_class = _class;
88+
res->_subclasses = [_subclasses mutableCopy];
89+
return res;
90+
}
91+
92+
- (Class) rawClass {
93+
return _class;
94+
}
95+
96+
- (NSString *) name {
97+
const char *rawName = class_getName(_class);
98+
return [NSString stringWithUTF8String: rawName];
99+
}
100+
101+
- (NSString *) description {
102+
return [NSString stringWithFormat: @"<OCTClass: %@>", [self name]];
103+
}
104+
105+
- (NSString *) libraryName {
106+
const char *fileName = class_getImageName(_class);
107+
if (fileName == NULL) return nil;
108+
NSString *filePath = [NSString stringWithUTF8String: fileName];
109+
return [filePath lastPathComponent];
110+
}
111+
112+
- (NSArray *) protocolNames {
113+
NSMutableArray *res = [NSMutableArray arrayWithCapacity: 4];
114+
115+
unsigned int protocolsCnt;
116+
Protocol **protocols = class_copyProtocolList(_class, &protocolsCnt);
117+
for (unsigned int i = 0; i < protocolsCnt; i++) {
118+
const char *rawName = protocol_getName(protocols[i]);
119+
NSString *name = [NSString stringWithUTF8String: rawName];
120+
[res addObject: name];
121+
}
122+
free(protocols);
123+
124+
return res;
125+
}
126+
127+
static void enumerateMethods(Class rawClass, void (^block)(SEL sel)) {
128+
unsigned int methodsCnt;
129+
Method *methods = class_copyMethodList(rawClass, &methodsCnt);
130+
for (unsigned int i = 0; i < methodsCnt; i++) {
131+
SEL sel = method_getName(methods[i]);
132+
block(sel);
133+
}
134+
free(methods);
135+
}
136+
137+
- (NSArray *) methods {
138+
NSMutableArray *res = [NSMutableArray new];
139+
140+
enumerateMethods(_class, ^(SEL sel) {
141+
OCTMethod *method = [OCTMethod methodWithSelector: sel
142+
isInstanceMethod: YES];
143+
[res addObject: method];
144+
});
145+
146+
enumerateMethods(object_getClass(_class), ^(SEL sel) {
147+
OCTMethod *method = [OCTMethod methodWithSelector: sel
148+
isInstanceMethod: NO];
149+
[res addObject: method];
150+
});
151+
152+
return [res autorelease];
153+
}
154+
155+
@end

src/OCTClassesDataSource.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/* objc-class-tree
2+
*
3+
* Copyright © 2019 Sergey Bugaev <bugaevc@gmail.com>
4+
*
5+
* This program is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU General Public License as published by
7+
* the Free Software Foundation, either version 3 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU General Public License
16+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
17+
*/
18+
19+
#import <Foundation/Foundation.h>
20+
#import "OCTTreeFormatter.h"
21+
22+
@interface OCTClassesDataSource : NSObject<OCTTreeDataSource> {
23+
NSArray *_rootClasses;
24+
NSMutableArray *_treeRootClasses;
25+
}
26+
27+
@property BOOL displayLibraryNames;
28+
@property BOOL displayProtocols;
29+
@property BOOL displayMethods;
30+
31+
- (void) addTreeRoot: (Class) rawClass;
32+
33+
@end

0 commit comments

Comments
 (0)