diff --git a/jedi/api/__init__.py b/jedi/api/__init__.py index 00b29b7c..0dfa2c1f 100644 --- a/jedi/api/__init__.py +++ b/jedi/api/__init__.py @@ -38,7 +38,6 @@ from jedi.evaluate.syntax_tree import tree_name_to_contexts from jedi.evaluate.context import ModuleContext from jedi.evaluate.base_context import ContextSet from jedi.evaluate.context.iterable import unpack_tuple_to_dict -#from jedi.evaluate.gradual.typeshed import try_to_merge_with_stub from jedi.evaluate.gradual.stub_context import try_stubs_to_actual_context_set, \ try_stub_to_actual_names from jedi.evaluate.gradual.utils import load_proper_stub_module diff --git a/jedi/api/classes.py b/jedi/api/classes.py index 9a1b9822..90851d15 100644 --- a/jedi/api/classes.py +++ b/jedi/api/classes.py @@ -324,12 +324,8 @@ class BaseDefinition(object): ] def goto_assignments(self): - if self._name.tree_name is None: - return self - - names = self._name.goto() - names = try_stub_to_actual_names(names, prefer_stub_to_compiled=True) - return [Definition(self._evaluator, n) for n in names] + return [self if n == self._name else Definition(self._evaluator, n) + for n in self._name.goto()] def infer(self): tree_name = self._name.tree_name diff --git a/jedi/evaluate/__init__.py b/jedi/evaluate/__init__.py index d6d219b8..5b4cb8bf 100644 --- a/jedi/evaluate/__init__.py +++ b/jedi/evaluate/__init__.py @@ -85,7 +85,8 @@ from jedi.evaluate.context.iterable import CompForContext from jedi.evaluate.syntax_tree import eval_trailer, eval_expr_stmt, \ eval_node, check_tuple_assignments from jedi.evaluate.gradual.stub_context import \ - stub_to_actual_context_set, goto_with_stubs_if_possible, goto_non_stub + stub_to_actual_context_set, goto_with_stubs_if_possible, \ + try_stub_to_actual_names def _execute(context, arguments): @@ -322,6 +323,11 @@ class Evaluator(object): return None def goto(self, context, name): + names = self._goto(context, name) + names = try_stub_to_actual_names(names, prefer_stub_to_compiled=True) + return names + + def _goto(self, context, name): definition = name.get_definition(import_name_always=True) if definition is not None: type_ = definition.type @@ -334,11 +340,8 @@ class Evaluator(object): elif type_ == 'param': return [ParamName(context, name)] elif type_ in ('funcdef', 'classdef'): - if context.is_stub(): - return goto_non_stub(context, name) - else: - n = TreeNameDefinition(context, name) - return goto_with_stubs_if_possible(n) + n = TreeNameDefinition(context, name) + return goto_with_stubs_if_possible(n) elif type_ in ('import_from', 'import_name'): module_names = imports.infer_import(context, name, is_goto=True) return module_names diff --git a/jedi/evaluate/gradual/stub_context.py b/jedi/evaluate/gradual/stub_context.py index ceb3fa8f..0e384763 100644 --- a/jedi/evaluate/gradual/stub_context.py +++ b/jedi/evaluate/gradual/stub_context.py @@ -113,17 +113,16 @@ def goto_with_stubs_if_possible(name): ] or [name] -def goto_non_stub(parent_context, tree_name): - contexts = stub_to_actual_context_set(parent_context) - return contexts.py__getattribute__(tree_name, is_goto=True) - - def stub_to_actual_context_set(stub_context, ignore_compiled=False): stub_module = stub_context.get_root_context() if not stub_module.is_stub(): return ContextSet([stub_context]) qualified_names = stub_context.get_qualified_names() + return _infer_from_stub(stub_module, qualified_names, ignore_compiled) + + +def _infer_from_stub(stub_module, qualified_names, ignore_compiled): if qualified_names is None: return NO_CONTEXTS @@ -147,6 +146,30 @@ def try_stubs_to_actual_context_set(stub_contexts, prefer_stub_to_compiled=False @to_list def try_stub_to_actual_names(names, prefer_stub_to_compiled=False): for name in names: + module = name.get_root_context() + if not module.is_stub(): + yield name + continue + + name_list = name.get_qualified_names() + if name_list is None: + contexts = NO_CONTEXTS + else: + contexts = _infer_from_stub( + module, + name_list[:-1], + ignore_compiled=prefer_stub_to_compiled, + ) + if contexts: + if name_list: + for new_name in contexts.py__getattribute__(name_list[-1], is_goto=True): + yield new_name + else: + for c in contexts: + yield c.name + else: + yield name + continue # XXX # Using the tree_name is better, if it's available, becuase no # information is lost. If the name given is defineda as `foo: int` we # would otherwise land on int, which is not what we want. We want foo diff --git a/jedi/evaluate/names.py b/jedi/evaluate/names.py index 56a782af..1226bb23 100644 --- a/jedi/evaluate/names.py +++ b/jedi/evaluate/names.py @@ -23,6 +23,10 @@ class AbstractNameDefinition(object): # name will always result on itself. return {self} + @abstractmethod + def get_qualified_names(self): + raise NotImplementedError + def get_root_context(self): return self.parent_context.get_root_context() @@ -44,6 +48,12 @@ class AbstractTreeName(AbstractNameDefinition): self.parent_context = parent_context self.tree_name = tree_name + def get_qualified_names(self): + parent_names = self.parent_context.get_qualified_names() + if parent_names is None: + return None + return parent_names + [self.tree_name.value] + def goto(self): return self.parent_context.evaluator.goto(self.parent_context, self.tree_name) @@ -64,6 +74,9 @@ class ContextNameMixin(object): def infer(self): return ContextSet([self._context]) + def get_qualified_names(self): + return self._context.get_qualified_names() + def get_root_context(self): if self.parent_context is None: # A module return self._context @@ -79,6 +92,10 @@ class ContextName(ContextNameMixin, AbstractTreeName): super(ContextName, self).__init__(context.parent_context, tree_name) self._context = context + def goto(self): + from jedi.evaluate.gradual.stub_context import try_stub_to_actual_names + return try_stub_to_actual_names([self._context.name]) + class TreeNameDefinition(AbstractTreeName): _API_TYPES = dict( @@ -143,6 +160,9 @@ class ImportName(AbstractNameDefinition): self._from_module_context = parent_context self.string_name = string_name + def get_qualified_names(self): + return [] + @property def parent_context(self): m = self._from_module_context