Repository: astral-sh/ruff
File: crates/ruff_linter/src/rules/pydocstyle/rules/sections.rs (Rust)

Code before:
            let arg_name = arg.name.as_str();
            let starred_arg_name = format!("**{arg_name}");
            if !arg_name.starts_with('_')
                && !docstrings_args.contains(arg_name)
                && !docstrings_args.contains(&starred_arg_name)
            {
                missing_arg_names.insert(starred_arg_name);
            }
        }
    }

    if !missing_arg_names.is_empty() {
        if let Some(definition) = docstring.definition.name() {
            let names = missing_arg_names.into_iter().sorted().collect();
            checker.report_diagnostic(
                UndocumentedParam {
                    definition: definition.to_string(),
                    names,
                },
                function.identifier(),
            );
        }
    }
}

fn should_ignore_kwarg_check(checker: &Checker, parameter: &Parameter) -> bool {
    if let Some(annotation) = &parameter.annotation {
        checker
            .semantic()
            .match_typing_expr(map_subscript(annotation), "Unpack")
    } else {
        false
    }
}

// See: `GOOGLE_ARGS_REGEX` in `pydocstyle/checker.py`.
static GOOGLE_ARGS_REGEX: LazyLock<Regex> =
    LazyLock::new(|| Regex::new(r"^\s*(\*?\*?\w+)\s*(\(.*?\))?\s*:(\r\n|\n)?\s*.+").unwrap());

fn args_section(context: &SectionContext) -> FxHashSet<String> {
    let mut following_lines = context.following_lines();
    let Some(first_line) = following_lines.next() else {
        return FxHashSet::default();
    };

    // Normalize leading whitespace, by removing any lines with less indentation
    // than the first.
    let leading_space = leading_space(first_line.as_str());
    let relevant_lines = std::iter::once(first_line)
        .chain(following_lines)
        .filter(|line| {

Review comment (suggestion):
Might be worth a short docstring here too, maybe something like:

```suggestion
/// Returns `true` if `parameter` is annotated with `typing.Unpack`
fn should_ignore_kwarg_check(checker: &Checker, parameter: &Parameter) -> bool {
```

Along those lines, a slightly better function name might be something like `has_unpack_annotation`.

Code after:
        }
        if let Some(arg) = function.parameters.kwarg.as_ref()
            && !has_unpack_annotation(checker, arg)
        {
            let arg_name = arg.name.as_str();
            let starred_arg_name = format!("**{arg_name}");
            if !arg_name.starts_with('_')
                && !docstrings_args.contains(arg_name)
                && !docstrings_args.contains(&starred_arg_name)
            {
                missing_arg_names.insert(starred_arg_name);
            }
        }
    }

    if !missing_arg_names.is_empty() {
        if let Some(definition) = docstring.definition.name() {
            let names = missing_arg_names.into_iter().sorted().collect();
            checker.report_diagnostic(
                UndocumentedParam {
                    definition: definition.to_string(),
                    names,
                },
                function.identifier(),
            );
        }
    }
}

/// Returns `true` if the parameter is annotated with `typing.Unpack`
fn has_unpack_annotation(checker: &Checker, parameter: &Parameter) -> bool {
    parameter.annotation.as_ref().is_some_and(|annotation| {
        checker
            .semantic()
            .match_typing_expr(map_subscript(annotation), "Unpack")
    })
}

// See: `GOOGLE_ARGS_REGEX` in `pydocstyle/checker.py`.
static GOOGLE_ARGS_REGEX: LazyLock<Regex> =
    LazyLock::new(|| Regex::new(r"^\s*(\*?\*?\w+)\s*(\(.*?\))?\s*:(\r\n|\n)?\s*.+").unwrap());

fn args_section(context: &SectionContext) -> FxHashSet<String> {
    let mut following_lines = context.following_lines();
    let Some(first_line) = following_lines.next() else {
        return FxHashSet::default();
    };

    // Normalize leading whitespace, by removing any lines with less indentation
    // than the first.
    let leading_space = leading_space(first_line.as_str());