diff --git a/jedi/evaluate/__init__.py b/jedi/evaluate/__init__.py index 5af3056b..d62fc7b7 100644 --- a/jedi/evaluate/__init__.py +++ b/jedi/evaluate/__init__.py @@ -86,6 +86,7 @@ from jedi.evaluate import stdlib from jedi.evaluate import finder from jedi.evaluate import compiled from jedi.evaluate import precedence +from jedi.evaluate import param from jedi.evaluate.helpers import FakeStatement, deep_ast_copy @@ -183,7 +184,7 @@ class Evaluator(object): """ if isinstance(atom, pr.Name): # This is the first global lookup. - stmt = atom.get_parent_until(pr.ExprStmt) + stmt = atom.get_parent_until((pr.ExprStmt, pr.ReturnStmt)) return self.find_types(stmt.parent, atom, stmt.start_pos, search_global=True) elif isinstance(atom, pr.Literal): @@ -194,7 +195,7 @@ class Evaluator(object): def eval_trailer(self, types, trailer): trailer_op, node = trailer.children[:2] if node == ')': # `arglist` is optional. - node = None + node = () new_types = [] for typ in types: if trailer_op == '.': @@ -207,7 +208,7 @@ class Evaluator(object): @debug.increase_indent def execute(self, obj, arguments=()): - arguments = er.Arguments(self, arguments) + arguments = param.Arguments(self, arguments) if obj.isinstance(er.Function): obj = obj.get_decorated_func() diff --git a/jedi/evaluate/param.py b/jedi/evaluate/param.py index 3ac8ad9f..136d6b2c 100644 --- a/jedi/evaluate/param.py +++ b/jedi/evaluate/param.py @@ -9,6 +9,56 @@ from jedi.evaluate import helpers from jedi.evaluate import analysis +class Arguments(object): + def __init__(self, evaluator, argument_node): + """ + The argument_node is either a parser node or a list of evaluated + objects. + """ + self._argument_node = argument_node + self._evaluator = evaluator + + def _split(self): + if isinstance(self._argument_node, (tuple, list)): + for el in self._argument_node: + yield 0 + else: + iterator = iter(self._argument_node.children) + for child in iterator: + if child == ',': + continue + elif child in ('*', '**'): + yield len(child), next(iterator) + else: + yield 0, child + + def iterate(self): + """Returns key/value tuples, as statements.""" + for stars, el in self._split(): + if stars == 1: + arrays = self._evaluator.eval_element(el) + iterators = [_iterate_star_args(self._evaluator, a, expression_list[1:], func) + for a in arrays] + for values in list(zip_longest(*iterators)): + yield None, [v for v in values if v is not None] + elif stars == 2: + raise NotImplementedError + else: + yield None, [el] + + def kwargs(self): + return [] + + def args(self): + return [] + + def eval_args(self): + return [self._evaluator.eval_element(el) for stars, el in self._split()] + + def __repr__(self): + return '<%s: %s>' % (type(self).__name__, self._argument_node) + + class ExecutedParam(pr.Param): def __init__(self): """Don't use this method, it's just here to overwrite the old one.""" @@ -198,7 +248,7 @@ def _unpack_var_args(evaluator, var_args, func): argument_list.append((None, [helpers.FakeStatement([func.instance])])) # `var_args` is typically an Array, and not a list. - for stmt in _reorder_var_args(var_args): + for stmt in _reorder_var_args(var_args.iterate()): if not isinstance(stmt, pr.Statement): if stmt is None: argument_list.append((None, [])) @@ -214,7 +264,7 @@ def _unpack_var_args(evaluator, var_args, func): # *args if expression_list[0] == '*': arrays = evaluator.eval_expression_list(expression_list[1:]) - iterators = [_iterate_star_args(evaluator, a, expression_list[1:], func) + iterators = [_iterate_star_args(evaluator, arr, func) for a in arrays] for values in list(zip_longest(*iterators)): argument_list.append((None, [v for v in values if v is not None])) diff --git a/jedi/evaluate/representation.py b/jedi/evaluate/representation.py index 1cf2703c..f7f403c0 100644 --- a/jedi/evaluate/representation.py +++ b/jedi/evaluate/representation.py @@ -335,31 +335,6 @@ class InstanceElement(use_metaclass(CachedMetaClass, pr.Base)): return "<%s of %s>" % (type(self).__name__, self.var) -class Arguments(object): - def __init__(self, evaluator, argument_node): - self._argument_node = argument_node - self._evaluator = evaluator - - def _split(self): - iterator = iter(self._argument_node.children) - for child in iterator: - if child == ',': - continue - elif child in ('*', '**'): - yield len(child), next(iterator) - else: - yield 0, child - - def kwargs(self): - return [] - - def args(self): - return [] - - def eval_args(self): - return [self._evaluator.eval_element(el) for stars, el in self._split()] - - class Wrapper(pr.Base): def is_scope(self): return True @@ -599,19 +574,11 @@ class FunctionExecution(Executed): types = list(docstrings.find_return_types(self._evaluator, func)) for r in self.returns: - if isinstance(r, pr.KeywordStatement): - stmt = r.stmt - else: - stmt = r # Lambdas - - if stmt is None: - continue - check = flow_analysis.break_check(self._evaluator, self, r.parent) if check is flow_analysis.UNREACHABLE: debug.dbg('Return unreachable: %s', r) else: - types += self._evaluator.eval_statement(stmt) + types += self._evaluator.eval_element(r.children[1]) if check is flow_analysis.REACHABLE: debug.dbg('Return reachable: %s', r) break @@ -673,6 +640,11 @@ class FunctionExecution(Executed): def returns(self): return self._copy_list(self.base.returns) + @common.safe_property + @memoize_default([]) + def children(self): + return self._copy_list(self.base.children) + @common.safe_property @memoize_default([]) def asserts(self): diff --git a/jedi/parser/representation.py b/jedi/parser/representation.py index 4f6abf6b..7c0c37fd 100644 --- a/jedi/parser/representation.py +++ b/jedi/parser/representation.py @@ -696,8 +696,12 @@ class Function(Scope): def name(self): return self.children[1] # First token after `def` + @property def params(self): - return self.children[3].children # After def foo( + third = self.children[3] # After def foo( + if isinstance(third, Operator): + return [] + return self.children[3].children def annotation(self): try: