mirror of
https://github.com/davidhalter/jedi.git
synced 2025-12-08 14:54:47 +08:00
Introduce an additional node parameter for py__iter__ which helps static analysis.
This commit is contained in:
@@ -164,8 +164,9 @@ class Evaluator(object):
|
|||||||
# Iterate through result and add the values, that's possible
|
# Iterate through result and add the values, that's possible
|
||||||
# only in for loops without clutter, because they are
|
# only in for loops without clutter, because they are
|
||||||
# predictable. Also only do it, if the variable is not a tuple.
|
# predictable. Also only do it, if the variable is not a tuple.
|
||||||
for_iterables = self.eval_element(for_stmt.get_input_node())
|
node = for_stmt.get_input_node()
|
||||||
ordered = list(iterable.py__iter__(self, for_iterables))
|
for_iterables = self.eval_element(node)
|
||||||
|
ordered = list(iterable.py__iter__(self, for_iterables, node))
|
||||||
|
|
||||||
for index_types in ordered:
|
for index_types in ordered:
|
||||||
dct = {str(for_stmt.children[1]): index_types}
|
dct = {str(for_stmt.children[1]): index_types}
|
||||||
|
|||||||
@@ -198,16 +198,19 @@ class CompiledObject(Base):
|
|||||||
pass # self.obj maynot have an __iter__ method.
|
pass # self.obj maynot have an __iter__ method.
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
@property
|
||||||
def py__iter__(self):
|
def py__iter__(self):
|
||||||
if not hasattr(self.obj, '__iter__'):
|
if not hasattr(self.obj, '__iter__'):
|
||||||
debug.warning('Tried to call __getitem__ on non-iterable.')
|
raise AttributeError('No __iter__ on %s' % self.obj)
|
||||||
return
|
|
||||||
if type(self.obj) not in (str, list, tuple, unicode, bytes, bytearray, dict):
|
|
||||||
# Get rid of side effects, we won't call custom `__getitem__`s.
|
|
||||||
return
|
|
||||||
|
|
||||||
for obj in self.obj:
|
def actual():
|
||||||
yield set([CompiledObject(obj)])
|
if type(self.obj) not in (str, list, tuple, unicode, bytes, bytearray, dict):
|
||||||
|
# Get rid of side effects, we won't call custom `__getitem__`s.
|
||||||
|
return
|
||||||
|
|
||||||
|
for obj in self.obj:
|
||||||
|
yield set([CompiledObject(obj)])
|
||||||
|
return actual
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
|
|||||||
@@ -301,7 +301,7 @@ def _name_to_types(evaluator, name, scope):
|
|||||||
typ = name.get_definition()
|
typ = name.get_definition()
|
||||||
if typ.isinstance(tree.ForStmt, tree.CompFor):
|
if typ.isinstance(tree.ForStmt, tree.CompFor):
|
||||||
container_types = evaluator.eval_element(typ.children[3])
|
container_types = evaluator.eval_element(typ.children[3])
|
||||||
for_types = iterable.py__iter__types(evaluator, container_types)
|
for_types = iterable.py__iter__types(evaluator, container_types, typ.children[3])
|
||||||
types = check_tuple_assignments(for_types, name)
|
types = check_tuple_assignments(for_types, name)
|
||||||
elif isinstance(typ, tree.Param):
|
elif isinstance(typ, tree.Param):
|
||||||
types = _eval_param(evaluator, typ, scope)
|
types = _eval_param(evaluator, typ, scope)
|
||||||
|
|||||||
@@ -151,8 +151,8 @@ class Comprehension(IterableWrapper):
|
|||||||
return helpers.deep_ast_copy(self._get_comprehension().children[0], parent=last_comp)
|
return helpers.deep_ast_copy(self._get_comprehension().children[0], parent=last_comp)
|
||||||
|
|
||||||
def py__iter__(self):
|
def py__iter__(self):
|
||||||
def nested(input_types, comp_fors):
|
def nested(input_types, comp_fors, node):
|
||||||
iterated = py__iter__(evaluator, input_types)
|
iterated = py__iter__(evaluator, input_types, node)
|
||||||
comp_for = comp_fors[0]
|
comp_for = comp_fors[0]
|
||||||
exprlist = comp_for.children[1]
|
exprlist = comp_for.children[1]
|
||||||
for types in iterated:
|
for types in iterated:
|
||||||
@@ -160,7 +160,7 @@ class Comprehension(IterableWrapper):
|
|||||||
unpack_tuple_to_dict(evaluator, types, exprlist)
|
unpack_tuple_to_dict(evaluator, types, exprlist)
|
||||||
try:
|
try:
|
||||||
if len(comp_fors) > 1:
|
if len(comp_fors) > 1:
|
||||||
for result in nested(types, comp_fors[1:]):
|
for result in nested(types, comp_fors[1:], exprlist):
|
||||||
yield result
|
yield result
|
||||||
else:
|
else:
|
||||||
yield evaluator.eval_element(self.eval_node())
|
yield evaluator.eval_element(self.eval_node())
|
||||||
@@ -171,7 +171,7 @@ class Comprehension(IterableWrapper):
|
|||||||
comp_fors = list(self._get_comp_for().get_comp_fors())
|
comp_fors = list(self._get_comp_for().get_comp_fors())
|
||||||
input_node = comp_fors[0].children[-1]
|
input_node = comp_fors[0].children[-1]
|
||||||
input_types = evaluator.eval_element(input_node)
|
input_types = evaluator.eval_element(input_node)
|
||||||
for result in nested(input_types, comp_fors):
|
for result in nested(input_types, comp_fors, input_node):
|
||||||
yield result
|
yield result
|
||||||
|
|
||||||
def get_exact_index_types(self, index):
|
def get_exact_index_types(self, index):
|
||||||
@@ -466,26 +466,24 @@ def unpack_tuple_to_dict(evaluator, types, exprlist):
|
|||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
||||||
def py__iter__(evaluator, types):
|
def py__iter__(evaluator, types, node):
|
||||||
debug.dbg('py__iter__')
|
debug.dbg('py__iter__')
|
||||||
for typ in types:
|
for typ in types:
|
||||||
try:
|
try:
|
||||||
iter_method = typ.py__iter__
|
iter_method = typ.py__iter__
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
raise NotImplementedError
|
analysis.add(evaluator, 'type-error-not-iterable', node)
|
||||||
analysis.add(evaluator, 'type-error-not-iterable', element)
|
|
||||||
debug.warning('iterator/for loop input wrong: %s', it)
|
|
||||||
else:
|
else:
|
||||||
for result in iter_method():
|
for result in iter_method():
|
||||||
yield result
|
yield result
|
||||||
|
|
||||||
|
|
||||||
def py__iter__types(evaluator, types):
|
def py__iter__types(evaluator, types, node):
|
||||||
"""
|
"""
|
||||||
Calls `py__iter__`, but ignores the ordering in the end and just returns
|
Calls `py__iter__`, but ignores the ordering in the end and just returns
|
||||||
all types that it contains.
|
all types that it contains.
|
||||||
"""
|
"""
|
||||||
return unite(py__iter__(evaluator, types))
|
return unite(py__iter__(evaluator, types, node))
|
||||||
|
|
||||||
|
|
||||||
def check_array_additions(evaluator, array):
|
def check_array_additions(evaluator, array):
|
||||||
@@ -529,8 +527,9 @@ def _check_array_additions(evaluator, compare_array, module, is_list):
|
|||||||
result |= unite(evaluator.eval_element(node) for node in nodes)
|
result |= unite(evaluator.eval_element(node) for node in nodes)
|
||||||
elif add_name in ['extend', 'update']:
|
elif add_name in ['extend', 'update']:
|
||||||
for key, nodes in params:
|
for key, nodes in params:
|
||||||
types = unite(evaluator.eval_element(n) for n in nodes)
|
for node in nodes:
|
||||||
result |= py__iter__types(evaluator, types)
|
types = evaluator.eval_element(node)
|
||||||
|
result |= py__iter__types(evaluator, types, node)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
from jedi.evaluate import representation as er, param
|
from jedi.evaluate import representation as er, param
|
||||||
@@ -641,8 +640,9 @@ class _ArrayInstance(IterableWrapper):
|
|||||||
"""
|
"""
|
||||||
items = set()
|
items = set()
|
||||||
for key, nodes in self.var_args.unpack():
|
for key, nodes in self.var_args.unpack():
|
||||||
types = unite(self._evaluator.eval_element(n) for n in nodes)
|
for node in nodes:
|
||||||
items |= py__iter__types(self._evaluator, types)
|
types = self._evaluator.eval_element(node)
|
||||||
|
items |= py__iter__types(self._evaluator, types, node)
|
||||||
|
|
||||||
module = self.var_args.get_parent_until()
|
module = self.var_args.get_parent_until()
|
||||||
is_list = str(self.instance.name) == 'list'
|
is_list = str(self.instance.name) == 'list'
|
||||||
@@ -657,13 +657,13 @@ class _ArrayInstance(IterableWrapper):
|
|||||||
else:
|
else:
|
||||||
types = unite(self._evaluator.eval_element(node) for node in first_nodes)
|
types = unite(self._evaluator.eval_element(node) for node in first_nodes)
|
||||||
|
|
||||||
for types in py__iter__(self._evaluator, types):
|
for types in py__iter__(self._evaluator, types, first_nodes[0]):
|
||||||
yield types
|
yield types
|
||||||
module = self.var_args.get_parent_until()
|
module = self.var_args.get_parent_until()
|
||||||
is_list = str(self.instance.name) == 'list'
|
is_list = str(self.instance.name) == 'list'
|
||||||
additions = _check_array_additions(self._evaluator, self.instance, module, is_list)
|
additions = _check_array_additions(self._evaluator, self.instance, module, is_list)
|
||||||
if additions:
|
if additions:
|
||||||
yield additions
|
yield additions
|
||||||
|
|
||||||
|
|
||||||
class Slice(object):
|
class Slice(object):
|
||||||
|
|||||||
@@ -16,11 +16,12 @@ def try_iter_content(types):
|
|||||||
"""Helper method for static analysis."""
|
"""Helper method for static analysis."""
|
||||||
for typ in types:
|
for typ in types:
|
||||||
try:
|
try:
|
||||||
f = typ.iter_content
|
f = typ.py__iter__
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
try_iter_content(f())
|
for iter_types in f():
|
||||||
|
try_iter_content(iter_types)
|
||||||
|
|
||||||
|
|
||||||
class Arguments(tree.Base):
|
class Arguments(tree.Base):
|
||||||
|
|||||||
@@ -688,8 +688,9 @@ class FunctionExecution(Executed):
|
|||||||
for yield_ in yields:
|
for yield_ in yields:
|
||||||
yield evaluator.eval_element(yield_.children[1])
|
yield evaluator.eval_element(yield_.children[1])
|
||||||
else:
|
else:
|
||||||
for_types = evaluator.eval_element(for_stmt.get_input_node())
|
input_node = for_stmt.get_input_node()
|
||||||
ordered = iterable.py__iter__(evaluator, for_types)
|
for_types = evaluator.eval_element(input_node)
|
||||||
|
ordered = iterable.py__iter__(evaluator, for_types, input_node)
|
||||||
for index_types in ordered:
|
for index_types in ordered:
|
||||||
dct = {str(for_stmt.children[1]): index_types}
|
dct = {str(for_stmt.children[1]): index_types}
|
||||||
evaluator.predefined_if_name_dict_dict[for_stmt] = dct
|
evaluator.predefined_if_name_dict_dict[for_stmt] = dct
|
||||||
|
|||||||
Reference in New Issue
Block a user