mirror of
https://github.com/davidhalter/jedi.git
synced 2026-03-07 04:31:53 +08:00
Better working flow scopes.
This commit is contained in:
@@ -133,11 +133,9 @@ class ParserTreeFilter(AbstractUsedNamesFilter):
|
|||||||
|
|
||||||
def _check_flows(self, names):
|
def _check_flows(self, names):
|
||||||
for name in sorted(names, key=lambda name: name.start_pos, reverse=True):
|
for name in sorted(names, key=lambda name: name.start_pos, reverse=True):
|
||||||
stmt = name.get_definition()
|
check = flow_analysis.reachability_check(
|
||||||
check = flow_analysis.UNSURE
|
self._context, self._parser_scope, name, self._origin_scope
|
||||||
#name_scope = self._evaluator.wrap(stmt.get_parent_scope())
|
)
|
||||||
#check = flow_analysis.break_check(self._evaluator, name_scope,
|
|
||||||
# stmt, self._origin_scope)
|
|
||||||
if check is not flow_analysis.UNREACHABLE:
|
if check is not flow_analysis.UNREACHABLE:
|
||||||
yield name
|
yield name
|
||||||
|
|
||||||
|
|||||||
@@ -210,7 +210,7 @@ class NameFinder(object):
|
|||||||
# deliver types.
|
# deliver types.
|
||||||
self._found_predefined_if_name = types
|
self._found_predefined_if_name = types
|
||||||
else:
|
else:
|
||||||
check = flow_analysis.break_check(self._evaluator, self.context,
|
check = flow_analysis.reachability_check(self._context, self.context,
|
||||||
origin_scope)
|
origin_scope)
|
||||||
if check is flow_analysis.UNREACHABLE:
|
if check is flow_analysis.UNREACHABLE:
|
||||||
self._found_predefined_if_name = set()
|
self._found_predefined_if_name = set()
|
||||||
@@ -225,7 +225,7 @@ class NameFinder(object):
|
|||||||
if isinstance(stmt.parent, compiled.CompiledObject):
|
if isinstance(stmt.parent, compiled.CompiledObject):
|
||||||
# TODO seriously? this is stupid.
|
# TODO seriously? this is stupid.
|
||||||
continue
|
continue
|
||||||
check = flow_analysis.break_check(self._evaluator, name_scope,
|
check = flow_analysis.reachability_check(self._context, name_scope,
|
||||||
stmt, origin_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)
|
||||||
|
|||||||
@@ -32,9 +32,8 @@ UNREACHABLE = Status(False, 'unreachable')
|
|||||||
UNSURE = Status(None, 'unsure')
|
UNSURE = Status(None, 'unsure')
|
||||||
|
|
||||||
|
|
||||||
def break_check(evaluator, base_scope, stmt, origin_scope=None):
|
def reachability_check(context, context_scope, node, origin_scope=None):
|
||||||
raise NotImplementedError
|
flow_scope = node.get_parent_scope(include_flows=True)
|
||||||
element_scope = evaluator.wrap(stmt.get_parent_scope(include_flows=True))
|
|
||||||
# Direct parents get resolved, we filter scopes that are separate branches.
|
# Direct parents get resolved, we filter scopes that are separate branches.
|
||||||
# This makes sense for autocompletion and static analysis. For actual
|
# This makes sense for autocompletion and static analysis. For actual
|
||||||
# Python it doesn't matter, because we're talking about potentially
|
# 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
|
# unaccessible. This is not a "problem" in Python, because the code is
|
||||||
# never called. In Jedi though, we still want to infer types.
|
# never called. In Jedi though, we still want to infer types.
|
||||||
while origin_scope is not None:
|
while origin_scope is not None:
|
||||||
if element_scope == origin_scope:
|
if flow_scope == origin_scope:
|
||||||
return REACHABLE
|
return REACHABLE
|
||||||
origin_scope = origin_scope.parent
|
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):
|
def _break_check(context, context_scope, flow_scope, node):
|
||||||
element_scope = evaluator.wrap(element_scope)
|
|
||||||
base_scope = evaluator.wrap(base_scope)
|
|
||||||
|
|
||||||
reachable = REACHABLE
|
reachable = REACHABLE
|
||||||
if isinstance(element_scope, tree.IfStmt):
|
if flow_scope.type == 'if_stmt':
|
||||||
if element_scope.node_after_else(stmt):
|
if flow_scope.node_after_else(node):
|
||||||
for check_node in element_scope.check_nodes():
|
for check_node in flow_scope.check_nodes():
|
||||||
reachable = _check_if(evaluator, check_node)
|
reachable = _check_if(context, check_node)
|
||||||
if reachable in (REACHABLE, UNSURE):
|
if reachable in (REACHABLE, UNSURE):
|
||||||
break
|
break
|
||||||
reachable = reachable.invert()
|
reachable = reachable.invert()
|
||||||
else:
|
else:
|
||||||
node = element_scope.node_in_which_check_node(stmt)
|
node = flow_scope.node_in_which_check_node(node)
|
||||||
if node is not None:
|
if node is not None:
|
||||||
reachable = _check_if(evaluator, node)
|
reachable = _check_if(context, node)
|
||||||
elif isinstance(element_scope, (tree.TryStmt, tree.WhileStmt)):
|
elif flow_scope.type in ('try_stmt', 'while_stmt'):
|
||||||
return UNSURE
|
return UNSURE
|
||||||
|
|
||||||
# Only reachable branches need to be examined further.
|
# Only reachable branches need to be examined further.
|
||||||
if reachable in (UNREACHABLE, UNSURE):
|
if reachable in (UNREACHABLE, UNSURE):
|
||||||
return reachable
|
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
|
# The definition is in another module and therefore just return what we
|
||||||
# have generated.
|
# have generated.
|
||||||
return reachable
|
# return reachable
|
||||||
if base_scope != element_scope and base_scope != element_scope.parent:
|
if context_scope != flow_scope and context_scope != flow_scope.parent:
|
||||||
return reachable & _break_check(evaluator, stmt, base_scope, element_scope.parent)
|
flow_scope = flow_scope.get_parent_scope(include_flows=True)
|
||||||
|
return reachable & _break_check(context, context_scope, flow_scope, node)
|
||||||
else:
|
else:
|
||||||
return reachable
|
return reachable
|
||||||
|
|
||||||
|
|
||||||
def _check_if(evaluator, node):
|
def _check_if(context, node):
|
||||||
types = evaluator.eval_element(node)
|
types = context.eval_node(node)
|
||||||
values = set(x.py__bool__() for x in types)
|
values = set(x.py__bool__() for x in types)
|
||||||
if len(values) == 1:
|
if len(values) == 1:
|
||||||
return Status.lookup_table[values.pop()]
|
return Status.lookup_table[values.pop()]
|
||||||
|
|||||||
@@ -689,8 +689,7 @@ class FunctionExecutionContext(Executed):
|
|||||||
|
|
||||||
for r in returns:
|
for r in returns:
|
||||||
types |= self.eval_node(r.children[1])
|
types |= self.eval_node(r.children[1])
|
||||||
continue # TODO REMOVE
|
check = flow_analysis.reachability_check(self, funcdef, r)
|
||||||
check = flow_analysis.break_check(self._evaluator, self, r)
|
|
||||||
if check is flow_analysis.UNREACHABLE:
|
if check is flow_analysis.UNREACHABLE:
|
||||||
debug.dbg('Return unreachable: %s', r)
|
debug.dbg('Return unreachable: %s', r)
|
||||||
else:
|
else:
|
||||||
|
|||||||
Reference in New Issue
Block a user