diff --git a/jedi/api/__init__.py b/jedi/api/__init__.py index d2eaf427..6c3c619b 100644 --- a/jedi/api/__init__.py +++ b/jedi/api/__init__.py @@ -442,18 +442,13 @@ class Script(object): user_stmt = self._parser.user_stmt() stmt = self._get_under_cursor_stmt(goto_path) - expression_list = stmt.expression_list() - if len(expression_list) == 0: - return [] - # The reverse tokenizer only generates parses call. - assert len(expression_list) == 1 - call = expression_list[0] - if isinstance(call, pr.Call): - call_path = list(call.generate_call_path()) - else: - # goto_assignments on Operator returns nothing. + if stmt is None: return [] + last_name = stmt + while not isinstance(last_name, pr.Name): + last_name = last_name.children[-1] + if next(context) in ('class', 'def'): # The cursor is on a class/function name. user_scope = self._parser.user_scope() @@ -476,14 +471,14 @@ class Script(object): # The Evaluator.goto function checks for definitions, but since we # use a reverse tokenizer, we have new name_part objects, so we # have to check the user_stmt here for positions. - if isinstance(user_stmt, pr.ExprStmt): + if False and isinstance(user_stmt, pr.ExprStmt): for name in user_stmt.get_defined_names(): if name.start_pos <= self._pos <= name.end_pos \ and (not isinstance(name.parent, pr.Call) or name.parent.next is None): return [name] - defs = self._evaluator.goto(stmt, call_path) + defs = self._evaluator.goto(last_name) definitions = follow_inexistent_imports(defs) return definitions diff --git a/jedi/evaluate/__init__.py b/jedi/evaluate/__init__.py index 07e7eb3b..6723db11 100644 --- a/jedi/evaluate/__init__.py +++ b/jedi/evaluate/__init__.py @@ -442,7 +442,15 @@ class Evaluator(object): call = call_of_name(name) return self.eval_element(call) - def goto(self, stmt, call_path): + def goto(self, name): + scope = name.get_parent_scope() + if pr.is_node(name.parent, 'trailer'): + call = call_of_name(name, cut_own_trailer=True) + types = self.eval_element(call) + return iterable.unite(self.find_types(typ, name, is_goto=True) + for typ in types) + else: + return self.find_types(scope, name, search_global=True, is_goto=True) if isinstance(stmt, pr.Import): # Nowhere to goto for aliases if stmt.alias == call_path[0]: diff --git a/jedi/evaluate/helpers.py b/jedi/evaluate/helpers.py index 7967b869..b16449c7 100644 --- a/jedi/evaluate/helpers.py +++ b/jedi/evaluate/helpers.py @@ -97,7 +97,7 @@ def deep_ast_copy(obj, new_elements_default=None): return recursion(obj) -def call_of_name(name): +def call_of_name(name, cut_own_trailer=False): """ Creates a "call" node that consist of all ``trailer`` and ``power`` objects. E.g. if you call it with ``append``:: @@ -119,10 +119,14 @@ def call_of_name(name): par = power # Now the name must be part of a trailer index = par.children.index(name.parent) - if index != len(par.children) - 1: + if index != len(par.children) - 1 or cut_own_trailer: # Now we have to cut the other trailers away. par = deep_ast_copy(par) - par.children[index + 1:] = [] + if not cut_own_trailer: + # Normally we would remove just the stuff after the index, but + # if the option is set remove the index as well. (for goto) + index = index + 1 + par.children[index:] = [] return par