forked from VimPlug/jedi
Compiled objects should also have a names_dict.
This commit is contained in:
+4
-5
@@ -149,16 +149,15 @@ def underscore_memoization(func):
|
|||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
def memoize(func):
|
def memoize_method(method):
|
||||||
"""A normal memoize function."""
|
"""A normal memoize function."""
|
||||||
dct = {}
|
def wrapper(self, *args, **kwargs):
|
||||||
|
dct = self.__dict__.setdefault('_memoize_method_dct', {})
|
||||||
def wrapper(*args, **kwargs):
|
|
||||||
key = (args, frozenset(kwargs.items()))
|
key = (args, frozenset(kwargs.items()))
|
||||||
try:
|
try:
|
||||||
return dct[key]
|
return dct[key]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
result = func(*args, **kwargs)
|
result = method(self, *args, **kwargs)
|
||||||
dct[key] = result
|
dct[key] = result
|
||||||
return result
|
return result
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|||||||
@@ -6,12 +6,13 @@ import re
|
|||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
from functools import partial
|
from functools import partial
|
||||||
|
from itertools import chain
|
||||||
|
|
||||||
from jedi._compatibility import builtins as _builtins, unicode
|
from jedi._compatibility import builtins as _builtins, unicode
|
||||||
from jedi import debug
|
from jedi import debug
|
||||||
from jedi.cache import underscore_memoization, memoize
|
from jedi.cache import underscore_memoization, memoize_method
|
||||||
from jedi.evaluate.sys_path import get_sys_path
|
from jedi.evaluate.sys_path import get_sys_path
|
||||||
from jedi.parser.tree import Param, SubModule, Base, Operator
|
from jedi.parser.tree import Param, Base
|
||||||
from jedi.evaluate.helpers import FakeName
|
from jedi.evaluate.helpers import FakeName
|
||||||
from . import fake
|
from . import fake
|
||||||
|
|
||||||
@@ -137,11 +138,19 @@ class CompiledObject(Base):
|
|||||||
return self
|
return self
|
||||||
|
|
||||||
def get_defined_names(self):
|
def get_defined_names(self):
|
||||||
|
return list(chain.from_iterable(self.names_dict.values()))
|
||||||
|
|
||||||
|
# TODO still used?
|
||||||
if inspect.ismodule(self.obj):
|
if inspect.ismodule(self.obj):
|
||||||
return self.instance_names()
|
return self.instance_names()
|
||||||
else:
|
else:
|
||||||
return type_names + self.instance_names()
|
return type_names + self.instance_names()
|
||||||
|
|
||||||
|
@property
|
||||||
|
@underscore_memoization
|
||||||
|
def names_dict(self):
|
||||||
|
return LazyNamesDict(self._cls())
|
||||||
|
|
||||||
def scope_names_generator(self, position=None, add_class_vars=True):
|
def scope_names_generator(self, position=None, add_class_vars=True):
|
||||||
yield self, self.get_defined_names()
|
yield self, self.get_defined_names()
|
||||||
|
|
||||||
@@ -237,6 +246,38 @@ class CompiledObject(Base):
|
|||||||
return [] # Builtins don't have imports
|
return [] # Builtins don't have imports
|
||||||
|
|
||||||
|
|
||||||
|
class LazyNamesDict(object):
|
||||||
|
"""
|
||||||
|
A names_dict instance for compiled objects, resembles the parser.tree.
|
||||||
|
"""
|
||||||
|
def __init__(self, compiled_obj):
|
||||||
|
self._compiled_obj = compiled_obj
|
||||||
|
|
||||||
|
@memoize_method
|
||||||
|
def __getitem__(self, name):
|
||||||
|
try:
|
||||||
|
getattr(self._compiled_obj.obj, name)
|
||||||
|
except AttributeError:
|
||||||
|
raise KeyError('%s in %s not found.' % (name, self._compiled_obj))
|
||||||
|
return [CompiledName(self._compiled_obj, name)]
|
||||||
|
|
||||||
|
def values(self):
|
||||||
|
obj = self._compiled_obj.obj
|
||||||
|
names = dir(obj)
|
||||||
|
|
||||||
|
values = []
|
||||||
|
for name in names:
|
||||||
|
try:
|
||||||
|
values.append(self[name])
|
||||||
|
except KeyError:
|
||||||
|
# The dir function can be wrong.
|
||||||
|
pass
|
||||||
|
|
||||||
|
if not inspect.ismodule(obj):
|
||||||
|
values.append(type_names)
|
||||||
|
return values
|
||||||
|
|
||||||
|
|
||||||
class CompiledName(FakeName):
|
class CompiledName(FakeName):
|
||||||
def __init__(self, obj, name):
|
def __init__(self, obj, name):
|
||||||
super(CompiledName, self).__init__(name)
|
super(CompiledName, self).__init__(name)
|
||||||
@@ -250,6 +291,9 @@ class CompiledName(FakeName):
|
|||||||
name = None
|
name = None
|
||||||
return '<%s: (%s).%s>' % (type(self).__name__, name, self.name)
|
return '<%s: (%s).%s>' % (type(self).__name__, name, self.name)
|
||||||
|
|
||||||
|
def is_definition(self):
|
||||||
|
return True
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@underscore_memoization
|
@underscore_memoization
|
||||||
def parent(self):
|
def parent(self):
|
||||||
@@ -408,14 +452,10 @@ def _parse_function_doc(doc):
|
|||||||
return param_str, ret
|
return param_str, ret
|
||||||
|
|
||||||
|
|
||||||
class Builtin(CompiledObject, Base):
|
class Builtin(CompiledObject):
|
||||||
@memoize
|
@memoize_method
|
||||||
def get_by_name(self, name):
|
def get_by_name(self, name):
|
||||||
item = [n for n in self.get_defined_names() if n.get_code() == name][0]
|
return self.names_dict[name][0].parent
|
||||||
return item.parent
|
|
||||||
|
|
||||||
def is_scope(self):
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def _a_generator(foo):
|
def _a_generator(foo):
|
||||||
|
|||||||
+10
-4
@@ -88,14 +88,18 @@ class NameFinder(object):
|
|||||||
# Only the names defined in the last position are valid definitions.
|
# Only the names defined in the last position are valid definitions.
|
||||||
last_names = []
|
last_names = []
|
||||||
for name in reversed(sorted(names, key=lambda name: name.start_pos)):
|
for name in reversed(sorted(names, key=lambda name: name.start_pos)):
|
||||||
|
if isinstance(name, compiled.CompiledName):
|
||||||
|
last_names.append(name)
|
||||||
|
continue
|
||||||
|
|
||||||
if isinstance(self.name_str, pr.Name):
|
if isinstance(self.name_str, pr.Name):
|
||||||
origin_scope = self.name_str.get_definition().parent
|
origin_scope = self.name_str.get_definition().parent
|
||||||
else:
|
else:
|
||||||
origin_scope = None
|
origin_scope = None
|
||||||
check = flow_analysis.break_check(self._evaluator,
|
stmt = name.get_definition()
|
||||||
scope,
|
if isinstance(stmt.parent, compiled.CompiledObject):
|
||||||
name.get_definition(),
|
continue
|
||||||
origin_scope)
|
check = flow_analysis.break_check(self._evaluator, scope, stmt, origin_scope)
|
||||||
if check is not flow_analysis.UNREACHABLE:
|
if check is not flow_analysis.UNREACHABLE:
|
||||||
last_names.append(name)
|
last_names.append(name)
|
||||||
if check is flow_analysis.REACHABLE:
|
if check is flow_analysis.REACHABLE:
|
||||||
@@ -166,8 +170,10 @@ class NameFinder(object):
|
|||||||
or isinstance(name_list_scope, (pr.Lambda, er.Instance, InterpreterNamespace)) \
|
or isinstance(name_list_scope, (pr.Lambda, er.Instance, InterpreterNamespace)) \
|
||||||
or isinstance(scope, compiled.CompiledObject):
|
or isinstance(scope, compiled.CompiledObject):
|
||||||
# Always reachable.
|
# Always reachable.
|
||||||
|
print('nons', scope)
|
||||||
names.append(name)
|
names.append(name)
|
||||||
else:
|
else:
|
||||||
|
print('yess', scope)
|
||||||
check = flow_analysis.break_check(self._evaluator,
|
check = flow_analysis.break_check(self._evaluator,
|
||||||
name_list_scope,
|
name_list_scope,
|
||||||
stmt,
|
stmt,
|
||||||
|
|||||||
Reference in New Issue
Block a user