Skip to content

Instantly share code, notes, and snippets.

@persenlee
Created November 12, 2018 06:41
Show Gist options
  • Save persenlee/04090db394b8537f8f9198173160a38f to your computer and use it in GitHub Desktop.
Save persenlee/04090db394b8537f8f9198173160a38f to your computer and use it in GitHub Desktop.
find objective-c unused classes
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()
@ACommonChinese
Copy link

Find useless should start in Mach-O file

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment