1
0
forked from VimPlug/jedi

Add a filter for global names.

This commit is contained in:
Dave Halter
2016-10-11 16:01:26 +02:00
parent 37ba971787
commit 5f46b48433
3 changed files with 72 additions and 35 deletions

View File

@@ -6,14 +6,15 @@ from abc import abstractmethod
from jedi.parser.tree import search_ancestor from jedi.parser.tree import search_ancestor
from jedi.evaluate import flow_analysis from jedi.evaluate import flow_analysis
from jedi.common import to_list
class AbstractFilter(object): class AbstractFilter(object):
_until_position = None
def __init__(self, origin_scope=None): def __init__(self, origin_scope=None):
self._origin_scope = origin_scope self._origin_scope = origin_scope
_until_position = None
def _filter(self, names): def _filter(self, names):
if self._until_position is not None: if self._until_position is not None:
return [n for n in names if n.start_pos < self._until_position] return [n for n in names if n.start_pos < self._until_position]
@@ -21,32 +22,46 @@ class AbstractFilter(object):
@abstractmethod @abstractmethod
def get(self, name): def get(self, name):
pass raise NotImplementedError
@abstractmethod @abstractmethod
def values(self): def values(self):
pass raise NotImplementedError
class ParserTreeFilter(AbstractFilter): class AbstractUsedNamesFilter(AbstractFilter):
def __init__(self, parser_scope, until_position=None, origin_scope=None): def __init__(self, parser_scope, origin_scope=None):
super(ParserTreeFilter, self).__init__(origin_scope) super(AbstractUsedNamesFilter, self).__init__(origin_scope)
self._parser_scope = parser_scope self._parser_scope = parser_scope
self._used_names = self._parser_scope.get_root_node().used_names self._used_names = self._parser_scope.get_root_node().used_names
def get(self, name):
try:
names = self._used_names[str(name)]
except KeyError:
return []
return list(self._filter(names))
def values(self):
return self._filter(self._used_names.values())
class ParserTreeFilter(AbstractUsedNamesFilter):
def __init__(self, evaluator, parser_scope, until_position=None, origin_scope=None):
super(ParserTreeFilter, self).__init__(parser_scope, origin_scope)
self._until_position = until_position self._until_position = until_position
self._origin_scope = origin_scope self._evaluator = evaluator
def _filter(self, names): def _filter(self, names):
names = super(ParserTreeFilter, self)._filter(names) names = super(ParserTreeFilter, self)._filter(names)
names = [n for n in names if n.is_definition()] names = [n for n in names if n.is_definition()]
names = [n for n in names if n.parent.get_parent_scope() == self._parser_scope] names = [n for n in names if n.parent.get_parent_scope() == self._parser_scope]
return list(self._check_flows(sorted(names, key=lambda name: name.start_pos))) return list(self._check_flows(names))
def _check_flows(self, names): def _check_flows(self, names):
for name in names: for name in sorted(names, key=lambda name: name.start_pos, reverse=True):
yield name
continue
stmt = name.get_definition() stmt = name.get_definition()
name_scope = self._evaluator.wrap(stmt.get_parent_scope()) name_scope = self._evaluator.wrap(stmt.get_parent_scope())
check = flow_analysis.break_check(self._evaluator, name_scope, check = flow_analysis.break_check(self._evaluator, name_scope,
@@ -57,22 +72,12 @@ class ParserTreeFilter(AbstractFilter):
if check is flow_analysis.REACHABLE: if check is flow_analysis.REACHABLE:
break break
def get(self, name):
try:
names = self._used_names[str(name)]
except KeyError:
return []
return self._filter(names)
def values(self):
return self._filter(self._used_names.values())
class FunctionExecutionFilter(ParserTreeFilter): class FunctionExecutionFilter(ParserTreeFilter):
def __init__(self, parser_scope, executed_function, param_by_name, def __init__(self, evaluator, parser_scope, executed_function, param_by_name,
until_position=None, origin_scope=None): until_position=None, origin_scope=None):
super(FunctionExecutionFilter, self).__init__( super(FunctionExecutionFilter, self).__init__(
evaluator,
parser_scope, parser_scope,
until_position, until_position,
origin_scope origin_scope
@@ -89,6 +94,17 @@ class FunctionExecutionFilter(ParserTreeFilter):
return names return names
class GlobalNameFilter(AbstractUsedNamesFilter):
def __init__(self, parser_scope, origin_scope=None):
super(GlobalNameFilter, self).__init__(parser_scope)
@to_list
def _filter(self, names):
for name in names:
if name.parent.type == 'global_stmt':
yield name
def get_global_filters(evaluator, context, until_position): def get_global_filters(evaluator, context, until_position):
""" """
Returns all filters in order of priority for name resolution. Returns all filters in order of priority for name resolution.

View File

@@ -370,7 +370,7 @@ def _name_to_types(evaluator, name, scope):
elif typ.type == 'global_stmt': elif typ.type == 'global_stmt':
for s in _get_global_stmt_scopes(evaluator, typ, name): for s in _get_global_stmt_scopes(evaluator, typ, name):
finder = NameFinder(evaluator, s, str(name)) finder = NameFinder(evaluator, s, str(name))
names_dicts = finder.scopes(search_global=True) names_dicts = finder.get_filters(search_global=True)
# For global_stmt lookups, we only need the first possible scope, # For global_stmt lookups, we only need the first possible scope,
# which means the function itself. # which means the function itself.
names_dicts = [next(names_dicts)] names_dicts = [next(names_dicts)]

View File

@@ -55,7 +55,7 @@ from jedi.evaluate import helpers
from jedi.evaluate import param from jedi.evaluate import param
from jedi.evaluate import flow_analysis from jedi.evaluate import flow_analysis
from jedi.evaluate import imports from jedi.evaluate import imports
from jedi.evaluate.filters import ParserTreeFilter, FunctionExecutionFilter from jedi.evaluate.filters import ParserTreeFilter, FunctionExecutionFilter, GlobalNameFilter
class Executed(tree.Base): class Executed(tree.Base):
@@ -208,8 +208,12 @@ class Instance(use_metaclass(CachedMetaClass, Executed)):
yield LazyInstanceDict(self._evaluator, self, names_dict) yield LazyInstanceDict(self._evaluator, self, names_dict)
def get_filters(self, search_global, until_position=None, origin_scope=None): def get_filters(self, search_global, until_position=None, origin_scope=None):
#for s in self.base.py__mro__(): for cls in self.base.py__mro__():
#yield self._self_names_dict() if isinstance(cls, compiled.CompiledObject):
yield SelfNameFilter(self._evaluator, self, cls, origin_scope)
else:
yield SelfNameFilter(self._evaluator, self, cls.base, origin_scope)
for cls in self.base.py__mro__(): for cls in self.base.py__mro__():
if isinstance(cls, compiled.CompiledObject): if isinstance(cls, compiled.CompiledObject):
yield CompiledInstanceClassFilter(self._evaluator, self, cls, origin_scope) yield CompiledInstanceClassFilter(self._evaluator, self, cls, origin_scope)
@@ -286,10 +290,10 @@ class CompiledInstanceClassFilter(compiled.CompiledObjectFilter):
class InstanceClassFilter(ParserTreeFilter): class InstanceClassFilter(ParserTreeFilter):
def __init__(self, evaluator, instance, parser_scope, origin_scope): def __init__(self, evaluator, instance, parser_scope, origin_scope):
super(InstanceClassFilter, self).__init__( super(InstanceClassFilter, self).__init__(
parser_scope, evaluator=evaluator,
parser_scope=parser_scope,
origin_scope=origin_scope origin_scope=origin_scope
) )
self._evaluator = evaluator
self._instance = instance self._instance = instance
def _filter(self, names): def _filter(self, names):
@@ -298,6 +302,21 @@ class InstanceClassFilter(ParserTreeFilter):
for name in names] for name in names]
class SelfNameFilter(InstanceClassFilter):
def _filter(self, names):
names = self._filter_self_names(names)
return list(self._check_flows(names))
def _filter_self_names(self, names):
for name in names:
trailer = name.parent
if tree.is_node(trailer, 'trailer') \
and len(trailer.children) == 2 \
and trailer.children[0] == '.':
if name.is_definition():
yield get_instance_el(self._evaluator, self._instance, name)
class LazyInstanceDict(object): class LazyInstanceDict(object):
def __init__(self, evaluator, instance, dct): def __init__(self, evaluator, instance, dct):
self._evaluator = evaluator self._evaluator = evaluator
@@ -360,6 +379,7 @@ class InstanceElement(use_metaclass(CachedMetaClass, tree.Base)):
def parent(self): def parent(self):
par = self.var.parent par = self.var.parent
if isinstance(par, Class) and par == self.instance.base \ if isinstance(par, Class) and par == self.instance.base \
or not isinstance(self.instance.base, tree.Class) \
or isinstance(par, tree.Class) \ or isinstance(par, tree.Class) \
and par == self.instance.base.base: and par == self.instance.base.base:
par = self.instance par = self.instance
@@ -529,13 +549,13 @@ class Class(use_metaclass(CachedMetaClass, Wrapper)):
def get_filters(self, search_global, until_position=None, is_instance=False): def get_filters(self, search_global, until_position=None, is_instance=False):
if search_global: if search_global:
yield ParserTreeFilter(self.base, until_position) yield ParserTreeFilter(self._evaluator, self.base, until_position)
else: else:
for scope in self.py__mro__(): for scope in self.py__mro__():
if isinstance(scope, compiled.CompiledObject): if isinstance(scope, compiled.CompiledObject):
raise NotImplementedError raise NotImplementedError
else: else:
yield ParserTreeFilter(self.base) yield ParserTreeFilter(self._evaluator, self.base)
def is_class(self): def is_class(self):
return True return True
@@ -635,7 +655,7 @@ class Function(use_metaclass(CachedMetaClass, Wrapper)):
def get_filters(self, search_global, until_position=None): def get_filters(self, search_global, until_position=None):
if search_global: if search_global:
yield ParserTreeFilter(self.base, until_position) yield ParserTreeFilter(self._evaluator, self.base, until_position)
else: else:
scope = self.py__class__() scope = self.py__class__()
for filter in scope.get_filters(search_global=False): for filter in scope.get_filters(search_global=False):
@@ -813,7 +833,7 @@ class FunctionExecution(Executed):
del evaluator.predefined_if_name_dict_dict[for_stmt] del evaluator.predefined_if_name_dict_dict[for_stmt]
def get_filters(self, search_global, until_position=None): def get_filters(self, search_global, until_position=None):
yield FunctionExecutionFilter(self._original_function, yield FunctionExecutionFilter(self._evaluator, self._original_function,
self._copied_funcdef, self._copied_funcdef,
self.param_by_name, self.param_by_name,
until_position) until_position)
@@ -890,7 +910,8 @@ class ModuleWrapper(use_metaclass(CachedMetaClass, tree.Module, Wrapper)):
yield self._sub_modules_dict() yield self._sub_modules_dict()
def get_filters(self, search_global, until_position=None): def get_filters(self, search_global, until_position=None):
yield ParserTreeFilter(self._module, until_position) yield ParserTreeFilter(self._evaluator, self._module, until_position)
yield GlobalNameFilter(self._module)
# TODO # TODO
''' '''
yield self._module_attributes_dict() yield self._module_attributes_dict()