Bug 1316844 - Make the linter detect unused dependencies. r=chmanchester

--HG--
extra : rebase_source : 44fea4820c95b5e0d274fa1b3bf6ce563af2c30a
This commit is contained in:
Mike Hommey 2016-11-11 12:52:58 +09:00
parent 6fa3828b4e
commit 3e149877ae
3 changed files with 115 additions and 4 deletions

View File

@ -210,7 +210,7 @@ class ConfigureSandbox(dict):
self._all_paths = set()
self._templates = set()
# Associate SandboxDependsFunctions to DependsFunctions.
self._depends = {}
self._depends = OrderedDict()
self._seen = set()
# Store the @imports added to a given function.
self._imports = {}
@ -388,6 +388,9 @@ class ConfigureSandbox(dict):
raise KeyError('Cannot assign `%s` because it is neither a '
'@depends nor a @template' % key)
if isinstance(value, SandboxDependsFunction):
self._depends[value].func.__name__ = key
return super(ConfigureSandbox, self).__setitem__(key, value)
def _resolve(self, arg, need_help_dependency=True):

View File

@ -4,6 +4,7 @@
from __future__ import absolute_import, print_function, unicode_literals
import inspect
from functools import wraps
from StringIO import StringIO
from . import (
@ -32,6 +33,46 @@ class LintSandbox(ConfigureSandbox):
if path:
self.include_file(path)
for dep in self._depends.itervalues():
self._check_dependencies(dep)
def _check_dependencies(self, obj):
if isinstance(obj, CombinedDependsFunction) or obj in (self._always,
self._never):
return
func, glob = self.unwrap(obj.func)
loc = '%s:%d' % (func.func_code.co_filename,
func.func_code.co_firstlineno)
func_args = inspect.getargspec(func)
if func_args.keywords:
raise ConfigureError(
'%s: Keyword arguments are not allowed in @depends functions'
% loc
)
all_args = list(func_args.args)
if func_args.varargs:
all_args.append(func_args.varargs)
used_args = set()
for op, arg in disassemble_as_iter(func):
if op in ('LOAD_FAST', 'LOAD_CLOSURE'):
if arg in all_args:
used_args.add(arg)
for num, arg in enumerate(all_args):
if arg not in used_args:
dep = obj.dependencies[num]
if dep != self._help_option:
if isinstance(dep, DependsFunction):
dep = dep.name
else:
dep = dep.option
raise ConfigureError(
'%s: The dependency on `%s` is unused.'
% (loc, dep)
)
def _missing_help_dependency(self, obj):
if isinstance(obj, CombinedDependsFunction):
return False

View File

@ -44,7 +44,7 @@ class TestLint(unittest.TestCase):
@depends('--help', foo)
def bar(help, foo):
return
return foo
'''):
self.lint_test()
@ -58,7 +58,7 @@ class TestLint(unittest.TestCase):
@depends('--help', foo)
def bar(help, foo):
return
return foo
'''):
self.lint_test()
@ -80,7 +80,7 @@ class TestLint(unittest.TestCase):
@depends('--help', foo)
def bar(help, foo):
return
return foo
tmpl()
'''):
self.lint_test()
@ -127,6 +127,73 @@ class TestLint(unittest.TestCase):
'''):
self.lint_test()
with self.assertRaises(ConfigureError) as e:
with self.moz_configure('''
option('--foo', help='foo')
@depends('--foo')
def foo(value):
return
include(foo)
'''):
self.lint_test()
self.assertEquals(e.exception.message,
"%s:3: The dependency on `--foo` is unused."
% mozpath.join(test_data_path, 'moz.configure'))
with self.assertRaises(ConfigureError) as e:
with self.moz_configure('''
@depends(when=True)
def bar():
return
@depends(bar)
def foo(value):
return
include(foo)
'''):
self.lint_test()
self.assertEquals(e.exception.message,
"%s:5: The dependency on `bar` is unused."
% mozpath.join(test_data_path, 'moz.configure'))
with self.assertRaises(ConfigureError) as e:
with self.moz_configure('''
@depends(depends(when=True)(lambda: None))
def foo(value):
return
include(foo)
'''):
self.lint_test()
self.assertEquals(e.exception.message,
"%s:2: The dependency on `<lambda>` is unused."
% mozpath.join(test_data_path, 'moz.configure'))
with self.assertRaises(ConfigureError) as e:
with self.moz_configure('''
@template
def tmpl():
@depends(when=True)
def bar():
return
return bar
qux = tmpl()
@depends(qux)
def foo(value):
return
include(foo)
'''):
self.lint_test()
self.assertEquals(e.exception.message,
"%s:9: The dependency on `qux` is unused."
% mozpath.join(test_data_path, 'moz.configure'))
if __name__ == '__main__':
main()