diff --git a/dynamic.py b/dynamic.py index eabce27b..e2a28399 100644 --- a/dynamic.py +++ b/dynamic.py @@ -8,16 +8,16 @@ working quite good. import parsing import evaluate -import builtin import helpers import settings +import debug # This is something like the sys.path, but only for searching params. It means # that this is the order in which Jedi searches params. search_param_modules = ['.'] - search_param_cache = {} + def search_param_memoize(func): """ Is only good for search params memoize, respectively the closure, @@ -128,6 +128,7 @@ def _check_array_additions(compare_array, module, is_list): """ if not settings.dynamic_array_additions: return [] + def scan_array(arr, search_name): """ Returns the function Calls that match func_name """ result = [] @@ -153,9 +154,27 @@ def _check_array_additions(compare_array, module, is_list): position = c.parent_stmt().start_pos scope = c.parent_stmt().parent() - e = evaluate.follow_call_path(backtrack_path, scope, position) - if not compare_array in e: + found = evaluate.follow_call_path(backtrack_path, scope, position) + if not compare_array in found: # the `append`, etc. belong to other arrays + if isinstance(comp_arr_parent, evaluate.Execution): + found_bases = [] + for f in found: + base = get_execution_parent(f, parsing.Function) + found_bases.append(base) + #for f in found_bases: + #print 'adsf', c.start_pos, found, found_bases + if comp_arr_parent.base.base_func in found_bases: + stmt = comp_arr_parent.\ + get_statement_for_position(c.start_pos) + if stmt is not None: + #print 'LA', stmt.parent(), stmt + ass = stmt.get_assignment_calls() + result += check_calls(scan_array(ass, add_name), + add_name) + #print found_bases, comp_arr_parent.base.base_func + #print found, found[0]._array.parent_stmt().parent() + #print compare_array_parent.base continue params = call_path[separate_index + 1] @@ -175,8 +194,19 @@ def _check_array_additions(compare_array, module, is_list): result += evaluate.get_iterator_types(iterators) return result + def get_execution_parent(element, *stop_classes): + if isinstance(element, evaluate.Array): + stmt = element._array.parent_stmt() + else: + # must be instance + stmt = element.var_args.parent_stmt() + return stmt.get_parent_until(*stop_classes) + search_names = ['append', 'extend', 'insert'] if is_list else \ ['add', 'update'] + #print compare_array + comp_arr_parent = get_execution_parent(compare_array, evaluate.Execution) + #print 'par', comp_arr_parent possible_stmts = [] result = [] for n in search_names: @@ -195,7 +225,7 @@ def check_array_instances(instance): if not settings.dynamic_arrays_instances: return instance.var_args ai = ArrayInstance(instance) - return helpers.generate_param_array([ai]) + return helpers.generate_param_array([ai], instance.var_args.parent_stmt()) class ArrayInstance(parsing.Base): @@ -223,7 +253,13 @@ class ArrayInstance(parsing.Base): temp = array.var_args[0][0] if isinstance(temp, ArrayInstance): #print items, self, id(self.var_args), id(self.var_args.parent_stmt()), array - items += temp.iter_content() + # prevent recursions + # TODO compare Modules + if self.var_args.start_pos != temp.var_args.start_pos: + items += temp.iter_content() + else: + debug.warning('ArrayInstance recursion', self.var_args) + print 'yippie' continue items += evaluate.get_iterator_types([array]) diff --git a/evaluate.py b/evaluate.py index 4a359ad8..44824e8f 100644 --- a/evaluate.py +++ b/evaluate.py @@ -653,7 +653,7 @@ class Execution(Executable): Call the default method with the own instance (self implements all the necessary functions). Add also the params. """ - return self.get_params() + parsing.Scope._get_set_vars(self) + return self.get_params() + parsing.Scope.get_set_vars(self) def copy_properties(self, prop): # Copy all these lists into this local function. @@ -691,6 +691,9 @@ class Execution(Executable): def subscopes(self): return self.copy_properties('subscopes') + def get_statement_for_position(self, pos): + return parsing.Scope.get_statement_for_position(self, pos) + def __repr__(self): return "<%s of %s>" % \ (self.__class__.__name__, self.base) diff --git a/parsing.py b/parsing.py index b37e8c1f..61072120 100644 --- a/parsing.py +++ b/parsing.py @@ -202,7 +202,13 @@ class Scope(Simple): @Python3Method def get_statement_for_position(self, pos): for s in self.statements: - if s.start_pos <= pos < self.end_pos: + if isinstance(s, Flow): + p = s.get_statement_for_position(pos) + if s.next and not p: + p = s.next.get_statement_for_position(pos) + if p: + return p + elif s.start_pos <= pos < s.end_pos: return s for s in self.subscopes: diff --git a/test/completion/dynamic.py b/test/completion/dynamic.py index 7d1c9837..c10c6893 100644 --- a/test/completion/dynamic.py +++ b/test/completion/dynamic.py @@ -248,8 +248,81 @@ arr3[10] #? float() str() int() set() res[10] +# ----------------- +# returns, special because the module dicts are not correct here. +# ----------------- def blub(): a = [] a.append(1.0) #? float() a[0] + return a + +#? float() +blub()[0] + +# list with default +def blub(): + a = list([1]) + a.append(1.0) + return a + +#? int() float() +blub()[0] + +# empty list +def blub(): + a = list() + a.append(1.0) + return a +#? float() +blub()[0] + +# with if +def blub(): + if 1: + a = [] + a.append(1.0) + return a + +#? float() +blub()[0] + +# with else clause +def blub(): + if 1: + 1 + else: + a = [] + a.append(1) + return a + +#? int() +blub()[0] + +# ----------------- +# array recursions +# ----------------- + +a = set([1.0]) +a.update(a) +a.update([1]) + +#? float() int() +list(a)[0] + +def first(a): + b = [] + b.append(a) + #b.extend(second(a)) + return b + +def second(a): + b = [] + b.append(a) + b.extend(first(a)) + b.extend(second(a)) + return list(b) + +#? float() +first(1.0)[0] diff --git a/test/completion/generators.py b/test/completion/generators.py index 2ae227ae..9df7b215 100644 --- a/test/completion/generators.py +++ b/test/completion/generators.py @@ -89,3 +89,19 @@ class Counter: for c in Counter(3, 8): #? int() print c + +# ----------------- +# tuples +# ----------------- +def gen(): + if a: + yield 1, "" + else: + yield 2, 1.0 + + +a, b = next(gen()) +#? int() +a +#? str() float() +b