Fix comprehensions type issues.

This commit is contained in:
Dave Halter
2015-09-22 02:13:20 +02:00
parent 4ffc24a919
commit 3a306a4f25
5 changed files with 47 additions and 26 deletions

View File

@@ -30,6 +30,7 @@ from jedi.evaluate import Evaluator
from jedi.evaluate import representation as er from jedi.evaluate import representation as er
from jedi.evaluate import compiled from jedi.evaluate import compiled
from jedi.evaluate import imports from jedi.evaluate import imports
from jedi.evaluate.param import try_iter_content
from jedi.evaluate.cache import memoize_default from jedi.evaluate.cache import memoize_default
from jedi.evaluate.helpers import FakeName, get_module_names from jedi.evaluate.helpers import FakeName, get_module_names
from jedi.evaluate.finder import global_names_dict_generator, filter_definition_names from jedi.evaluate.finder import global_names_dict_generator, filter_definition_names
@@ -524,32 +525,27 @@ class Script(object):
for o in origins if hasattr(o, 'py__call__')] for o in origins if hasattr(o, 'py__call__')]
def _analysis(self): def _analysis(self):
def check_types(types): self._evaluator.is_analysis = True
for typ in types: try:
try: for node in self._parser.module().nodes_to_execute():
f = typ.iter_content if node.type in ('funcdef', 'classdef'):
except AttributeError: if node.type == 'classdef':
pass continue
raise NotImplementedError
er.Function(self._evaluator, node).get_decorated_func()
elif isinstance(node, tree.Import):
import_names = set(node.get_defined_names())
if node.is_nested():
import_names |= set(path[-1] for path in node.paths())
for n in import_names:
imports.ImportWrapper(self._evaluator, n).follow()
else: else:
check_types(f()) try_iter_content(self._evaluator.eval_element(node))
for node in self._parser.module().nodes_to_execute(): ana = [a for a in self._evaluator.analysis if self.path == a.path]
if node.type in ('funcdef', 'classdef'): return sorted(set(ana), key=lambda x: x.line)
if node.type == 'classdef': finally:
continue self._evaluator.is_analysis = False
raise NotImplementedError
er.Function(self._evaluator, node).get_decorated_func()
elif isinstance(node, tree.Import):
import_names = set(node.get_defined_names())
if node.is_nested():
import_names |= set(path[-1] for path in node.paths())
for n in import_names:
imports.ImportWrapper(self._evaluator, n).follow()
else:
check_types(self._evaluator.eval_element(node))
ana = [a for a in self._evaluator.analysis if self.path == a.path]
return sorted(set(ana), key=lambda x: x.line)
class Interpreter(Script): class Interpreter(Script):

View File

@@ -89,6 +89,7 @@ class Evaluator(object):
self.execution_recursion_detector = recursion.ExecutionRecursionDetector() self.execution_recursion_detector = recursion.ExecutionRecursionDetector()
self.analysis = [] self.analysis = []
self.predefined_if_name_dict_dict = {} self.predefined_if_name_dict_dict = {}
self.is_analysis = False
def wrap(self, element): def wrap(self, element):
if isinstance(element, tree.Class): if isinstance(element, tree.Class):
@@ -343,6 +344,9 @@ class Evaluator(object):
if not isinstance(arguments, param.Arguments): if not isinstance(arguments, param.Arguments):
arguments = param.Arguments(self, arguments, trailer) arguments = param.Arguments(self, arguments, trailer)
if self.is_analysis:
arguments.eval_all()
if obj.isinstance(er.Function): if obj.isinstance(er.Function):
obj = obj.get_decorated_func() obj = obj.get_decorated_func()

View File

@@ -148,7 +148,7 @@ class Comprehension(IterableWrapper):
return [self._evaluator.eval_element(self.eval_node())[index]] return [self._evaluator.eval_element(self.eval_node())[index]]
def __repr__(self): def __repr__(self):
return "<e%s of %s>" % (type(self).__name__, self._atom) return "<%s of %s>" % (type(self).__name__, self._atom)
class ArrayMixin(object): class ArrayMixin(object):

View File

@@ -12,6 +12,17 @@ from jedi.evaluate.helpers import FakeName
from jedi.cache import underscore_memoization from jedi.cache import underscore_memoization
def try_iter_content(types):
"""Helper method for static analysis."""
for typ in types:
try:
f = typ.iter_content
except AttributeError:
pass
else:
try_iter_content(f())
class Arguments(tree.Base): class Arguments(tree.Base):
def __init__(self, evaluator, argument_node, trailer=None): def __init__(self, evaluator, argument_node, trailer=None):
""" """
@@ -160,6 +171,16 @@ class Arguments(tree.Base):
else: else:
return None return None
def eval_all(self, func=None):
"""
Evaluates all arguments as a support for static analysis
(normally Jedi).
"""
for key, element_values in self.unpack():
for element in element_values:
types = self._evaluator.eval_element(element)
try_iter_content(types)
class ExecutedParam(tree.Param): class ExecutedParam(tree.Param):
"""Fake a param and give it values.""" """Fake a param and give it values."""

View File

@@ -517,7 +517,7 @@ class Node(BaseNode):
For static analysis. For static analysis.
""" """
result = [] result = []
if self.type not in Node._IGNORE_EXECUTE_NODES: if self.type not in Node._IGNORE_EXECUTE_NODES and not last_added:
result.append(self) result.append(self)
last_added = True last_added = True