Пример #1
0
def usages(module_context, tree_name):
    search_name = tree_name.value
    found_names = _find_names(module_context, tree_name)
    modules = set(d.get_root_context() for d in found_names.values())
    modules = set(m for m in modules if isinstance(m, ModuleContext))

    non_matching_usage_maps = {}
    for m in imports.get_modules_containing_name(module_context.evaluator,
                                                 modules, search_name):
        for name_leaf in m.tree_node.get_used_names().get(search_name, []):
            new = _find_names(m, name_leaf)
            if any(tree_name in found_names for tree_name in new):
                found_names.update(new)
                for tree_name in new:
                    for dct in non_matching_usage_maps.get(tree_name, []):
                        # A usage that was previously searched for matches with
                        # a now found name. Merge.
                        found_names.update(dct)
                    try:
                        del non_matching_usage_maps[tree_name]
                    except KeyError:
                        pass
            else:
                for name in new:
                    non_matching_usage_maps.setdefault(name, []).append(new)
    return found_names.values()
Пример #2
0
def usages(module_context, tree_name):
    search_name = tree_name.value
    found_names = _find_names(module_context, tree_name)
    modules = set(d.get_root_context() for d in found_names.values())
    modules = set(m for m in modules if isinstance(m, ModuleContext))

    non_matching_usage_maps = {}
    for m in imports.get_modules_containing_name(module_context.evaluator, modules, search_name):
        for name_leaf in m.tree_node.get_used_names().get(search_name, []):
            new = _find_names(m, name_leaf)
            if any(tree_name in found_names for tree_name in new):
                found_names.update(new)
                for tree_name in new:
                    for dct in non_matching_usage_maps.get(tree_name, []):
                        # A usage that was previously searched for matches with
                        # a now found name. Merge.
                        found_names.update(dct)
                    try:
                        del non_matching_usage_maps[tree_name]
                    except KeyError:
                        pass
            else:
                for name in new:
                    non_matching_usage_maps.setdefault(name, []).append(new)
    return found_names.values()
Пример #3
0
def usages(evaluator, definition_names, mods):
    """
    :param definitions: list of Name
    """
    def compare_array(definitions):
        """ `definitions` are being compared by module/start_pos, because
        sometimes the id's of the objects change (e.g. executions).
        """
        result = []
        for d in definitions:
            module = d.get_parent_until()
            result.append((module, d.start_pos))
        return result

    search_name = unicode(list(definition_names)[0])
    compare_definitions = compare_array(definition_names)
    mods |= set([d.get_parent_until() for d in definition_names])
    definitions = []
    for m in imports.get_modules_containing_name(evaluator, mods, search_name):
        try:
            check_names = m.used_names[search_name]
        except KeyError:
            continue
        for name in check_names:

            result = evaluator.goto(name)
            if [c for c in compare_array(result) if c in compare_definitions]:
                definitions.append(classes.Definition(evaluator, name))
                # Previous definitions might be imports, so include them
                # (because goto might return that import name).
                compare_definitions += compare_array([name])
    return definitions
Пример #4
0
def test_get_modules_containing_name(evaluator, path, goal, is_package):
    module = imports._load_python_module(
        evaluator,
        FileIO(path),
        import_names=('ok', 'lala', 'x'),
        is_package=is_package,
    )
    assert module
    input_module, found_module = imports.get_modules_containing_name(
        evaluator, [module], 'string_that_only_exists_here')
    assert input_module is module
    assert found_module.string_names == goal
Пример #5
0
def usages(evaluator, definition_names, mods):
    """
    :param definitions: list of Name
    """
    def resolve_names(definition_names):
        for name in definition_names:
            if name.api_type == 'module':
                found = False
                for context in name.infer():
                    found = True
                    yield context.name
                if not found:
                    yield name
            else:
                yield name

    def compare_array(definition_names):
        """ `definitions` are being compared by module/start_pos, because
        sometimes the id's of the objects change (e.g. executions).
        """
        return [(name.get_root_context(), name.start_pos)
                for name in resolve_names(definition_names)]

    search_name = list(definition_names)[0].string_name
    compare_definitions = compare_array(definition_names)
    mods = mods | set([d.get_root_context() for d in definition_names])
    definition_names = set(resolve_names(definition_names))
    for m in imports.get_modules_containing_name(evaluator, mods, search_name):
        if isinstance(m, ModuleContext):
            for name_node in m.tree_node.used_names.get(search_name, []):
                context = evaluator.create_context(m, name_node)
                try:
                    result = evaluator.goto(context, name_node)
                except (NotImplementedError, RecursionError) as err:
                    logger.error(err)
                    continue
                if any(
                        compare_contexts(c1, c2)
                        for c1 in compare_array(result)
                        for c2 in compare_definitions):
                    name = TreeNameDefinition(context, name_node)
                    definition_names.add(name)
                    # Previous definitions might be imports, so include them
                    # (because goto might return that import name).
                    compare_definitions += compare_array([name])
        else:
            # compiled objects
            definition_names.add(m.name)

    return [classes.Definition(evaluator, n) for n in definition_names]
Пример #6
0
def usages(evaluator, definition_names, mods):
    """
    :param definitions: list of Name
    """
    def resolve_names(definition_names):
        for name in definition_names:
            if name.api_type == 'module':
                found = False
                for context in name.infer():
                    if isinstance(context, ModuleContext):
                        found = True
                        yield context.name
                if not found:
                    yield name
            else:
                yield name

    def compare_array(definition_names):
        """ `definitions` are being compared by module/start_pos, because
        sometimes the id's of the objects change (e.g. executions).
        """
        return [
            (name.get_root_context(), name.start_pos)
            for name in resolve_names(definition_names)
        ]

    search_name = list(definition_names)[0].string_name
    compare_definitions = compare_array(definition_names)
    mods = mods | set([d.get_root_context() for d in definition_names])
    definition_names = set(resolve_names(definition_names))
    for m in imports.get_modules_containing_name(evaluator, mods, search_name):
        if isinstance(m, ModuleContext):
            for name_node in m.tree_node.used_names.get(search_name, []):
                context = evaluator.create_context(m, name_node)
                result = evaluator.goto(context, name_node)
                if any(compare_contexts(c1, c2)
                       for c1 in compare_array(result)
                       for c2 in compare_definitions):
                    name = TreeNameDefinition(context, name_node)
                    definition_names.add(name)
                    # Previous definitions might be imports, so include them
                    # (because goto might return that import name).
                    compare_definitions += compare_array([name])
        else:
            # compiled objects
            definition_names.add(m.name)

    return [classes.Definition(evaluator, n) for n in definition_names]
Пример #7
0
def _search_function_executions(evaluator, module_context, funcdef):
    """
    Returns a list of param names.
    """
    from jedi.evaluate import representation as er

    func_string_name = funcdef.name.value
    compare_node = funcdef
    if func_string_name == '__init__':
        cls = funcdef.get_parent_scope()
        if isinstance(cls, tree.Class):
            func_string_name = cls.name.value
            compare_node = cls

    found_executions = False
    i = 0
    for for_mod_context in imports.get_modules_containing_name(
            evaluator, [module_context], func_string_name):
        if not isinstance(module_context, er.ModuleContext):
            return
        for name, trailer in _get_possible_nodes(for_mod_context,
                                                 func_string_name):
            i += 1

            # This is a simple way to stop Jedi's dynamic param recursion
            # from going wild: The deeper Jedi's in the recursion, the less
            # code should be evaluated.
            if i * evaluator.dynamic_params_depth > MAX_PARAM_SEARCHES:
                return

            random_context = evaluator.create_context(for_mod_context, name)
            for function_execution in _check_name_for_execution(
                    evaluator, random_context, compare_node, name, trailer):
                found_executions = True
                yield function_execution

        # If there are results after processing a module, we're probably
        # good to process. This is a speed optimization.
        if found_executions:
            return
Пример #8
0
def _search_function_executions(evaluator, module_context, funcdef):
    """
    Returns a list of param names.
    """
    from jedi.evaluate import representation as er

    func_string_name = funcdef.name.value
    compare_node = funcdef
    if func_string_name == '__init__':
        cls = funcdef.get_parent_scope()
        if isinstance(cls, tree.Class):
            func_string_name = cls.name.value
            compare_node = cls

    found_executions = False
    i = 0
    for for_mod_context in imports.get_modules_containing_name(
            evaluator, [module_context], func_string_name):
        if not isinstance(module_context, er.ModuleContext):
            return
        for name, trailer in _get_possible_nodes(for_mod_context, func_string_name):
            i += 1

            # This is a simple way to stop Jedi's dynamic param recursion
            # from going wild: The deeper Jedi's in the recursion, the less
            # code should be evaluated.
            if i * evaluator.dynamic_params_depth > MAX_PARAM_SEARCHES:
                return

            random_context = evaluator.create_context(for_mod_context, name)
            for function_execution in _check_name_for_execution(
                    evaluator, random_context, compare_node, name, trailer):
                found_executions = True
                yield function_execution

        # If there are results after processing a module, we're probably
        # good to process. This is a speed optimization.
        if found_executions:
            return
Пример #9
0
def search_function_call(evaluator, func):
    """
    Returns a list of param names.
    """
    from jedi.evaluate import representation as er

    def get_possible_nodes(module, func_name):
        try:
            names = module.used_names[func_name]
        except KeyError:
            return

        for name in names:
            bracket = name.get_next_leaf()
            trailer = bracket.parent
            if trailer.type == 'trailer' and bracket == '(':
                yield name, trailer

    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)
    compare = func
    if func_name == '__init__':
        cls = func.get_parent_scope()
        if isinstance(cls, tree.Class):
            func_name = unicode(cls.name)
            compare = cls

    # add the listener
    listener = ParamListener()
    func.listeners.add(listener)

    try:
        result = []
        i = 0
        for mod in imports.get_modules_containing_name(evaluator,
                                                       [current_module],
                                                       func_name):
            for name, trailer in get_possible_nodes(mod, func_name):
                i += 1

                # This is a simple way to stop Jedi's dynamic param recursion
                # from going wild: The deeper Jedi's in the recursin, the less
                # code should be evaluated.
                if i * evaluator.dynamic_params_depth > MAX_PARAM_SEARCHES:
                    return listener.param_possibilities

                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:
                return result
    finally:
        # cleanup: remove the listener; important: should not stick.
        func.listeners.remove(listener)

    return set()
Пример #10
0
def search_params(evaluator, param):
    """
    This is a dynamic search for params. If you try to complete a type:

    >>> def func(foo):
    ...     foo
    >>> func(1)
    >>> func("")

    It is not known what the type is, because it cannot be guessed with
    recursive madness. Therefore one has to analyse the statements that are
    calling the function, as well as analyzing the incoming params.
    """
    if not settings.dynamic_params:
        return []

    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):
            try:
                possible_stmts = module.used_names[func_name]
            except KeyError:
                return []

            for stmt in possible_stmts:
                if isinstance(stmt, pr.Import):
                    continue
                calls = helpers.scan_statement_for_calls(stmt, func_name)
                for c in calls:
                    # no execution means that params cannot be set
                    call_path = list(c.generate_call_path())
                    pos = c.start_pos
                    scope = stmt.parent

                    # this whole stuff is just to not execute certain parts
                    # (speed improvement), basically we could just call
                    # ``eval_call_path`` on the call_path and it would
                    # also work.
                    def listRightIndex(lst, value):
                        return len(lst) - lst[-1::-1].index(value) - 1

                    # Need to take right index, because there could be a
                    # func usage before.
                    i = listRightIndex(call_path, func_name)
                    first, last = call_path[:i], call_path[i + 1:]
                    if not last and not call_path.index(func_name) != i:
                        continue
                    scopes = [scope]
                    if first:
                        scopes = evaluator.eval_call_path(
                            iter(first), scope, pos)
                        pos = None
                    from jedi.evaluate import representation as er
                    for scope in scopes:
                        s = evaluator.find_types(scope,
                                                 func_name,
                                                 position=pos,
                                                 search_global=not first,
                                                 resolve_decorator=False)

                        c = [
                            getattr(escope, 'base_func', None) or escope.base
                            for escope in s
                            if escope.isinstance(er.Function, er.Class)
                        ]
                        if compare in c:
                            # only if we have the correct function we execute
                            # it, otherwise just ignore it.
                            evaluator.follow_path(iter(last), s, scope)

            return listener.param_possibilities

        result = []
        for params in get_posibilities(evaluator, module, func_name):
            for p in params:
                if str(p) == param_name:
                    result += evaluator.eval_statement(p.parent)
        return result

    func = param.get_parent_until(pr.Function)
    current_module = param.get_parent_until()
    func_name = str(func.name)
    compare = func
    if func_name == '__init__' and isinstance(func.parent, pr.Class):
        func_name = str(func.parent.name)
        compare = func.parent

    # get the param name
    if param.assignment_details:
        # first assignment details, others would be a syntax error
        expression_list, op = param.assignment_details[0]
    else:
        expression_list = param.expression_list()
    offset = 1 if expression_list[0] in ['*', '**'] else 0
    param_name = str(expression_list[offset].name)

    # add the listener
    listener = ParamListener()
    func.listeners.add(listener)

    result = []
    # This is like backtracking: Get the first possible result.
    for mod in imports.get_modules_containing_name([current_module],
                                                   func_name):
        result = get_params_for_module(mod)
        if result:
            break

    # cleanup: remove the listener; important: should not stick.
    func.listeners.remove(listener)

    return result
Пример #11
0
def search_function_call(evaluator, func):
    """
    Returns a list of param names.
    """
    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):
            try:
                names = module.used_names[func_name]
            except KeyError:
                return []

            for name in names:
                parent = name.parent
                if tree.is_node(parent, 'trailer'):
                    parent = parent.parent

                trailer = None
                if tree.is_node(parent, 'power'):
                    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_definition(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)

    current_module = func.get_parent_until()
    func_name = unicode(func.name)
    compare = func
    if func_name == '__init__':
        cls = func.get_parent_scope()
        if isinstance(cls, tree.Class):
            func_name = unicode(cls.name)
            compare = cls

    # add the listener
    listener = ParamListener()
    func.listeners.add(listener)

    try:
        result = []
        # This is like backtracking: Get the first possible result.
        for mod in imports.get_modules_containing_name(evaluator, [current_module], func_name):
            result = get_params_for_module(mod)
            if result:
                break
    finally:
        # cleanup: remove the listener; important: should not stick.
        func.listeners.remove(listener)

    return result
Пример #12
0
def usages(evaluator, definitions, search_name, mods):
    def compare_array(definitions):
        """ `definitions` are being compared by module/start_pos, because
        sometimes the id's of the objects change (e.g. executions).
        """
        result = []
        for d in definitions:
            module = d.get_parent_until()
            result.append((module, d.start_pos))
        return result

    def check_call_for_usage(call):
        stmt = call.parent
        while not isinstance(stmt.parent, pr.IsScope):
            stmt = stmt.parent
        # New definition, call cannot be a part of stmt
        if len(call.name) == 1 and call.execution is None \
                and call.name in stmt.get_defined_names():
            # Class params are not definitions (like function params). They
            # are super classes, that need to be resolved.
            if not (isinstance(stmt, pr.Param)
                    and isinstance(stmt.parent, pr.Class)):
                return

        follow = []  # There might be multiple search_name's in one call_path
        call_path = list(call.generate_call_path())
        for i, name in enumerate(call_path):
            # name is `pr.NamePart`.
            if u(name) == search_name:
                follow.append(call_path[:i + 1])

        for call_path in follow:
            follow_res, search = evaluator.goto(call.parent, call_path)
            # names can change (getattr stuff), therefore filter names that
            # don't match `search`.

            # TODO add something like that in the future - for now usages are
            # completely broken anyway.
            #follow_res = [r for r in follow_res if str(r) == search]
            #print search.start_pos,search_name.start_pos
            #print follow_res, search, search_name, [(r, r.start_pos) for r in follow_res]
            follow_res = usages_add_import_modules(evaluator, follow_res,
                                                   search)

            compare_follow_res = compare_array(follow_res)
            # compare to see if they match
            if any(r in compare_definitions for r in compare_follow_res):
                yield classes.Definition(evaluator, search)

    if not definitions:
        return set()

    compare_definitions = compare_array(definitions)
    mods |= set([d.get_parent_until() for d in definitions])
    names = []
    for m in imports.get_modules_containing_name(mods, search_name):
        try:
            stmts = m.used_names[search_name]
        except KeyError:
            continue
        for stmt in stmts:
            if isinstance(stmt, pr.Import):
                count = 0
                imps = []
                for i in stmt.get_all_import_names():
                    for name_part in i.names:
                        count += 1
                        if unicode(name_part) == search_name:
                            imps.append((count, name_part))

                for used_count, name_part in imps:
                    i = imports.ImportWrapper(evaluator,
                                              stmt,
                                              kill_count=count - used_count,
                                              nested_resolve=True)
                    f = i.follow(is_goto=True)
                    if set(f) & set(definitions):
                        names.append(classes.Definition(evaluator, name_part))
            else:
                for call in helpers.scan_statement_for_calls(
                        stmt, search_name, assignment_details=True):
                    names += check_call_for_usage(call)
    return names
Пример #13
0
def search_function_call(evaluator, func):
    """
    Returns a list of param names.
    """
    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):
            try:
                names = module.used_names[func_name]
            except KeyError:
                return []

            for name in names:
                parent = name.parent
                if pr.is_node(parent, 'trailer'):
                    parent = parent.parent

                trailer = None
                if pr.is_node(parent, 'power'):
                    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_definition(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 er.wrap(evaluator, 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)

    current_module = func.get_parent_until()
    func_name = unicode(func.name)
    compare = func
    if func_name == '__init__':
        cls = func.get_parent_scope()
        if isinstance(cls, pr.Class):
            func_name = unicode(cls.name)
            compare = cls

    # add the listener
    listener = ParamListener()
    func.listeners.add(listener)

    try:
        result = []
        # This is like backtracking: Get the first possible result.
        for mod in imports.get_modules_containing_name(evaluator,
                                                       [current_module],
                                                       func_name):
            result = get_params_for_module(mod)
            if result:
                break
    finally:
        # cleanup: remove the listener; important: should not stick.
        func.listeners.remove(listener)

    return result
Пример #14
0
def search_params(evaluator, param):
    """
    This is a dynamic search for params. If you try to complete a type:

    >>> def func(foo):
    ...     foo
    >>> func(1)
    >>> func("")

    It is not known what the type is, because it cannot be guessed with
    recursive madness. Therefore one has to analyse the statements that are
    calling the function, as well as analyzing the incoming params.
    """
    if not settings.dynamic_params:
        return []

    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):
            try:
                possible_stmts = module.used_names[func_name]
            except KeyError:
                return []

            for stmt in possible_stmts:
                if isinstance(stmt, pr.Import):
                    continue
                calls = helpers.scan_statement_for_calls(stmt, func_name)
                for c in calls:
                    # no execution means that params cannot be set
                    call_path = list(c.generate_call_path())
                    pos = c.start_pos
                    scope = stmt.parent

                    # this whole stuff is just to not execute certain parts
                    # (speed improvement), basically we could just call
                    # ``eval_call_path`` on the call_path and it would
                    # also work.
                    def listRightIndex(lst, value):
                        return len(lst) - lst[-1::-1].index(value) - 1

                    # Need to take right index, because there could be a
                    # func usage before.
                    call_path_simple = [unicode(d) if isinstance(d, pr.NamePart)
                                        else d for d in call_path]
                    i = listRightIndex(call_path_simple, func_name)
                    first, last = call_path[:i], call_path[i + 1:]
                    if not last and not call_path_simple.index(func_name) != i:
                        continue
                    scopes = [scope]
                    if first:
                        scopes = evaluator.eval_call_path(iter(first), scope, pos)
                        pos = None
                    from jedi.evaluate import representation as er
                    for scope in scopes:
                        s = evaluator.find_types(scope, func_name, position=pos,
                                                 search_global=not first,
                                                 resolve_decorator=False)

                        c = [getattr(escope, 'base_func', None) or escope.base
                             for escope in s
                             if escope.isinstance(er.Function, er.Class)]
                        if compare in c:
                            # only if we have the correct function we execute
                            # it, otherwise just ignore it.
                            evaluator.follow_path(iter(last), s, scope)

            return listener.param_possibilities

        result = []
        for params in get_posibilities(evaluator, module, func_name):
            for p in params:
                if str(p) == param_name:
                    result += evaluator.eval_statement(p.parent)
        return result

    func = param.get_parent_until(pr.Function)
    current_module = param.get_parent_until()
    func_name = unicode(func.name)
    compare = func
    if func_name == '__init__' and isinstance(func.parent, pr.Class):
        func_name = unicode(func.parent.name)
        compare = func.parent

    # get the param name
    if param.assignment_details:
        # first assignment details, others would be a syntax error
        expression_list, op = param.assignment_details[0]
    else:
        expression_list = param.expression_list()
    offset = 1 if expression_list[0] in ['*', '**'] else 0
    param_name = str(expression_list[offset].name)

    # add the listener
    listener = ParamListener()
    func.listeners.add(listener)

    result = []
    # This is like backtracking: Get the first possible result.
    for mod in imports.get_modules_containing_name([current_module], func_name):
        result = get_params_for_module(mod)
        if result:
            break

    # cleanup: remove the listener; important: should not stick.
    func.listeners.remove(listener)

    return result
Пример #15
0
def search_function_call(evaluator, func):
    """
    Returns a list of param names.
    """
    from jedi.evaluate import representation as er

    def get_possible_nodes(module, func_name):
        try:
            names = module.used_names[func_name]
        except KeyError:
            return

        for name in names:
            bracket = name.get_next_leaf()
            trailer = bracket.parent
            if trailer.type == "trailer" and bracket == "(":
                yield name, trailer

    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)
    compare = func
    if func_name == "__init__":
        cls = func.get_parent_scope()
        if isinstance(cls, tree.Class):
            func_name = unicode(cls.name)
            compare = cls

    # add the listener
    listener = ParamListener()
    func.listeners.add(listener)

    try:
        result = []
        i = 0
        for mod in imports.get_modules_containing_name(evaluator, [current_module], func_name):
            for name, trailer in get_possible_nodes(mod, func_name):
                i += 1

                # This is a simple way to stop Jedi's dynamic param recursion
                # from going wild: The deeper Jedi's in the recursin, the less
                # code should be evaluated.
                if i * evaluator.dynamic_params_depth > MAX_PARAM_SEARCHES:
                    return listener.param_possibilities

                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:
                return result
    finally:
        # cleanup: remove the listener; important: should not stick.
        func.listeners.remove(listener)

    return set()
Пример #16
0
def usages(evaluator, definitions, search_name, mods):
    def compare_array(definitions):
        """ `definitions` are being compared by module/start_pos, because
        sometimes the id's of the objects change (e.g. executions).
        """
        result = []
        for d in definitions:
            module = d.get_parent_until()
            result.append((module, d.start_pos))
        return result

    def check_call_for_usage(call):
        stmt = call.parent
        while not isinstance(stmt.parent, pr.IsScope):
            stmt = stmt.parent
        # New definition, call cannot be a part of stmt
        if len(call.name) == 1 and call.execution is None \
                and call.name in stmt.get_defined_names():
            # Class params are not definitions (like function params). They
            # are super classes, that need to be resolved.
            if not (isinstance(stmt, pr.Param) and isinstance(stmt.parent, pr.Class)):
                return

        follow = []  # There might be multiple search_name's in one call_path
        call_path = list(call.generate_call_path())
        for i, name in enumerate(call_path):
            # name is `pr.NamePart`.
            if u(name) == search_name:
                follow.append(call_path[:i + 1])

        for call_path in follow:
            follow_res, search = evaluator.goto(call.parent, call_path)
            # names can change (getattr stuff), therefore filter names that
            # don't match `search`.

            # TODO add something like that in the future - for now usages are
            # completely broken anyway.
            #follow_res = [r for r in follow_res if str(r) == search]
            #print search.start_pos,search_name.start_pos
            #print follow_res, search, search_name, [(r, r.start_pos) for r in follow_res]
            follow_res = usages_add_import_modules(evaluator, follow_res, search)

            compare_follow_res = compare_array(follow_res)
            # compare to see if they match
            if any(r in compare_definitions for r in compare_follow_res):
                yield classes.Definition(evaluator, search)

    if not definitions:
        return set()

    compare_definitions = compare_array(definitions)
    mods |= set([d.get_parent_until() for d in definitions])
    names = []
    for m in imports.get_modules_containing_name(mods, search_name):
        try:
            stmts = m.used_names[search_name]
        except KeyError:
            continue
        for stmt in stmts:
            if isinstance(stmt, pr.Import):
                count = 0
                imps = []
                for i in stmt.get_all_import_names():
                    for name_part in i.names:
                        count += 1
                        if unicode(name_part) == search_name:
                            imps.append((count, name_part))

                for used_count, name_part in imps:
                    i = imports.ImportWrapper(evaluator, stmt, kill_count=count - used_count,
                                              nested_resolve=True)
                    f = i.follow(is_goto=True)
                    if set(f) & set(definitions):
                        names.append(classes.Definition(evaluator, name_part))
            else:
                for call in helpers.scan_statement_for_calls(stmt, search_name, assignment_details=True):
                    names += check_call_for_usage(call)
    return names