diff --git a/dynamic.py b/dynamic.py index e2a28399..21ed4e54 100644 --- a/dynamic.py +++ b/dynamic.py @@ -156,25 +156,27 @@ def _check_array_additions(compare_array, module, is_list): scope = c.parent_stmt().parent() found = evaluate.follow_call_path(backtrack_path, scope, position) if not compare_array in found: - # the `append`, etc. belong to other arrays + # Check if the original scope is an execution. If it is, one + # can search for the same statement, that is in the module + # dict. Executions are somewhat special in jedi, since they + # literally copy the contents of a function. 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.\ + stmt = comp_arr_parent. \ get_statement_for_position(c.start_pos) if stmt is not None: - #print 'LA', stmt.parent(), stmt + if evaluate.follow_statement.push_stmt(stmt): + # check recursion + continue 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 + new_calls = scan_array(ass, add_name) + #print [c.start_pos for c in new_calls], stmt.start_pos + result += check_calls(new_calls, add_name) + evaluate.follow_statement.pop_stmt() continue params = call_path[separate_index + 1] @@ -204,9 +206,7 @@ def _check_array_additions(compare_array, module, is_list): 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: @@ -246,6 +246,9 @@ class ArrayInstance(parsing.Base): items = [] #print 'ic', self.var_args, self.var_args.parent_stmt() stmt = self.var_args.parent_stmt() + #if evaluate.follow_statement.push_stmt(stmt): + # check recursion + #return [] #if stmt.get_parent_until() == builtin.Builtin.scope: #evaluate.follow_statement.push(stmt) for array in evaluate.follow_call_list(self.var_args): @@ -255,11 +258,15 @@ class ArrayInstance(parsing.Base): #print items, self, id(self.var_args), id(self.var_args.parent_stmt()), array # prevent recursions # TODO compare Modules + #if evaluate.follow_statement.push_stmt(stmt): + # check recursion + # continue 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' + #evaluate.follow_statement.pop_stmt() continue items += evaluate.get_iterator_types([array]) @@ -269,4 +276,5 @@ class ArrayInstance(parsing.Base): module = self.var_args.parent_stmt().get_parent_until() is_list = str(self.instance.name) == 'list' items += _check_array_additions(self.instance, module, is_list) + #evaluate.follow_statement.pop_stmt() return items diff --git a/helpers.py b/helpers.py index 45b8a92f..a69ab53f 100644 --- a/helpers.py +++ b/helpers.py @@ -15,51 +15,64 @@ class RecursionDecorator(object): self.current = None def __call__(self, stmt, *args, **kwargs): - r = RecursionNode(stmt, self.current) - - # Don't check param instances, they are not causing recursions - # The same's true for the builtins, because the builtins are really - # simple. - if isinstance(stmt, parsing.Param) \ - or (r.script == builtin.Builtin.scope and - stmt.start_pos[0] != 538000): - return self.func(stmt, *args, **kwargs) - if r.script == builtin.Builtin.scope: - print 'rec_catch', stmt, stmt.parent().parent() - #print stmt - - if self._check_recursion(r): - debug.warning('catched recursion', stmt, args, kwargs) + if self.push_stmt(stmt): return [] - parent, self.current = self.current, r - result = self.func(stmt, *args, **kwargs) - self.current = parent + else: + result = self.func(stmt, *args, **kwargs) + self.pop_stmt() return result - def _check_recursion(self, new): + def push_stmt(self, stmt): + self.current = RecursionNode(stmt, self.current) + if self._check_recursion(): + debug.warning('catched recursion', stmt) + self.pop_stmt() + return True + return False + + def pop_stmt(self): + self.current = self.current.parent + + def _check_recursion(self): test = self.current while True: - if new == test: + test = test.parent + if self.current == test: return True if not test: return False - test = test.parent def reset(self): self.top = None self.current = None + def node_statements(self): + result = [] + n = self.current + while n: + result.append(n.stmt) + n = n.parent + return result + class RecursionNode(object): def __init__(self, stmt, parent): self.script = stmt.get_parent_until() self.position = stmt.start_pos self.parent = parent + self.stmt = stmt + + # Don't check param instances, they are not causing recursions + # The same's true for the builtins, because the builtins are really + # simple. + self.is_ignored = isinstance(stmt, parsing.Param) \ + or (self.script == builtin.Builtin.scope) def __eq__(self, other): if not other: return None - return self.script == other.script and self.position == other.position + return self.script == other.script \ + and self.position == other.position and not self.is_ignored def fast_parent_copy(obj): diff --git a/test/completion/dynamic.py b/test/completion/dynamic.py index c10c6893..e8f6d4a0 100644 --- a/test/completion/dynamic.py +++ b/test/completion/dynamic.py @@ -299,6 +299,28 @@ def blub(): #? int() blub()[0] +# ----------------- +# returns, the same for classes +# ----------------- +class C(): + def blub(self, b): + if 1: + a = [] + a.append(b) + return a + + def blub2(self): + """ mapper function """ + a = self.blub(1.0) + #? float() + a[0] + return a + +#? int() +C().blub(1)[0] + +#? float() +C().blub2(1)[0] # ----------------- # array recursions @@ -314,15 +336,20 @@ list(a)[0] def first(a): b = [] b.append(a) - #b.extend(second(a)) - return b + b.extend(second(a)) + return list(b) def second(a): b = [] - b.append(a) b.extend(first(a)) - b.extend(second(a)) return list(b) #? float() first(1.0)[0] + +def third(): + b = [] + b.extend(first()) + return list(b) +#? +third()[0]