diff --git a/src/pydocstyle/plugins.rs b/src/pydocstyle/plugins.rs index ab9e1a3c87a0a..285209d5e783c 100644 --- a/src/pydocstyle/plugins.rs +++ b/src/pydocstyle/plugins.rs @@ -1413,24 +1413,56 @@ fn missing_args(checker: &mut Checker, docstring: &Docstring, docstrings_args: & // See: `GOOGLE_ARGS_REGEX` in `pydocstyle/checker.py`. static GOOGLE_ARGS_REGEX: Lazy = - Lazy::new(|| Regex::new(r"^\s*(\*?\*?\w+)\s*(\(.*?\))?\s*:.+").unwrap()); + Lazy::new(|| Regex::new(r"^\s*(\*?\*?\w+)\s*(\(.*?\))?\s*:\n?\s*.+").unwrap()); fn args_section(checker: &mut Checker, docstring: &Docstring, context: &SectionContext) { + if context.following_lines.is_empty() { + missing_args(checker, docstring, &FxHashSet::default()); + return; + } + + // Normalize leading whitespace, by removing any lines with less indentation + // than the first. + let leading_space = whitespace::leading_space(context.following_lines[0]); + let relevant_lines = context + .following_lines + .iter() + .filter(|line| line.starts_with(leading_space) || line.is_empty()) + .join("\n"); + let args_content = textwrap::dedent(&relevant_lines); + + // Reformat each section. + let mut args_sections: Vec = vec![]; + for line in args_content.trim().lines() { + if line.chars().next().map_or(true, char::is_whitespace) { + // This is a continuation of the documentation for the previous parameter, + // because it starts with whitespace. + if let Some(last) = args_sections.last_mut() { + last.push_str(line); + last.push('\n'); + } + } else { + // This line is the start of documentation for the next parameter, because it + // doesn't start with any whitespace. + let mut line = line.to_string(); + line.push('\n'); + args_sections.push(line); + } + } + + // Extract the argument name from each section. let mut matches = Vec::new(); - for line in context.following_lines { - if let Some(captures) = GOOGLE_ARGS_REGEX.captures(line) { + for section in &args_sections { + if let Some(captures) = GOOGLE_ARGS_REGEX.captures(section) { matches.push(captures); } } + let docstrings_args = matches + .iter() + .filter_map(|captures| captures.get(1).map(|arg_name| arg_name.as_str())) + .collect(); - missing_args( - checker, - docstring, - &matches - .iter() - .filter_map(|captures| captures.get(1).map(|arg_name| arg_name.as_str())) - .collect(), - ); + missing_args(checker, docstring, &docstrings_args); } fn parameters_section(checker: &mut Checker, docstring: &Docstring, context: &SectionContext) { diff --git a/src/pydocstyle/snapshots/ruff__pydocstyle__tests__D417_sections.py.snap b/src/pydocstyle/snapshots/ruff__pydocstyle__tests__D417_sections.py.snap index c0887077aca5b..c15c5a3c4ac76 100644 --- a/src/pydocstyle/snapshots/ruff__pydocstyle__tests__D417_sections.py.snap +++ b/src/pydocstyle/snapshots/ruff__pydocstyle__tests__D417_sections.py.snap @@ -75,18 +75,6 @@ expression: checks column: 11 fix: ~ parent: ~ -- kind: - DocumentAllArguments: - - skip - - verbose - location: - row: 370 - column: 4 - end_location: - row: 382 - column: 11 - fix: ~ - parent: ~ - kind: DocumentAllArguments: - y diff --git a/src/pydocstyle/snapshots/ruff__pydocstyle__tests__d417_google.snap b/src/pydocstyle/snapshots/ruff__pydocstyle__tests__d417_google.snap index 625549e636f93..a8048157c5474 100644 --- a/src/pydocstyle/snapshots/ruff__pydocstyle__tests__d417_google.snap +++ b/src/pydocstyle/snapshots/ruff__pydocstyle__tests__d417_google.snap @@ -16,7 +16,6 @@ expression: checks parent: ~ - kind: DocumentAllArguments: - - x - y - z location: @@ -29,7 +28,6 @@ expression: checks parent: ~ - kind: DocumentAllArguments: - - x - y - z location: diff --git a/src/pydocstyle/snapshots/ruff__pydocstyle__tests__d417_unspecified.snap b/src/pydocstyle/snapshots/ruff__pydocstyle__tests__d417_unspecified.snap index 89073f1b0b1a5..b60a2bd248aed 100644 --- a/src/pydocstyle/snapshots/ruff__pydocstyle__tests__d417_unspecified.snap +++ b/src/pydocstyle/snapshots/ruff__pydocstyle__tests__d417_unspecified.snap @@ -4,7 +4,6 @@ expression: checks --- - kind: DocumentAllArguments: - - x - y - z location: