Skip to content

Instantly share code, notes, and snippets.

@rodrigosetti
Created February 7, 2013 21:49
Show Gist options
  • Star 14 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save rodrigosetti/4734557 to your computer and use it in GitHub Desktop.
Save rodrigosetti/4734557 to your computer and use it in GitHub Desktop.
Removes unused imports from a bunch of Java files.
#! /usr/bin/env python
# coding: utf-8
"""This script reads all .java files from a directory tree and removes unused
import statements. It may have errors in detecting import lines (e.g. import
lines within block comments, or import lines with another statement in the same
line), and it may have false-negatives when deciding to remove an import (i.e.
it only removes if the last import symbol word doesn't appear at all -
including comments - in the code).
Warning: use it at your own risk. Better have a source control to rollback if
necessary.
"""
import fnmatch
import re
import sys
import os
#: The regular expression to match a Java import line. It captures the last
#: symbol (i.e. the class name)
IMPORT_RE = re.compile(r'^\s*import\s+[\w\.]+\.(\w+)\s*;\s*(?://.*)?$')
def locate(pattern, root=os.curdir):
'''Locate all files matching supplied filename pattern in and below
supplied root directory.'''
for path, dirs, files in os.walk(os.path.abspath(root)):
for filename in fnmatch.filter(files, pattern):
yield os.path.join(path, filename)
if __name__ == "__main__":
# locate files in current directory or one specified in command line arg
root_dir = sys.argv[1] if len(sys.argv) == 2 else os.curdir
for filename in locate("*.java", root_dir):
import_lines = {}
other_lines = []
# read all lines from file
with open(filename) as f:
all_lines = f.readlines()
for n, line in enumerate(all_lines):
m = IMPORT_RE.match(line)
if m:
# this is an import line, associate the line number with
# the symbol imported
import_lines[n] = m.group(1)
else:
# this is a non-import line (everything else)
other_lines.append(line)
# get the code excluding the import line
other_code = ''.join(other_lines)
# now that we got all, let's write only the imports that
# are found in other_lines (non-import lines)
with open(filename, 'w') as f:
for n, line in enumerate(all_lines):
if (n in import_lines and
not re.search(r'(?<!\w)%s(?!\w)' % import_lines[n],
other_code)):
# import not found in code... continue (not writing)
print "unused: %s at %s:%d" % (line, filename, n)
continue
f.write(line)
print "Please compile your project to make sure I haven't break anything."
@soulseekah
Copy link

I've been looking for this for quite a while! Worked perfectly well, got rid of lots of old rubbish imports. Thanks!

@mjg123
Copy link

mjg123 commented May 13, 2013

It's a great script, and works fine. But it's properly annoying that you can't extract the classes from Eclipse to do this kind of thing :(

@alecmuffett
Copy link

awesome! thank you!

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