示例#1
0
文件: __init__.py 项目: orn688/jedi
def names(source=None, path=None, encoding='utf-8', all_scopes=False,
          definitions=True, references=False, environment=None):
    """
    Returns a list of `Definition` objects, containing name parts.
    This means you can call ``Definition.goto_assignments()`` and get the
    reference of a name.
    The parameters are the same as in :py:class:`Script`, except or the
    following ones:

    :param all_scopes: If True lists the names of all scopes instead of only
        the module namespace.
    :param definitions: If True lists the names that have been defined by a
        class, function or a statement (``a = b`` returns ``a``).
    :param references: If True lists all the names that are not listed by
        ``definitions=True``. E.g. ``a = b`` returns ``b``.
    """
    def def_ref_filter(_def):
        is_def = _def._name.tree_name.is_definition()
        return definitions and is_def or references and not is_def

    # Set line/column to a random position, because they don't matter.
    script = Script(source, line=1, column=0, path=path, encoding=encoding, environment=environment)
    module_context = script._get_module()
    defs = [
        classes.Definition(
            script._evaluator,
            TreeNameDefinition(
                module_context.create_context(name if name.parent.type == 'file_input' else name.parent),
                name
            )
        ) for name in get_module_names(script._module_node, all_scopes)
    ]
    return sorted(filter(def_ref_filter, defs), key=lambda x: (x.line, x.column))
示例#2
0
def usages_with_additional_modules(
    script: jedi.api.Script,
    additional_module_contexts: Tuple[ModuleContext] = ()):
    """
    Based on `jedi.api.Script.usages`, except `additional_modules` are also searched

    Forked from `jedi.api.Script.usages` on 2017-02-02.

    Return :class:`classes.Definition` objects, which contain all
    names that point to the definition of the name under the cursor. This
    is very useful for refactoring (renaming), or to show all usages of a
    variable.

    .. todo:: Implement additional_module_paths

    :rtype: list of :class:`classes.Definition`
    """
    from jedi import settings
    from jedi.api import usages
    from jedi.api import helpers
    from . import api_usages as alt_api_usages

    self = script

    temp, settings.dynamic_flow_information = \
        settings.dynamic_flow_information, False
    try:
        module_node = self._get_module_node()
        user_stmt = module_node.get_statement_for_position(self._pos)
        definition_names = self._goto()

        #assert not definition_names
        if not definition_names and isinstance(user_stmt, tree_Import):
            # For not defined imports (goto doesn't find something, we take
            # the name as a definition. This is enough, because every name
            # points to it.
            name = user_stmt.name_for_position(self._pos)
            if name is None:
                # Must be syntax
                return []
            definition_names = [TreeNameDefinition(self._get_module(), name)]

        if not definition_names:
            # Without a definition for a name we cannot find references.
            return []

        definition_names = usages.resolve_potential_imports(
            self._evaluator, definition_names)

        modules = set([d.get_root_context() for d in definition_names])
        modules.add(self._get_module())
        for additional_module_context in additional_module_contexts:
            modules.add(additional_module_context)
        definitions = alt_api_usages.usages(self._evaluator, definition_names,
                                            modules)
    finally:
        settings.dynamic_flow_information = temp

    return helpers.sorted_definitions(set(definitions))
示例#3
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]
    def usages(self, additional_module_paths=()):
        """
        Return :class:`classes.Definition` objects, which contain all
        names that point to the definition of the name under the cursor. This
        is very useful for refactoring (renaming), or to show all usages of a
        variable.

        .. todo:: Implement additional_module_paths

        :rtype: list of :class:`classes.Definition`
        """
        temp, settings.dynamic_flow_information = \
            settings.dynamic_flow_information, False
        try:
            module_node = self._get_module_node()
            user_stmt = get_statement_of_position(module_node, self._pos)
            definition_names = self._goto()
            if not definition_names and isinstance(user_stmt, tree.Import):
                # For not defined imports (goto doesn't find something, we take
                # the name as a definition. This is enough, because every name
                # points to it.
                name = user_stmt.get_name_of_position(self._pos)
                if name is None:
                    # Must be syntax
                    return []
                definition_names = [
                    TreeNameDefinition(self._get_module(), name)
                ]

            if not definition_names:
                # Without a definition for a name we cannot find references.
                return []

            definition_names = usages.resolve_potential_imports(
                self._evaluator, definition_names)

            modules = set([d.get_root_context() for d in definition_names])
            modules.add(self._get_module())
            definitions = usages.usages(self._evaluator, definition_names,
                                        modules)
        finally:
            settings.dynamic_flow_information = temp

        return helpers.sorted_definitions(set(definitions))
示例#5
0
    def goto(self, context, name):
        definition = name.get_definition(import_name_always=True)
        if definition is not None:
            type_ = definition.type
            if type_ == 'expr_stmt':
                # Only take the parent, because if it's more complicated than just
                # a name it's something you can "goto" again.
                is_simple_name = name.parent.type not in ('power', 'trailer')
                if is_simple_name:
                    return [TreeNameDefinition(context, name)]
            elif type_ == 'param':
                return [ParamName(context, name)]
            elif type_ in ('funcdef', 'classdef'):
                return [TreeNameDefinition(context, name)]
            elif type_ in ('import_from', 'import_name'):
                module_names = imports.infer_import(context, name, is_goto=True)
                return module_names

        par = name.parent
        node_type = par.type
        if node_type == 'argument' and par.children[1] == '=' and par.children[0] == name:
            # Named param goto.
            trailer = par.parent
            if trailer.type == 'arglist':
                trailer = trailer.parent
            if trailer.type != 'classdef':
                if trailer.type == 'decorator':
                    context_set = context.eval_node(trailer.children[1])
                else:
                    i = trailer.parent.children.index(trailer)
                    to_evaluate = trailer.parent.children[:i]
                    if to_evaluate[0] == 'await':
                        to_evaluate.pop(0)
                    context_set = context.eval_node(to_evaluate[0])
                    for trailer in to_evaluate[1:]:
                        context_set = eval_trailer(context, context_set, trailer)
                param_names = []
                for context in context_set:
                    try:
                        get_param_names = context.get_param_names
                    except AttributeError:
                        pass
                    else:
                        for param_name in get_param_names():
                            if param_name.string_name == name.value:
                                param_names.append(param_name)
                return param_names
        elif node_type == 'dotted_name':  # Is a decorator.
            index = par.children.index(name)
            if index > 0:
                new_dotted = helpers.deep_ast_copy(par)
                new_dotted.children[index - 1:] = []
                values = context.eval_node(new_dotted)
                return unite(
                    value.py__getattribute__(name, name_context=context, is_goto=True)
                    for value in values
                )

        if node_type == 'trailer' and par.children[0] == '.':
            values = helpers.evaluate_call_of_leaf(context, name, cut_own_trailer=True)
            return unite(
                value.py__getattribute__(name, name_context=context, is_goto=True)
                for value in values
            )
        else:
            stmt = tree.search_ancestor(
                name, 'expr_stmt', 'lambdef'
            ) or name
            if stmt.type == 'lambdef':
                stmt = name
            return context.py__getattribute__(
                name,
                position=stmt.start_pos,
                search_global=True, is_goto=True
            )
示例#6
0
def _find_names(module_context, tree_name):
    context = module_context.create_context(tree_name)
    name = TreeNameDefinition(context, tree_name)
    found_names = set(name.goto())
    found_names.add(name)
    return _dictionarize(_resolve_names(found_names))
示例#7
0
def _find_names(module_context, tree_name):
    context = module_context.create_context(tree_name)
    name = TreeNameDefinition(context, tree_name)
    found_names = set(name.goto())
    found_names.add(name)
    return _dictionarize(_resolve_names(found_names))
示例#8
0
    def goto(self, context, name):
        stmt = name.get_definition()
        par = name.parent
        if par.type == 'argument' and par.children[1] == '=' and par.children[
                0] == name:
            # Named param goto.
            trailer = par.parent
            if trailer.type == 'arglist':
                trailer = trailer.parent
            if trailer.type != 'classdef':
                if trailer.type == 'decorator':
                    types = self.eval_element(context, trailer.children[1])
                else:
                    i = trailer.parent.children.index(trailer)
                    to_evaluate = trailer.parent.children[:i]
                    types = self.eval_element(context, to_evaluate[0])
                    for trailer in to_evaluate[1:]:
                        types = self.eval_trailer(context, types, trailer)
                param_names = []
                for typ in types:
                    try:
                        get_param_names = typ.get_param_names
                    except AttributeError:
                        pass
                    else:
                        for param_name in get_param_names():
                            if param_name.string_name == name.value:
                                param_names.append(param_name)
                return param_names
        elif par.type == 'expr_stmt' and name in par.get_defined_names():
            # Only take the parent, because if it's more complicated than just
            # a name it's something you can "goto" again.
            return [TreeNameDefinition(context, name)]
        elif par.type == 'param' and par.name:
            return [ParamName(context, name)]
        elif isinstance(
                par,
            (tree.Param, tree.Function, tree.Class)) and par.name is name:
            return [TreeNameDefinition(context, name)]
        elif isinstance(stmt, tree.Import):
            module_names = imports.infer_import(context, name, is_goto=True)
            return module_names
        elif par.type == 'dotted_name':  # Is a decorator.
            index = par.children.index(name)
            if index > 0:
                new_dotted = helpers.deep_ast_copy(par)
                new_dotted.children[index - 1:] = []
                values = self.eval_element(context, new_dotted)
                return unite(
                    value.py__getattribute__(
                        name, name_context=context, is_goto=True)
                    for value in values)

        if par.type == 'trailer' and par.children[0] == '.':
            values = helpers.evaluate_call_of_leaf(context,
                                                   name,
                                                   cut_own_trailer=True)
            return unite(
                value.py__getattribute__(
                    name, name_context=context, is_goto=True)
                for value in values)
        else:
            if stmt.type != 'expr_stmt':
                # We only need to adjust the start_pos for statements, because
                # there the name cannot be used.
                stmt = name
            return context.py__getattribute__(name,
                                              position=stmt.start_pos,
                                              search_global=True,
                                              is_goto=True)