forked from VimPlug/jedi
A lot of call signature refactorings. Note that this commit is totally broken.
This commit is contained in:
@@ -182,8 +182,12 @@ class Script(object):
|
||||
|
||||
:rtype: list of :class:`classes.Definition`
|
||||
"""
|
||||
c = helpers.ContextResults(self._evaluator, self.source, self._get_module(), self._pos)
|
||||
definitions = c.get_results()
|
||||
leaf = self._get_module().name_for_position(self._pos)
|
||||
if leaf is None:
|
||||
leaf = self._get_module().get_leaf_for_position(self._pos)
|
||||
if leaf is None:
|
||||
return []
|
||||
definitions = helpers.evaluate_goto_definition(self._evaluator, leaf)
|
||||
|
||||
names = [s.name for s in definitions]
|
||||
defs = [classes.Definition(self._evaluator, name) for name in names]
|
||||
@@ -272,26 +276,30 @@ class Script(object):
|
||||
|
||||
abs()# <-- cursor is here
|
||||
|
||||
This would return ``None``.
|
||||
This would return an empty list..
|
||||
|
||||
:rtype: list of :class:`classes.CallSignature`
|
||||
"""
|
||||
call_txt, call_index, key_name, start_pos = self._user_context.call_signature()
|
||||
if call_txt is None:
|
||||
call_signature_details = \
|
||||
helpers.get_call_signature_details(self._get_module(), self._pos)
|
||||
if call_signature_details is None:
|
||||
return []
|
||||
|
||||
stmt = inference.get_under_cursor_stmt(self._evaluator, self._parser,
|
||||
call_txt, start_pos)
|
||||
if stmt is None:
|
||||
return []
|
||||
|
||||
with common.scale_speed_settings(settings.scale_call_signatures):
|
||||
origins = cache.cache_call_signatures(self._evaluator, stmt,
|
||||
self.source, self._pos)
|
||||
# TODO insert caching again here.
|
||||
#with common.scale_speed_settings(settings.scale_call_signatures):
|
||||
# definitions = cache.cache_call_signatures(self._evaluator, stmt,
|
||||
# self.source, self._pos)
|
||||
definitions = helpers.evaluate_goto_definition(
|
||||
self._evaluator,
|
||||
call_signature_details.leaf
|
||||
)
|
||||
debug.speed('func_call followed')
|
||||
|
||||
return [classes.CallSignature(self._evaluator, o.name, stmt, call_index, key_name)
|
||||
for o in origins if hasattr(o, 'py__call__')]
|
||||
return [classes.CallSignature(self._evaluator, d.name,
|
||||
call_signature_details.leaf.start_pos,
|
||||
call_signature_details.call_index,
|
||||
call_signature_details.keyword_name)
|
||||
for d in definitions if hasattr(d, 'py__call__')]
|
||||
|
||||
def _analysis(self):
|
||||
self._evaluator.is_analysis = True
|
||||
|
||||
@@ -629,11 +629,11 @@ class CallSignature(Definition):
|
||||
It knows what functions you are currently in. e.g. `isinstance(` would
|
||||
return the `isinstance` function. without `(` it would return nothing.
|
||||
"""
|
||||
def __init__(self, evaluator, executable_name, call_stmt, index, key_name):
|
||||
def __init__(self, evaluator, executable_name, bracket_start_pos, index, key_name):
|
||||
super(CallSignature, self).__init__(evaluator, executable_name)
|
||||
self._index = index
|
||||
self._key_name = key_name
|
||||
self._call_stmt = call_stmt
|
||||
self._bracket_start_pos = bracket_start_pos
|
||||
|
||||
@property
|
||||
def index(self):
|
||||
@@ -665,7 +665,7 @@ class CallSignature(Definition):
|
||||
The indent of the bracket that is responsible for the last function
|
||||
call.
|
||||
"""
|
||||
return self._call_stmt.end_pos
|
||||
return self._bracket_start_pos
|
||||
|
||||
@property
|
||||
def call_name(self):
|
||||
|
||||
@@ -6,6 +6,7 @@ from collections import namedtuple
|
||||
|
||||
from jedi import common
|
||||
from jedi.evaluate import imports
|
||||
from jedi.evaluate.helpers import deep_ast_copy
|
||||
from jedi import parser
|
||||
from jedi.parser import tokenize, token
|
||||
|
||||
@@ -169,68 +170,63 @@ def get_possible_completion_types(grammar, stack):
|
||||
return keywords, grammar_labels
|
||||
|
||||
|
||||
class ContextResults():
|
||||
def __init__(self, evaluator, source, module, pos):
|
||||
self._evaluator = evaluator
|
||||
self._module = module
|
||||
self._source = source
|
||||
self._pos = pos
|
||||
def evaluate_goto_definition(evaluator, leaf):
|
||||
if leaf.type == 'name':
|
||||
# In case of a name we can just use goto_definition which does all the
|
||||
# magic itself.
|
||||
return evaluator.goto_definitions(leaf)
|
||||
|
||||
def _on_defining_name(self, leaf):
|
||||
return [self._evaluator.wrap(self._parser.user_scope())]
|
||||
node = None
|
||||
parent = leaf.parent
|
||||
if parent.type == 'atom':
|
||||
node = leaf.parent
|
||||
elif parent.type == 'trailer':
|
||||
index = parent.parent.children.index(parent)
|
||||
node = deep_ast_copy(parent.parent)
|
||||
node.children = node.children[:index + 1]
|
||||
|
||||
def get_results(self):
|
||||
'''
|
||||
try:
|
||||
stack = get_stack_at_position(self._evaluator.grammar, self._source, self._module, self._leaf.end_pos)
|
||||
except OnErrorLeaf:
|
||||
if node is None:
|
||||
return []
|
||||
'''
|
||||
return evaluator.eval_element(node)
|
||||
|
||||
name = self._module.name_for_position(self._pos)
|
||||
if name is not None:
|
||||
return self._evaluator.goto_definitions(name)
|
||||
|
||||
leaf = self._module.get_leaf_for_position(self._pos)
|
||||
if leaf is None:
|
||||
return []
|
||||
|
||||
if leaf.parent.type == 'atom':
|
||||
return self._evaluator.eval_element(leaf.parent)
|
||||
if leaf.parent.type == 'trailer':
|
||||
return self._evaluator.eval_element(leaf.parent.parent)
|
||||
return []
|
||||
symbol_names = list(stack.get_node_names(self._evaluator.grammar))
|
||||
|
||||
nodes = list(stack.get_nodes())
|
||||
|
||||
if "import_stmt" in symbol_names:
|
||||
level = 0
|
||||
only_modules = True
|
||||
level, names = self._parse_dotted_names(nodes)
|
||||
if "import_from" in symbol_names:
|
||||
if 'import' in nodes:
|
||||
only_modules = False
|
||||
else:
|
||||
assert "import_name" in symbol_names
|
||||
|
||||
completion_names += self._get_importer_names(
|
||||
names,
|
||||
level,
|
||||
only_modules
|
||||
CallSignatureDetails = namedtuple(
|
||||
'CallSignatureDetails',
|
||||
['leaf', 'call_index', 'keyword_name']
|
||||
)
|
||||
elif nodes[-2] in ('as', 'def', 'class'):
|
||||
# No completions for ``with x as foo`` and ``import x as foo``.
|
||||
# Also true for defining names as a class or function.
|
||||
return self._on_defining_name(self._leaf)
|
||||
else:
|
||||
completion_names += self._simple_complete(completion_parts)
|
||||
return
|
||||
|
||||
|
||||
class GotoDefinition(ContextResults):
|
||||
def _():
|
||||
definitions = inference.type_inference(
|
||||
self._evaluator, self._parser, self._user_context,
|
||||
self._pos, goto_path
|
||||
)
|
||||
def _get_call_signature_details_from_error_node(node, position):
|
||||
for index, element in reversed(list(enumerate(node.children))):
|
||||
# `index > 0` means that it's a trailer and not an atom.
|
||||
if element == '(' and element.end_pos <= position and index > 0:
|
||||
name = element.get_previous_leaf()
|
||||
if name.type == 'name':
|
||||
nodes_before = [c for c in node.children[index:] if c.start_pos < position]
|
||||
return CallSignatureDetails(name, nodes_before.count(','), None)
|
||||
|
||||
|
||||
def get_call_signature_details(module, position):
|
||||
leaf = module.get_leaf_for_position(position, include_prefixes=True)
|
||||
if leaf == ')':
|
||||
if leaf.end_pos == position:
|
||||
leaf = leaf.get_next_leaf()
|
||||
# Now that we know where we are in the syntax tree, we start to look at
|
||||
# parents for possible function definitions.
|
||||
node = leaf.parent
|
||||
name = None
|
||||
while node is not None:
|
||||
for n in node.children:
|
||||
if n.start_pos < position and n.type == 'error_node':
|
||||
result = _get_call_signature_details_from_error_node(n, position)
|
||||
if result is not None:
|
||||
return result
|
||||
|
||||
if node.type == 'trailer' and node.children[0] == '(':
|
||||
name = node.get_previous_sibling()
|
||||
nodes_before = [c for c in node.children if c.start_pos < position]
|
||||
return CallSignatureDetails(name, nodes_before.count(','), None)
|
||||
|
||||
node = node.parent
|
||||
|
||||
return None
|
||||
|
||||
@@ -81,15 +81,32 @@ def call_of_name(name, cut_own_trailer=False):
|
||||
# TODO remove cut_own_trailer option, since its always used with it. Just
|
||||
# ignore it, It's not what we want anyway. Or document it better?
|
||||
"""
|
||||
par = name
|
||||
if tree.is_node(par.parent, 'trailer'):
|
||||
trailer = name.parent
|
||||
if trailer.type != 'trailer' or trailer.children[0] != '.':
|
||||
return name
|
||||
|
||||
assert not cut_own_trailer # TODO remove
|
||||
power = trailer.parent
|
||||
index = power.children.index(trailer)
|
||||
power = deep_ast_copy(power)
|
||||
power.children[index + 1:] = []
|
||||
|
||||
if power.type == 'error_node':
|
||||
transformed = tree.Node('power', power.children)
|
||||
transformed.parent = power.parent
|
||||
return transformed
|
||||
|
||||
return power
|
||||
if 1:
|
||||
par = par.parent
|
||||
if par.children[0] in ('(', '['):
|
||||
# The trailer is not a NAME.NAME trailer, but a call to something.
|
||||
return name
|
||||
|
||||
power = par.parent
|
||||
if tree.is_node(power, 'power', 'atom_expr') \
|
||||
# `atom_expr` got introduced in Python 3.5 and is essentially just the
|
||||
# whole call part without the optional ** power element.
|
||||
if power.type in ('power', 'atom_expr') \
|
||||
and power.children[0] != name \
|
||||
and not (power.children[-2] == '**' and
|
||||
name.start_pos > power.children[-1].start_pos):
|
||||
|
||||
@@ -83,6 +83,9 @@ TestClass.var_local.
|
||||
|
||||
#? int()
|
||||
TestClass().ret(1)
|
||||
# Should not return int(), because we want the type before `.ret(1)`.
|
||||
#? 11 TestClass()
|
||||
TestClass().ret(1)
|
||||
#? int()
|
||||
inst.ret(1)
|
||||
|
||||
|
||||
@@ -14,7 +14,8 @@ class TestCallSignatures(TestCase):
|
||||
assert len(signatures) <= 1
|
||||
|
||||
if not signatures:
|
||||
assert expected_name is None
|
||||
assert expected_name is None, \
|
||||
'There are no signatures, but %s expected.' % expected_name
|
||||
else:
|
||||
assert signatures[0].name == expected_name
|
||||
assert signatures[0].index == expected_index
|
||||
@@ -27,9 +28,6 @@ class TestCallSignatures(TestCase):
|
||||
|
||||
def test_simple(self):
|
||||
run = self._run_simple
|
||||
s7 = "str().upper().center("
|
||||
s8 = "str(int[zip("
|
||||
run(s7, 'center', 0)
|
||||
|
||||
# simple
|
||||
s1 = "sorted(a, str("
|
||||
|
||||
Reference in New Issue
Block a user