From 00d15da143cf19ff2e888d08c1a034162191ecd7 Mon Sep 17 00:00:00 2001 From: Dave Halter Date: Mon, 18 Aug 2014 14:51:38 +0200 Subject: [PATCH] refactor search_call_signatures. Now we don't need to set Call.next.parent in a strange way anymore and the whole thing seems to be more logical. --- jedi/api/__init__.py | 16 ++------- jedi/evaluate/helpers.py | 66 +++++++++++++++++++++-------------- jedi/parser/representation.py | 4 +-- 3 files changed, 44 insertions(+), 42 deletions(-) diff --git a/jedi/api/__init__.py b/jedi/api/__init__.py index 3cdc3508..57718790 100644 --- a/jedi/api/__init__.py +++ b/jedi/api/__init__.py @@ -379,7 +379,7 @@ class Script(object): else: # Fetch definition of callee, if there's no path otherwise. if not goto_path: - (call, _) = search_call_signatures(user_stmt, self._pos) + (call, _, _) = search_call_signatures(user_stmt, self._pos) if call is not None: while call.next is not None: call = call.next @@ -559,22 +559,12 @@ class Script(object): :rtype: list of :class:`classes.CallSignature` """ user_stmt = self._parser.user_stmt_with_whitespace() - call, index = search_call_signatures(user_stmt, self._pos) + call, execution_arr, index = search_call_signatures(user_stmt, self._pos) if call is None: return [] - stmt_el = call - while isinstance(stmt_el.parent, pr.StatementElement): - # Go to parent literal/variable until not possible anymore. This - # makes it possible to return the whole expression. - stmt_el = stmt_el.parent - # We can change the execution since it's a new object - # (fast_parent_copy). - execution_arr, call.execution = call.execution, None - call.next = None - with common.scale_speed_settings(settings.scale_call_signatures): - _callable = lambda: self._evaluator.eval_call(stmt_el) + _callable = lambda: self._evaluator.eval_call(call) origins = cache.cache_call_signatures(_callable, self.source, self._pos, user_stmt) debug.speed('func_call followed') diff --git a/jedi/evaluate/helpers.py b/jedi/evaluate/helpers.py index fc998660..71611ce4 100644 --- a/jedi/evaluate/helpers.py +++ b/jedi/evaluate/helpers.py @@ -78,50 +78,53 @@ def fast_parent_copy(obj): def call_signature_array_for_pos(stmt, pos): """ Searches for the array and position of a tuple. + Returns a tuple of (array, index-in-the-array, call). """ def search_array(arr, pos, origin_call=None): accepted_types = pr.Array.TUPLE, pr.Array.NOARRAY if arr.type == 'dict': for stmt in arr.values + arr.keys: - new_arr, index = call_signature_array_for_pos(stmt, pos) - if new_arr is not None: - return new_arr, index + tup = call_signature_array_for_pos(stmt, pos) + if tup[0] is not None: + return tup else: for i, stmt in enumerate(arr): - new_arr, index = call_signature_array_for_pos(stmt, pos) - if new_arr is not None: - return new_arr, index + tup = call_signature_array_for_pos(stmt, pos) + if tup[0] is not None: + return tup - # TODO couldn't we merge with the len(arr) == 0 check? + # Since we need the index, we duplicate efforts (with empty + # arrays). if arr.start_pos < pos <= stmt.end_pos: if arr.type in accepted_types and isinstance(origin_call, pr.Call): - return arr, i + return arr, i, origin_call + if len(arr) == 0 and arr.start_pos < pos < arr.end_pos: if arr.type in accepted_types and isinstance(origin_call, pr.Call): - return arr, 0 - return None, 0 + return arr, 0, origin_call + return None, 0, None def search_call(call, pos, origin_call=None): - arr, index = None, 0 + tup = None, 0, None if call.next is not None: method = search_array if isinstance(call.next, pr.Array) else search_call - arr, index = method(call.next, pos, origin_call or call) - if not arr and call.execution is not None: - arr, index = search_array(call.execution, pos, origin_call) - return arr, index + tup = method(call.next, pos, origin_call or call) + if not tup[0] and call.execution is not None: + tup = search_array(call.execution, pos, origin_call) + return tup if stmt.start_pos >= pos >= stmt.end_pos: - return None, 0 + return None, 0, None + tup = None, 0, None for command in stmt.expression_list(): - arr = None if isinstance(command, pr.Array): - arr, index = search_array(command, pos) + tup = search_array(command, pos) elif isinstance(command, pr.StatementElement): - arr, index = search_call(command, pos, command) - if arr is not None: - return arr, index - return None, 0 + tup = search_call(command, pos, command) + if tup[0] is not None: + break + return tup def search_call_signatures(user_stmt, position): @@ -129,16 +132,25 @@ def search_call_signatures(user_stmt, position): Returns the function Call that matches the position before. """ debug.speed('func_call start') - call, index = None, 0 + call, arr, index = None, None, 0 if user_stmt is not None and isinstance(user_stmt, pr.Statement): # some parts will of the statement will be removed user_stmt = fast_parent_copy(user_stmt) - arr, index = call_signature_array_for_pos(user_stmt, position) - if arr is not None: - call = arr.parent + arr, index, call = call_signature_array_for_pos(user_stmt, position) + + # Now remove the part after the call. Including the array from the + # statement. + stmt_el = call + while isinstance(stmt_el, pr.StatementElement): + if stmt_el.execution == arr: + stmt_el.execution = None + stmt_el.next = None + break + + stmt_el = stmt_el.next debug.speed('func_call parsed') - return call, index + return call, arr, index def scan_statement_for_calls(stmt, search_name, assignment_details=False): diff --git a/jedi/parser/representation.py b/jedi/parser/representation.py index 42e95b9c..1296bc81 100644 --- a/jedi/parser/representation.py +++ b/jedi/parser/representation.py @@ -1277,7 +1277,7 @@ class StatementElement(Simple): def set_next(self, call): """ Adds another part of the statement""" - call.parent = self + call.parent = self.parent if self.next is not None: self.next.set_next(call) else: @@ -1288,7 +1288,7 @@ class StatementElement(Simple): An execution is nothing else than brackets, with params in them, which shows access on the internals of this name. """ - call.parent = self + call.parent = self.parent if self.next is not None: self.next.set_execution(call) elif self.execution is not None: