Cleanup finder.

This commit is contained in:
Dave Halter
2014-12-16 17:31:28 +01:00
parent 869b0b4189
commit 3d080afd71

View File

@@ -14,7 +14,7 @@ check for -> a is a string). There's big potential in these checks.
from itertools import chain from itertools import chain
from jedi._compatibility import hasattr, unicode, u from jedi._compatibility import hasattr, unicode, u
from jedi.parser import tree as pr, tokenize from jedi.parser import tree as pr
from jedi.parser import fast from jedi.parser import fast
from jedi import debug from jedi import debug
from jedi import common from jedi import common
@@ -157,27 +157,25 @@ class NameFinder(object):
# filter_private_variable(name_list_scope, scope, name.value): # filter_private_variable(name_list_scope, scope, name.value):
# continue # continue
# Exclude `arr[1] =` from the result set. # TODO we ignore a lot of elements here that should not be
if not self._name_is_array_assignment(name, stmt): # ignored. But then again flow_analysis also stops when the
# TODO we ignore a lot of elements here that should not be # input scope is reached. This is not correct: variables
# ignored. But then again flow_analysis also stops when the # might still have conditions if defined outside of the
# input scope is reached. This is not correct: variables # current scope.
# might still have conditions if defined outside of the if isinstance(stmt, (pr.Param, pr.Import)) \
# current scope. or isinstance(name_list_scope, (pr.Lambda, er.Instance, InterpreterNamespace)) \
if isinstance(stmt, (pr.Param, pr.Import)) \ or isinstance(scope, compiled.CompiledObject):
or isinstance(name_list_scope, (pr.Lambda, er.Instance, InterpreterNamespace)) \ # Always reachable.
or isinstance(scope, compiled.CompiledObject): names.append(name)
# Always reachable. else:
check = flow_analysis.break_check(self._evaluator,
name_list_scope,
stmt,
self.scope)
if check is not flow_analysis.UNREACHABLE:
names.append(name) names.append(name)
else: if check is flow_analysis.REACHABLE:
check = flow_analysis.break_check(self._evaluator, break
name_list_scope,
stmt,
self.scope)
if check is not flow_analysis.UNREACHABLE:
names.append(name)
if check is flow_analysis.REACHABLE:
break
if names and self._is_name_break_scope(stmt): if names and self._is_name_break_scope(stmt):
if self._does_scope_break_immediately(scope, name_list_scope): if self._does_scope_break_immediately(scope, name_list_scope):
@@ -253,36 +251,6 @@ class NameFinder(object):
else: else:
return True return True
def _name_is_array_assignment(self, name, stmt):
return False
# TODO DELETE this? or change it?
if stmt.isinstance(pr.ExprStmt):
def is_execution(calls):
for c in calls:
if isinstance(c, (unicode, str, tokenize.Token)):
continue
if c.isinstance(pr.Array):
if is_execution(c):
return True
elif c.isinstance(pr.Call):
# Compare start_pos, because names may be different
# because of executions.
if c.name.start_pos == name.start_pos \
and isinstance(c.next, pr.Array):
return True
return False
is_exe = False
for assignee, op in stmt.assignment_details:
is_exe |= is_execution(assignee)
if is_exe:
# filter array[3] = ...
# TODO check executions for dict contents
return True
return False
def _names_to_types(self, names): def _names_to_types(self, names):
types = [] types = []
@@ -573,82 +541,9 @@ def get_names_of_scope(evaluator, scope, position=None, star_search=True, includ
and isinstance(in_func_scope, (pr.Function, er.FunctionExecution)): and isinstance(in_func_scope, (pr.Function, er.FunctionExecution)):
position = None position = None
# Add star imports. # Add builtins to the global scope.
if star_search: if include_builtin:
""" yield compiled.builtin, compiled.builtin.get_defined_names()
for s in imports.remove_star_imports(evaluator, origin_scope.get_parent_until()):
for g in get_names_of_scope(evaluator, s, star_search=False):
yield g
"""
# Add builtins to the global scope.
if include_builtin:
yield compiled.builtin, compiled.builtin.get_defined_names()
def _assign_tuples(tup, results, seek_name):
"""
This is a normal assignment checker. In python functions and other things
can return tuples:
>>> a, b = 1, ""
>>> a, (b, c) = 1, ("", 1.0)
Here, if `seek_name` is "a", the number type will be returned.
The first part (before `=`) is the param tuples, the second one result.
:type tup: pr.Array
"""
def eval_results(index):
types = []
for r in results:
try:
func = r.get_exact_index_types
except AttributeError:
debug.warning("invalid tuple lookup %s of result %s in %s",
tup, results, seek_name)
else:
with common.ignored(IndexError):
types += func(index)
return types
result = []
for i, stmt in enumerate(tup):
# Used in assignments. There is just one call and no other things,
# therefore we can just assume, that the first part is important.
command = stmt.expression_list()[0]
if tup.type == pr.Array.NOARRAY:
# unnessecary braces -> just remove.
r = results
else:
r = eval_results(i)
# LHS of tuples can be nested, so resolve it recursively
result += find_assignments(command, r, seek_name)
return result
def find_assignments(lhs, results, seek_name):
"""
Check if `seek_name` is in the left hand side `lhs` of assignment.
`lhs` can simply be a variable (`pr.Call`) or a tuple/list (`pr.Array`)
representing the following cases::
a = 1 # lhs is pr.Call
(a, b) = 2 # lhs is pr.Array
:type lhs: pr.Call
:type results: list
:type seek_name: str
"""
if isinstance(lhs, pr.Array):
return _assign_tuples(lhs, results, seek_name)
elif unicode(lhs.name) == seek_name:
return results
else:
return []
def check_tuple_assignments(types, name): def check_tuple_assignments(types, name):