From 84ba7f5384a0d99231d23861b03f10bf764c76ca Mon Sep 17 00:00:00 2001 From: ukyen Date: Fri, 12 Jul 2024 23:18:58 +0100 Subject: [PATCH] Escaped single-quote docsting within single-quote docstring --- .../test/fixtures/pydocstyle/D301.py | 42 ++++++++++++++--- .../src/rules/pydocstyle/rules/backslashes.rs | 12 +++-- ...ules__pydocstyle__tests__D301_D301.py.snap | 45 ++++++++++++++----- 3 files changed, 76 insertions(+), 23 deletions(-) diff --git a/crates/ruff_linter/resources/test/fixtures/pydocstyle/D301.py b/crates/ruff_linter/resources/test/fixtures/pydocstyle/D301.py index 4b9075d87148ef..6622bc37b4f7cd 100644 --- a/crates/ruff_linter/resources/test/fixtures/pydocstyle/D301.py +++ b/crates/ruff_linter/resources/test/fixtures/pydocstyle/D301.py @@ -37,31 +37,59 @@ def shouldnt_add_raw_here2(): u"Sum\\mary." -def shouldnt_add_raw_for_docstring_contains_docstring(): +def shouldnt_add_raw_for_double_quote_docstring_contains_docstring(): """ - This docstring contains another docstring. + This docstring contains another double-quote docstring. def foo(): \"\"\"Foo.\"\"\" """ -def shouldnt_add_raw_for_docstring_contains_docstring2(): +def shouldnt_add_raw_for_double_quote_docstring_contains_docstring2(): """ - This docstring contains another docstring. + This docstring contains another double-quote docstring. def bar(): \"""Bar.\""" """ -def shouldnt_add_raw_for_docstring_contains_escaped_triple_quotes(): +def shouldnt_add_raw_for_single_quote_docstring_contains_docstring(): + ''' + This docstring contains another single-quote docstring. + + def foo(): + \'\'\'Foo.\'\'\' + ''' + + +def shouldnt_add_raw_for_single_quote_docstring_contains_docstring2(): + ''' + This docstring contains another single-quote docstring. + + def bar(): + \'''Bar.\''' + ''' + +def shouldnt_add_raw_for_docstring_contains_escaped_double_triple_quotes(): """ Escaped triple quote \""" or \"\"\". """ +def shouldnt_add_raw_for_docstring_contains_escaped_single_triple_quotes(): + ''' + Escaped triple quote \''' or \'\'\'. + ''' + -def should_add_raw_for_single_quote_escape(): +def should_add_raw_for_single_double_quote_escape(): """ This is single quote escape \". - """ \ No newline at end of file + """ + + +def should_add_raw_for_single_single_quote_escape(): + ''' + This is single quote escape \'. + ''' diff --git a/crates/ruff_linter/src/rules/pydocstyle/rules/backslashes.rs b/crates/ruff_linter/src/rules/pydocstyle/rules/backslashes.rs index 8fdfbf725029db..17c4388632a90b 100644 --- a/crates/ruff_linter/src/rules/pydocstyle/rules/backslashes.rs +++ b/crates/ruff_linter/src/rules/pydocstyle/rules/backslashes.rs @@ -70,24 +70,28 @@ pub(crate) fn backslashes(checker: &mut Checker, docstring: &Docstring) { let body = docstring.body(); let bytes = body.as_bytes(); let mut backslash_index = 0; - let escaped_docstring_backslashes_pattern = b"\"\\\"\\\""; + let double_quote_docstring_backslashes_pattern = b"\"\\\"\\\""; + let single_quote_docstring_backslashes_pattern = b"\'\\\'\\\'"; if memchr_iter(b'\\', bytes).any(|position| { let escaped_char = bytes.get(position.saturating_add(1)); // Allow escaped docstring. - if matches!(escaped_char, Some(b'"')) { + if matches!(escaped_char, Some(b'"' | b'\'')) { // If the next chars is equal to `"""`, it is a escaped docstring pattern. let escaped_triple_quotes = &bytes[position.saturating_add(1)..position.saturating_add(4)]; - if escaped_triple_quotes == b"\"\"\"" { + if escaped_triple_quotes == b"\"\"\"" || escaped_triple_quotes == b"\'\'\'" { return false; } + // For the `"\"\"` pattern, each iteration advances by 2 characters. // For example, the sequence progresses from `"\"\"` to `"\"` and then to `"`. // Therefore, we utilize an index to keep track of the remaining characters. let escaped_quotes_backslashes = &bytes [position.saturating_add(1)..position.saturating_add(6 - backslash_index * 2)]; if escaped_quotes_backslashes - == &escaped_docstring_backslashes_pattern[backslash_index * 2..] + == &double_quote_docstring_backslashes_pattern[backslash_index * 2..] + || escaped_quotes_backslashes + == &single_quote_docstring_backslashes_pattern[backslash_index * 2..] { backslash_index += 1; // Reset to avoid overflow. diff --git a/crates/ruff_linter/src/rules/pydocstyle/snapshots/ruff_linter__rules__pydocstyle__tests__D301_D301.py.snap b/crates/ruff_linter/src/rules/pydocstyle/snapshots/ruff_linter__rules__pydocstyle__tests__D301_D301.py.snap index e85ca90e131b58..5b7014ddb1c17c 100644 --- a/crates/ruff_linter/src/rules/pydocstyle/snapshots/ruff_linter__rules__pydocstyle__tests__D301_D301.py.snap +++ b/crates/ruff_linter/src/rules/pydocstyle/snapshots/ruff_linter__rules__pydocstyle__tests__D301_D301.py.snap @@ -25,22 +25,43 @@ D301.py:37:5: D301 Use `r"""` if any backslashes in a docstring | = help: Add `r` prefix -D301.py:65:5: D301 [*] Use `r"""` if any backslashes in a docstring +D301.py:87:5: D301 [*] Use `r"""` if any backslashes in a docstring | -64 | def should_add_raw_for_single_quote_escape(): -65 | """ +86 | def should_add_raw_for_single_double_quote_escape(): +87 | """ | _____^ -66 | | This is single quote escape \". -67 | | """ +88 | | This is single quote escape \". +89 | | """ | |_______^ D301 | = help: Add `r` prefix ℹ Unsafe fix -62 62 | -63 63 | -64 64 | def should_add_raw_for_single_quote_escape(): -65 |- """ - 65 |+ r""" -66 66 | This is single quote escape \". -67 67 | """ +84 84 | +85 85 | +86 86 | def should_add_raw_for_single_double_quote_escape(): +87 |- """ + 87 |+ r""" +88 88 | This is single quote escape \". +89 89 | """ +90 90 | + +D301.py:93:5: D301 [*] Use `r"""` if any backslashes in a docstring + | +92 | def should_add_raw_for_single_single_quote_escape(): +93 | ''' + | _____^ +94 | | This is single quote escape \'. +95 | | ''' + | |_______^ D301 + | + = help: Add `r` prefix + +ℹ Unsafe fix +90 90 | +91 91 | +92 92 | def should_add_raw_for_single_single_quote_escape(): +93 |- ''' + 93 |+ r''' +94 94 | This is single quote escape \'. +95 95 | '''