diff --git a/crates/ruff_linter/resources/test/fixtures/pydocstyle/D402.py b/crates/ruff_linter/resources/test/fixtures/pydocstyle/D402.py new file mode 100644 index 00000000000000..542d65e5aa954e --- /dev/null +++ b/crates/ruff_linter/resources/test/fixtures/pydocstyle/D402.py @@ -0,0 +1,8 @@ +def foo(): + """Returns foo().""" + +def foo(): + """"Use prefix_foo().""" + +def foo(): + """"Use this function; foo().""" diff --git a/crates/ruff_linter/src/rules/pydocstyle/mod.rs b/crates/ruff_linter/src/rules/pydocstyle/mod.rs index 1ea3ff9ffd3acd..4d129b1430eccf 100644 --- a/crates/ruff_linter/src/rules/pydocstyle/mod.rs +++ b/crates/ruff_linter/src/rules/pydocstyle/mod.rs @@ -49,6 +49,7 @@ mod tests { #[test_case(Rule::OverIndentation, Path::new("D.py"))] #[test_case(Rule::OverIndentation, Path::new("D208.py"))] #[test_case(Rule::NoSignature, Path::new("D.py"))] + #[test_case(Rule::NoSignature, Path::new("D402.py"))] #[test_case(Rule::SurroundingWhitespace, Path::new("D.py"))] #[test_case(Rule::DocstringStartsWithThis, Path::new("D.py"))] #[test_case(Rule::UnderIndentation, Path::new("D.py"))] diff --git a/crates/ruff_linter/src/rules/pydocstyle/rules/no_signature.rs b/crates/ruff_linter/src/rules/pydocstyle/rules/no_signature.rs index bbd492cad10d23..eda6bc959f7f4e 100644 --- a/crates/ruff_linter/src/rules/pydocstyle/rules/no_signature.rs +++ b/crates/ruff_linter/src/rules/pydocstyle/rules/no_signature.rs @@ -66,7 +66,25 @@ pub(crate) fn no_signature(checker: &mut Checker, docstring: &Docstring) { // a function named `foo`). if first_line .match_indices(function.name.as_str()) - .any(|(index, _)| first_line[index + function.name.len()..].starts_with('(')) + .any(|(index, _)| { + // The function name must be preceded by a word boundary. + let preceded_by_word_boundary = first_line[..index] + .chars() + .next_back() + .map_or(true, |c| matches!(c, ' ' | '\t' | ';' | ',')); + if !preceded_by_word_boundary { + return false; + } + + // The function name must be followed by an open parenthesis. + let followed_by_open_parenthesis = + first_line[index + function.name.len()..].starts_with('('); + if !followed_by_open_parenthesis { + return false; + } + + true + }) { checker .diagnostics diff --git a/crates/ruff_linter/src/rules/pydocstyle/snapshots/ruff_linter__rules__pydocstyle__tests__D402_D402.py.snap b/crates/ruff_linter/src/rules/pydocstyle/snapshots/ruff_linter__rules__pydocstyle__tests__D402_D402.py.snap new file mode 100644 index 00000000000000..ce5ec50a898809 --- /dev/null +++ b/crates/ruff_linter/src/rules/pydocstyle/snapshots/ruff_linter__rules__pydocstyle__tests__D402_D402.py.snap @@ -0,0 +1,18 @@ +--- +source: crates/ruff_linter/src/rules/pydocstyle/mod.rs +--- +D402.py:2:5: D402 First line should not be the function's signature + | +1 | def foo(): +2 | """Returns foo().""" + | ^^^^^^^^^^^^^^^^^^^^ D402 +3 | +4 | def foo(): + | + +D402.py:8:5: D402 First line should not be the function's signature + | +7 | def foo(): +8 | """"Use this function; foo().""" + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ D402 + |