| Index: tools/telemetry/third_party/rope/rope/contrib/finderrors.py
|
| diff --git a/tools/telemetry/third_party/rope/rope/contrib/finderrors.py b/tools/telemetry/third_party/rope/rope/contrib/finderrors.py
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..9ee7dd15f97a738ec757c17aaf5637aade9bcf4a
|
| --- /dev/null
|
| +++ b/tools/telemetry/third_party/rope/rope/contrib/finderrors.py
|
| @@ -0,0 +1,91 @@
|
| +"""Finding bad name and attribute accesses
|
| +
|
| +`find_errors` function can be used to find possible bad name and
|
| +attribute accesses. As an example::
|
| +
|
| + errors = find_errors(project, project.get_resource('mod.py'))
|
| + for error in errors:
|
| + print '%s: %s' % (error.lineno, error.error)
|
| +
|
| +prints possible errors for ``mod.py`` file.
|
| +
|
| +TODO:
|
| +
|
| +* use task handles
|
| +* reporting names at most once
|
| +* attributes of extension modules that don't appear in
|
| + extension_modules project config can be ignored
|
| +* not calling `PyScope.get_inner_scope_for_line()` if it is a
|
| + bottleneck; needs profiling
|
| +* not reporting occurrences where rope cannot infer the object
|
| +* rope saves multiple objects for some of the names in its objectdb
|
| + use all of them not to give false positives
|
| +* ... ;-)
|
| +
|
| +"""
|
| +from rope.base import ast, evaluate, pyobjects
|
| +
|
| +
|
| +def find_errors(project, resource):
|
| + """Find possible bad name and attribute accesses
|
| +
|
| + It returns a list of `Error`\s.
|
| + """
|
| + pymodule = project.get_pymodule(resource)
|
| + finder = _BadAccessFinder(pymodule)
|
| + ast.walk(pymodule.get_ast(), finder)
|
| + return finder.errors
|
| +
|
| +
|
| +class _BadAccessFinder(object):
|
| +
|
| + def __init__(self, pymodule):
|
| + self.pymodule = pymodule
|
| + self.scope = pymodule.get_scope()
|
| + self.errors = []
|
| +
|
| + def _Name(self, node):
|
| + if isinstance(node.ctx, (ast.Store, ast.Param)):
|
| + return
|
| + scope = self.scope.get_inner_scope_for_line(node.lineno)
|
| + pyname = scope.lookup(node.id)
|
| + if pyname is None:
|
| + self._add_error(node, 'Unresolved variable')
|
| + elif self._is_defined_after(scope, pyname, node.lineno):
|
| + self._add_error(node, 'Defined later')
|
| +
|
| + def _Attribute(self, node):
|
| + if not isinstance(node.ctx, ast.Store):
|
| + scope = self.scope.get_inner_scope_for_line(node.lineno)
|
| + pyname = evaluate.eval_node(scope, node.value)
|
| + if pyname is not None and \
|
| + pyname.get_object() != pyobjects.get_unknown():
|
| + if node.attr not in pyname.get_object():
|
| + self._add_error(node, 'Unresolved attribute')
|
| + ast.walk(node.value, self)
|
| +
|
| + def _add_error(self, node, msg):
|
| + if isinstance(node, ast.Attribute):
|
| + name = node.attr
|
| + else:
|
| + name = node.id
|
| + if name != 'None':
|
| + error = Error(node.lineno, msg + ' ' + name)
|
| + self.errors.append(error)
|
| +
|
| + def _is_defined_after(self, scope, pyname, lineno):
|
| + location = pyname.get_definition_location()
|
| + if location is not None and location[1] is not None:
|
| + if location[0] == self.pymodule and \
|
| + lineno <= location[1] <= scope.get_end():
|
| + return True
|
| +
|
| +
|
| +class Error(object):
|
| +
|
| + def __init__(self, lineno, error):
|
| + self.lineno = lineno
|
| + self.error = error
|
| +
|
| + def __str__(self):
|
| + return '%s: %s' % (self.lineno, self.error)
|
|
|