diff --git a/jedi/evaluate/dynamic.py b/jedi/evaluate/dynamic.py index fcf1e646..0f8f9b09 100644 --- a/jedi/evaluate/dynamic.py +++ b/jedi/evaluate/dynamic.py @@ -79,52 +79,29 @@ def search_function_call(evaluator, func): """ from jedi.evaluate import representation as er - def get_params_for_module(module): - """ - Returns the values of a param, or an empty array. - """ - @memoize_default([], evaluator_is_first_arg=True) - def get_posibilities(evaluator, module, func_name): + def get_possible_nodes(module, func_name): try: names = module.used_names[func_name] except KeyError: - return [] + return for name in names: - parent = name.parent - if tree.is_node(parent, 'trailer'): - parent = parent.parent + bracket = name.get_next_leaf() + trailer = bracket.parent + if trailer.type == 'trailer' and bracket == '(': + yield name, trailer - trailer = None - if tree.is_node(parent, 'power', 'atom_expr'): - for t in parent.children[1:]: - if t == '**': - break - if t.start_pos > name.start_pos and t.children[0] == '(': - trailer = t - break - if trailer is not None: - types = evaluator.goto_definitions(name) - - # We have to remove decorators, because they are not the - # "original" functions, this way we can easily compare. - # At the same time we also have to remove InstanceElements. - undec = [] - for escope in types: - if escope.isinstance(er.Function, er.Instance) \ - and escope.decorates is not None: - undec.append(escope.decorates) - elif isinstance(escope, er.InstanceElement): - undec.append(escope.var) - else: - undec.append(escope) - - if evaluator.wrap(compare) in undec: - # Only if we have the correct function we execute - # it, otherwise just ignore it. - evaluator.eval_trailer(types, trailer) - return listener.param_possibilities - return get_posibilities(evaluator, module, func_name) + def undecorate(typ): + # We have to remove decorators, because they are not the + # "original" functions, this way we can easily compare. + # At the same time we also have to remove InstanceElements. + if typ.isinstance(er.Function, er.Instance) \ + and typ.decorates is not None: + return typ.decorates + elif isinstance(typ, er.InstanceElement): + return typ.var + else: + return typ current_module = func.get_parent_until() func_name = unicode(func.name) @@ -141,13 +118,26 @@ def search_function_call(evaluator, func): try: result = [] - # This is like backtracking: Get the first possible result. + i = 0 for mod in imports.get_modules_containing_name(evaluator, [current_module], func_name): - result = get_params_for_module(mod) + for name, trailer in get_possible_nodes(mod, func_name): + i += 1 + + for typ in evaluator.goto_definitions(name): + undecorated = undecorate(typ) + if evaluator.wrap(compare) == undecorated: + # Only if we have the correct function we execute + # it, otherwise just ignore it. + evaluator.eval_trailer([typ], trailer) + + result = listener.param_possibilities + + # If there are results after processing a module, we're probably + # good to process. if result: - break + return result finally: # cleanup: remove the listener; important: should not stick. func.listeners.remove(listener) - return result + return set()