Skip to content

Commit 50a0a5b

Browse files
committed
Improve how we determine if a symbol was imported from other libraries
1 parent 07c131f commit 50a0a5b

File tree

1 file changed

+33
-13
lines changed

1 file changed

+33
-13
lines changed

pylsp/plugins/symbols.py

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -33,27 +33,47 @@ def pylsp_document_symbols(config, document):
3333
if ' import ' in code or 'import ' in code:
3434
continue
3535

36-
# Skip comparing module names.
36+
# Skip imported symbols comparing module names.
3737
sym_full_name = d.full_name
38-
module_name = document.dot_path
38+
document_dot_path = document.dot_path
3939
if sym_full_name is not None:
40-
# module_name returns where the symbol is imported, whereas
41-
# full_name says where it really comes from. So if the parent
42-
# modules in full_name are not in module_name, it means the
43-
# symbol was not defined there.
44-
# Note: The last element of sym_full_name is the symbol itself,
45-
# so we don't need to use it below.
40+
# We assume a symbol is imported from another module to start
41+
# with.
4642
imported_symbol = True
47-
for mod in sym_full_name.split('.')[:-1]:
48-
if mod in module_name:
49-
imported_symbol = False
43+
44+
# The last element of sym_full_name is the symbol itself, so
45+
# we need to discard it to do module comparisons below.
46+
if '.' in sym_full_name:
47+
sym_module_name = sym_full_name.rpartition('.')[0]
48+
49+
# This is necessary to display symbols in init files (the checks
50+
# below fail without it).
51+
if document_dot_path.endswith('__init__'):
52+
document_dot_path = document_dot_path.rpartition('.')[0]
53+
54+
# document_dot_path is the module where the symbol is imported,
55+
# whereas sym_module_name is the one where it was declared.
56+
if sym_module_name.startswith(document_dot_path):
57+
# If sym_module_name starts with the same string as document_dot_path,
58+
# we can safely assume it was declared in the document.
59+
imported_symbol = False
60+
elif sym_module_name.split('.')[0] in document_dot_path.split('.'):
61+
# If the first module in sym_module_name is one of the modules in
62+
# document_dot_path, we need to check if sym_module_name starts
63+
# with the modules in document_dot_path.
64+
document_mods = document_dot_path.split('.')
65+
for i in range(1, len(document_mods) + 1):
66+
submod = '.'.join(document_mods[-i:])
67+
if sym_module_name.startswith(submod):
68+
imported_symbol = False
69+
break
5070

5171
# When there's no __init__.py next to a file or in one of its
52-
# parents, the check above fails. However, Jedi has a nice way
72+
# parents, the checks above fail. However, Jedi has a nice way
5373
# to tell if the symbol was declared in the same file: if
5474
# full_name starts by __main__.
5575
if imported_symbol:
56-
if not sym_full_name.startswith('__main__'):
76+
if not sym_module_name.startswith('__main__'):
5777
continue
5878

5979
try:

0 commit comments

Comments
 (0)