NameFinder refactoring to make it possible to cache names_to_types.

This commit is contained in:
Dave Halter
2014-12-10 11:23:12 +01:00
parent 2536dede28
commit d4dfcfe321

View File

@@ -29,6 +29,7 @@ from jedi.evaluate import analysis
from jedi.evaluate import flow_analysis from jedi.evaluate import flow_analysis
from jedi.evaluate import param from jedi.evaluate import param
from jedi.evaluate import helpers from jedi.evaluate import helpers
from jedi.evaluate.cache import memoize_default
class NameFinder(object): class NameFinder(object):
@@ -284,7 +285,6 @@ class NameFinder(object):
def _names_to_types(self, names): def _names_to_types(self, names):
types = [] types = []
evaluator = self._evaluator
# Add isinstance and other if/assert knowledge. # Add isinstance and other if/assert knowledge.
if isinstance(self.name_str, pr.Name): if isinstance(self.name_str, pr.Name):
@@ -293,30 +293,56 @@ class NameFinder(object):
until = flow_scope.get_parent_until(er.FunctionExecution) until = flow_scope.get_parent_until(er.FunctionExecution)
while flow_scope and not isinstance(until, er.FunctionExecution): while flow_scope and not isinstance(until, er.FunctionExecution):
# TODO check if result is in scope -> no evaluation necessary # TODO check if result is in scope -> no evaluation necessary
n = check_flow_information(evaluator, flow_scope, n = check_flow_information(self._evaluator, flow_scope,
self.name_str, self.position) self.name_str, self.position)
if n: if n:
return n return n
flow_scope = flow_scope.parent flow_scope = flow_scope.parent
for name in names: for name in names:
types += _name_to_types(self._evaluator, name, self.scope)
if not names and isinstance(self.scope, er.Instance):
# handling __getattr__ / __getattribute__
types = self._check_getattr(self.scope)
return types
def _resolve_descriptors(self, types):
"""Processes descriptors"""
if not self.maybe_descriptor:
return types
result = []
for r in types:
if isinstance(self.scope, (er.Instance, er.Class)) \
and hasattr(r, 'get_descriptor_return'):
# handle descriptors
with common.ignored(KeyError):
result += r.get_descriptor_return(self.scope)
continue
result.append(r)
return result
@memoize_default(evaluator_is_first_arg=True)
def _name_to_types(evaluator, name, scope):
types = []
typ = name.get_definition() typ = name.get_definition()
if typ.isinstance(pr.ForStmt): if typ.isinstance(pr.ForStmt):
for_types = self._evaluator.eval_element(typ.children[-3]) for_types = evaluator.eval_element(typ.children[-3])
for_types = iterable.get_iterator_types(for_types) for_types = iterable.get_iterator_types(for_types)
types += check_tuple_assignments(for_types, name) types += check_tuple_assignments(for_types, name)
elif typ.isinstance(pr.CompFor): elif typ.isinstance(pr.CompFor):
for_types = self._evaluator.eval_element(typ.children[3]) for_types = evaluator.eval_element(typ.children[3])
for_types = iterable.get_iterator_types(for_types) for_types = iterable.get_iterator_types(for_types)
types += check_tuple_assignments(for_types, name) types += check_tuple_assignments(for_types, name)
elif isinstance(typ, pr.Param): elif isinstance(typ, pr.Param):
types += self._eval_param(typ) types += _eval_param(evaluator, typ, scope)
elif typ.isinstance(pr.ExprStmt): elif typ.isinstance(pr.ExprStmt):
types += self._remove_statements(typ, name) types += _remove_statements(evaluator, typ, name)
elif typ.isinstance(pr.WithStmt): elif typ.isinstance(pr.WithStmt):
types += evaluator.eval_element(typ.node_from_name(name)) types += evaluator.eval_element(typ.node_from_name(name))
elif isinstance(typ, pr.Import): elif isinstance(typ, pr.Import):
types += imports.ImportWrapper(self._evaluator, name).follow() types += imports.ImportWrapper(evaluator, name).follow()
elif isinstance(typ, pr.GlobalStmt): elif isinstance(typ, pr.GlobalStmt):
types += evaluator.find_types(typ.get_parent_scope(), str(name)) types += evaluator.find_types(typ.get_parent_scope(), str(name))
elif isinstance(typ, pr.TryStmt): elif isinstance(typ, pr.TryStmt):
@@ -330,21 +356,16 @@ class NameFinder(object):
if typ.isinstance(er.Function): if typ.isinstance(er.Function):
typ = typ.get_decorated_func() typ = typ.get_decorated_func()
types.append(typ) types.append(typ)
if not names and isinstance(self.scope, er.Instance):
# handling __getattr__ / __getattribute__
types = self._check_getattr(self.scope)
return types return types
def _remove_statements(self, stmt, name):
def _remove_statements(evaluator, stmt, name):
""" """
This is the part where statements are being stripped. This is the part where statements are being stripped.
Due to lazy evaluation, statements like a = func; b = a; b() have to be Due to lazy evaluation, statements like a = func; b = a; b() have to be
evaluated. evaluated.
""" """
evaluator = self._evaluator
types = [] types = []
# Remove the statement docstr stuff for now, that has to be # Remove the statement docstr stuff for now, that has to be
# implemented with the evaluator class. # implemented with the evaluator class.
@@ -365,8 +386,8 @@ class NameFinder(object):
else a for a in types] else a for a in types]
return types return types
def _eval_param(self, param):
evaluator = self._evaluator def _eval_param(evaluator, param, scope):
res_new = [] res_new = []
func = param.parent func = param.parent
@@ -377,8 +398,8 @@ class NameFinder(object):
and not isinstance(param, ExecutedParam): and not isinstance(param, ExecutedParam):
# This is where we add self - if it has never been # This is where we add self - if it has never been
# instantiated. # instantiated.
if isinstance(self.scope, er.InstanceElement): if isinstance(scope, er.InstanceElement):
res_new.append(self.scope.instance) res_new.append(scope.instance)
else: else:
inst = er.Instance(evaluator, er.wrap(evaluator, cls), inst = er.Instance(evaluator, er.wrap(evaluator, cls),
Arguments(evaluator, ()), is_generated=True) Arguments(evaluator, ()), is_generated=True)
@@ -397,7 +418,7 @@ class NameFinder(object):
return doc_params return doc_params
if isinstance(param, ExecutedParam): if isinstance(param, ExecutedParam):
return res_new + param.eval(self._evaluator) return res_new + param.eval(evaluator)
else: else:
# Param owns no information itself. # Param owns no information itself.
res_new += dynamic.search_params(evaluator, param) res_new += dynamic.search_params(evaluator, param)
@@ -410,21 +431,6 @@ class NameFinder(object):
res_new += evaluator.eval_element(param.default) res_new += evaluator.eval_element(param.default)
return res_new return res_new
def _resolve_descriptors(self, types):
"""Processes descriptors"""
if not self.maybe_descriptor:
return types
result = []
for r in types:
if isinstance(self.scope, (er.Instance, er.Class)) \
and hasattr(r, 'get_descriptor_return'):
# handle descriptors
with common.ignored(KeyError):
result += r.get_descriptor_return(self.scope)
continue
result.append(r)
return result
def check_flow_information(evaluator, flow, search_name_part, pos): def check_flow_information(evaluator, flow, search_name_part, pos):
""" Try to find out the type of a variable just with the information that """ Try to find out the type of a variable just with the information that