| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091 |
- """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.pycore.resource_to_pyobject(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)
|