forked from VimPlug/jedi
Enable better ways for analysis to analyze loop variables.
This commit is contained in:
@@ -570,7 +570,7 @@ class Script(object):
|
|||||||
# Iterate tuples.
|
# Iterate tuples.
|
||||||
unpack_tuple_to_dict(self._evaluator, types, testlist)
|
unpack_tuple_to_dict(self._evaluator, types, testlist)
|
||||||
else:
|
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]
|
ana = [a for a in self._evaluator.analysis if self.path == a.path]
|
||||||
return sorted(set(ana), key=lambda x: x.line)
|
return sorted(set(ana), key=lambda x: x.line)
|
||||||
|
|||||||
@@ -409,9 +409,15 @@ class Evaluator(object):
|
|||||||
# TODO rename to goto_definitions
|
# TODO rename to goto_definitions
|
||||||
def_ = name.get_definition()
|
def_ = name.get_definition()
|
||||||
if def_.type == 'expr_stmt' and name in def_.get_defined_names():
|
if def_.type == 'expr_stmt' and name in def_.get_defined_names():
|
||||||
return self.eval_statement(def_, name)
|
types = self.eval_statement(def_, name)
|
||||||
call = helpers.call_of_name(name)
|
elif def_.type == 'for_stmt':
|
||||||
return self.eval_element(call)
|
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)
|
||||||
|
types = self.eval_element(call)
|
||||||
|
return types
|
||||||
|
|
||||||
def goto(self, name):
|
def goto(self, name):
|
||||||
def resolve_implicit_imports(names):
|
def resolve_implicit_imports(names):
|
||||||
|
|||||||
@@ -251,7 +251,6 @@ class NameFinder(object):
|
|||||||
def _names_to_types(self, names, search_global):
|
def _names_to_types(self, names, search_global):
|
||||||
types = set()
|
types = set()
|
||||||
|
|
||||||
debug.warning('start nt %s', names)
|
|
||||||
# Add isinstance and other if/assert knowledge.
|
# Add isinstance and other if/assert knowledge.
|
||||||
if isinstance(self.name_str, tree.Name):
|
if isinstance(self.name_str, tree.Name):
|
||||||
# Ignore FunctionExecution parents for now.
|
# Ignore FunctionExecution parents for now.
|
||||||
|
|||||||
@@ -452,7 +452,6 @@ def py__getitem__(evaluator, types, index, node):
|
|||||||
if isinstance(typ, Array) and typ.type == 'dict':
|
if isinstance(typ, Array) and typ.type == 'dict':
|
||||||
types.remove(typ)
|
types.remove(typ)
|
||||||
result |= typ.dict_values()
|
result |= typ.dict_values()
|
||||||
print('ITER', types, py__iter__types(evaluator, types))
|
|
||||||
return result | py__iter__types(evaluator, types)
|
return result | py__iter__types(evaluator, types)
|
||||||
|
|
||||||
for typ in types:
|
for typ in types:
|
||||||
|
|||||||
@@ -144,6 +144,51 @@ class Base(object):
|
|||||||
scope = scope.parent
|
scope = scope.parent
|
||||||
return scope
|
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):
|
def is_scope(self):
|
||||||
# Default is not being a scope. Just inherit from Scope.
|
# Default is not being a scope. Just inherit from Scope.
|
||||||
return False
|
return False
|
||||||
@@ -288,22 +333,6 @@ class Name(Leaf):
|
|||||||
return "<%s: %s@%s,%s>" % (type(self).__name__, self.value,
|
return "<%s: %s@%s,%s>" % (type(self).__name__, self.value,
|
||||||
self.start_pos[0], self.start_pos[1])
|
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):
|
def is_definition(self):
|
||||||
stmt = self.get_definition()
|
stmt = self.get_definition()
|
||||||
if stmt.type in ('funcdef', 'classdef', 'file_input', 'param'):
|
if stmt.type in ('funcdef', 'classdef', 'file_input', 'param'):
|
||||||
@@ -317,35 +346,6 @@ class Name(Leaf):
|
|||||||
'comp_for', 'with_stmt') \
|
'comp_for', 'with_stmt') \
|
||||||
and self in stmt.get_defined_names()
|
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):
|
def nodes_to_execute(self, last_added=False):
|
||||||
if last_added is False:
|
if last_added is False:
|
||||||
yield self
|
yield self
|
||||||
@@ -500,7 +500,8 @@ class Node(BaseNode):
|
|||||||
_IGNORE_EXECUTE_NODES = set([
|
_IGNORE_EXECUTE_NODES = set([
|
||||||
'suite', 'subscriptlist', 'subscript', 'simple_stmt', 'sliceop',
|
'suite', 'subscriptlist', 'subscript', 'simple_stmt', 'sliceop',
|
||||||
'testlist_comp', 'dictorsetmaker', 'trailer', 'decorators',
|
'testlist_comp', 'dictorsetmaker', 'trailer', 'decorators',
|
||||||
'decorated', 'arglist', 'argument'
|
'decorated', 'arglist', 'argument', 'exprlist', 'testlist',
|
||||||
|
'testlist_safe', 'testlist1'
|
||||||
])
|
])
|
||||||
|
|
||||||
def __init__(self, type, children):
|
def __init__(self, type, children):
|
||||||
@@ -1024,12 +1025,6 @@ class ForStmt(Flow):
|
|||||||
type = 'for_stmt'
|
type = 'for_stmt'
|
||||||
__slots__ = ()
|
__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):
|
def get_input_node(self):
|
||||||
"""
|
"""
|
||||||
Returns the input node ``y`` from: ``for x in y:``.
|
Returns the input node ``y`` from: ``for x in y:``.
|
||||||
|
|||||||
@@ -4,3 +4,11 @@ a
|
|||||||
|
|
||||||
x = [1]
|
x = [1]
|
||||||
x[0], b = {'a': 1, 'b': '2'}
|
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
|
||||||
|
|||||||
Reference in New Issue
Block a user