1
0
forked from VimPlug/jedi

Fixed a few small things in the parser. Flow analysis is working again. Completely.

This commit is contained in:
Dave Halter
2014-11-06 04:41:16 +01:00
parent 56102e408e
commit aa0c73c9ab
4 changed files with 24 additions and 11 deletions

View File

@@ -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:

View File

@@ -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)

View File

@@ -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

View File

@@ -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()