1
0
forked from VimPlug/jedi

Improve call signature detection by a lot

Fixes #1399
This commit is contained in:
Dave Halter
2019-12-04 23:55:26 +01:00
parent 4ba3dc69b3
commit 700bd12122
3 changed files with 53 additions and 10 deletions

View File

@@ -330,17 +330,14 @@ def _get_call_signature_details_from_error_node(node, additional_children, posit
def get_call_signature_details(module, position): def get_call_signature_details(module, position):
leaf = module.get_leaf_for_position(position, include_prefixes=True) leaf = module.get_leaf_for_position(position, include_prefixes=True)
# It's easier to deal with the previous token than the next one in this
# case.
if leaf.start_pos >= position: if leaf.start_pos >= position:
# Whitespace / comments after the leaf count towards the previous leaf. # Whitespace / comments after the leaf count towards the previous leaf.
leaf = leaf.get_previous_leaf() leaf = leaf.get_previous_leaf()
if leaf is None: if leaf is None:
return None return None
if leaf == ')':
# TODO is this ok?
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 # Now that we know where we are in the syntax tree, we start to look at
# parents for possible function definitions. # parents for possible function definitions.
node = leaf.parent node = leaf.parent
@@ -364,11 +361,17 @@ def get_call_signature_details(module, position):
continue continue
additional_children.insert(0, n) additional_children.insert(0, n)
# Find a valid trailer
if node.type == 'trailer' and node.children[0] == '(': if node.type == 'trailer' and node.children[0] == '(':
leaf = node.get_previous_leaf() # Additionally we have to check that an ending parenthesis isn't
if leaf is None: # interpreted wrong. There are two cases:
return None # 1. Cursor before paren -> The current signature is good
return CallDetails(node.children[0], node.children, position) # 2. Cursor after paren -> We need to skip the current signature
if not (leaf is node.children[-1] and position >= leaf.end_pos):
leaf = node.get_previous_leaf()
if leaf is None:
return None
return CallDetails(node.children[0], node.children, position)
node = node.parent node = node.parent

View File

@@ -8,7 +8,7 @@ just one.
""" """
from functools import reduce from functools import reduce
from operator import add from operator import add
from parso.python.tree import ExprStmt, SyncCompFor, Name from parso.python.tree import Name
from jedi import debug from jedi import debug
from jedi._compatibility import zip_longest, unicode from jedi._compatibility import zip_longest, unicode

View File

@@ -491,6 +491,13 @@ _calls = [
(code4, 'i(?b,*r,c', 1), (code4, 'i(?b,*r,c', 1),
(code4, 'i(?*', 0), (code4, 'i(?*', 0),
(code4, 'i(?**', (0, 1)), (code4, 'i(?**', (0, 1)),
# Random
(code4, 'i(()', 0),
(code4, 'i((),', 1),
(code4, 'i([(),', 0),
(code4, 'i([(,', 1),
(code4, 'i(x,()', 1),
] ]
@@ -625,3 +632,36 @@ def test_call_magic_method(Script):
assert [p.name for p in sig.params] == ['self', 'baz'] assert [p.name for p in sig.params] == ['self', 'baz']
sig, = Script(code + 'X().__call__(').call_signatures() sig, = Script(code + 'X().__call__(').call_signatures()
assert [p.name for p in sig.params] == ['baz'] assert [p.name for p in sig.params] == ['baz']
@pytest.mark.parametrize('column', [6, 9])
def test_cursor_after_signature(Script, column):
source = dedent("""
def foo(*args):
pass
foo() # _
""")
script = Script(source, 4, column)
assert not script.call_signatures()
@pytest.mark.parametrize(
'code, line, column, name, index', [
('abs(()\ndef foo(): pass', 1, None, 'abs', 0),
('abs(chr() \ndef foo(): pass', 1, 10, 'abs', 0),
('abs(chr()\ndef foo(): pass', 1, None, 'abs', 0),
('abs(chr()\ndef foo(): pass', 1, 8, 'chr', 0),
('abs(chr()\ndef foo(): pass', 1, 7, 'abs', 0),
('abs(chr ( \nclass y: pass', 1, None, 'chr', 0),
('abs(chr ( \nclass y: pass', 1, 8, 'abs', 0),
('abs(chr ( \nclass y: pass', 1, 9, 'abs', 0),
('abs(chr ( \nclass y: pass', 1, 10, 'chr', 0),
]
)
def test_base_signatures(Script, code, line, column, name, index):
sig, = Script(code, line=line, column=column).call_signatures()
assert sig.name == name
assert sig.index == index