1
0
forked from VimPlug/jedi

Enable better ways for analysis to analyze loop variables.

This commit is contained in:
Dave Halter
2015-12-11 20:25:49 +01:00
parent 8d3be10270
commit 75ac2b9686
6 changed files with 65 additions and 58 deletions

View File

@@ -570,7 +570,7 @@ class Script(object):
# Iterate tuples.
unpack_tuple_to_dict(self._evaluator, types, testlist)
else:
try_iter_content(self._evaluator.eval_element(node))
try_iter_content(self._evaluator.goto_definition(node))
ana = [a for a in self._evaluator.analysis if self.path == a.path]
return sorted(set(ana), key=lambda x: x.line)

View File

@@ -409,9 +409,15 @@ class Evaluator(object):
# TODO rename to goto_definitions
def_ = name.get_definition()
if def_.type == 'expr_stmt' and name in def_.get_defined_names():
return self.eval_statement(def_, name)
types = self.eval_statement(def_, name)
elif def_.type == 'for_stmt':
container_types = self.eval_element(def_.children[3])
for_types = iterable.py__iter__types(self, container_types, def_.children[3])
types = finder.check_tuple_assignments(self, for_types, name)
else:
call = helpers.call_of_name(name)
return self.eval_element(call)
types = self.eval_element(call)
return types
def goto(self, name):
def resolve_implicit_imports(names):

View File

@@ -251,7 +251,6 @@ class NameFinder(object):
def _names_to_types(self, names, search_global):
types = set()
debug.warning('start nt %s', names)
# Add isinstance and other if/assert knowledge.
if isinstance(self.name_str, tree.Name):
# Ignore FunctionExecution parents for now.

View File

@@ -452,7 +452,6 @@ def py__getitem__(evaluator, types, index, node):
if isinstance(typ, Array) and typ.type == 'dict':
types.remove(typ)
result |= typ.dict_values()
print('ITER', types, py__iter__types(evaluator, types))
return result | py__iter__types(evaluator, types)
for typ in types:

View File

@@ -144,6 +144,51 @@ class Base(object):
scope = scope.parent
return scope
def get_definition(self):
scope = self
while scope.parent is not None:
parent = scope.parent
if scope.isinstance(Node, Name) and parent.type != 'simple_stmt':
if scope.type == 'testlist_comp':
try:
if isinstance(scope.children[1], CompFor):
return scope.children[1]
except IndexError:
pass
scope = parent
else:
break
return scope
def assignment_indexes(self):
"""
Returns an array of tuple(int, node) of the indexes that are used in
tuple assignments.
For example if the name is ``y`` in the following code::
x, (y, z) = 2, ''
would result in ``[(1, xyz_node), (0, yz_node)]``.
"""
indexes = []
node = self.parent
compare = self
while node is not None:
if is_node(node, 'testlist_comp', 'testlist_star_expr', 'exprlist'):
for i, child in enumerate(node.children):
if child == compare:
indexes.insert(0, (int(i / 2), node))
break
else:
raise LookupError("Couldn't find the assignment.")
elif isinstance(node, (ExprStmt, CompFor)):
break
compare = node
node = node.parent
return indexes
def is_scope(self):
# Default is not being a scope. Just inherit from Scope.
return False
@@ -288,22 +333,6 @@ class Name(Leaf):
return "<%s: %s@%s,%s>" % (type(self).__name__, self.value,
self.start_pos[0], self.start_pos[1])
def get_definition(self):
scope = self
while scope.parent is not None:
parent = scope.parent
if scope.isinstance(Node, Name) and parent.type != 'simple_stmt':
if scope.type == 'testlist_comp':
try:
if isinstance(scope.children[1], CompFor):
return scope.children[1]
except IndexError:
pass
scope = parent
else:
break
return scope
def is_definition(self):
stmt = self.get_definition()
if stmt.type in ('funcdef', 'classdef', 'file_input', 'param'):
@@ -317,35 +346,6 @@ class Name(Leaf):
'comp_for', 'with_stmt') \
and self in stmt.get_defined_names()
def assignment_indexes(self):
"""
Returns an array of tuple(int, node) of the indexes that are used in
tuple assignments.
For example if the name is ``y`` in the following code::
x, (y, z) = 2, ''
would result in ``[(1, xyz_node), (0, yz_node)]``.
"""
indexes = []
node = self.parent
compare = self
while node is not None:
if is_node(node, 'testlist_comp', 'testlist_star_expr', 'exprlist'):
for i, child in enumerate(node.children):
if child == compare:
indexes.insert(0, (int(i / 2), node))
break
else:
raise LookupError("Couldn't find the assignment.")
elif isinstance(node, (ExprStmt, CompFor)):
break
compare = node
node = node.parent
return indexes
def nodes_to_execute(self, last_added=False):
if last_added is False:
yield self
@@ -500,7 +500,8 @@ class Node(BaseNode):
_IGNORE_EXECUTE_NODES = set([
'suite', 'subscriptlist', 'subscript', 'simple_stmt', 'sliceop',
'testlist_comp', 'dictorsetmaker', 'trailer', 'decorators',
'decorated', 'arglist', 'argument'
'decorated', 'arglist', 'argument', 'exprlist', 'testlist',
'testlist_safe', 'testlist1'
])
def __init__(self, type, children):
@@ -1024,12 +1025,6 @@ class ForStmt(Flow):
type = 'for_stmt'
__slots__ = ()
def nodes_to_execute(self, last_added=False):
# We shouldn't include the definitions.
for child in self.children[3:]:
for node_to_execute in child.nodes_to_execute():
yield node_to_execute
def get_input_node(self):
"""
Returns the input node ``y`` from: ``for x in y:``.

View File

@@ -4,3 +4,11 @@ a
x = [1]
x[0], b = {'a': 1, 'b': '2'}
dct = {3: ''}
for x in dct:
pass
#! 4 type-error-not-iterable
for x, y in dct:
pass