forked from VimPlug/jedi
Starting to improve function calls.
This commit is contained in:
@@ -77,6 +77,7 @@ from jedi.evaluate import compiled
|
|||||||
from jedi.evaluate import precedence
|
from jedi.evaluate import precedence
|
||||||
from jedi.evaluate import param
|
from jedi.evaluate import param
|
||||||
from jedi.evaluate import helpers
|
from jedi.evaluate import helpers
|
||||||
|
from jedi.evaluate.context import Context
|
||||||
|
|
||||||
|
|
||||||
class Evaluator(object):
|
class Evaluator(object):
|
||||||
@@ -110,8 +111,7 @@ class Evaluator(object):
|
|||||||
self.execution_recursion_detector = recursion.ExecutionRecursionDetector(self)
|
self.execution_recursion_detector = recursion.ExecutionRecursionDetector(self)
|
||||||
|
|
||||||
def wrap(self, element, parent_context):
|
def wrap(self, element, parent_context):
|
||||||
if isinstance(element, (er.Wrapper, er.InstanceElement,
|
if isinstance(element, Context) or element is None:
|
||||||
er.ModuleContext, er.FunctionExecution, er.Instance, compiled.CompiledObject)) or element is None:
|
|
||||||
# TODO this is so ugly, please refactor.
|
# TODO this is so ugly, please refactor.
|
||||||
return element
|
return element
|
||||||
|
|
||||||
@@ -328,7 +328,7 @@ class Evaluator(object):
|
|||||||
elif element.type == 'eval_input':
|
elif element.type == 'eval_input':
|
||||||
types = self._eval_element_not_cached(context, element.children[0])
|
types = self._eval_element_not_cached(context, element.children[0])
|
||||||
else:
|
else:
|
||||||
types = precedence.calculate_children(self, element.children)
|
types = precedence.calculate_children(self, context, element.children)
|
||||||
debug.dbg('eval_element result %s', types)
|
debug.dbg('eval_element result %s', types)
|
||||||
return types
|
return types
|
||||||
|
|
||||||
@@ -341,13 +341,13 @@ class Evaluator(object):
|
|||||||
if isinstance(atom, tree.Name):
|
if isinstance(atom, tree.Name):
|
||||||
# This is the first global lookup.
|
# This is the first global lookup.
|
||||||
stmt = atom.get_definition()
|
stmt = atom.get_definition()
|
||||||
if isinstance(context, er.FunctionExecution):
|
#if isinstance(context, er.FunctionExecution):
|
||||||
# Adjust scope: If the name is not in the suite, it's a param
|
## Adjust scope: If the name is not in the suite, it's a param
|
||||||
# default or annotation and will be resolved as part of the
|
## default or annotation and will be resolved as part of the
|
||||||
# parent scope.
|
## parent scope.
|
||||||
colon = scope.children.index(':')
|
#colon = scope.children.index(':')
|
||||||
if atom.start_pos < scope.children[colon + 1].start_pos:
|
#if atom.start_pos < scope.children[colon + 1].start_pos:
|
||||||
scope = scope.get_parent_scope()
|
##scope = scope.get_parent_scope()
|
||||||
if isinstance(stmt, tree.CompFor):
|
if isinstance(stmt, tree.CompFor):
|
||||||
stmt = stmt.get_parent_until((tree.ClassOrFunc, tree.ExprStmt))
|
stmt = stmt.get_parent_until((tree.ClassOrFunc, tree.ExprStmt))
|
||||||
if stmt.type != 'expr_stmt':
|
if stmt.type != 'expr_stmt':
|
||||||
|
|||||||
@@ -56,6 +56,15 @@ class TreeNameDefinition(ContextName):
|
|||||||
return _name_to_types(self.parent_context._evaluator, self.parent_context, self.name, None)
|
return _name_to_types(self.parent_context._evaluator, self.parent_context, self.name, None)
|
||||||
|
|
||||||
|
|
||||||
|
class ParamName(ContextName):
|
||||||
|
def __init__(self, parent_context, name):
|
||||||
|
self.parent_context = parent_context
|
||||||
|
self.name = name
|
||||||
|
|
||||||
|
def infer(self):
|
||||||
|
return set()
|
||||||
|
|
||||||
|
|
||||||
class AbstractFilter(object):
|
class AbstractFilter(object):
|
||||||
_until_position = None
|
_until_position = None
|
||||||
|
|
||||||
@@ -89,9 +98,9 @@ class AbstractUsedNamesFilter(AbstractFilter):
|
|||||||
except KeyError:
|
except KeyError:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
return self._convert_to_names(self._filter(names))
|
return self._convert_names(self._filter(names))
|
||||||
|
|
||||||
def _convert_to_names(self, names):
|
def _convert_names(self, names):
|
||||||
return [TreeNameDefinition(self._context, name) for name in names]
|
return [TreeNameDefinition(self._context, name) for name in names]
|
||||||
|
|
||||||
def values(self):
|
def values(self):
|
||||||
@@ -127,7 +136,7 @@ class ParserTreeFilter(AbstractUsedNamesFilter):
|
|||||||
|
|
||||||
|
|
||||||
class FunctionExecutionFilter(ParserTreeFilter):
|
class FunctionExecutionFilter(ParserTreeFilter):
|
||||||
def __init__(self, evaluator, context, parser_scope, executed_function, param_by_name,
|
def __init__(self, evaluator, context, parser_scope, param_by_name,
|
||||||
until_position=None, origin_scope=None):
|
until_position=None, origin_scope=None):
|
||||||
super(FunctionExecutionFilter, self).__init__(
|
super(FunctionExecutionFilter, self).__init__(
|
||||||
evaluator,
|
evaluator,
|
||||||
@@ -136,16 +145,15 @@ class FunctionExecutionFilter(ParserTreeFilter):
|
|||||||
until_position,
|
until_position,
|
||||||
origin_scope
|
origin_scope
|
||||||
)
|
)
|
||||||
self._executed_function = executed_function
|
|
||||||
self._param_by_name = param_by_name
|
|
||||||
|
|
||||||
def _filter(self, names):
|
def _convert_names(self, names):
|
||||||
names = super(FunctionExecutionFilter, self)._filter(names)
|
for name in names:
|
||||||
|
param = search_ancestor(name, 'param')
|
||||||
names = [self._executed_function.name_for_position(name.start_pos) for name in names]
|
if param:
|
||||||
names = [self._param_by_name(str(name)) if search_ancestor(name, 'param') else name
|
#yield self.context._param_by_name(str(name))
|
||||||
for name in names]
|
yield ParamName(self._context, name)
|
||||||
return names
|
else:
|
||||||
|
yield TreeNameDefinition(self._context, name)
|
||||||
|
|
||||||
|
|
||||||
class GlobalNameFilter(AbstractUsedNamesFilter):
|
class GlobalNameFilter(AbstractUsedNamesFilter):
|
||||||
|
|||||||
@@ -295,19 +295,19 @@ class NameFinder(object):
|
|||||||
types = set()
|
types = set()
|
||||||
|
|
||||||
# Add isinstance and other if/assert knowledge.
|
# Add isinstance and other if/assert knowledge.
|
||||||
if isinstance(self.name_str, tree.Name):
|
#if isinstance(self.name_str, tree.Name):
|
||||||
# Ignore FunctionExecution parents for now.
|
## Ignore FunctionExecution parents for now.
|
||||||
flow_scope = self.name_str
|
#flow_scope = self.name_str
|
||||||
until = flow_scope.get_parent_until(er.FunctionExecution)
|
#until = flow_scope.get_parent_until(er.FunctionExecution)
|
||||||
while not isinstance(until, er.FunctionExecution):
|
#while not isinstance(until, er.FunctionExecution):
|
||||||
flow_scope = flow_scope.get_parent_scope(include_flows=True)
|
#flow_scope = flow_scope.get_parent_scope(include_flows=True)
|
||||||
if flow_scope is None:
|
#if flow_scope is None:
|
||||||
break
|
#break
|
||||||
# TODO check if result is in scope -> no evaluation necessary
|
## TODO check if result is in scope -> no evaluation necessary
|
||||||
n = check_flow_information(self._evaluator, flow_scope,
|
#n = check_flow_information(self._evaluator, flow_scope,
|
||||||
self.name_str, self.position)
|
#self.name_str, self.position)
|
||||||
if n:
|
#if n:
|
||||||
return n
|
#return n
|
||||||
|
|
||||||
for name in names:
|
for name in names:
|
||||||
new_types = name.infer()
|
new_types = name.infer()
|
||||||
|
|||||||
@@ -83,9 +83,22 @@ def follow_param(evaluator, param):
|
|||||||
return _evaluate_for_annotation(evaluator, annotation)
|
return _evaluate_for_annotation(evaluator, annotation)
|
||||||
|
|
||||||
|
|
||||||
|
def py__annotations__(funcdef):
|
||||||
|
return_annotation = funcdef.annotation()
|
||||||
|
if return_annotation:
|
||||||
|
dct = {'return': return_annotation}
|
||||||
|
else:
|
||||||
|
dct = {}
|
||||||
|
for function_param in funcdef.params:
|
||||||
|
param_annotation = function_param.annotation()
|
||||||
|
if param_annotation is not None:
|
||||||
|
dct[function_param.name.value] = param_annotation
|
||||||
|
return dct
|
||||||
|
|
||||||
|
|
||||||
@memoize_default(None, evaluator_is_first_arg=True)
|
@memoize_default(None, evaluator_is_first_arg=True)
|
||||||
def find_return_types(evaluator, func):
|
def find_return_types(evaluator, func):
|
||||||
annotation = func.py__annotations__().get("return", None)
|
annotation = py__annotations__(func).get("return", None)
|
||||||
return _evaluate_for_annotation(evaluator, annotation)
|
return _evaluate_for_annotation(evaluator, annotation)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -30,19 +30,19 @@ def literals_to_types(evaluator, result):
|
|||||||
if is_literal(typ):
|
if is_literal(typ):
|
||||||
# Literals are only valid as long as the operations are
|
# Literals are only valid as long as the operations are
|
||||||
# correct. Otherwise add a value-free instance.
|
# correct. Otherwise add a value-free instance.
|
||||||
cls = builtin_from_name(evaluator, typ.name.value)
|
cls = builtin_from_name(evaluator, typ.name.string_name)
|
||||||
new_result |= evaluator.execute(cls)
|
new_result |= evaluator.execute(cls)
|
||||||
else:
|
else:
|
||||||
new_result.add(typ)
|
new_result.add(typ)
|
||||||
return new_result
|
return new_result
|
||||||
|
|
||||||
|
|
||||||
def calculate_children(evaluator, children):
|
def calculate_children(evaluator, context, children):
|
||||||
"""
|
"""
|
||||||
Calculate a list of children with operators.
|
Calculate a list of children with operators.
|
||||||
"""
|
"""
|
||||||
iterator = iter(children)
|
iterator = iter(children)
|
||||||
types = evaluator.eval_element(next(iterator))
|
types = context.eval_node(next(iterator))
|
||||||
for operator in iterator:
|
for operator in iterator:
|
||||||
right = next(iterator)
|
right = next(iterator)
|
||||||
if tree.is_node(operator, 'comp_op'): # not in / is not
|
if tree.is_node(operator, 'comp_op'): # not in / is not
|
||||||
@@ -53,14 +53,14 @@ def calculate_children(evaluator, children):
|
|||||||
left_bools = set([left.py__bool__() for left in types])
|
left_bools = set([left.py__bool__() for left in types])
|
||||||
if left_bools == set([True]):
|
if left_bools == set([True]):
|
||||||
if operator == 'and':
|
if operator == 'and':
|
||||||
types = evaluator.eval_element(right)
|
types = context.eval_node(right)
|
||||||
elif left_bools == set([False]):
|
elif left_bools == set([False]):
|
||||||
if operator != 'and':
|
if operator != 'and':
|
||||||
types = evaluator.eval_element(right)
|
types = context.eval_node(right)
|
||||||
# Otherwise continue, because of uncertainty.
|
# Otherwise continue, because of uncertainty.
|
||||||
else:
|
else:
|
||||||
types = calculate(evaluator, types, operator,
|
types = calculate(evaluator, types, operator,
|
||||||
evaluator.eval_element(right))
|
context.eval_node(right))
|
||||||
debug.dbg('calculate_children types %s', types)
|
debug.dbg('calculate_children types %s', types)
|
||||||
return types
|
return types
|
||||||
|
|
||||||
|
|||||||
@@ -92,6 +92,7 @@ class _RecursionNode(object):
|
|||||||
|
|
||||||
|
|
||||||
def execution_recursion_decorator(func):
|
def execution_recursion_decorator(func):
|
||||||
|
return func # TODO remove
|
||||||
def run(execution, **kwargs):
|
def run(execution, **kwargs):
|
||||||
detector = execution._evaluator.execution_recursion_detector
|
detector = execution._evaluator.execution_recursion_detector
|
||||||
if detector.push_execution(execution):
|
if detector.push_execution(execution):
|
||||||
@@ -130,9 +131,6 @@ class ExecutionRecursionDetector(object):
|
|||||||
self.recursion_level -= 1
|
self.recursion_level -= 1
|
||||||
|
|
||||||
def push_execution(self, execution):
|
def push_execution(self, execution):
|
||||||
self.execution_funcs.add(execution.base)
|
|
||||||
self.parent_execution_funcs.append(execution.base)
|
|
||||||
return True # Remove
|
|
||||||
in_par_execution_funcs = execution.base in self.parent_execution_funcs
|
in_par_execution_funcs = execution.base in self.parent_execution_funcs
|
||||||
in_execution_funcs = execution.base in self.execution_funcs
|
in_execution_funcs = execution.base in self.execution_funcs
|
||||||
self.recursion_level += 1
|
self.recursion_level += 1
|
||||||
|
|||||||
@@ -57,25 +57,21 @@ from jedi.evaluate import flow_analysis
|
|||||||
from jedi.evaluate import imports
|
from jedi.evaluate import imports
|
||||||
from jedi.evaluate.filters import ParserTreeFilter, FunctionExecutionFilter, \
|
from jedi.evaluate.filters import ParserTreeFilter, FunctionExecutionFilter, \
|
||||||
GlobalNameFilter, DictFilter, ContextName
|
GlobalNameFilter, DictFilter, ContextName
|
||||||
from jedi.evaluate.context import Context
|
from jedi.evaluate.context import TreeContext
|
||||||
|
|
||||||
|
|
||||||
class Executed(Context):
|
class Executed(TreeContext):
|
||||||
"""
|
"""
|
||||||
An instance is also an executable - because __init__ is called
|
An instance is also an executable - because __init__ is called
|
||||||
:param var_args: The param input array, consist of a parser node or a list.
|
:param var_args: The param input array, consist of a parser node or a list.
|
||||||
"""
|
"""
|
||||||
def __init__(self, evaluator, parent_context, base, var_args):
|
def __init__(self, evaluator, parent_context, var_args):
|
||||||
super(Executed, self).__init__(evaluator, parent_context=parent_context)
|
super(Executed, self).__init__(evaluator, parent_context=parent_context)
|
||||||
self.base = base
|
|
||||||
self.var_args = var_args
|
self.var_args = var_args
|
||||||
|
|
||||||
def is_scope(self):
|
def is_scope(self):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def get_parent_until(self, *args, **kwargs):
|
|
||||||
return tree.Base.get_parent_until(self, *args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class Instance(use_metaclass(CachedMetaClass, Executed)):
|
class Instance(use_metaclass(CachedMetaClass, Executed)):
|
||||||
"""
|
"""
|
||||||
@@ -132,7 +128,7 @@ class Instance(use_metaclass(CachedMetaClass, Executed)):
|
|||||||
func = self.get_subscope_by_name('__init__')
|
func = self.get_subscope_by_name('__init__')
|
||||||
except KeyError:
|
except KeyError:
|
||||||
return None
|
return None
|
||||||
return FunctionExecution(self._evaluator, self, func, self.var_args)
|
return FunctionExecutionContext(self._evaluator, self, func, self.var_args)
|
||||||
|
|
||||||
def _get_func_self_name(self, func):
|
def _get_func_self_name(self, func):
|
||||||
"""
|
"""
|
||||||
@@ -257,12 +253,6 @@ class Instance(use_metaclass(CachedMetaClass, Executed)):
|
|||||||
def name(self):
|
def name(self):
|
||||||
return ContextName(self, self.base.name)
|
return ContextName(self, self.base.name)
|
||||||
|
|
||||||
def __getattr__(self, name):
|
|
||||||
if name not in ['start_pos', 'end_pos', 'get_imports', 'type',
|
|
||||||
'doc', 'raw_doc']:
|
|
||||||
return super(Instance, self).__getattribute__(name)
|
|
||||||
return getattr(self.base, name)
|
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
dec = ''
|
dec = ''
|
||||||
if self.decorates is not None:
|
if self.decorates is not None:
|
||||||
@@ -380,7 +370,7 @@ def get_instance_el(evaluator, instance, var, is_class_var=False):
|
|||||||
return InstanceName(var, parent)
|
return InstanceName(var, parent)
|
||||||
elif var.type != 'funcdef' \
|
elif var.type != 'funcdef' \
|
||||||
and isinstance(var, (Instance, compiled.CompiledObject, tree.Leaf,
|
and isinstance(var, (Instance, compiled.CompiledObject, tree.Leaf,
|
||||||
tree.Module, FunctionExecution)):
|
tree.Module, FunctionExecutionContext)):
|
||||||
return var
|
return var
|
||||||
|
|
||||||
var = evaluator.wrap(var)
|
var = evaluator.wrap(var)
|
||||||
@@ -451,9 +441,6 @@ class InstanceElement(use_metaclass(CachedMetaClass, tree.Base)):
|
|||||||
return get_instance_el(self._evaluator, self.instance, self.var[index],
|
return get_instance_el(self._evaluator, self.instance, self.var[index],
|
||||||
self.is_class_var)
|
self.is_class_var)
|
||||||
|
|
||||||
def __getattr__(self, name):
|
|
||||||
return getattr(self.var, name)
|
|
||||||
|
|
||||||
def isinstance(self, *cls):
|
def isinstance(self, *cls):
|
||||||
return isinstance(self.var, cls)
|
return isinstance(self.var, cls)
|
||||||
|
|
||||||
@@ -496,7 +483,7 @@ class Wrapper(tree.Base):
|
|||||||
return ContextName(self, name)
|
return ContextName(self, name)
|
||||||
|
|
||||||
|
|
||||||
class ClassContext(use_metaclass(CachedMetaClass, Context, Wrapper)):
|
class ClassContext(use_metaclass(CachedMetaClass, TreeContext, Wrapper)):
|
||||||
"""
|
"""
|
||||||
This class is not only important to extend `tree.Class`, it is also a
|
This class is not only important to extend `tree.Class`, it is also a
|
||||||
important for descriptors (if the descriptor methods are evaluated or not).
|
important for descriptors (if the descriptor methods are evaluated or not).
|
||||||
@@ -602,7 +589,7 @@ class ClassContext(use_metaclass(CachedMetaClass, Context, Wrapper)):
|
|||||||
return "<e%s of %s>" % (type(self).__name__, self.base)
|
return "<e%s of %s>" % (type(self).__name__, self.base)
|
||||||
|
|
||||||
|
|
||||||
class Function(use_metaclass(CachedMetaClass, Context, Wrapper)):
|
class Function(use_metaclass(CachedMetaClass, TreeContext, Wrapper)):
|
||||||
"""
|
"""
|
||||||
Needed because of decorators. Decorators are evaluated here.
|
Needed because of decorators. Decorators are evaluated here.
|
||||||
"""
|
"""
|
||||||
@@ -690,21 +677,12 @@ class Function(use_metaclass(CachedMetaClass, Context, Wrapper)):
|
|||||||
if self.base.is_generator():
|
if self.base.is_generator():
|
||||||
return set([iterable.Generator(self._evaluator, self, params)])
|
return set([iterable.Generator(self._evaluator, self, params)])
|
||||||
else:
|
else:
|
||||||
return FunctionExecution(self._evaluator, self.parent_context, self, params).get_return_types()
|
return FunctionExecutionContext(
|
||||||
|
self._evaluator,
|
||||||
@memoize_default()
|
self.parent_context,
|
||||||
def py__annotations__(self):
|
self.base,
|
||||||
parser_func = self.base
|
params
|
||||||
return_annotation = parser_func.annotation()
|
).get_return_types()
|
||||||
if return_annotation:
|
|
||||||
dct = {'return': return_annotation}
|
|
||||||
else:
|
|
||||||
dct = {}
|
|
||||||
for function_param in parser_func.params:
|
|
||||||
param_annotation = function_param.annotation()
|
|
||||||
if param_annotation is not None:
|
|
||||||
dct[function_param.name.value] = param_annotation
|
|
||||||
return dct
|
|
||||||
|
|
||||||
def py__class__(self):
|
def py__class__(self):
|
||||||
# This differentiation is only necessary for Python2. Python3 does not
|
# This differentiation is only necessary for Python2. Python3 does not
|
||||||
@@ -715,9 +693,6 @@ class Function(use_metaclass(CachedMetaClass, Context, Wrapper)):
|
|||||||
name = 'FUNCTION_CLASS'
|
name = 'FUNCTION_CLASS'
|
||||||
return compiled.get_special_object(self._evaluator, name)
|
return compiled.get_special_object(self._evaluator, name)
|
||||||
|
|
||||||
def __getattr__(self, name):
|
|
||||||
return getattr(self.base_func, name)
|
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
dec = ''
|
dec = ''
|
||||||
if self.decorates is not None:
|
if self.decorates is not None:
|
||||||
@@ -730,7 +705,7 @@ class LambdaWrapper(Function):
|
|||||||
return self
|
return self
|
||||||
|
|
||||||
|
|
||||||
class FunctionExecution(Executed):
|
class FunctionExecutionContext(Executed):
|
||||||
"""
|
"""
|
||||||
This class is used to evaluate functions and their returns.
|
This class is used to evaluate functions and their returns.
|
||||||
|
|
||||||
@@ -741,10 +716,9 @@ class FunctionExecution(Executed):
|
|||||||
"""
|
"""
|
||||||
type = 'funcdef'
|
type = 'funcdef'
|
||||||
|
|
||||||
def __init__(self, evaluator, parent_context, base, var_args):
|
def __init__(self, evaluator, parent_context, funcdef, var_args):
|
||||||
super(FunctionExecution, self).__init__(evaluator, parent_context, base, var_args)
|
super(FunctionExecutionContext, self).__init__(evaluator, parent_context, var_args)
|
||||||
self._copy_dict = {}
|
self._funcdef = funcdef
|
||||||
self._original_function = funcdef = base
|
|
||||||
if isinstance(funcdef, mixed.MixedObject):
|
if isinstance(funcdef, mixed.MixedObject):
|
||||||
# The extra information in mixed is not needed anymore. We can just
|
# The extra information in mixed is not needed anymore. We can just
|
||||||
# unpack it and give it the tree object.
|
# unpack it and give it the tree object.
|
||||||
@@ -763,11 +737,11 @@ class FunctionExecution(Executed):
|
|||||||
@memoize_default(default=set())
|
@memoize_default(default=set())
|
||||||
@recursion.execution_recursion_decorator
|
@recursion.execution_recursion_decorator
|
||||||
def get_return_types(self, check_yields=False):
|
def get_return_types(self, check_yields=False):
|
||||||
func = self.base
|
funcdef = self._funcdef
|
||||||
|
if funcdef.type in ('lambdef', 'lambdef_nocond'):
|
||||||
if func.isinstance(LambdaWrapper):
|
|
||||||
return self._evaluator.eval_element(self.children[-1])
|
return self._evaluator.eval_element(self.children[-1])
|
||||||
|
|
||||||
|
"""
|
||||||
if func.listeners:
|
if func.listeners:
|
||||||
# Feed the listeners, with the params.
|
# Feed the listeners, with the params.
|
||||||
for listener in func.listeners:
|
for listener in func.listeners:
|
||||||
@@ -776,16 +750,19 @@ class FunctionExecution(Executed):
|
|||||||
# execution ongoing. In this case Jedi is interested in the
|
# execution ongoing. In this case Jedi is interested in the
|
||||||
# inserted params, not in the actual execution of the function.
|
# inserted params, not in the actual execution of the function.
|
||||||
return set()
|
return set()
|
||||||
|
"""
|
||||||
|
|
||||||
if check_yields:
|
if check_yields:
|
||||||
types = set()
|
types = set()
|
||||||
returns = self.yields
|
returns = funcdef.yields
|
||||||
else:
|
else:
|
||||||
returns = self.returns
|
returns = funcdef.returns
|
||||||
types = set(docstrings.find_return_types(self._evaluator, func))
|
types = set(docstrings.find_return_types(self._evaluator, funcdef))
|
||||||
types |= set(pep0484.find_return_types(self._evaluator, func))
|
types |= set(pep0484.find_return_types(self._evaluator, funcdef))
|
||||||
|
|
||||||
for r in returns:
|
for r in returns:
|
||||||
|
types |= self.eval_node(r.children[1])
|
||||||
|
continue # TODO REMOVE
|
||||||
check = flow_analysis.break_check(self._evaluator, self, r)
|
check = flow_analysis.break_check(self._evaluator, self, r)
|
||||||
if check is flow_analysis.UNREACHABLE:
|
if check is flow_analysis.UNREACHABLE:
|
||||||
debug.dbg('Return unreachable: %s', r)
|
debug.dbg('Return unreachable: %s', r)
|
||||||
@@ -793,26 +770,26 @@ class FunctionExecution(Executed):
|
|||||||
if check_yields:
|
if check_yields:
|
||||||
types |= iterable.unite(self._eval_yield(r))
|
types |= iterable.unite(self._eval_yield(r))
|
||||||
else:
|
else:
|
||||||
types |= self._evaluator.eval_element(r.children[1])
|
types |= self.eval_node(r.children[1])
|
||||||
if check is flow_analysis.REACHABLE:
|
if check is flow_analysis.REACHABLE:
|
||||||
debug.dbg('Return reachable: %s', r)
|
debug.dbg('Return reachable: %s', r)
|
||||||
break
|
break
|
||||||
return types
|
return types
|
||||||
|
|
||||||
def _eval_yield(self, yield_expr):
|
def _eval_yield(self, yield_expr):
|
||||||
element = yield_expr.children[1]
|
node = yield_expr.children[1]
|
||||||
if element.type == 'yield_arg':
|
if node.type == 'yield_arg':
|
||||||
# It must be a yield from.
|
# It must be a yield from.
|
||||||
yield_from_types = self._evaluator.eval_element(element.children[1])
|
yield_from_types = self.eval_node(node)
|
||||||
for result in iterable.py__iter__(self._evaluator, yield_from_types, element):
|
for result in iterable.py__iter__(self._evaluator, yield_from_types, node):
|
||||||
yield result
|
yield result
|
||||||
else:
|
else:
|
||||||
yield self._evaluator.eval_element(element)
|
yield self.eval_node(node)
|
||||||
|
|
||||||
@recursion.execution_recursion_decorator
|
@recursion.execution_recursion_decorator
|
||||||
def get_yield_types(self):
|
def get_yield_types(self):
|
||||||
yields = self.yields
|
yields = self.yields
|
||||||
stopAt = tree.ForStmt, tree.WhileStmt, FunctionExecution, tree.IfStmt
|
stopAt = tree.ForStmt, tree.WhileStmt, tree.IfStmt
|
||||||
for_parents = [(x, x.get_parent_until((stopAt))) for x in yields]
|
for_parents = [(x, x.get_parent_until((stopAt))) for x in yields]
|
||||||
|
|
||||||
# Calculate if the yields are placed within the same for loop.
|
# Calculate if the yields are placed within the same for loop.
|
||||||
@@ -857,55 +834,20 @@ class FunctionExecution(Executed):
|
|||||||
del evaluator.predefined_if_name_dict_dict[for_stmt]
|
del evaluator.predefined_if_name_dict_dict[for_stmt]
|
||||||
|
|
||||||
def get_filters(self, search_global, until_position=None, origin_scope=None):
|
def get_filters(self, search_global, until_position=None, origin_scope=None):
|
||||||
yield FunctionExecutionFilter(self._evaluator, self, self._original_function,
|
yield FunctionExecutionFilter(self._evaluator, self, self._funcdef,
|
||||||
self._copied_funcdef,
|
|
||||||
self.param_by_name,
|
self.param_by_name,
|
||||||
until_position,
|
until_position,
|
||||||
origin_scope=origin_scope)
|
origin_scope=origin_scope)
|
||||||
|
|
||||||
@memoize_default(default=NO_DEFAULT)
|
@memoize_default(default=NO_DEFAULT)
|
||||||
def _get_params(self):
|
def _get_params(self):
|
||||||
"""
|
return param.get_params(self._evaluator, self._funcdef, self.var_args)
|
||||||
This returns the params for an TODO and is injected as a
|
|
||||||
'hack' into the tree.Function class.
|
|
||||||
This needs to be here, because Instance can have __init__ functions,
|
|
||||||
which act the same way as normal functions.
|
|
||||||
"""
|
|
||||||
return param.get_params(self._evaluator, self.base, self.var_args)
|
|
||||||
|
|
||||||
def param_by_name(self, name):
|
def param_by_name(self, name):
|
||||||
return [n for n in self._get_params() if str(n) == name][0]
|
return [n for n in self._get_params() if str(n) == name][0]
|
||||||
|
|
||||||
def name_for_position(self, position):
|
|
||||||
return tree.Function.name_for_position(self, position)
|
|
||||||
|
|
||||||
def __getattr__(self, name):
|
|
||||||
if name not in ['start_pos', 'end_pos', 'imports', 'name', 'type']:
|
|
||||||
return super(FunctionExecution, self).__getattribute__(name)
|
|
||||||
return getattr(self.base, name)
|
|
||||||
|
|
||||||
@common.safe_property
|
|
||||||
@memoize_default()
|
|
||||||
def returns(self):
|
|
||||||
return tree.Scope._search_in_scope(self, tree.ReturnStmt)
|
|
||||||
|
|
||||||
@common.safe_property
|
|
||||||
@memoize_default()
|
|
||||||
def yields(self):
|
|
||||||
return tree.Scope._search_in_scope(self, tree.YieldExpr)
|
|
||||||
|
|
||||||
@common.safe_property
|
|
||||||
@memoize_default()
|
|
||||||
def statements(self):
|
|
||||||
return tree.Scope._search_in_scope(self, tree.ExprStmt)
|
|
||||||
|
|
||||||
@common.safe_property
|
|
||||||
@memoize_default()
|
|
||||||
def subscopes(self):
|
|
||||||
return tree.Scope._search_in_scope(self, tree.Scope)
|
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<%s of %s>" % (type(self).__name__, self.base)
|
return "<%s of %s>" % (type(self).__name__, self._funcdef)
|
||||||
|
|
||||||
|
|
||||||
class GlobalName(helpers.FakeName):
|
class GlobalName(helpers.FakeName):
|
||||||
@@ -919,7 +861,7 @@ class GlobalName(helpers.FakeName):
|
|||||||
name.start_pos, is_definition=True)
|
name.start_pos, is_definition=True)
|
||||||
|
|
||||||
|
|
||||||
class ModuleContext(use_metaclass(CachedMetaClass, tree.Module, Wrapper)):
|
class ModuleContext(use_metaclass(CachedMetaClass, TreeContext, Wrapper)):
|
||||||
parent_context = None
|
parent_context = None
|
||||||
|
|
||||||
def __init__(self, evaluator, module, parent_module=None):
|
def __init__(self, evaluator, module, parent_module=None):
|
||||||
@@ -1095,8 +1037,5 @@ class ModuleContext(use_metaclass(CachedMetaClass, tree.Module, Wrapper)):
|
|||||||
def py__class__(self):
|
def py__class__(self):
|
||||||
return compiled.get_special_object(self._evaluator, 'MODULE_CLASS')
|
return compiled.get_special_object(self._evaluator, 'MODULE_CLASS')
|
||||||
|
|
||||||
def __getattr__(self, name):
|
|
||||||
return getattr(self._module, name)
|
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<%s: %s>" % (type(self).__name__, self._module)
|
return "<%s: %s>" % (type(self).__name__, self._module)
|
||||||
|
|||||||
@@ -37,8 +37,8 @@ def execute(evaluator, obj, arguments):
|
|||||||
else:
|
else:
|
||||||
if obj.parent_context == evaluator.BUILTINS:
|
if obj.parent_context == evaluator.BUILTINS:
|
||||||
module_name = 'builtins'
|
module_name = 'builtins'
|
||||||
elif isinstance(obj.parent, tree.Module):
|
elif isinstance(obj.parent_context, er.ModuleContext):
|
||||||
module_name = str(obj.parent.name)
|
module_name = obj.parent_context.name.string_name
|
||||||
else:
|
else:
|
||||||
module_name = ''
|
module_name = ''
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user