diff --git a/jedi/evaluate/finder.py b/jedi/evaluate/finder.py index 68483aae..13d2fd1d 100644 --- a/jedi/evaluate/finder.py +++ b/jedi/evaluate/finder.py @@ -327,13 +327,14 @@ class NameFinder(object): not isinstance(self._name_context, AbstractInstanceContext): # Ignore FunctionExecution parents for now. flow_scope = self._name - while flow_scope != self._name_context.get_node(): + while True: flow_scope = flow_scope.get_parent_scope(include_flows=True) - # TODO check if result is in scope -> no evaluation necessary n = _check_flow_information(self._name_context, flow_scope, self._name, self._position) if n is not None: return n + if flow_scope == self._name_context.get_node(): + break return types def _resolve_descriptors(self, name, types): @@ -533,20 +534,25 @@ def _check_flow_information(context, flow, search_name, pos): if not settings.dynamic_flow_information: return None - result = set() + result = None if flow.is_scope(): # Check for asserts. + module_node = flow.get_root_node() try: - names = reversed(flow.names_dict[search_name.value]) - except (KeyError, AttributeError): - names = [] + names = module_node.used_names[search_name.value] + except KeyError: + return None + names = reversed([ + n for n in names + if flow.start_pos <= n.start_pos < (pos or flow.end_pos) + ]) for name in names: - ass = name.get_parent_until(tree.AssertStmt) - if isinstance(ass, tree.AssertStmt) and pos is not None and ass.start_pos < pos: + ass = tree.search_ancestor(name, 'assert_stmt') + if ass is not None: result = _check_isinstance_type(context, ass.assertion(), search_name) - if result: - break + if result is not None: + return result if isinstance(flow, (tree.IfStmt, tree.WhileStmt)): potential_ifs = [c for c in flow.children[1::4] if c != ':'] @@ -580,7 +586,7 @@ def _check_isinstance_type(context, element, search_name): # and everything will be all right. assert is_instance_call.get_code(normalized=True) == call.get_code(normalized=True) except AssertionError: - return set() + return None result = set() for cls_or_tup in lazy_context_cls.infer(): diff --git a/jedi/evaluate/flow_analysis.py b/jedi/evaluate/flow_analysis.py index 7ae07019..2bdd5ab5 100644 --- a/jedi/evaluate/flow_analysis.py +++ b/jedi/evaluate/flow_analysis.py @@ -41,7 +41,7 @@ def _get_flow_scopes(node): def reachability_check(context, context_scope, node, origin_scope=None): - flow_scope = node.get_parent_scope(include_flows=True) + first_flow_scope = node.get_parent_scope(include_flows=True) if origin_scope is not None: origin_flow_scopes = list(_get_flow_scopes(origin_scope)) node_flow_scopes = list(_get_flow_scopes(node)) @@ -69,11 +69,11 @@ def reachability_check(context, context_scope, node, 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 flow_scope == origin_scope and branch_matches: + if first_flow_scope == origin_scope and branch_matches: return REACHABLE origin_scope = origin_scope.parent - return _break_check(context, context_scope, flow_scope, node) + return _break_check(context, context_scope, first_flow_scope, node) def _break_check(context, context_scope, flow_scope, node): @@ -96,11 +96,6 @@ def _break_check(context, context_scope, flow_scope, node): if reachable in (UNREACHABLE, UNSURE): return reachable - # 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 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)