From bbb1d1e04c96b868d1752bfb8cb82e093e72330e Mon Sep 17 00:00:00 2001 From: Dave Halter Date: Fri, 28 Oct 2016 00:36:17 +0200 Subject: [PATCH] Better working flow scopes. --- jedi/evaluate/filters.py | 8 +++--- jedi/evaluate/finder.py | 4 +-- jedi/evaluate/flow_analysis.py | 44 ++++++++++++++++----------------- jedi/evaluate/representation.py | 3 +-- 4 files changed, 27 insertions(+), 32 deletions(-) diff --git a/jedi/evaluate/filters.py b/jedi/evaluate/filters.py index c920f45c..a870b5be 100644 --- a/jedi/evaluate/filters.py +++ b/jedi/evaluate/filters.py @@ -133,11 +133,9 @@ class ParserTreeFilter(AbstractUsedNamesFilter): def _check_flows(self, names): for name in sorted(names, key=lambda name: name.start_pos, reverse=True): - stmt = name.get_definition() - check = flow_analysis.UNSURE - #name_scope = self._evaluator.wrap(stmt.get_parent_scope()) - #check = flow_analysis.break_check(self._evaluator, name_scope, - # stmt, self._origin_scope) + check = flow_analysis.reachability_check( + self._context, self._parser_scope, name, self._origin_scope + ) if check is not flow_analysis.UNREACHABLE: yield name diff --git a/jedi/evaluate/finder.py b/jedi/evaluate/finder.py index 619d01a5..7060f909 100644 --- a/jedi/evaluate/finder.py +++ b/jedi/evaluate/finder.py @@ -210,7 +210,7 @@ class NameFinder(object): # deliver types. self._found_predefined_if_name = types else: - check = flow_analysis.break_check(self._evaluator, self.context, + check = flow_analysis.reachability_check(self._context, self.context, origin_scope) if check is flow_analysis.UNREACHABLE: self._found_predefined_if_name = set() @@ -225,7 +225,7 @@ class NameFinder(object): if isinstance(stmt.parent, compiled.CompiledObject): # TODO seriously? this is stupid. continue - check = flow_analysis.break_check(self._evaluator, name_scope, + check = flow_analysis.reachability_check(self._context, name_scope, stmt, origin_scope) if check is not flow_analysis.UNREACHABLE: last_names.append(name) diff --git a/jedi/evaluate/flow_analysis.py b/jedi/evaluate/flow_analysis.py index 04fde867..385b4099 100644 --- a/jedi/evaluate/flow_analysis.py +++ b/jedi/evaluate/flow_analysis.py @@ -32,9 +32,8 @@ UNREACHABLE = Status(False, 'unreachable') UNSURE = Status(None, 'unsure') -def break_check(evaluator, base_scope, stmt, origin_scope=None): - raise NotImplementedError - element_scope = evaluator.wrap(stmt.get_parent_scope(include_flows=True)) +def reachability_check(context, context_scope, node, origin_scope=None): + flow_scope = node.get_parent_scope(include_flows=True) # Direct parents get resolved, we filter scopes that are separate branches. # This makes sense for autocompletion and static analysis. For actual # Python it doesn't matter, because we're talking about potentially @@ -43,48 +42,47 @@ def break_check(evaluator, base_scope, stmt, origin_scope=None): # unaccessible. This is not a "problem" in Python, because the code is # never called. In Jedi though, we still want to infer types. while origin_scope is not None: - if element_scope == origin_scope: + if flow_scope == origin_scope: return REACHABLE origin_scope = origin_scope.parent - x = _break_check(evaluator, stmt, base_scope, element_scope) - return x + + return _break_check(context, context_scope, flow_scope, node) -def _break_check(evaluator, stmt, base_scope, element_scope): - element_scope = evaluator.wrap(element_scope) - base_scope = evaluator.wrap(base_scope) - +def _break_check(context, context_scope, flow_scope, node): reachable = REACHABLE - if isinstance(element_scope, tree.IfStmt): - if element_scope.node_after_else(stmt): - for check_node in element_scope.check_nodes(): - reachable = _check_if(evaluator, check_node) + if flow_scope.type == 'if_stmt': + if flow_scope.node_after_else(node): + for check_node in flow_scope.check_nodes(): + reachable = _check_if(context, check_node) if reachable in (REACHABLE, UNSURE): break reachable = reachable.invert() else: - node = element_scope.node_in_which_check_node(stmt) + node = flow_scope.node_in_which_check_node(node) if node is not None: - reachable = _check_if(evaluator, node) - elif isinstance(element_scope, (tree.TryStmt, tree.WhileStmt)): + reachable = _check_if(context, node) + elif flow_scope.type in ('try_stmt', 'while_stmt'): return UNSURE # Only reachable branches need to be examined further. if reachable in (UNREACHABLE, UNSURE): return reachable - if element_scope.type == 'file_input': + # TODO REMOVE WTF + #if element_scope.type == 'file_input': # The definition is in another module and therefore just return what we # have generated. - return reachable - if base_scope != element_scope and base_scope != element_scope.parent: - return reachable & _break_check(evaluator, stmt, base_scope, element_scope.parent) + # return reachable + if context_scope != flow_scope and context_scope != flow_scope.parent: + flow_scope = flow_scope.get_parent_scope(include_flows=True) + return reachable & _break_check(context, context_scope, flow_scope, node) else: return reachable -def _check_if(evaluator, node): - types = evaluator.eval_element(node) +def _check_if(context, node): + types = context.eval_node(node) values = set(x.py__bool__() for x in types) if len(values) == 1: return Status.lookup_table[values.pop()] diff --git a/jedi/evaluate/representation.py b/jedi/evaluate/representation.py index 42d223c9..d96eeb05 100644 --- a/jedi/evaluate/representation.py +++ b/jedi/evaluate/representation.py @@ -689,8 +689,7 @@ class FunctionExecutionContext(Executed): for r in returns: types |= self.eval_node(r.children[1]) - continue # TODO REMOVE - check = flow_analysis.break_check(self._evaluator, self, r) + check = flow_analysis.reachability_check(self, funcdef, r) if check is flow_analysis.UNREACHABLE: debug.dbg('Return unreachable: %s', r) else: