diff --git a/jedi/evaluate/filters.py b/jedi/evaluate/filters.py new file mode 100644 index 00000000..b727da60 --- /dev/null +++ b/jedi/evaluate/filters.py @@ -0,0 +1,47 @@ +""" +Filters are objects that you can use to filter names in different scopes. They +are needed for name resolution. +""" +from abc import abstractmethod + + +def filter_scope_names(names, scope, until_position=None, name=None): + return names + + +class AbstractFilter(object): + def _filter(self, names, until_position): + if until_position is not None: + return [n for n in names if n.start_pos < until_position] + return names + + @abstractmethod + def get(self, name, until_position=None): + pass + + @abstractmethod + def values(self, until_position=None): + pass + + +class ParserTreeFilter(AbstractFilter): + def __init__(self, parser_scope): + self._parser_scope = parser_scope + self._used_names = self._parser_scope.get_root_node().used_names + + def _filter(self, names, until_position): + names = super(ParserTreeFilter, self)._filter(names, until_position) + names = [n for n in names if n.is_definition()] + names = [n for n in names if n.get_parent_scope() == self._parser_scope] + return names + + def get(self, name, until_position=None): + try: + names = self._used_names[name] + except KeyError: + return [] + + return self._filter(names, until_position) + + def values(self, name, until_position=None): + return self._filter(self._used_names.values(), until_position) diff --git a/jedi/evaluate/representation.py b/jedi/evaluate/representation.py index 251d9cbb..1c1c48f9 100644 --- a/jedi/evaluate/representation.py +++ b/jedi/evaluate/representation.py @@ -55,6 +55,7 @@ from jedi.evaluate import helpers from jedi.evaluate import param from jedi.evaluate import flow_analysis from jedi.evaluate import imports +from jedi.evaluate.filters import ParserTreeFilter class Executed(tree.Base): @@ -206,6 +207,11 @@ class Instance(use_metaclass(CachedMetaClass, Executed)): for names_dict in self.base.names_dicts(search_global=False, is_instance=True): yield LazyInstanceDict(self._evaluator, self, names_dict) + def get_filters(self, search_global): + raise NotImplementedError + yield self._self_names_dict() + yield ParserTreeFilter(self.base) + def py__getitem__(self, index): try: method = self.get_subscope_by_name('__getitem__') @@ -486,6 +492,16 @@ class Class(use_metaclass(CachedMetaClass, Wrapper)): else: yield scope.names_dict + def get_filters(self, search_global): + if search_global: + yield ParserTreeFilter(self.base) + else: + for scope in self.py__mro__(): + if isinstance(scope, compiled.CompiledObject): + raise NotImplementedError + else: + yield ParserTreeFilter(self.base) + def is_class(self): return True @@ -582,6 +598,14 @@ class Function(use_metaclass(CachedMetaClass, Wrapper)): for names_dict in scope.names_dicts(False): yield names_dict + def get_filters(self, search_global): + if search_global: + yield ParserTreeFilter(self.base) + else: + scope = self.py__class__() + for filter in scope.get_filters(search_global=False): + yield filter + @Python3Method def py__call__(self, params): if self.base.is_generator(): @@ -752,8 +776,8 @@ class FunctionExecution(Executed): yield result del evaluator.predefined_if_name_dict_dict[for_stmt] - def names_dicts(self, search_global): - yield self.names_dict + def get_filters(self, search_global): + yield ParserTreeFilter(self.base) @memoize_default(default=NO_DEFAULT) def _get_params(self): @@ -826,6 +850,19 @@ class ModuleWrapper(use_metaclass(CachedMetaClass, tree.Module, Wrapper)): yield dict((str(n), [GlobalName(n)]) for n in self.base.global_names) yield self._sub_modules_dict() + def get_filters(self, search_global): + yield ParserTreeFilter(self._module) + # TODO + ''' + yield self._module_attributes_dict() + + for star_module in self.star_imports(): + yield star_module.names_dict + + yield dict((str(n), [GlobalName(n)]) for n in self.base.global_names) + yield self._sub_modules_dict() + ''' + # I'm not sure if the star import cache is really that effective anymore # with all the other really fast import caches. Recheck. Also we would need # to push the star imports into Evaluator.modules, if we reenable this. diff --git a/jedi/parser/tree.py b/jedi/parser/tree.py index 5a888ee8..cd8f530e 100644 --- a/jedi/parser/tree.py +++ b/jedi/parser/tree.py @@ -125,6 +125,12 @@ class Base(object): def isinstance(self, *cls): return isinstance(self, cls) + def get_root_node(self): + scope = self + while scope.parent is not None: + scope = scope.parent + return scope + @Python3Method def get_parent_until(self, classes=(), reverse=False, include_current=True):