forked from VimPlug/jedi
Move inference_state.goto to the name and _follow_error_node_imports_if_possible away from inference_state
This commit is contained in:
@@ -69,7 +69,6 @@ from jedi.file_io import FileIO
|
|||||||
|
|
||||||
from jedi import debug
|
from jedi import debug
|
||||||
from jedi import parser_utils
|
from jedi import parser_utils
|
||||||
from jedi.inference.utils import unite
|
|
||||||
from jedi.inference import imports
|
from jedi.inference import imports
|
||||||
from jedi.inference import recursion
|
from jedi.inference import recursion
|
||||||
from jedi.inference.cache import inference_state_function_cache
|
from jedi.inference.cache import inference_state_function_cache
|
||||||
@@ -79,8 +78,9 @@ from jedi.inference.base_value import ContextualizedNode, \
|
|||||||
ValueSet, NO_VALUES, iterate_values
|
ValueSet, NO_VALUES, iterate_values
|
||||||
from jedi.inference.value import ClassValue, FunctionValue
|
from jedi.inference.value import ClassValue, FunctionValue
|
||||||
from jedi.inference.context import CompForContext
|
from jedi.inference.context import CompForContext
|
||||||
from jedi.inference.syntax_tree import infer_trailer, infer_expr_stmt, \
|
from jedi.inference.syntax_tree import infer_expr_stmt, \
|
||||||
infer_node, check_tuple_assignments
|
infer_node, check_tuple_assignments
|
||||||
|
from jedi.inference.imports import follow_error_node_imports_if_possible
|
||||||
from jedi.plugins import plugin_manager
|
from jedi.plugins import plugin_manager
|
||||||
|
|
||||||
|
|
||||||
@@ -261,106 +261,12 @@ class InferenceState(object):
|
|||||||
if type_ in ('import_from', 'import_name'):
|
if type_ in ('import_from', 'import_name'):
|
||||||
return imports.infer_import(context, name)
|
return imports.infer_import(context, name)
|
||||||
else:
|
else:
|
||||||
result = self._follow_error_node_imports_if_possible(context, name)
|
result = follow_error_node_imports_if_possible(context, name)
|
||||||
if result is not None:
|
if result is not None:
|
||||||
return result
|
return result
|
||||||
|
|
||||||
return helpers.infer_call_of_leaf(context, name)
|
return helpers.infer_call_of_leaf(context, name)
|
||||||
|
|
||||||
def _follow_error_node_imports_if_possible(self, context, name):
|
|
||||||
error_node = tree.search_ancestor(name, 'error_node')
|
|
||||||
if error_node is not None:
|
|
||||||
# Get the first command start of a started simple_stmt. The error
|
|
||||||
# node is sometimes a small_stmt and sometimes a simple_stmt. Check
|
|
||||||
# for ; leaves that start a new statements.
|
|
||||||
start_index = 0
|
|
||||||
for index, n in enumerate(error_node.children):
|
|
||||||
if n.start_pos > name.start_pos:
|
|
||||||
break
|
|
||||||
if n == ';':
|
|
||||||
start_index = index + 1
|
|
||||||
nodes = error_node.children[start_index:]
|
|
||||||
first_name = nodes[0].get_first_leaf().value
|
|
||||||
|
|
||||||
# Make it possible to infer stuff like `import foo.` or
|
|
||||||
# `from foo.bar`.
|
|
||||||
if first_name in ('from', 'import'):
|
|
||||||
is_import_from = first_name == 'from'
|
|
||||||
level, names = helpers.parse_dotted_names(
|
|
||||||
nodes,
|
|
||||||
is_import_from=is_import_from,
|
|
||||||
until_node=name,
|
|
||||||
)
|
|
||||||
return imports.Importer(self, names, context.get_root_context(), level).follow()
|
|
||||||
return None
|
|
||||||
|
|
||||||
def goto(self, context, name):
|
|
||||||
definition = name.get_definition(import_name_always=True)
|
|
||||||
if definition is not None:
|
|
||||||
type_ = definition.type
|
|
||||||
if type_ == 'expr_stmt':
|
|
||||||
# Only take the parent, because if it's more complicated than just
|
|
||||||
# a name it's something you can "goto" again.
|
|
||||||
is_simple_name = name.parent.type not in ('power', 'trailer')
|
|
||||||
if is_simple_name:
|
|
||||||
return [TreeNameDefinition(context, name)]
|
|
||||||
elif type_ in ('import_from', 'import_name'):
|
|
||||||
module_names = imports.goto_import(context, name)
|
|
||||||
return module_names
|
|
||||||
else:
|
|
||||||
return [TreeNameDefinition(context, name)]
|
|
||||||
else:
|
|
||||||
values = self._follow_error_node_imports_if_possible(context, name)
|
|
||||||
if values is not None:
|
|
||||||
return [value.name for value in values]
|
|
||||||
|
|
||||||
par = name.parent
|
|
||||||
node_type = par.type
|
|
||||||
if node_type == 'argument' and par.children[1] == '=' and par.children[0] == name:
|
|
||||||
# Named param goto.
|
|
||||||
trailer = par.parent
|
|
||||||
if trailer.type == 'arglist':
|
|
||||||
trailer = trailer.parent
|
|
||||||
if trailer.type != 'classdef':
|
|
||||||
if trailer.type == 'decorator':
|
|
||||||
value_set = context.infer_node(trailer.children[1])
|
|
||||||
else:
|
|
||||||
i = trailer.parent.children.index(trailer)
|
|
||||||
to_infer = trailer.parent.children[:i]
|
|
||||||
if to_infer[0] == 'await':
|
|
||||||
to_infer.pop(0)
|
|
||||||
value_set = context.infer_node(to_infer[0])
|
|
||||||
for trailer in to_infer[1:]:
|
|
||||||
value_set = infer_trailer(context, value_set, trailer)
|
|
||||||
param_names = []
|
|
||||||
for value in value_set:
|
|
||||||
for signature in value.get_signatures():
|
|
||||||
for param_name in signature.get_param_names():
|
|
||||||
if param_name.string_name == name.value:
|
|
||||||
param_names.append(param_name)
|
|
||||||
return param_names
|
|
||||||
elif node_type == 'dotted_name': # Is a decorator.
|
|
||||||
index = par.children.index(name)
|
|
||||||
if index > 0:
|
|
||||||
new_dotted = helpers.deep_ast_copy(par)
|
|
||||||
new_dotted.children[index - 1:] = []
|
|
||||||
values = context.infer_node(new_dotted)
|
|
||||||
return unite(
|
|
||||||
value.goto(name, name_context=value.as_context())
|
|
||||||
for value in values
|
|
||||||
)
|
|
||||||
|
|
||||||
if node_type == 'trailer' and par.children[0] == '.':
|
|
||||||
values = helpers.infer_call_of_leaf(context, name, cut_own_trailer=True)
|
|
||||||
return values.goto(name, name_context=context)
|
|
||||||
else:
|
|
||||||
stmt = tree.search_ancestor(
|
|
||||||
name, 'expr_stmt', 'lambdef'
|
|
||||||
) or name
|
|
||||||
if stmt.type == 'lambdef':
|
|
||||||
stmt = name
|
|
||||||
return context.goto(name, position=stmt.start_pos)
|
|
||||||
|
|
||||||
def parse_and_get_code(self, code=None, path=None, encoding='utf-8',
|
def parse_and_get_code(self, code=None, path=None, encoding='utf-8',
|
||||||
use_latest_grammar=False, file_io=None, **kwargs):
|
use_latest_grammar=False, file_io=None, **kwargs):
|
||||||
if self.allow_different_encoding:
|
if self.allow_different_encoding:
|
||||||
|
|||||||
@@ -577,3 +577,33 @@ def get_module_contexts_containing_name(inference_state, module_contexts, name):
|
|||||||
m = check_fs(file_io, base_names)
|
m = check_fs(file_io, base_names)
|
||||||
if m is not None:
|
if m is not None:
|
||||||
yield m
|
yield m
|
||||||
|
|
||||||
|
|
||||||
|
def follow_error_node_imports_if_possible(context, name):
|
||||||
|
error_node = tree.search_ancestor(name, 'error_node')
|
||||||
|
if error_node is not None:
|
||||||
|
# Get the first command start of a started simple_stmt. The error
|
||||||
|
# node is sometimes a small_stmt and sometimes a simple_stmt. Check
|
||||||
|
# for ; leaves that start a new statements.
|
||||||
|
start_index = 0
|
||||||
|
for index, n in enumerate(error_node.children):
|
||||||
|
if n.start_pos > name.start_pos:
|
||||||
|
break
|
||||||
|
if n == ';':
|
||||||
|
start_index = index + 1
|
||||||
|
nodes = error_node.children[start_index:]
|
||||||
|
first_name = nodes[0].get_first_leaf().value
|
||||||
|
|
||||||
|
# Make it possible to infer stuff like `import foo.` or
|
||||||
|
# `from foo.bar`.
|
||||||
|
if first_name in ('from', 'import'):
|
||||||
|
is_import_from = first_name == 'from'
|
||||||
|
level, names = helpers.parse_dotted_names(
|
||||||
|
nodes,
|
||||||
|
is_import_from=is_import_from,
|
||||||
|
until_node=name,
|
||||||
|
)
|
||||||
|
return Importer(
|
||||||
|
context.inference_state, names, context.get_root_context(), level).follow()
|
||||||
|
return None
|
||||||
|
|
||||||
|
|||||||
@@ -3,9 +3,11 @@ from abc import abstractmethod
|
|||||||
from parso.tree import search_ancestor
|
from parso.tree import search_ancestor
|
||||||
|
|
||||||
from jedi._compatibility import Parameter
|
from jedi._compatibility import Parameter
|
||||||
|
from jedi.inference.utils import unite
|
||||||
from jedi.inference.base_value import ValueSet, NO_VALUES
|
from jedi.inference.base_value import ValueSet, NO_VALUES
|
||||||
from jedi.inference import docstrings
|
from jedi.inference import docstrings
|
||||||
from jedi.cache import memoize_method
|
from jedi.cache import memoize_method
|
||||||
|
from jedi.inference.helpers import deep_ast_copy, infer_call_of_leaf
|
||||||
|
|
||||||
|
|
||||||
class AbstractNameDefinition(object):
|
class AbstractNameDefinition(object):
|
||||||
@@ -106,10 +108,77 @@ class AbstractTreeName(AbstractNameDefinition):
|
|||||||
return None
|
return None
|
||||||
return parent_names + (self.tree_name.value,)
|
return parent_names + (self.tree_name.value,)
|
||||||
|
|
||||||
def goto(self, **kwargs):
|
def goto(self):
|
||||||
return self.parent_context.inference_state.goto(
|
context = self.parent_context
|
||||||
self.parent_context, self.tree_name, **kwargs
|
name = self.tree_name
|
||||||
)
|
definition = name.get_definition(import_name_always=True)
|
||||||
|
if definition is not None:
|
||||||
|
type_ = definition.type
|
||||||
|
if type_ == 'expr_stmt':
|
||||||
|
# Only take the parent, because if it's more complicated than just
|
||||||
|
# a name it's something you can "goto" again.
|
||||||
|
is_simple_name = name.parent.type not in ('power', 'trailer')
|
||||||
|
if is_simple_name:
|
||||||
|
return [TreeNameDefinition(context, name)]
|
||||||
|
elif type_ in ('import_from', 'import_name'):
|
||||||
|
from jedi.inference.imports import goto_import
|
||||||
|
module_names = goto_import(context, name)
|
||||||
|
return module_names
|
||||||
|
else:
|
||||||
|
return [TreeNameDefinition(context, name)]
|
||||||
|
else:
|
||||||
|
from jedi.inference.imports import follow_error_node_imports_if_possible
|
||||||
|
values = follow_error_node_imports_if_possible(context, name)
|
||||||
|
if values is not None:
|
||||||
|
return [value.name for value in values]
|
||||||
|
|
||||||
|
par = name.parent
|
||||||
|
node_type = par.type
|
||||||
|
if node_type == 'argument' and par.children[1] == '=' and par.children[0] == name:
|
||||||
|
# Named param goto.
|
||||||
|
trailer = par.parent
|
||||||
|
if trailer.type == 'arglist':
|
||||||
|
trailer = trailer.parent
|
||||||
|
if trailer.type != 'classdef':
|
||||||
|
if trailer.type == 'decorator':
|
||||||
|
value_set = context.infer_node(trailer.children[1])
|
||||||
|
else:
|
||||||
|
i = trailer.parent.children.index(trailer)
|
||||||
|
to_infer = trailer.parent.children[:i]
|
||||||
|
if to_infer[0] == 'await':
|
||||||
|
to_infer.pop(0)
|
||||||
|
value_set = context.infer_node(to_infer[0])
|
||||||
|
from jedi.inference.syntax_tree import infer_trailer
|
||||||
|
for trailer in to_infer[1:]:
|
||||||
|
value_set = infer_trailer(context, value_set, trailer)
|
||||||
|
param_names = []
|
||||||
|
for value in value_set:
|
||||||
|
for signature in value.get_signatures():
|
||||||
|
for param_name in signature.get_param_names():
|
||||||
|
if param_name.string_name == name.value:
|
||||||
|
param_names.append(param_name)
|
||||||
|
return param_names
|
||||||
|
elif node_type == 'dotted_name': # Is a decorator.
|
||||||
|
index = par.children.index(name)
|
||||||
|
if index > 0:
|
||||||
|
new_dotted = deep_ast_copy(par)
|
||||||
|
new_dotted.children[index - 1:] = []
|
||||||
|
values = context.infer_node(new_dotted)
|
||||||
|
return unite(
|
||||||
|
value.goto(name, name_context=value.as_context())
|
||||||
|
for value in values
|
||||||
|
)
|
||||||
|
|
||||||
|
if node_type == 'trailer' and par.children[0] == '.':
|
||||||
|
values = infer_call_of_leaf(context, name, cut_own_trailer=True)
|
||||||
|
return values.goto(name, name_context=context)
|
||||||
|
else:
|
||||||
|
stmt = search_ancestor(
|
||||||
|
name, 'expr_stmt', 'lambdef'
|
||||||
|
) or name
|
||||||
|
if stmt.type == 'lambdef':
|
||||||
|
stmt = name
|
||||||
|
return context.goto(name, position=stmt.start_pos)
|
||||||
|
|
||||||
def is_import(self):
|
def is_import(self):
|
||||||
imp = search_ancestor(self.tree_name, 'import_from', 'import_name')
|
imp = search_ancestor(self.tree_name, 'import_from', 'import_name')
|
||||||
@@ -216,6 +285,7 @@ class TreeNameDefinition(AbstractTreeName):
|
|||||||
node = node.parent
|
node = node.parent
|
||||||
return indexes
|
return indexes
|
||||||
|
|
||||||
|
|
||||||
class _ParamMixin(object):
|
class _ParamMixin(object):
|
||||||
def maybe_positional_argument(self, include_star=True):
|
def maybe_positional_argument(self, include_star=True):
|
||||||
options = [Parameter.POSITIONAL_ONLY, Parameter.POSITIONAL_OR_KEYWORD]
|
options = [Parameter.POSITIONAL_ONLY, Parameter.POSITIONAL_OR_KEYWORD]
|
||||||
|
|||||||
Reference in New Issue
Block a user