completions on jedi now don't run into almost endless loop anymore

This commit is contained in:
David Halter
2012-08-23 02:05:45 +02:00
parent ddc7c73c46
commit cfba8216c9
5 changed files with 49 additions and 30 deletions

View File

@@ -111,12 +111,16 @@ def search_params(param):
return result return result
def check_array_additions(array): def check_array_additions(array):
""" Just a mapper function for the internal _check_array_additions """ """ Just a mapper function for the internal _check_array_additions """
if array._array.type not in ['list', 'tuple']:
# TODO also check for dict updates
return []
is_list = array._array.type == 'list' is_list = array._array.type == 'list'
current_module = array._array.parent_stmt().get_parent_until() current_module = array._array.parent_stmt().get_parent_until()
return _check_array_additions(array, current_module, is_list) res = _check_array_additions(array, current_module, is_list)
return res
@evaluate.memoize_default([]) @evaluate.memoize_default([])
@@ -154,7 +158,16 @@ def _check_array_additions(compare_array, module, is_list):
position = c.parent_stmt().start_pos position = c.parent_stmt().start_pos
scope = c.parent_stmt().parent() scope = c.parent_stmt().parent()
# Special assignments should not be evaluated in this case. This
# would cause big recursion problems, because in cases like the
# code of jedi itself, += something is called and this call leads
# to many other things including params, which are not defined.
# This would lead again to dynamic param completion, and so on.
# In the end the definition is needed, and that's not with `+=`.
settings.evaluate_special_assignments = False
found = evaluate.follow_call_path(backtrack_path, scope, position) found = evaluate.follow_call_path(backtrack_path, scope, position)
settings.evaluate_special_assignments = True
if not compare_array in found: if not compare_array in found:
# Check if the original scope is an execution. If it is, one # Check if the original scope is an execution. If it is, one
# can search for the same statement, that is in the module # can search for the same statement, that is in the module
@@ -244,37 +257,20 @@ class ArrayInstance(parsing.Base):
lists/sets are too complicated too handle that. lists/sets are too complicated too handle that.
""" """
items = [] 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): for array in evaluate.follow_call_list(self.var_args):
if isinstance(array, evaluate.Instance) and len(array.var_args): if isinstance(array, evaluate.Instance) and len(array.var_args):
temp = array.var_args[0][0] temp = array.var_args[0][0]
if isinstance(temp, ArrayInstance): if isinstance(temp, ArrayInstance):
#print items, self, id(self.var_args), id(self.var_args.parent_stmt()), array
# prevent recursions # prevent recursions
# TODO compare Modules # TODO compare Modules
#if evaluate.follow_statement.push_stmt(stmt):
# check recursion
# continue
if self.var_args.start_pos != temp.var_args.start_pos: if self.var_args.start_pos != temp.var_args.start_pos:
items += temp.iter_content() items += temp.iter_content()
else: else:
debug.warning('ArrayInstance recursion', self.var_args) debug.warning('ArrayInstance recursion', self.var_args)
print 'yippie'
#evaluate.follow_statement.pop_stmt()
continue continue
items += evaluate.get_iterator_types([array]) items += evaluate.get_iterator_types([array])
#if stmt.get_parent_until() == builtin.Builtin.scope:
#evaluate.follow_statement.pop()
#print 'ic finish', self.var_args
module = self.var_args.parent_stmt().get_parent_until() module = self.var_args.parent_stmt().get_parent_until()
is_list = str(self.instance.name) == 'list' is_list = str(self.instance.name) == 'list'
items += _check_array_additions(self.instance, module, is_list) items += _check_array_additions(self.instance, module, is_list)
#evaluate.follow_statement.pop_stmt()
return items return items

View File

@@ -30,6 +30,7 @@ import builtin
import imports import imports
import helpers import helpers
import dynamic import dynamic
import settings
memoize_caches = [] memoize_caches = []
statement_path = [] statement_path = []
@@ -407,7 +408,7 @@ class Function(parsing.Base):
return f return f
def get_decorated_func(self): def get_decorated_func(self):
if self._decorated_func == None: if self._decorated_func is None:
raise DecoratorNotFound() raise DecoratorNotFound()
if self._decorated_func == self.base_func: if self._decorated_func == self.base_func:
return self return self
@@ -723,6 +724,7 @@ class Generator(parsing.Base):
def iter_content(self): def iter_content(self):
""" returns the content of __iter__ """ """ returns the content of __iter__ """
#print self, follow_statement.node_statements()
return Execution(self.func, self.var_args).get_return_types(True) return Execution(self.func, self.var_args).get_return_types(True)
def get_index_types(self, index=None): def get_index_types(self, index=None):
@@ -833,7 +835,7 @@ class ArrayElement(object):
def __getattr__(self, name): def __getattr__(self, name):
# Set access privileges: # Set access privileges:
if name not in ['parent', 'names', 'start_pos', 'end_pos']: if name not in ['parent', 'names', 'start_pos', 'end_pos', 'get_code']:
raise AttributeError('Strange access: %s.' % name) raise AttributeError('Strange access: %s.' % name)
return getattr(self.name, name) return getattr(self.name, name)
@@ -848,12 +850,13 @@ def get_defined_names_for_position(obj, position=None, start_scope=None):
names = obj.get_defined_names() names = obj.get_defined_names()
# Instances have special rules, always return all the possible completions, # Instances have special rules, always return all the possible completions,
# because class variables are always valid and the `self.` variables, too. # because class variables are always valid and the `self.` variables, too.
if not position or isinstance(obj, Instance) or start_scope != obj \ if not position or isinstance(obj, (Instance, Array)) \
or start_scope != obj \
and isinstance(start_scope, (parsing.Function, Execution)): and isinstance(start_scope, (parsing.Function, Execution)):
return names return names
names_new = [] names_new = []
for n in names: for n in names:
if (n.start_pos) < position: if n.start_pos < position:
names_new.append(n) names_new.append(n)
return names_new return names_new
@@ -1089,7 +1092,7 @@ def get_iterator_types(inputs):
# __iter__ returned an instance. # __iter__ returned an instance.
name = '__next__' if is_py3k() else 'next' name = '__next__' if is_py3k() else 'next'
try: try:
result += it.execute_subscope_by_name(name) result += gen.execute_subscope_by_name(name)
except KeyError: except KeyError:
debug.warning('Instance has no __next__ function', gen) debug.warning('Instance has no __next__ function', gen)
else: else:
@@ -1152,8 +1155,12 @@ def assign_tuples(tup, results, seek_name):
def follow_statement(stmt, seek_name=None): def follow_statement(stmt, seek_name=None):
""" """
:param stmt: contains a statement :param stmt: contains a statement
:param scope: contains a scope. If not given, takes the parent of stmt.
""" """
if not settings.evaluate_special_assignments:
det = stmt.assignment_details
if det and det[0][0] != '=':
return []
statement_path.append(stmt) # important to know for the goto function statement_path.append(stmt) # important to know for the goto function
debug.dbg('follow_stmt %s (%s)' % (stmt, seek_name)) debug.dbg('follow_stmt %s (%s)' % (stmt, seek_name))
@@ -1225,6 +1232,9 @@ def follow_call(call):
""" Follow a call is following a function, variable, string, etc. """ """ Follow a call is following a function, variable, string, etc. """
scope = call.parent_stmt().parent() scope = call.parent_stmt().parent()
path = call.generate_call_path() path = call.generate_call_path()
path = list(path)
#print 'p', scope, path
path = iter(path)
position = call.parent_stmt().start_pos position = call.parent_stmt().start_pos
return follow_call_path(path, scope, position) return follow_call_path(path, scope, position)

View File

@@ -1,4 +1,14 @@
# ----------------
# global settings
# ----------------
dynamic_arrays_instances = True dynamic_arrays_instances = True
dynamic_array_additions = True dynamic_array_additions = True
dynamic_params = True dynamic_params = True
# ----------------
# internally used:
# ----------------
# evaluation of +=, -=, /=, etc.
evaluate_special_assignments = True

View File

@@ -14,21 +14,21 @@ scopes, path, dot, like = \
source_path, True) source_path, True)
# has problems with that (sometimes) very deep nesting. # has problems with that (sometimes) very deep nesting.
##? set() #? set()
el = scopes el = scopes
# get_names_for_scope is also recursion stuff # get_names_for_scope is also recursion stuff
##? tuple() #? tuple()
el = list(evaluate.get_names_for_scope())[0] el = list(evaluate.get_names_for_scope())[0]
##? int() parsing.Module() #? int() parsing.Module()
el = list(evaluate.get_names_for_scope(1))[0][0] el = list(evaluate.get_names_for_scope(1))[0][0]
#? parsing.Module() #? parsing.Module()
el = list(evaluate.get_names_for_scope())[0][0] el = list(evaluate.get_names_for_scope())[0][0]
##? list() #? list()
el = list(evaluate.get_names_for_scope(1))[0][1] el = list(evaluate.get_names_for_scope(1))[0][1]
##? list() #? list()
el = list(evaluate.get_names_for_scope())[0][1] el = list(evaluate.get_names_for_scope())[0][1]
# TODO here should stand evaluate.Instance() and so on. # TODO here should stand evaluate.Instance() and so on.

View File

@@ -36,6 +36,9 @@ arr2 = [1,2,3]
#? ['append'] #? ['append']
arr2.app arr2.app
#? int()
arr.count(1)
# ----------------- # -----------------
# dicts # dicts
# ----------------- # -----------------