as_context caching

This commit is contained in:
Dave Halter
2019-08-18 17:52:15 +02:00
parent 8e60689bcf
commit 6fb49eaadf
10 changed files with 42 additions and 33 deletions

View File

@@ -222,7 +222,11 @@ class Value(HelperValueMixin, BaseValue):
# The root value knows if it's a stub or not.
return self.parent_context.is_stub()
@memoize_method
def as_context(self):
return self._as_context()
def _as_context(self):
raise NotImplementedError('Not all values need to be converted to contexts')

View File

@@ -263,7 +263,7 @@ class CompiledObject(Value):
def get_metaclasses(self):
return NO_VALUES
def as_context(self):
def _as_context(self):
return AbstractContext(self)

View File

@@ -59,7 +59,7 @@ class TypingModuleWrapper(StubModuleValue):
for f in filters:
yield f
def as_context(self):
def _as_context(self):
return TypingModuleContext(self)

View File

@@ -626,7 +626,7 @@ class AbstractAnnotatedClass(ClassMixin, ValueWrapper):
generics=tuple(new_generics)
)])
def as_context(self):
def _as_context(self):
return AnnotatedClassContext(self)
def __repr__(self):

View File

@@ -37,14 +37,17 @@ def _find_names(module_context, tree_name):
def usages(module_context, tree_name):
search_name = tree_name.value
found_names = _find_names(module_context, tree_name)
modules = set(d.get_root_context() for d in found_names.values())
modules = set(m for m in modules if m.is_module() and not m.is_compiled())
module_contexts = set(d.get_root_context() for d in found_names.values())
module_contexts = set(m for m in module_contexts if not m.is_compiled())
non_matching_usage_maps = {}
inf = module_context.inference_state
for m in imports.get_modules_containing_name(inf, modules, search_name):
for name_leaf in m.tree_node.get_used_names().get(search_name, []):
new = _find_names(m, name_leaf)
potential_modules = imports.get_module_contexts_containing_name(
inf, module_contexts, search_name
)
for module_context in potential_modules:
for name_leaf in module_context.tree_node.get_used_names().get(search_name, []):
new = _find_names(module_context, name_leaf)
if any(tree_name in found_names for tree_name in new):
found_names.update(new)
for tree_name in new:

View File

@@ -93,7 +93,7 @@ class FunctionMixin(object):
return FunctionExecutionContext(self, arguments)
def as_context(self):
def _as_context(self):
return self.get_function_execution()
def get_signatures(self):
@@ -110,7 +110,7 @@ class FunctionValue(use_metaclass(CachedMetaClass, FunctionMixin, FunctionAndCla
if context.is_class():
return MethodValue(
context.inference_state,
context,
context._value, # TODO private access!
parent_context=parent_context,
tree_node=tree_node
)
@@ -148,17 +148,17 @@ class FunctionValue(use_metaclass(CachedMetaClass, FunctionMixin, FunctionAndCla
class MethodValue(FunctionValue):
def __init__(self, inference_state, class_context, *args, **kwargs):
def __init__(self, inference_state, class_value, *args, **kwargs):
super(MethodValue, self).__init__(inference_state, *args, **kwargs)
self.class_context = class_context
self.class_value = class_value
def get_default_param_context(self):
return self.class_context
return self.class_value
def get_qualified_names(self):
# Need to implement this, because the parent value of a method
# value is not the class value but the module.
names = self.class_context.get_qualified_names()
names = self.class_value.get_qualified_names()
if names is None:
return None
return names + (self.py__name__(),)

View File

@@ -198,33 +198,33 @@ class AbstractInstanceValue(Value):
yield bound_method.get_function_execution(self.var_args)
@inference_state_method_cache()
def create_instance_value(self, class_value, node):
def create_instance_context(self, class_context, node):
if node.parent.type in ('funcdef', 'classdef'):
node = node.parent
scope = get_parent_scope(node)
if scope == class_value.tree_node:
return class_value
if scope == class_context.tree_node:
return class_context
else:
parent_context = self.create_instance_value(class_value, scope)
parent_context = self.create_instance_context(class_context, scope)
if scope.type == 'funcdef':
func = FunctionValue.from_context(
parent_context,
scope,
)
bound_method = BoundMethod(self, func)
if scope.name.value == '__init__' and parent_context == class_value:
if scope.name.value == '__init__' and parent_context == class_context:
return bound_method.get_function_execution(self.var_args)
else:
return bound_method.get_function_execution()
elif scope.type == 'classdef':
class_value = ClassValue(self.inference_state, parent_context, scope)
return class_value
class_context = ClassValue(self.inference_state, parent_context, scope)
return class_context.as_context()
elif scope.type in ('comp_for', 'sync_comp_for'):
# Comprehensions currently don't have a special scope in Jedi.
return self.create_instance_value(class_value, scope)
return self.create_instance_context(class_context, scope)
else:
raise NotImplementedError
return class_value
return class_context
def get_signatures(self):
call_funcs = self.py__getattribute__('__call__').py__get__(self, self.class_value)
@@ -425,7 +425,10 @@ class SelfName(TreeNameDefinition):
@property
def parent_context(self):
return self._instance.create_instance_value(self.class_value, self.tree_name)
return self._instance.create_instance_context(
self.class_value.as_context(),
self.tree_name
)
class LazyInstanceClassName(object):

View File

@@ -674,8 +674,8 @@ def _check_array_additions(context, sequence):
debug.dbg('Dynamic array search aborted.', color='MAGENTA')
return NO_VALUES
def find_additions(value, arglist, add_name):
params = list(arguments.TreeArguments(value.inference_state, value, arglist).unpack())
def find_additions(context, arglist, add_name):
params = list(arguments.TreeArguments(context.inference_state, context, arglist).unpack())
result = set()
if add_name in ['insert']:
params = params[1:]
@@ -717,7 +717,6 @@ def _check_array_additions(context, sequence):
or execution_trailer.children[1] == ')':
continue
raise NotImplementedError
random_context = context.create_context(name)
with recursion.execution_allowed(context.inference_state, power) as allowed:
@@ -783,8 +782,8 @@ class _ArrayInstance(HelperValueMixin):
class Slice(object):
def __init__(self, value, start, stop, step):
self._value = value
def __init__(self, python_value, start, stop, step):
self._python_value = python_value
self._slice_object = None
# All of them are either a Precedence or None.
self._start = start
@@ -793,7 +792,7 @@ class Slice(object):
def __getattr__(self, name):
if self._slice_object is None:
value = compiled.builtin_from_name(self._value.inference_state, 'slice')
value = compiled.builtin_from_name(self._python_value.inference_state, 'slice')
self._slice_object, = value.execute_with_values()
return getattr(self._slice_object, name)
@@ -807,7 +806,7 @@ class Slice(object):
if element is None:
return None
result = self._value.infer_node(element)
result = self._python_value.infer_node(element)
if len(result) != 1:
# For simplicity, we want slices to be clear defined with just
# one type. Otherwise we will return an empty slice object.

View File

@@ -225,7 +225,7 @@ class ClassMixin(object):
init_funcs = self.py__call__().py__getattribute__('__init__')
return [sig.bind(self) for sig in init_funcs.get_signatures()]
def as_context(self):
def _as_context(self):
return ClassContext(self)

View File

@@ -275,7 +275,7 @@ class ModuleValue(ModuleMixin, TreeValue):
else:
raise AttributeError('Only packages have __path__ attributes.')
def as_context(self):
def _as_context(self):
return ModuleContext(self)
def __repr__(self):