diff --git a/crates/ruff_linter/src/rules/pydocstyle/rules/indent.rs b/crates/ruff_linter/src/rules/pydocstyle/rules/indent.rs index ae59026687db55..3a0809529b8e00 100644 --- a/crates/ruff_linter/src/rules/pydocstyle/rules/indent.rs +++ b/crates/ruff_linter/src/rules/pydocstyle/rules/indent.rs @@ -223,8 +223,20 @@ pub(crate) fn indent(checker: &mut Checker, docstring: &Docstring) { // We report under-indentation on every line. This isn't great, but enables // fix. if (is_last || !is_blank) && line_indent_size < docstring_indent_size { - let mut diagnostic = - Diagnostic::new(UnderIndentation, TextRange::empty(line.start())); + // Previously, this used `TextRange::empty(line.start())`, + // but this creates an offset immediately after the line + // terminator. Probably, our renderer should create an + // annotation that points to the beginning of the following + // line. But it doesn't at present and this have proved + // difficult to fix without regressing other cases. So for now, + // we work around this by creating a range that points at the + // first codepoint in the corresponding line. This makes the + // renderer do what we want. ---AG + let start = line.start(); + let end = checker + .locator() + .ceil_char_boundary(start + TextSize::from(1)); + let mut diagnostic = Diagnostic::new(UnderIndentation, TextRange::new(start, end)); diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement( clean_space(docstring.indentation), TextRange::at(line.start(), line_indent.text_len()), @@ -281,8 +293,16 @@ pub(crate) fn indent(checker: &mut Checker, docstring: &Docstring) { // We report over-indentation on every line. This isn't great, but // enables the fix capability. - let mut diagnostic = - Diagnostic::new(OverIndentation, TextRange::empty(line.start())); + // + // Also, we ensure that our range points to the first character + // of the line instead of the empty spance immediately + // preceding the line. See above for how we handle under + // indentation for more explanation. ---AG + let start = line.start(); + let end = checker + .locator() + .ceil_char_boundary(start + TextSize::from(1)); + let mut diagnostic = Diagnostic::new(OverIndentation, TextRange::new(start, end)); let edit = if indent.is_empty() { // Delete the entire indent. @@ -324,8 +344,15 @@ pub(crate) fn indent(checker: &mut Checker, docstring: &Docstring) { let is_indent_only = line_indent.len() == last.len(); if last_line_over_indent > 0 && is_indent_only { - let mut diagnostic = - Diagnostic::new(OverIndentation, TextRange::empty(last.start())); + // We ensure that our range points to the first character of + // the line instead of the empty spance immediately preceding + // the line. See above for how we handle under indentation for + // more explanation. ---AG + let start = last.start(); + let end = checker + .locator() + .ceil_char_boundary(start + TextSize::from(1)); + let mut diagnostic = Diagnostic::new(OverIndentation, TextRange::new(start, end)); let indent = clean_space(docstring.indentation); let range = TextRange::at(last.start(), line_indent.text_len()); let edit = if indent.is_empty() { diff --git a/crates/ruff_linter/src/rules/pydocstyle/snapshots/ruff_linter__rules__pydocstyle__tests__D207_D.py.snap b/crates/ruff_linter/src/rules/pydocstyle/snapshots/ruff_linter__rules__pydocstyle__tests__D207_D.py.snap index c330b6cde7be86..e06aa71405ab2c 100644 --- a/crates/ruff_linter/src/rules/pydocstyle/snapshots/ruff_linter__rules__pydocstyle__tests__D207_D.py.snap +++ b/crates/ruff_linter/src/rules/pydocstyle/snapshots/ruff_linter__rules__pydocstyle__tests__D207_D.py.snap @@ -1,14 +1,13 @@ --- source: crates/ruff_linter/src/rules/pydocstyle/mod.rs -snapshot_kind: text --- D.py:232:1: D207 [*] Docstring is under-indented | 230 | """Summary. -231 | +231 | 232 | Description. - | D207 -233 | + | ^ D207 +233 | 234 | """ | = help: Increase indentation @@ -26,9 +25,9 @@ D.py:232:1: D207 [*] Docstring is under-indented D.py:244:1: D207 [*] Docstring is under-indented | 242 | Description. -243 | +243 | 244 | """ - | D207 + | ^ D207 | = help: Increase indentation @@ -45,9 +44,9 @@ D.py:244:1: D207 [*] Docstring is under-indented D.py:440:1: D207 [*] Docstring is under-indented | 438 | def docstring_start_in_same_line(): """First Line. -439 | +439 | 440 | Second Line - | D207 + | ^ D207 441 | """ | = help: Increase indentation @@ -66,7 +65,7 @@ D.py:441:1: D207 [*] Docstring is under-indented | 440 | Second Line 441 | """ - | D207 + | ^ D207 | = help: Increase indentation diff --git a/crates/ruff_linter/src/rules/pydocstyle/snapshots/ruff_linter__rules__pydocstyle__tests__D208_D.py.snap b/crates/ruff_linter/src/rules/pydocstyle/snapshots/ruff_linter__rules__pydocstyle__tests__D208_D.py.snap index fd8b5e3228750a..c3ba66a565115d 100644 --- a/crates/ruff_linter/src/rules/pydocstyle/snapshots/ruff_linter__rules__pydocstyle__tests__D208_D.py.snap +++ b/crates/ruff_linter/src/rules/pydocstyle/snapshots/ruff_linter__rules__pydocstyle__tests__D208_D.py.snap @@ -1,14 +1,13 @@ --- source: crates/ruff_linter/src/rules/pydocstyle/mod.rs -snapshot_kind: text --- D.py:252:1: D208 [*] Docstring is over-indented | 250 | """Summary. -251 | +251 | 252 | Description. - | D208 -253 | + | ^ D208 +253 | 254 | """ | = help: Remove over-indentation @@ -26,9 +25,9 @@ D.py:252:1: D208 [*] Docstring is over-indented D.py:264:1: D208 [*] Docstring is over-indented | 262 | Description. -263 | +263 | 264 | """ - | D208 + | ^ D208 | = help: Remove over-indentation @@ -45,10 +44,10 @@ D.py:264:1: D208 [*] Docstring is over-indented D.py:272:1: D208 [*] Docstring is over-indented | 270 | """Summary. -271 | +271 | 272 | Description. - | D208 -273 | + | ^ D208 +273 | 274 | """ | = help: Remove over-indentation @@ -66,9 +65,9 @@ D.py:272:1: D208 [*] Docstring is over-indented D.py:673:1: D208 [*] Docstring is over-indented | 671 | """Summary. -672 | +672 | 673 | This is overindented - | D208 + | ^ D208 674 | And so is this, but it we should preserve the extra space on this line relative 675 | to the one before | @@ -88,7 +87,7 @@ D.py:674:1: D208 [*] Docstring is over-indented | 673 | This is overindented 674 | And so is this, but it we should preserve the extra space on this line relative - | D208 + | ^ D208 675 | to the one before 676 | """ | @@ -109,7 +108,7 @@ D.py:675:1: D208 [*] Docstring is over-indented 673 | This is overindented 674 | And so is this, but it we should preserve the extra space on this line relative 675 | to the one before - | D208 + | ^ D208 676 | """ | = help: Remove over-indentation @@ -127,9 +126,9 @@ D.py:675:1: D208 [*] Docstring is over-indented D.py:682:1: D208 [*] Docstring is over-indented | 680 | """Summary. -681 | +681 | 682 | This is overindented - | D208 + | ^ D208 683 | And so is this, but it we should preserve the extra space on this line relative 684 | to the one before | @@ -149,7 +148,7 @@ D.py:683:1: D208 [*] Docstring is over-indented | 682 | This is overindented 683 | And so is this, but it we should preserve the extra space on this line relative - | D208 + | ^ D208 684 | to the one before 685 | This is also overindented | @@ -170,7 +169,7 @@ D.py:684:1: D208 [*] Docstring is over-indented 682 | This is overindented 683 | And so is this, but it we should preserve the extra space on this line relative 684 | to the one before - | D208 + | ^ D208 685 | This is also overindented 686 | And so is this, but it we should preserve the extra space on this line relative | @@ -191,7 +190,7 @@ D.py:685:1: D208 [*] Docstring is over-indented 683 | And so is this, but it we should preserve the extra space on this line relative 684 | to the one before 685 | This is also overindented - | D208 + | ^ D208 686 | And so is this, but it we should preserve the extra space on this line relative 687 | to the one before | @@ -212,7 +211,7 @@ D.py:686:1: D208 [*] Docstring is over-indented 684 | to the one before 685 | This is also overindented 686 | And so is this, but it we should preserve the extra space on this line relative - | D208 + | ^ D208 687 | to the one before 688 | """ | @@ -233,7 +232,7 @@ D.py:687:1: D208 [*] Docstring is over-indented 685 | This is also overindented 686 | And so is this, but it we should preserve the extra space on this line relative 687 | to the one before - | D208 + | ^ D208 688 | """ | = help: Remove over-indentation @@ -251,9 +250,9 @@ D.py:687:1: D208 [*] Docstring is over-indented D.py:695:1: D208 [*] Docstring is over-indented | 693 | """Summary. -694 | +694 | 695 | This is overindented - | D208 + | ^ D208 696 | And so is this, but it we should preserve the extra space on this line relative 697 | to the one before | @@ -273,7 +272,7 @@ D.py:696:1: D208 [*] Docstring is over-indented | 695 | This is overindented 696 | And so is this, but it we should preserve the extra space on this line relative - | D208 + | ^ D208 697 | to the one before 698 | And the relative indent here should be preserved too | @@ -294,7 +293,7 @@ D.py:697:1: D208 [*] Docstring is over-indented 695 | This is overindented 696 | And so is this, but it we should preserve the extra space on this line relative 697 | to the one before - | D208 + | ^ D208 698 | And the relative indent here should be preserved too 699 | """ | @@ -315,7 +314,7 @@ D.py:698:1: D208 [*] Docstring is over-indented 696 | And so is this, but it we should preserve the extra space on this line relative 697 | to the one before 698 | And the relative indent here should be preserved too - | D208 + | ^ D208 699 | """ | = help: Remove over-indentation @@ -333,9 +332,9 @@ D.py:698:1: D208 [*] Docstring is over-indented D.py:704:1: D208 [*] Docstring is over-indented | 702 | """Summary. -703 | +703 | 704 | This is overindented - | D208 + | ^ D208 705 | And so is this, but it we should preserve the extra space on this line relative 706 | This is overindented | @@ -355,7 +354,7 @@ D.py:705:1: D208 [*] Docstring is over-indented | 704 | This is overindented 705 | And so is this, but it we should preserve the extra space on this line relative - | D208 + | ^ D208 706 | This is overindented 707 | This is overindented | @@ -376,7 +375,7 @@ D.py:706:1: D208 [*] Docstring is over-indented 704 | This is overindented 705 | And so is this, but it we should preserve the extra space on this line relative 706 | This is overindented - | D208 + | ^ D208 707 | This is overindented 708 | """ | @@ -397,7 +396,7 @@ D.py:707:1: D208 [*] Docstring is over-indented 705 | And so is this, but it we should preserve the extra space on this line relative 706 | This is overindented 707 | This is overindented - | D208 + | ^ D208 708 | """ | = help: Remove over-indentation @@ -415,9 +414,9 @@ D.py:707:1: D208 [*] Docstring is over-indented D.py:723:1: D208 [*] Docstring is over-indented | 721 | """There's a non-breaking space (2-bytes) after 3 spaces (https://github.com/astral-sh/ruff/issues/9080). -722 | +722 | 723 |     Returns: - | D208 + | ^ D208 724 | """ | = help: Remove over-indentation diff --git a/crates/ruff_linter/src/rules/pydocstyle/snapshots/ruff_linter__rules__pydocstyle__tests__D208_D208.py.snap b/crates/ruff_linter/src/rules/pydocstyle/snapshots/ruff_linter__rules__pydocstyle__tests__D208_D208.py.snap index da42cdc858db42..afcfd6d347cf0b 100644 --- a/crates/ruff_linter/src/rules/pydocstyle/snapshots/ruff_linter__rules__pydocstyle__tests__D208_D208.py.snap +++ b/crates/ruff_linter/src/rules/pydocstyle/snapshots/ruff_linter__rules__pydocstyle__tests__D208_D208.py.snap @@ -1,12 +1,11 @@ --- source: crates/ruff_linter/src/rules/pydocstyle/mod.rs -snapshot_kind: text --- D208.py:2:1: D208 [*] Docstring is over-indented | 1 | """ 2 | Author - | D208 + | ^ D208 3 | """ | = help: Remove over-indentation @@ -24,7 +23,7 @@ D208.py:8:1: D208 [*] Docstring is over-indented 6 | class Platform: 7 | """ Remove sampler 8 | Args: - | D208 + | ^ D208 9 |     Returns: 10 | """ | @@ -45,7 +44,7 @@ D208.py:9:1: D208 [*] Docstring is over-indented 7 | """ Remove sampler 8 | Args: 9 |     Returns: - | D208 + | ^ D208 10 | """ | = help: Remove over-indentation @@ -65,7 +64,7 @@ D208.py:10:1: D208 [*] Docstring is over-indented 8 | Args: 9 |     Returns: 10 | """ - | D208 + | ^ D208 | = help: Remove over-indentation @@ -84,7 +83,7 @@ D208.py:24:1: D208 [*] Docstring is over-indented 22 | Args: 23 | Returns: 24 | """ - | D208 + | ^ D208 | = help: Remove over-indentation @@ -103,7 +102,7 @@ D208.py:29:1: D208 [*] Docstring is over-indented 27 | class Platform: 28 | """All lines are over indented including the last containing the closing quotes 29 | Args: - | D208 + | ^ D208 30 | Returns: 31 | """ | @@ -124,7 +123,7 @@ D208.py:30:1: D208 [*] Docstring is over-indented 28 | """All lines are over indented including the last containing the closing quotes 29 | Args: 30 | Returns: - | D208 + | ^ D208 31 | """ | = help: Remove over-indentation @@ -144,8 +143,8 @@ D208.py:31:1: D208 [*] Docstring is over-indented 29 | Args: 30 | Returns: 31 | """ - | D208 -32 | + | ^ D208 +32 | 33 | class Platform: | = help: Remove over-indentation @@ -165,7 +164,7 @@ D208.py:35:1: D208 [*] Docstring is over-indented 33 | class Platform: 34 | """All lines are over indented including the last 35 | Args: - | D208 + | ^ D208 36 | Returns""" | = help: Remove over-indentation @@ -185,8 +184,8 @@ D208.py:36:1: D208 [*] Docstring is over-indented 34 | """All lines are over indented including the last 35 | Args: 36 | Returns""" - | D208 -37 | + | ^ D208 +37 | 38 | # OK: This doesn't get flagged because it is accepted when the closing quotes are on a separate line (see next test). Raises D209 | = help: Remove over-indentation