1
0
forked from VimPlug/jedi

fix a lot of the dynamic issues

This commit is contained in:
Dave Halter
2013-12-25 18:16:40 +01:00
parent b768e214eb
commit 5d486f0e3c
3 changed files with 31 additions and 25 deletions
+2 -2
View File
@@ -424,8 +424,8 @@ class Evaluator(object):
while flow_scope: while flow_scope:
# TODO check if result is in scope -> no evaluation necessary # TODO check if result is in scope -> no evaluation necessary
n = dynamic.check_flow_information(flow_scope, name_str, n = dynamic.check_flow_information(self, flow_scope,
position) name_str, position)
if n: if n:
result = n result = n
break break
+26 -20
View File
@@ -192,6 +192,7 @@ def search_params(evaluator, param):
if first: if first:
scopes = evaluator.follow_call_path(iter(first), scope, pos) scopes = evaluator.follow_call_path(iter(first), scope, pos)
pos = None pos = None
from jedi.evaluate import representation as er
for scope in scopes: for scope in scopes:
s = evaluator.find_name(scope, func_name, position=pos, s = evaluator.find_name(scope, func_name, position=pos,
search_global=not first, search_global=not first,
@@ -248,7 +249,7 @@ def search_params(evaluator, param):
return result return result
def check_array_additions(array): def check_array_additions(evaluator, array):
""" Just a mapper function for the internal _check_array_additions """ """ Just a mapper function for the internal _check_array_additions """
if not pr.Array.is_type(array._array, pr.Array.LIST, pr.Array.SET): if not pr.Array.is_type(array._array, pr.Array.LIST, pr.Array.SET):
# TODO also check for dict updates # TODO also check for dict updates
@@ -296,8 +297,8 @@ def _scan_statement(stmt, search_name, assignment_details=False):
return result return result
@memoize_default([]) @memoize_default([], evaluator_is_first_arg=True)
def _check_array_additions(compare_array, module, is_list): def _check_array_additions(evaluator, compare_array, module, is_list):
""" """
Checks if a `pr.Array` has "add" statements: Checks if a `pr.Array` has "add" statements:
>>> a = [""] >>> a = [""]
@@ -324,7 +325,7 @@ def _check_array_additions(compare_array, module, is_list):
position = c.start_pos position = c.start_pos
scope = c.get_parent_until(pr.IsScope) scope = c.get_parent_until(pr.IsScope)
found = evaluate.follow_call_path(backtrack_path, scope, position) found = evaluator.follow_call_path(backtrack_path, scope, position)
if not compare_array in found: if not compare_array in found:
continue continue
@@ -333,20 +334,22 @@ def _check_array_additions(compare_array, module, is_list):
continue # no params: just ignore it continue # no params: just ignore it
if add_name in ['append', 'add']: if add_name in ['append', 'add']:
for param in params: for param in params:
result += evaluate.follow_statement(param) result += evaluator.follow_statement(param)
elif add_name in ['insert']: elif add_name in ['insert']:
try: try:
second_param = params[1] second_param = params[1]
except IndexError: except IndexError:
continue continue
else: else:
result += evaluate.follow_statement(second_param) result += evaluator.follow_statement(second_param)
elif add_name in ['extend', 'update']: elif add_name in ['extend', 'update']:
for param in params: for param in params:
iterators = evaluate.follow_statement(param) iterators = evaluator.follow_statement(param)
result += evaluate.get_iterator_types(iterators) result += evaluator.get_iterator_types(iterators)
return result return result
from jedi.evaluate import representation as er
def get_execution_parent(element, *stop_classes): def get_execution_parent(element, *stop_classes):
""" Used to get an Instance/Execution parent """ """ Used to get an Instance/Execution parent """
if isinstance(element, er.Array): if isinstance(element, er.Array):
@@ -387,21 +390,21 @@ def _check_array_additions(compare_array, module, is_list):
if isinstance(comp_arr_parent, er.InstanceElement): if isinstance(comp_arr_parent, er.InstanceElement):
stmt = er.InstanceElement(comp_arr_parent.instance, stmt) stmt = er.InstanceElement(comp_arr_parent.instance, stmt)
if evaluate.follow_statement.push_stmt(stmt): if evaluator.follow_statement.push_stmt(stmt):
# check recursion # check recursion
continue continue
res += check_calls(_scan_statement(stmt, n), n) res += check_calls(_scan_statement(stmt, n), n)
evaluate.follow_statement.pop_stmt() evaluator.follow_statement.pop_stmt()
# reset settings # reset settings
settings.dynamic_params_for_other_modules = temp_param_add settings.dynamic_params_for_other_modules = temp_param_add
return res return res
def check_array_instances(instance): def check_array_instances(evaluator, instance):
"""Used for set() and list() instances.""" """Used for set() and list() instances."""
if not settings.dynamic_arrays_instances: if not settings.dynamic_arrays_instances:
return instance.var_args return instance.var_args
ai = ArrayInstance(instance) ai = ArrayInstance(evaluator, instance)
return [ai] return [ai]
@@ -411,7 +414,8 @@ class ArrayInstance(pr.Base):
This is definitely a hack, but a good one :-) This is definitely a hack, but a good one :-)
It makes it possible to use set/list conversions. It makes it possible to use set/list conversions.
""" """
def __init__(self, instance): def __init__(self, evaluator, instance):
self._evaluator = evaluator
self.instance = instance self.instance = instance
self.var_args = instance.var_args self.var_args = instance.var_args
@@ -421,8 +425,9 @@ class ArrayInstance(pr.Base):
lists/sets are too complicated too handle that. lists/sets are too complicated too handle that.
""" """
items = [] items = []
from jedi.evaluate import representation as er
for stmt in self.var_args: for stmt in self.var_args:
for typ in evaluate.follow_statement(stmt): for typ in self._evaluator.follow_statement(stmt):
if isinstance(typ, er.Instance) and len(typ.var_args): if isinstance(typ, er.Instance) and len(typ.var_args):
array = typ.var_args[0] array = typ.var_args[0]
if isinstance(array, ArrayInstance): if isinstance(array, ArrayInstance):
@@ -435,7 +440,7 @@ class ArrayInstance(pr.Base):
'ArrayInstance recursion', 'ArrayInstance recursion',
self.var_args) self.var_args)
continue continue
items += evaluate.get_iterator_types([typ]) items += self._evaluator.get_iterator_types([typ])
# TODO check if exclusion of tuple is a problem here. # TODO check if exclusion of tuple is a problem here.
if isinstance(self.var_args, tuple) or self.var_args.parent is None: if isinstance(self.var_args, tuple) or self.var_args.parent is None:
@@ -447,7 +452,7 @@ class ArrayInstance(pr.Base):
return items return items
def check_flow_information(flow, search_name, pos): def check_flow_information(evaluator, flow, search_name, pos):
""" Try to find out the type of a variable just with the information that """ Try to find out the type of a variable just with the information that
is given by the flows: e.g. It is also responsible for assert checks.:: is given by the flows: e.g. It is also responsible for assert checks.::
@@ -463,17 +468,18 @@ def check_flow_information(flow, search_name, pos):
for ass in reversed(flow.asserts): for ass in reversed(flow.asserts):
if pos is None or ass.start_pos > pos: if pos is None or ass.start_pos > pos:
continue continue
result = _check_isinstance_type(ass, search_name) result = _check_isinstance_type(evaluator, ass, search_name)
if result: if result:
break break
if isinstance(flow, pr.Flow) and not result: if isinstance(flow, pr.Flow) and not result:
if flow.command in ['if', 'while'] and len(flow.inputs) == 1: if flow.command in ['if', 'while'] and len(flow.inputs) == 1:
result = _check_isinstance_type(flow.inputs[0], search_name) result = _check_isinstance_type(evaluator, flow.inputs[0], search_name)
return result return result
def _check_isinstance_type(stmt, search_name): def _check_isinstance_type(evaluator, stmt, search_name):
from jedi.evaluate import representation as er
try: try:
commands = stmt.get_commands() commands = stmt.get_commands()
# this might be removed if we analyze and, etc # this might be removed if we analyze and, etc
@@ -496,7 +502,7 @@ def _check_isinstance_type(stmt, search_name):
return [] return []
result = [] result = []
for c in evaluate.follow_call(classes[0]): for c in evaluator.follow_call(classes[0]):
if isinstance(c, er.Array): if isinstance(c, er.Array):
result += c.get_index_types() result += c.get_index_types()
else: else:
+3 -3
View File
@@ -62,7 +62,7 @@ class Instance(use_metaclass(CachedMetaClass, Executable)):
if str(base.name) in ['list', 'set'] \ if str(base.name) in ['list', 'set'] \
and builtin.Builtin.scope == base.get_parent_until(): and builtin.Builtin.scope == base.get_parent_until():
# compare the module path with the builtin name. # compare the module path with the builtin name.
self.var_args = dynamic.check_array_instances(self) self.var_args = dynamic.check_array_instances(evaluator, self)
else: else:
# need to execute the __init__ function, because the dynamic param # need to execute the __init__ function, because the dynamic param
# searching needs it. # searching needs it.
@@ -785,8 +785,8 @@ class Execution(Executable):
class Generator(use_metaclass(CachedMetaClass, pr.Base, Iterable)): class Generator(use_metaclass(CachedMetaClass, pr.Base, Iterable)):
""" Cares for `yield` statements. """ """ Cares for `yield` statements. """
def __init__(self, evaluator, func, var_args): def __init__(self, evaluator, func, var_args):
# Need evaluator for `CachedMetaClass`.
super(Generator, self).__init__() super(Generator, self).__init__()
self._evaluator = evaluator
self.func = func self.func = func
self.var_args = var_args self.var_args = var_args
@@ -860,7 +860,7 @@ class Array(use_metaclass(CachedMetaClass, pr.Base, Iterable)):
return self.get_exact_index_types(index.var_args[0]) return self.get_exact_index_types(index.var_args[0])
result = list(self._follow_values(self._array.values)) result = list(self._follow_values(self._array.values))
result += dynamic.check_array_additions(self) result += dynamic.check_array_additions(evaluator, self)
return set(result) return set(result)
def get_exact_index_types(self, mixed_index): def get_exact_index_types(self, mixed_index):