import ast


def arg_rename_in_place(node):
    """
    Can this argument node by safely renamed

    'self', 'cls', 'args', and 'kwargs' are not commonly referenced by the caller, so
    can be safely renamed. Comprehension arguments are not accessible from outside, so
    can be renamed.

    If the argument is positional-only, it can be safely renamed

    Other arguments may be referenced by the caller as keyword arguments, so should not be
    renamed in place. The name assigner may still decide to bind the argument to a new name
    inside the function namespace.

    :param node: The argument node
    :rtype node: :class:`ast.arg`
    :rtype: bool

    """

    func = node.namespace

    if isinstance(func, ast.comprehension):
        return True

    if isinstance(func.namespace, ast.ClassDef) and not isinstance(func, ast.Lambda):
        if len(func.args.args) > 0 and node is func.args.args[0]:
            if len(func.decorator_list) == 0:
                # rename 'self'
                return True
            elif (
                len(func.decorator_list) == 1
                and isinstance(func.decorator_list[0], ast.Name)
                and func.decorator_list[0].id == 'classmethod'
            ):
                # rename 'cls'
                return True

    if func.args.vararg is node or func.args.kwarg is node:
        # starargs
        return True

    if hasattr(func.args, 'posonlyargs') and node in func.args.posonlyargs:
        return True

    return False