forked from VimPlug/jedi
Fixed a few small things in the parser. Flow analysis is working again. Completely.
This commit is contained in:
@@ -83,7 +83,7 @@ class NameFinder(object):
|
|||||||
check = flow_analysis.break_check(self._evaluator,
|
check = flow_analysis.break_check(self._evaluator,
|
||||||
scope,
|
scope,
|
||||||
name.get_definition(),
|
name.get_definition(),
|
||||||
self.scope)
|
self.name_str.get_definition().parent)
|
||||||
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:
|
||||||
|
|||||||
@@ -34,16 +34,18 @@ UNSURE = Status(None, 'unsure')
|
|||||||
|
|
||||||
def break_check(evaluator, base_scope, stmt, origin_scope=None):
|
def break_check(evaluator, base_scope, stmt, origin_scope=None):
|
||||||
from jedi.evaluate.representation import wrap
|
from jedi.evaluate.representation import wrap
|
||||||
element_scope = wrap(evaluator, stmt.parent)
|
element_scope = wrap(evaluator, 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
|
||||||
# unreachable code.
|
# unreachable code.
|
||||||
s = origin_scope
|
# e.g. `if 0:` would cause all name lookup within the flow make
|
||||||
while s is not None:
|
# unaccessible. This is not a "problem" in Python, because the code is
|
||||||
if element_scope == s:
|
# never called. In Jedi though, we still want to infer types.
|
||||||
|
while origin_scope is not None:
|
||||||
|
if element_scope == origin_scope:
|
||||||
return REACHABLE
|
return REACHABLE
|
||||||
s = s.parent
|
origin_scope = origin_scope.parent
|
||||||
return _break_check(evaluator, stmt, base_scope, element_scope)
|
return _break_check(evaluator, stmt, base_scope, element_scope)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -155,12 +155,14 @@ class Base(object):
|
|||||||
scope = scope.parent
|
scope = scope.parent
|
||||||
return scope
|
return scope
|
||||||
|
|
||||||
def get_parent_scope(self):
|
def get_parent_scope(self, include_flows=False):
|
||||||
"""
|
"""
|
||||||
Returns the underlying scope.
|
Returns the underlying scope.
|
||||||
"""
|
"""
|
||||||
scope = self.parent
|
scope = self.parent
|
||||||
while scope.parent is not None:
|
while scope.parent is not None:
|
||||||
|
if include_flows and isinstance(scope, Flow):
|
||||||
|
return scope
|
||||||
if scope.is_scope():
|
if scope.is_scope():
|
||||||
break
|
break
|
||||||
scope = scope.parent
|
scope = scope.parent
|
||||||
@@ -466,13 +468,17 @@ class Scope(Simple, DocstringMixin):
|
|||||||
def subscopes(self):
|
def subscopes(self):
|
||||||
return self._search_in_scope(Scope)
|
return self._search_in_scope(Scope)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def flows(self):
|
||||||
|
return self._search_in_scope(Flow)
|
||||||
|
|
||||||
def _search_in_scope(self, typ):
|
def _search_in_scope(self, typ):
|
||||||
def scan(children):
|
def scan(children):
|
||||||
elements = []
|
elements = []
|
||||||
for element in children:
|
for element in children:
|
||||||
if isinstance(element, typ):
|
if isinstance(element, typ):
|
||||||
elements.append(element)
|
elements.append(element)
|
||||||
elif is_node(element, 'suite') or is_node(element, 'simple_stmt') \
|
if is_node(element, 'suite') or is_node(element, 'simple_stmt') \
|
||||||
or isinstance(element, Flow):
|
or isinstance(element, Flow):
|
||||||
elements += scan(element.children)
|
elements += scan(element.children)
|
||||||
return elements
|
return elements
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ from jedi import common
|
|||||||
from jedi.parser import tokenize
|
from jedi.parser import tokenize
|
||||||
from jedi._compatibility import u
|
from jedi._compatibility import u
|
||||||
from jedi.parser.fast import FastParser
|
from jedi.parser.fast import FastParser
|
||||||
from jedi.parser import representation
|
from jedi.parser import representation as pr
|
||||||
from jedi import debug
|
from jedi import debug
|
||||||
from jedi.common import PushBackIterator
|
from jedi.common import PushBackIterator
|
||||||
|
|
||||||
@@ -244,12 +244,17 @@ class UserContextParser(object):
|
|||||||
|
|
||||||
@cache.underscore_memoization
|
@cache.underscore_memoization
|
||||||
def user_scope(self):
|
def user_scope(self):
|
||||||
|
"""
|
||||||
|
Returns the scope in which the user resides. This includes flows.
|
||||||
|
"""
|
||||||
user_stmt = self.user_stmt()
|
user_stmt = self.user_stmt()
|
||||||
if user_stmt is None:
|
if user_stmt is None:
|
||||||
def scan(scope):
|
def scan(scope):
|
||||||
for s in scope.statements + scope.subscopes:
|
for s in scope.subscopes + list(reversed(scope.flows)):
|
||||||
if isinstance(s, representation.Scope):
|
if isinstance(s, (pr.Scope, pr.Flow)):
|
||||||
if s.start_pos <= self._position <= s.end_pos:
|
if s.start_pos <= self._position <= s.end_pos:
|
||||||
|
if isinstance(s, pr.Flow):
|
||||||
|
return s
|
||||||
return scan(s) or s
|
return scan(s) or s
|
||||||
|
|
||||||
return scan(self.module()) or self.module()
|
return scan(self.module()) or self.module()
|
||||||
|
|||||||
Reference in New Issue
Block a user