forked from VimPlug/jedi
use weakrefs for parents now: evaluate.py
This commit is contained in:
41
evaluate.py
41
evaluate.py
@@ -22,6 +22,7 @@ from _compatibility import next, property, hasattr, is_py3k
|
|||||||
import sys
|
import sys
|
||||||
import itertools
|
import itertools
|
||||||
import copy
|
import copy
|
||||||
|
import weakref
|
||||||
|
|
||||||
import parsing
|
import parsing
|
||||||
import debug
|
import debug
|
||||||
@@ -127,9 +128,8 @@ class Executable(parsing.Base):
|
|||||||
def get_parent_until(self, *args):
|
def get_parent_until(self, *args):
|
||||||
return self.base.get_parent_until(*args)
|
return self.base.get_parent_until(*args)
|
||||||
|
|
||||||
@property
|
|
||||||
def parent(self):
|
def parent(self):
|
||||||
return self.base.parent
|
return self.base.parent()
|
||||||
|
|
||||||
|
|
||||||
class Instance(Executable):
|
class Instance(Executable):
|
||||||
@@ -253,10 +253,9 @@ class InstanceElement():
|
|||||||
self.instance = instance
|
self.instance = instance
|
||||||
self.var = var
|
self.var = var
|
||||||
|
|
||||||
@property
|
|
||||||
@memoize_default()
|
@memoize_default()
|
||||||
def parent(self):
|
def parent(self):
|
||||||
par = self.var.parent
|
par = self.var.parent()
|
||||||
if not isinstance(par, (parsing.Module, Class)):
|
if not isinstance(par, (parsing.Module, Class)):
|
||||||
par = InstanceElement(self.instance, par)
|
par = InstanceElement(self.instance, par)
|
||||||
return par
|
return par
|
||||||
@@ -498,7 +497,7 @@ class Execution(Executable):
|
|||||||
new_param._assignment_calls = calls
|
new_param._assignment_calls = calls
|
||||||
new_param.is_generated = True
|
new_param.is_generated = True
|
||||||
name = copy.copy(param.get_name())
|
name = copy.copy(param.get_name())
|
||||||
name.parent = new_param
|
name.parent = weakref.ref(new_param)
|
||||||
return name
|
return name
|
||||||
|
|
||||||
result = []
|
result = []
|
||||||
@@ -507,7 +506,7 @@ class Execution(Executable):
|
|||||||
# Care for self -> just exclude it and add the instance
|
# Care for self -> just exclude it and add the instance
|
||||||
start_offset = 1
|
start_offset = 1
|
||||||
self_name = copy.copy(self.base.params[0].get_name())
|
self_name = copy.copy(self.base.params[0].get_name())
|
||||||
self_name.parent = self.base.instance
|
self_name.parent = weakref.ref(self.base.instance)
|
||||||
result.append(self_name)
|
result.append(self_name)
|
||||||
|
|
||||||
param_dict = {}
|
param_dict = {}
|
||||||
@@ -656,7 +655,7 @@ class Execution(Executable):
|
|||||||
temp, element.parent = element.parent, None
|
temp, element.parent = element.parent, None
|
||||||
copied = copy.deepcopy(element)
|
copied = copy.deepcopy(element)
|
||||||
element.parent = temp
|
element.parent = temp
|
||||||
copied.parent = self
|
copied.parent = weakref.ref(self)
|
||||||
if isinstance(copied, parsing.Function):
|
if isinstance(copied, parsing.Function):
|
||||||
copied = Function(copied)
|
copied = Function(copied)
|
||||||
objects.append(copied)
|
objects.append(copied)
|
||||||
@@ -704,9 +703,7 @@ class Generator(parsing.Base):
|
|||||||
for n in ('close', 'throw') + executes_generator:
|
for n in ('close', 'throw') + executes_generator:
|
||||||
name = parsing.Name([n], none_pos, none_pos)
|
name = parsing.Name([n], none_pos, none_pos)
|
||||||
if n in executes_generator:
|
if n in executes_generator:
|
||||||
name.parent = self
|
name.parent = weakref.ref(self)
|
||||||
else:
|
|
||||||
name.parent = None
|
|
||||||
names.append(name)
|
names.append(name)
|
||||||
debug.dbg('generator names', names)
|
debug.dbg('generator names', names)
|
||||||
return names
|
return names
|
||||||
@@ -719,9 +716,8 @@ class Generator(parsing.Base):
|
|||||||
debug.warning('Tried to get array access on a generator', self)
|
debug.warning('Tried to get array access on a generator', self)
|
||||||
return []
|
return []
|
||||||
|
|
||||||
@property
|
|
||||||
def parent(self):
|
def parent(self):
|
||||||
return self.func.parent
|
return self.func.parent()
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<%s of %s>" % (self.__class__.__name__, self.func)
|
return "<%s of %s>" % (self.__class__.__name__, self.func)
|
||||||
@@ -802,7 +798,6 @@ class Array(parsing.Base):
|
|||||||
def get_contents(self):
|
def get_contents(self):
|
||||||
return self._array
|
return self._array
|
||||||
|
|
||||||
@property
|
|
||||||
def parent(self):
|
def parent(self):
|
||||||
"""
|
"""
|
||||||
Return the builtin scope as parent, because the arrays are builtins
|
Return the builtin scope as parent, because the arrays are builtins
|
||||||
@@ -870,7 +865,7 @@ def get_names_for_scope(scope, position=None, star_search=True,
|
|||||||
in_scope)
|
in_scope)
|
||||||
except StopIteration:
|
except StopIteration:
|
||||||
raise MultiLevelStopIteration('StopIteration raised somewhere')
|
raise MultiLevelStopIteration('StopIteration raised somewhere')
|
||||||
scope = scope.parent
|
scope = scope.parent()
|
||||||
# This is used, because subscopes (Flow scopes) would distort the
|
# This is used, because subscopes (Flow scopes) would distort the
|
||||||
# results.
|
# results.
|
||||||
if isinstance(scope, (Function, parsing.Function, Execution)):
|
if isinstance(scope, (Function, parsing.Function, Execution)):
|
||||||
@@ -908,7 +903,7 @@ def get_scopes_for_name(scope, name_str, position=None, search_global=False):
|
|||||||
if r.is_global():
|
if r.is_global():
|
||||||
for token_name in r.token_list[1:]:
|
for token_name in r.token_list[1:]:
|
||||||
if isinstance(token_name, parsing.Name):
|
if isinstance(token_name, parsing.Name):
|
||||||
res_new += get_scopes_for_name(r.parent,
|
res_new += get_scopes_for_name(r.parent(),
|
||||||
str(token_name))
|
str(token_name))
|
||||||
else:
|
else:
|
||||||
# generated objects are used within executions, where
|
# generated objects are used within executions, where
|
||||||
@@ -948,17 +943,17 @@ def get_scopes_for_name(scope, name_str, position=None, search_global=False):
|
|||||||
def handle_non_arrays(name):
|
def handle_non_arrays(name):
|
||||||
result = []
|
result = []
|
||||||
if isinstance(scope, InstanceElement) \
|
if isinstance(scope, InstanceElement) \
|
||||||
and scope.var == name.parent.parent:
|
and scope.var == name.parent().parent():
|
||||||
name = InstanceElement(scope.instance, name)
|
name = InstanceElement(scope.instance, name)
|
||||||
par = name.parent
|
par = name.parent()
|
||||||
if par.isinstance(parsing.Flow):
|
if par.isinstance(parsing.Flow):
|
||||||
if par.command == 'for':
|
if par.command == 'for':
|
||||||
result += handle_for_loops(par)
|
result += handle_for_loops(par)
|
||||||
else:
|
else:
|
||||||
debug.warning('Flow: Why are you here? %s' % par.command)
|
debug.warning('Flow: Why are you here? %s' % par.command)
|
||||||
elif isinstance(par, parsing.Param) \
|
elif isinstance(par, parsing.Param) \
|
||||||
and par.parent is not None \
|
and par.parent() is not None \
|
||||||
and isinstance(par.parent.parent, parsing.Class) \
|
and isinstance(par.parent().parent(), parsing.Class) \
|
||||||
and par.position == 0:
|
and par.position == 0:
|
||||||
# This is where self gets added - this happens at another
|
# This is where self gets added - this happens at another
|
||||||
# place, if the var_args are clear. But sometimes the class is
|
# place, if the var_args are clear. But sometimes the class is
|
||||||
@@ -967,7 +962,7 @@ def get_scopes_for_name(scope, name_str, position=None, search_global=False):
|
|||||||
if isinstance(scope, InstanceElement):
|
if isinstance(scope, InstanceElement):
|
||||||
inst = scope.instance
|
inst = scope.instance
|
||||||
else:
|
else:
|
||||||
inst = Instance(Class(par.parent.parent))
|
inst = Instance(Class(par.parent().parent()))
|
||||||
result.append(inst)
|
result.append(inst)
|
||||||
else:
|
else:
|
||||||
result.append(par)
|
result.append(par)
|
||||||
@@ -980,7 +975,7 @@ def get_scopes_for_name(scope, name_str, position=None, search_global=False):
|
|||||||
break_scopes = []
|
break_scopes = []
|
||||||
# here is the position stuff happening (sorting of variables)
|
# here is the position stuff happening (sorting of variables)
|
||||||
for name in sorted(name_list, key=comparison_func, reverse=True):
|
for name in sorted(name_list, key=comparison_func, reverse=True):
|
||||||
p = name.parent.parent if name.parent else None
|
p = name.parent().parent() if name.parent() else None
|
||||||
if isinstance(p, InstanceElement) \
|
if isinstance(p, InstanceElement) \
|
||||||
and isinstance(p.var, parsing.Class):
|
and isinstance(p.var, parsing.Class):
|
||||||
p = p.var
|
p = p.var
|
||||||
@@ -991,7 +986,7 @@ def get_scopes_for_name(scope, name_str, position=None, search_global=False):
|
|||||||
s = scope.base if isinstance(scope, Class) else scope
|
s = scope.base if isinstance(scope, Class) else scope
|
||||||
# this means that a definition was found and is not e.g.
|
# this means that a definition was found and is not e.g.
|
||||||
# in if/else.
|
# in if/else.
|
||||||
if not name.parent or p == s:
|
if not name.parent() or p == s:
|
||||||
break
|
break
|
||||||
break_scopes.append(p)
|
break_scopes.append(p)
|
||||||
# if there are results, ignore the other scopes
|
# if there are results, ignore the other scopes
|
||||||
@@ -1185,7 +1180,7 @@ def follow_call_list(call_list):
|
|||||||
|
|
||||||
def follow_call(call):
|
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()
|
||||||
|
|
||||||
position = call.parent_stmt.start_pos
|
position = call.parent_stmt.start_pos
|
||||||
|
|||||||
Reference in New Issue
Block a user