From 6bf154de5e16532a9651dca2e9f1bc32797409ef Mon Sep 17 00:00:00 2001 From: Dave Halter Date: Wed, 3 Dec 2014 16:15:31 +0100 Subject: [PATCH] Better goto for imports, which helps usages. --- jedi/api/__init__.py | 9 ++------- jedi/api/usages.py | 6 ++---- jedi/evaluate/__init__.py | 21 +++++++++++++++++++-- jedi/evaluate/representation.py | 2 +- test/completion/usages.py | 5 +++-- 5 files changed, 27 insertions(+), 16 deletions(-) diff --git a/jedi/api/__init__.py b/jedi/api/__init__.py index 7253779e..46308ffa 100644 --- a/jedi/api/__init__.py +++ b/jedi/api/__init__.py @@ -503,7 +503,7 @@ class Script(object): import_name = user_stmt.get_defined_names() # imports have only one name np = import_name[0] - if not user_stmt.star and unicode(name_part) == unicode(np): + if not user_stmt.is_star_import() and unicode(name_part) == unicode(np): definitions.append(np) else: # The Evaluator.goto function checks for definitions, but since we @@ -549,12 +549,7 @@ class Script(object): names = usages.usages(self._evaluator, definitions, module) for d in set(definitions): - try: - name_part = d.names[-1] - except AttributeError: - names.append(classes.Definition(self._evaluator, d)) - else: - names.append(classes.Definition(self._evaluator, name_part)) + names.append(classes.Definition(self._evaluator, d)) finally: settings.dynamic_flow_information = temp diff --git a/jedi/api/usages.py b/jedi/api/usages.py index 434d4bfb..91c65e4e 100644 --- a/jedi/api/usages.py +++ b/jedi/api/usages.py @@ -1,5 +1,4 @@ from jedi._compatibility import u, unicode -from jedi import common from jedi.api import classes from jedi.parser import tree as pr from jedi.evaluate import imports @@ -101,7 +100,6 @@ def usages_add_import_modules(evaluator, definitions): for d in definitions: imp_or_stmt = d.get_definition() if isinstance(imp_or_stmt, pr.Import): - s = imports.ImportWrapper(evaluator, imp_or_stmt, nested_resolve=True) - with common.ignored(IndexError): - new.add(s.follow(is_goto=True)[0]) + s = imports.ImportWrapper(evaluator, d) + new |= s.follow(is_goto=True) return set(definitions) | new diff --git a/jedi/evaluate/__init__.py b/jedi/evaluate/__init__.py index 4dafbe30..80320b18 100644 --- a/jedi/evaluate/__init__.py +++ b/jedi/evaluate/__init__.py @@ -85,6 +85,7 @@ from jedi.evaluate import finder from jedi.evaluate import compiled from jedi.evaluate import precedence from jedi.evaluate import param +from jedi.evaluate import helpers from jedi.evaluate.helpers import FakeStatement, deep_ast_copy, call_of_name @@ -455,21 +456,37 @@ class Evaluator(object): return self.eval_element(call) def goto(self, name): + def resolve_implicit_imports(names): + for name in names: + if isinstance(name, helpers.FakeName): + # Those are implicit imports. + s = imports.ImportWrapper(self, name) + for n in s.follow(is_goto=True): + yield n + yield name + + imp = name.get_definition() stmt = name.parent if isinstance(stmt, pr.ExprStmt) and name in stmt.get_defined_names(): + # TODO remove? I think this is never called. return [name] elif isinstance(stmt, (pr.Param, pr.Function, pr.Class)) and stmt.name is name: return [name] + elif isinstance(imp, pr.Import): + return imports.ImportWrapper(self, name).follow(is_goto=True) scope = name.get_parent_scope() if pr.is_node(name.parent, 'trailer'): call = call_of_name(name, cut_own_trailer=True) types = self.eval_element(call) - return iterable.unite(self.find_types(typ, name, is_goto=True) - for typ in types) + return resolve_implicit_imports(iterable.unite( + self.find_types(typ, name, is_goto=True) for typ in types + )) else: return self.find_types(scope, name, name.start_pos, search_global=True, is_goto=True) + + if isinstance(stmt, pr.Import): # Nowhere to goto for aliases if stmt.alias == call_path[0]: diff --git a/jedi/evaluate/representation.py b/jedi/evaluate/representation.py index dfee180b..004ded50 100644 --- a/jedi/evaluate/representation.py +++ b/jedi/evaluate/representation.py @@ -768,7 +768,7 @@ class ModuleWrapper(use_metaclass(CachedMetaClass, pr.Module, Wrapper)): @property @memoize_default() def name(self): - return helpers.FakeName(unicode(self.base.name), self) + return helpers.FakeName(unicode(self.base.name), self, (1, 0)) @memoize_default() def _sub_modules(self): diff --git a/test/completion/usages.py b/test/completion/usages.py index 6f835f69..bf476975 100644 --- a/test/completion/usages.py +++ b/test/completion/usages.py @@ -49,11 +49,12 @@ class Abc(): Abc.d.Abc -#< 4 (0,4), (4,1) +#< 4 (0,4), (5,1) def blubi(): + pass -#< (-4,4), (0,1) +#< (-5,4), (0,1) @blubi def a(): pass