Created
November 12, 2018 06:41
-
-
Save persenlee/04090db394b8537f8f9198173160a38f to your computer and use it in GitHub Desktop.
find objective-c unused classes
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import re | |
import sys | |
import os | |
from inspect import isfunction | |
class_prefix_filter = {'NS','UI','UN','AV','CA','CL','CI','CT','PH','PodsDummy','WK'} | |
all_classes = set() | |
all_super_classes = set() | |
reference_classes = set() | |
objc_refs_section = 'Contents of (__DATA,__objc_classrefs) section' | |
objc_superrefs_section = 'Contents of (__DATA,__objc_superrefs) section' | |
objc_list_section = 'Contents of (__DATA,__objc_classlist) section' | |
objc_catlist_section = 'Contents of (__DATA,__objc_catlist) section' | |
def validate_file_path(path): | |
if os.path.isfile(path): | |
cmd = 'file -b %s'%path | |
result = os.popen(cmd).read() | |
if result.startswith('Mach-O'): | |
return True | |
else: | |
print('%s is not a Mach-O type file' % path) | |
else: | |
print('%s is not a file' % path) | |
return False | |
def parse_all_classes(line): | |
prefix = '_OBJC_CLASS_\$_' | |
regex = '%s(.+)'%prefix | |
pattern = re.compile(regex) | |
results = pattern.findall(line) | |
if results: | |
result = results[0] | |
class_name = result | |
for pre in class_prefix_filter: | |
if class_name.startswith(pre): | |
return None | |
if line.find('superclass') >= 0: | |
all_super_classes.add(class_name) | |
all_classes.add(class_name) | |
def parse_references_classes(line): | |
prefix = '_OBJC_CLASS_\$_' | |
regex = '%s(.+)' % prefix | |
pattern = re.compile(regex) | |
results = pattern.findall(line) | |
if results: | |
result = results[0] | |
class_name = result | |
for pre in class_prefix_filter: | |
if class_name.startswith(pre): | |
return None | |
reference_classes.add(class_name) | |
def format_output(): | |
none_super_classes = all_classes.symmetric_difference(all_super_classes) | |
unreference_classes = none_super_classes.symmetric_difference(reference_classes) | |
# sortedSet = sorted(unreference_classes, key=lambda asd: asd[1], reverse=True) | |
for class_name in unreference_classes: | |
print(class_name) | |
def analyze(): | |
if len(sys.argv) > 1: | |
path = sys.argv[1] | |
if validate_file_path(path): | |
all_lines = os.popen('otool -oV %s' % path).readlines() | |
func = [''] | |
for line in all_lines: | |
if line.startswith(objc_list_section): | |
func[0] = parse_all_classes | |
elif line.startswith(objc_refs_section): | |
func[0] = parse_references_classes | |
elif line.startswith(objc_superrefs_section): | |
func[0] = parse_references_classes | |
elif line.startswith(objc_catlist_section): | |
func[0] = '' | |
else: | |
pass | |
if isfunction(func[0]): | |
func[0](line) | |
format_output() | |
else: | |
print 'invalidate arguments' | |
analyze() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Find useless should start in Mach-O file