From f1711f8f9cb0720cb35c08dcf03b9fe96af10ec4 Mon Sep 17 00:00:00 2001 From: Dave Halter Date: Sun, 10 Aug 2014 13:17:37 +0200 Subject: [PATCH] possible direction of branch checks for name resolution. --- jedi/evaluate/__init__.py | 2 +- jedi/evaluate/finder.py | 22 ++++++++++++++++++++-- jedi/evaluate/flow_analysis.py | 4 ++++ jedi/evaluate/iterable.py | 3 +++ jedi/evaluate/param.py | 1 - jedi/evaluate/representation.py | 14 +++++++++++++- test/completion/basic.py | 8 ++++---- 7 files changed, 45 insertions(+), 9 deletions(-) diff --git a/jedi/evaluate/__init__.py b/jedi/evaluate/__init__.py index f8344ece..eb9da089 100644 --- a/jedi/evaluate/__init__.py +++ b/jedi/evaluate/__init__.py @@ -139,7 +139,7 @@ class Evaluator(object): operator = copy.copy(_operator) operator.string = operator.string[:-1] name = str(expr_list[0].name) - parent = stmt.parent + parent = stmt.parent.get_parent_until(pr.Flow, reverse=True) if isinstance(parent, (pr.SubModule, fast.Module)): parent = er.ModuleWrapper(self, parent) left = self.find_types(parent, name, stmt.start_pos) diff --git a/jedi/evaluate/finder.py b/jedi/evaluate/finder.py index bb8eb817..f1e2a2b5 100644 --- a/jedi/evaluate/finder.py +++ b/jedi/evaluate/finder.py @@ -27,6 +27,7 @@ from jedi.evaluate import iterable from jedi.evaluate import imports from jedi.evaluate import analysis from jedi.evaluate import precedence +from jedi.evaluate import flow_analysis class NameFinder(object): @@ -86,13 +87,30 @@ class NameFinder(object): if unicode(self.name_str) != name.get_code(): continue - scope = name.parent.parent + stmt = name.parent + scope = stmt.parent if scope in break_scopes: continue # Exclude `arr[1] =` from the result set. if not self._name_is_array_assignment(name): - result.append(name) + if False: + result.append(name) + else: + if isinstance(stmt, (pr.Param, pr.Import)) \ + or isinstance(name_list_scope, (pr.ListComprehension, er.Instance)) \ + or isinstance(scope, compiled.CompiledObject) \ + or isinstance(stmt, pr.Statement) and stmt.is_global(): + # Always reachable. + result.append(name) + else: + check = flow_analysis.break_check(self._evaluator, + name_list_scope, + er.wrap(self._evaluator, scope)) + if check is not flow_analysis.UNREACHABLE: + result.append(name) + if check is flow_analysis.REACHABLE: + break if result and self._is_name_break_scope(name): if self._does_scope_break_immediately(scope, name_list_scope): diff --git a/jedi/evaluate/flow_analysis.py b/jedi/evaluate/flow_analysis.py index 1261a2cd..e4d93fc0 100644 --- a/jedi/evaluate/flow_analysis.py +++ b/jedi/evaluate/flow_analysis.py @@ -33,6 +33,10 @@ UNSURE = Status(None, 'unsure') def break_check(evaluator, base_scope, element_scope): + from jedi.evaluate.representation import wrap + base_scope = wrap(evaluator, base_scope) + element_scope = wrap(evaluator, element_scope) + reachable = REACHABLE if isinstance(element_scope, Flow): if element_scope.command == 'else': diff --git a/jedi/evaluate/iterable.py b/jedi/evaluate/iterable.py index 6c3ff211..26efb83d 100644 --- a/jedi/evaluate/iterable.py +++ b/jedi/evaluate/iterable.py @@ -123,6 +123,9 @@ class Array(use_metaclass(CachedMetaClass, pr.Base)): self._evaluator = evaluator self._array = array + def py__bool__(self): + return None # We don't know the length, because of appends. + @memoize_default(NO_DEFAULT) def get_index_types(self, index_array=()): """ diff --git a/jedi/evaluate/param.py b/jedi/evaluate/param.py index b5d4f183..2a74e433 100644 --- a/jedi/evaluate/param.py +++ b/jedi/evaluate/param.py @@ -6,7 +6,6 @@ from jedi.evaluate import iterable from jedi import common from jedi.evaluate import helpers from jedi.evaluate import analysis -from jedi.evaluate.compiled import CompiledObject class ExecutedParam(pr.Param): diff --git a/jedi/evaluate/representation.py b/jedi/evaluate/representation.py index f78ae399..04a19bd1 100644 --- a/jedi/evaluate/representation.py +++ b/jedi/evaluate/representation.py @@ -29,6 +29,18 @@ from jedi.evaluate import param from jedi.evaluate import flow_analysis +def wrap(evaluator, element): + if isinstance(element, pr.Class): + return Class(evaluator, element) + elif isinstance(element, pr.Function): + return Function(evaluator, element) + elif isinstance(element, (pr.Module)) \ + and not isinstance(element, ModuleWrapper): + return ModuleWrapper(evaluator, element) + else: + return element + + class Executed(pr.IsScope): """ An instance is also an executable - because __init__ is called @@ -203,7 +215,7 @@ def get_instance_el(evaluator, instance, var, is_class_var=False): untouched. """ if isinstance(var, (Instance, compiled.CompiledObject, pr.Operator, Token, - pr.Module)): + pr.Module, FunctionExecution)): return var if isinstance(var, pr.Function): diff --git a/test/completion/basic.py b/test/completion/basic.py index 80874e85..65aa4c9c 100644 --- a/test/completion/basic.py +++ b/test/completion/basic.py @@ -23,18 +23,18 @@ a(0):. # if/else/elif # ----------------- -if 1: +if (random.choice([0, 1])): 1 -elif(3): +elif(random.choice([0, 1])): a = 3 else: a = '' #? int() str() a def func(): - if 1: + if random.choice([0, 1]): 1 - elif(3): + elif(random.choice([0, 1])): a = 3 else: a = ''