diff --git a/jedi/api/completion.py b/jedi/api/completion.py index 852823d8..9a479c6c 100644 --- a/jedi/api/completion.py +++ b/jedi/api/completion.py @@ -1,5 +1,4 @@ from itertools import chain -import re from jedi.parser import token from jedi.parser import tree @@ -11,6 +10,7 @@ from jedi.api import inference from jedi.evaluate import imports from jedi.api import keywords from jedi.evaluate import compiled +from jedi.evaluate.helpers import call_of_leaf from jedi.evaluate.finder import global_names_dict_generator, filter_definition_names @@ -65,13 +65,7 @@ class Completion: def completions(self, path): completion_parts = helpers.get_completion_parts(path) - user_stmt = self._parser.user_stmt_with_whitespace() - - completion_names = self._get_context_completions(user_stmt, completion_parts) - - if not completion_parts.has_dot: - call_signatures = self._call_signatures_method() - completion_names += get_call_signature_param_names(call_signatures) + completion_names = self._get_context_completions(completion_parts) completions = filter_names(self._evaluator, completion_names, completion_parts.name) @@ -80,7 +74,7 @@ class Completion: x.name.startswith('_'), x.name.lower())) - def _get_context_completions(self, user_stmt, completion_parts): + def _get_context_completions(self, completion_parts): """ Analyzes the context that a completion is made in and decides what to return. @@ -147,11 +141,17 @@ class Completion: # No completions for ``with x as foo`` and ``import x as foo``. # Also true for defining names as a class or function. return [] - elif symbol_names[-1] == 'trailer' and '(' != nodes[-1]: - completion_names += self._trailer_completions(completion_parts) + elif symbol_names[-1] == 'trailer' and nodes[-1] == '.': + dot = self._module.get_leaf_for_position(pos) + atom_expr = call_of_leaf(dot.get_previous_leaf()) + completion_names += self._trailer_completions(atom_expr) else: completion_names += self._global_completions() + if 'trailer' in symbol_names: + call_signatures = self._call_signatures_method() + completion_names += get_call_signature_param_names(call_signatures) + return completion_names def _get_keyword_completion_names(self, keywords_): @@ -177,11 +177,8 @@ class Completion: ) return completion_names - def _trailer_completions(self, completion_parts): - scopes = list(inference.type_inference( - self._evaluator, self._parser, - self._pos, completion_parts.path - )) + def _trailer_completions(self, atom_expr): + scopes = self._evaluator.eval_element(atom_expr) completion_names = [] debug.dbg('possible completion scopes: %s', scopes) for s in scopes: diff --git a/jedi/api/inference.py b/jedi/api/inference.py index 5f82daee..3c26cb30 100644 --- a/jedi/api/inference.py +++ b/jedi/api/inference.py @@ -2,26 +2,10 @@ This module has helpers for doing type inference on strings. It is needed, because we still want to infer types where the syntax is invalid. """ -from jedi import debug from jedi.parser import Parser, ParseError from jedi.evaluate.cache import memoize_default -def type_inference(evaluator, parser, position, dotted_path): - """ - Base for completions/goto. Basically it returns the resolved scopes - under cursor. - """ - debug.dbg('start: %s in %s', dotted_path, parser.user_scope()) - - # Just parse one statement, take it and evaluate it. - eval_stmt = get_under_cursor_stmt(evaluator, parser, dotted_path, position) - if eval_stmt is None: - return [] - - return evaluator.eval_element(eval_stmt) - - @memoize_default(evaluator_is_first_arg=True) def get_under_cursor_stmt(evaluator, parser, cursor_txt, start_pos): """ diff --git a/jedi/evaluate/helpers.py b/jedi/evaluate/helpers.py index 2c79e606..321006aa 100644 --- a/jedi/evaluate/helpers.py +++ b/jedi/evaluate/helpers.py @@ -88,6 +88,8 @@ def call_of_leaf(leaf, cut_own_trailer=False): # different trailers: `( x )`, `[ x ]` and `.x`. In the first two examples # we should not match anything more than x. if trailer.type != 'trailer' or leaf not in (trailer.children[0], trailer.children[-1]): + if trailer.type == 'atom': + return trailer return leaf power = trailer.parent diff --git a/test/completion/named_param.py b/test/completion/named_param.py index 571bb076..2dd147e9 100644 --- a/test/completion/named_param.py +++ b/test/completion/named_param.py @@ -20,3 +20,12 @@ a(some_args) #? 13 [] a(some_kwargs) + +def multiple(foo, bar): + pass + +#? 17 ['bar'] +multiple(foo, bar) + +#? ['bar'] +multiple(foo, bar