diff --git a/README.md b/README.md index 4761165316..a44916a62f 100644 --- a/README.md +++ b/README.md @@ -952,10 +952,10 @@ For more, see [flake8-quotes](https://pypi.org/project/flake8-quotes/3.3.1/) on | Code | Name | Message | Fix | | ---- | ---- | ------- | --- | -| Q000 | BadQuotesInlineString | Single quotes found but double quotes preferred | | -| Q001 | BadQuotesMultilineString | Single quote multiline found but double quotes preferred | | -| Q002 | BadQuotesDocstring | Single quote docstring found but double quotes preferred | | -| Q003 | AvoidQuoteEscape | Change outer quotes to avoid escaping inner quotes | | +| Q000 | BadQuotesInlineString | Single quotes found but double quotes preferred | 🛠 | +| Q001 | BadQuotesMultilineString | Single quote multiline found but double quotes preferred | 🛠 | +| Q002 | BadQuotesDocstring | Single quote docstring found but double quotes preferred | 🛠 | +| Q003 | AvoidQuoteEscape | Change outer quotes to avoid escaping inner quotes | 🛠 | ### flake8-return (RET) diff --git a/resources/test/fixtures/flake8_quotes/doubles_escaped.py b/resources/test/fixtures/flake8_quotes/doubles_escaped.py index 5a8a12527e..401a7fcba6 100644 --- a/resources/test/fixtures/flake8_quotes/doubles_escaped.py +++ b/resources/test/fixtures/flake8_quotes/doubles_escaped.py @@ -1,4 +1,5 @@ this_should_raise_Q003 = 'This is a \'string\'' +this_should_raise_Q003 = 'This is \\ a \\\'string\'' this_is_fine = '"This" is a \'string\'' this_is_fine = "This is a 'string'" this_is_fine = "\"This\" is a 'string'" diff --git a/src/checkers/tokens.rs b/src/checkers/tokens.rs index d436375f36..be68c4f14b 100644 --- a/src/checkers/tokens.rs +++ b/src/checkers/tokens.rs @@ -67,7 +67,8 @@ pub fn check_tokens( start, end, is_docstring, - &settings.flake8_quotes, + settings, + autofix, ) { if settings.enabled.contains(diagnostic.kind.code()) { diagnostics.push(diagnostic); diff --git a/src/flake8_quotes/rules.rs b/src/flake8_quotes/rules.rs index c48dd9a31a..e70230c738 100644 --- a/src/flake8_quotes/rules.rs +++ b/src/flake8_quotes/rules.rs @@ -1,8 +1,10 @@ use rustpython_ast::Location; use crate::ast::types::Range; -use crate::flake8_quotes::settings::{Quote, Settings}; -use crate::registry::Diagnostic; +use crate::fix::Fix; +use crate::flake8_quotes::settings::Quote; +use crate::registry::{Diagnostic, RuleCode}; +use crate::settings::{flags, Settings}; use crate::source_code::Locator; use crate::violations; @@ -47,7 +49,9 @@ pub fn quotes( end: Location, is_docstring: bool, settings: &Settings, + autofix: flags::Autofix, ) -> Option { + let quotes_settings = &settings.flake8_quotes; let text = locator.slice_source_code_range(&Range::new(start, end)); // Remove any prefixes (e.g., remove `u` from `u"foo"`). @@ -68,54 +72,139 @@ pub fn quotes( }; if is_docstring { - if raw_text.contains(good_docstring(&settings.docstring_quotes)) { + if raw_text.contains(good_docstring("es_settings.docstring_quotes)) { return None; } - Some(Diagnostic::new( - violations::BadQuotesDocstring(settings.docstring_quotes.clone()), + let mut diagnostic = Diagnostic::new( + violations::BadQuotesDocstring(quotes_settings.docstring_quotes.clone()), Range::new(start, end), - )) + ); + if matches!(autofix, flags::Autofix::Enabled) && settings.fixable.contains(&RuleCode::Q002) + { + let quote_count = if is_multiline { 3 } else { 1 }; + let string_contents = &raw_text[quote_count..raw_text.len() - quote_count]; + let quote = good_docstring("es_settings.docstring_quotes).repeat(quote_count); + let mut fixed_contents = + String::with_capacity(prefix.len() + string_contents.len() + quote.len() * 2); + fixed_contents.push_str(prefix); + fixed_contents.push_str("e); + fixed_contents.push_str(string_contents); + fixed_contents.push_str("e); + diagnostic.amend(Fix::replacement(fixed_contents, start, end)); + } + Some(diagnostic) } else if is_multiline { // If our string is or contains a known good string, ignore it. - if raw_text.contains(good_multiline(&settings.multiline_quotes)) { + if raw_text.contains(good_multiline("es_settings.multiline_quotes)) { return None; } // If our string ends with a known good ending, then ignore it. - if raw_text.ends_with(good_multiline_ending(&settings.multiline_quotes)) { + if raw_text.ends_with(good_multiline_ending("es_settings.multiline_quotes)) { return None; } - Some(Diagnostic::new( - violations::BadQuotesMultilineString(settings.multiline_quotes.clone()), + let mut diagnostic = Diagnostic::new( + violations::BadQuotesMultilineString(quotes_settings.multiline_quotes.clone()), Range::new(start, end), - )) + ); + + if matches!(autofix, flags::Autofix::Enabled) && settings.fixable.contains(&RuleCode::Q001) + { + let string_contents = &raw_text[3..raw_text.len() - 3]; + let quote = good_multiline("es_settings.multiline_quotes); + let mut fixed_contents = + String::with_capacity(prefix.len() + string_contents.len() + quote.len() * 2); + fixed_contents.push_str(prefix); + fixed_contents.push_str(quote); + fixed_contents.push_str(string_contents); + fixed_contents.push_str(quote); + diagnostic.amend(Fix::replacement(fixed_contents, start, end)); + } + Some(diagnostic) } else { let string_contents = &raw_text[1..raw_text.len() - 1]; // If we're using the preferred quotation type, check for escapes. - if last_quote_char == good_single(&settings.inline_quotes) { - if !settings.avoid_escape || prefix.contains('r') { + if last_quote_char == good_single("es_settings.inline_quotes) { + if !quotes_settings.avoid_escape || prefix.contains('r') { return None; } - if string_contents.contains(good_single(&settings.inline_quotes)) - && !string_contents.contains(bad_single(&settings.inline_quotes)) + if string_contents.contains(good_single("es_settings.inline_quotes)) + && !string_contents.contains(bad_single("es_settings.inline_quotes)) { - return Some(Diagnostic::new( - violations::AvoidQuoteEscape, - Range::new(start, end), - )); + let mut diagnostic = + Diagnostic::new(violations::AvoidQuoteEscape, Range::new(start, end)); + if matches!(autofix, flags::Autofix::Enabled) + && settings.fixable.contains(&RuleCode::Q003) + { + let quote = bad_single("es_settings.inline_quotes); + + let mut fixed_contents = + String::with_capacity(prefix.len() + string_contents.len() + 2); + fixed_contents.push_str(prefix); + fixed_contents.push(quote); + + let chars: Vec = string_contents.chars().collect(); + let mut backslash_count = 0; + for col_offset in 0..chars.len() { + let char = chars[col_offset]; + if char != '\\' { + fixed_contents.push(char); + continue; + } + backslash_count += 1; + // If the previous character was also a backslash + if col_offset > 0 && chars[col_offset - 1] == '\\' && backslash_count == 2 { + fixed_contents.push(char); + // reset to 0 + backslash_count = 0; + continue; + } + // If we're at the end of the line + if col_offset == chars.len() - 1 { + fixed_contents.push(char); + continue; + } + let next_char = chars[col_offset + 1]; + // Remove quote escape + if next_char == '\'' || next_char == '"' { + // reset to 0 + backslash_count = 0; + continue; + } + fixed_contents.push(char); + } + + fixed_contents.push(quote); + + diagnostic.amend(Fix::replacement(fixed_contents, start, end)); + } + return Some(diagnostic); } return None; } // If we're not using the preferred type, only allow use to avoid escapes. - if !string_contents.contains(good_single(&settings.inline_quotes)) { - return Some(Diagnostic::new( - violations::BadQuotesInlineString(settings.inline_quotes.clone()), + if !string_contents.contains(good_single("es_settings.inline_quotes)) { + let mut diagnostic = Diagnostic::new( + violations::BadQuotesInlineString(quotes_settings.inline_quotes.clone()), Range::new(start, end), - )); + ); + if matches!(autofix, flags::Autofix::Enabled) + && settings.fixable.contains(&RuleCode::Q000) + { + let quote = good_single("es_settings.inline_quotes); + let mut fixed_contents = + String::with_capacity(prefix.len() + string_contents.len() + 2); + fixed_contents.push_str(prefix); + fixed_contents.push(quote); + fixed_contents.push_str(string_contents); + fixed_contents.push(quote); + diagnostic.amend(Fix::replacement(fixed_contents, start, end)); + } + return Some(diagnostic); } None diff --git a/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__double_docstring_docstring_doubles.py.snap b/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__double_docstring_docstring_doubles.py.snap index 9bac8e6a3e..04615aed80 100644 --- a/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__double_docstring_docstring_doubles.py.snap +++ b/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__double_docstring_docstring_doubles.py.snap @@ -1,6 +1,6 @@ --- source: src/flake8_quotes/mod.rs -expression: checks +expression: diagnostics --- - kind: BadQuotesMultilineString: single @@ -10,7 +10,14 @@ expression: checks end_location: row: 7 column: 3 - fix: ~ + fix: + content: "'''\nthis is not a docstring\n'''" + location: + row: 5 + column: 0 + end_location: + row: 7 + column: 3 parent: ~ - kind: BadQuotesMultilineString: single @@ -20,7 +27,14 @@ expression: checks end_location: row: 18 column: 7 - fix: ~ + fix: + content: "'''\n this is not a docstring\n '''" + location: + row: 16 + column: 4 + end_location: + row: 18 + column: 7 parent: ~ - kind: BadQuotesMultilineString: single @@ -30,7 +44,14 @@ expression: checks end_location: row: 22 column: 37 - fix: ~ + fix: + content: "'''\n definitely not a docstring'''" + location: + row: 21 + column: 20 + end_location: + row: 22 + column: 37 parent: ~ - kind: BadQuotesMultilineString: single @@ -40,7 +61,14 @@ expression: checks end_location: row: 32 column: 11 - fix: ~ + fix: + content: "'''\n this is not a docstring\n '''" + location: + row: 30 + column: 8 + end_location: + row: 32 + column: 11 parent: ~ - kind: BadQuotesMultilineString: single @@ -50,6 +78,13 @@ expression: checks end_location: row: 37 column: 15 - fix: ~ + fix: + content: "'''\n Looks like a docstring, but in reality it isn't - only modules, classes and functions\n '''" + location: + row: 35 + column: 12 + end_location: + row: 37 + column: 15 parent: ~ diff --git a/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__double_docstring_docstring_doubles_class.py.snap b/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__double_docstring_docstring_doubles_class.py.snap index 22c83a6298..58d7b6a8ec 100644 --- a/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__double_docstring_docstring_doubles_class.py.snap +++ b/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__double_docstring_docstring_doubles_class.py.snap @@ -1,6 +1,6 @@ --- source: src/flake8_quotes/mod.rs -expression: checks +expression: diagnostics --- - kind: BadQuotesMultilineString: single @@ -10,7 +10,14 @@ expression: checks end_location: row: 3 column: 27 - fix: ~ + fix: + content: "''' Not a docstring '''" + location: + row: 3 + column: 4 + end_location: + row: 3 + column: 27 parent: ~ - kind: BadQuotesMultilineString: single @@ -20,6 +27,13 @@ expression: checks end_location: row: 5 column: 43 - fix: ~ + fix: + content: "'''not a docstring'''" + location: + row: 5 + column: 22 + end_location: + row: 5 + column: 43 parent: ~ diff --git a/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__double_docstring_docstring_doubles_function.py.snap b/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__double_docstring_docstring_doubles_function.py.snap index d2bf8314f9..f26c974dc2 100644 --- a/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__double_docstring_docstring_doubles_function.py.snap +++ b/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__double_docstring_docstring_doubles_function.py.snap @@ -10,7 +10,14 @@ expression: diagnostics end_location: row: 3 column: 26 - fix: ~ + fix: + content: "''' not a docstring'''" + location: + row: 3 + column: 4 + end_location: + row: 3 + column: 26 parent: ~ - kind: BadQuotesMultilineString: single @@ -20,7 +27,14 @@ expression: diagnostics end_location: row: 11 column: 26 - fix: ~ + fix: + content: "''' not a docstring'''" + location: + row: 11 + column: 4 + end_location: + row: 11 + column: 26 parent: ~ - kind: BadQuotesMultilineString: single @@ -30,7 +44,14 @@ expression: diagnostics end_location: row: 17 column: 3 - fix: ~ + fix: + content: "'''\n not a\n'''" + location: + row: 15 + column: 38 + end_location: + row: 17 + column: 3 parent: ~ - kind: BadQuotesMultilineString: single @@ -40,7 +61,14 @@ expression: diagnostics end_location: row: 17 column: 19 - fix: ~ + fix: + content: "'''docstring'''" + location: + row: 17 + column: 4 + end_location: + row: 17 + column: 19 parent: ~ - kind: BadQuotesMultilineString: single @@ -50,6 +78,13 @@ expression: diagnostics end_location: row: 22 column: 27 - fix: ~ + fix: + content: "''' not a docstring '''" + location: + row: 22 + column: 4 + end_location: + row: 22 + column: 27 parent: ~ diff --git a/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__double_docstring_docstring_doubles_module_multiline.py.snap b/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__double_docstring_docstring_doubles_module_multiline.py.snap index b13ed4bfeb..8b69b4b1d8 100644 --- a/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__double_docstring_docstring_doubles_module_multiline.py.snap +++ b/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__double_docstring_docstring_doubles_module_multiline.py.snap @@ -1,6 +1,6 @@ --- source: src/flake8_quotes/mod.rs -expression: checks +expression: diagnostics --- - kind: BadQuotesMultilineString: single @@ -10,7 +10,14 @@ expression: checks end_location: row: 6 column: 3 - fix: ~ + fix: + content: "'''\nthis is not a docstring\n'''" + location: + row: 4 + column: 0 + end_location: + row: 6 + column: 3 parent: ~ - kind: BadQuotesMultilineString: single @@ -20,6 +27,13 @@ expression: checks end_location: row: 11 column: 3 - fix: ~ + fix: + content: "'''\nthis is not a docstring\n'''" + location: + row: 9 + column: 0 + end_location: + row: 11 + column: 3 parent: ~ diff --git a/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__double_docstring_docstring_doubles_module_singleline.py.snap b/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__double_docstring_docstring_doubles_module_singleline.py.snap index b4ff03a4f1..07d89d27a8 100644 --- a/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__double_docstring_docstring_doubles_module_singleline.py.snap +++ b/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__double_docstring_docstring_doubles_module_singleline.py.snap @@ -1,6 +1,6 @@ --- source: src/flake8_quotes/mod.rs -expression: checks +expression: diagnostics --- - kind: BadQuotesMultilineString: single @@ -10,7 +10,14 @@ expression: checks end_location: row: 2 column: 31 - fix: ~ + fix: + content: "''' this is not a docstring '''" + location: + row: 2 + column: 0 + end_location: + row: 2 + column: 31 parent: ~ - kind: BadQuotesMultilineString: single @@ -20,6 +27,13 @@ expression: checks end_location: row: 6 column: 31 - fix: ~ + fix: + content: "''' this is not a docstring '''" + location: + row: 6 + column: 0 + end_location: + row: 6 + column: 31 parent: ~ diff --git a/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__double_docstring_docstring_singles.py.snap b/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__double_docstring_docstring_singles.py.snap index 3d74cb7afd..5d0e69287b 100644 --- a/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__double_docstring_docstring_singles.py.snap +++ b/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__double_docstring_docstring_singles.py.snap @@ -1,6 +1,6 @@ --- source: src/flake8_quotes/mod.rs -expression: checks +expression: diagnostics --- - kind: BadQuotesDocstring: double @@ -10,7 +10,14 @@ expression: checks end_location: row: 3 column: 3 - fix: ~ + fix: + content: "\"\"\"\nSingle quotes multiline module docstring\n\"\"\"" + location: + row: 1 + column: 0 + end_location: + row: 3 + column: 3 parent: ~ - kind: BadQuotesDocstring: double @@ -20,7 +27,14 @@ expression: checks end_location: row: 16 column: 7 - fix: ~ + fix: + content: "\"\"\"\n Single quotes multiline class docstring\n \"\"\"" + location: + row: 14 + column: 4 + end_location: + row: 16 + column: 7 parent: ~ - kind: BadQuotesDocstring: double @@ -30,6 +44,13 @@ expression: checks end_location: row: 28 column: 11 - fix: ~ + fix: + content: "\"\"\"\n Single quotes multiline function docstring\n \"\"\"" + location: + row: 26 + column: 8 + end_location: + row: 28 + column: 11 parent: ~ diff --git a/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__double_docstring_docstring_singles_class.py.snap b/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__double_docstring_docstring_singles_class.py.snap index 3574722935..fb2b69cc5c 100644 --- a/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__double_docstring_docstring_singles_class.py.snap +++ b/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__double_docstring_docstring_singles_class.py.snap @@ -1,6 +1,6 @@ --- source: src/flake8_quotes/mod.rs -expression: checks +expression: diagnostics --- - kind: BadQuotesDocstring: double @@ -10,7 +10,14 @@ expression: checks end_location: row: 2 column: 53 - fix: ~ + fix: + content: "\"\"\" Double quotes single line class docstring \"\"\"" + location: + row: 2 + column: 4 + end_location: + row: 2 + column: 53 parent: ~ - kind: BadQuotesDocstring: double @@ -20,7 +27,14 @@ expression: checks end_location: row: 6 column: 57 - fix: ~ + fix: + content: "\"\"\" Double quotes single line method docstring\"\"\"" + location: + row: 6 + column: 8 + end_location: + row: 6 + column: 57 parent: ~ - kind: BadQuotesDocstring: double @@ -30,6 +44,13 @@ expression: checks end_location: row: 9 column: 52 - fix: ~ + fix: + content: "\"\"\" inline docstring \"\"\"" + location: + row: 9 + column: 28 + end_location: + row: 9 + column: 52 parent: ~ diff --git a/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__double_docstring_docstring_singles_function.py.snap b/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__double_docstring_docstring_singles_function.py.snap index 443c35a6f2..1d2a971114 100644 --- a/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__double_docstring_docstring_singles_function.py.snap +++ b/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__double_docstring_docstring_singles_function.py.snap @@ -10,7 +10,14 @@ expression: diagnostics end_location: row: 2 column: 56 - fix: ~ + fix: + content: "\"\"\"function without params, single line docstring\"\"\"" + location: + row: 2 + column: 4 + end_location: + row: 2 + column: 56 parent: ~ - kind: BadQuotesDocstring: double @@ -20,7 +27,14 @@ expression: diagnostics end_location: row: 10 column: 7 - fix: ~ + fix: + content: "\"\"\"\n function without params, multiline docstring\n \"\"\"" + location: + row: 8 + column: 4 + end_location: + row: 10 + column: 7 parent: ~ - kind: BadQuotesDocstring: double @@ -30,6 +44,13 @@ expression: diagnostics end_location: row: 27 column: 27 - fix: ~ + fix: + content: "\"Single line docstring\"" + location: + row: 27 + column: 4 + end_location: + row: 27 + column: 27 parent: ~ diff --git a/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__double_docstring_docstring_singles_module_multiline.py.snap b/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__double_docstring_docstring_singles_module_multiline.py.snap index 445a87591e..c00308ab12 100644 --- a/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__double_docstring_docstring_singles_module_multiline.py.snap +++ b/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__double_docstring_docstring_singles_module_multiline.py.snap @@ -1,6 +1,6 @@ --- source: src/flake8_quotes/mod.rs -expression: checks +expression: diagnostics --- - kind: BadQuotesDocstring: double @@ -10,6 +10,13 @@ expression: checks end_location: row: 3 column: 3 - fix: ~ + fix: + content: "\"\"\"\nDouble quotes multiline module docstring\n\"\"\"" + location: + row: 1 + column: 0 + end_location: + row: 3 + column: 3 parent: ~ diff --git a/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__double_docstring_docstring_singles_module_singleline.py.snap b/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__double_docstring_docstring_singles_module_singleline.py.snap index 5e9431d566..816863fe37 100644 --- a/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__double_docstring_docstring_singles_module_singleline.py.snap +++ b/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__double_docstring_docstring_singles_module_singleline.py.snap @@ -1,6 +1,6 @@ --- source: src/flake8_quotes/mod.rs -expression: checks +expression: diagnostics --- - kind: BadQuotesDocstring: double @@ -10,6 +10,13 @@ expression: checks end_location: row: 1 column: 49 - fix: ~ + fix: + content: "\"\"\" Double quotes singleline module docstring \"\"\"" + location: + row: 1 + column: 0 + end_location: + row: 1 + column: 49 parent: ~ diff --git a/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__doubles_doubles.py.snap b/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__doubles_doubles.py.snap index 3551b999c3..6a3f82974c 100644 --- a/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__doubles_doubles.py.snap +++ b/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__doubles_doubles.py.snap @@ -1,6 +1,6 @@ --- source: src/flake8_quotes/mod.rs -expression: checks +expression: diagnostics --- - kind: BadQuotesInlineString: single @@ -10,7 +10,14 @@ expression: checks end_location: row: 1 column: 45 - fix: ~ + fix: + content: "'double quote string'" + location: + row: 1 + column: 24 + end_location: + row: 1 + column: 45 parent: ~ - kind: BadQuotesInlineString: single @@ -20,6 +27,13 @@ expression: checks end_location: row: 2 column: 46 - fix: ~ + fix: + content: "u'double quote string'" + location: + row: 2 + column: 24 + end_location: + row: 2 + column: 46 parent: ~ diff --git a/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__doubles_doubles_escaped.py.snap b/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__doubles_doubles_escaped.py.snap index a9dc42ea24..0c2e02fe16 100644 --- a/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__doubles_doubles_escaped.py.snap +++ b/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__doubles_doubles_escaped.py.snap @@ -1,6 +1,6 @@ --- source: src/flake8_quotes/mod.rs -expression: checks +expression: diagnostics --- - kind: AvoidQuoteEscape: ~ @@ -10,6 +10,30 @@ expression: checks end_location: row: 1 column: 47 - fix: ~ + fix: + content: "\"This is a 'string'\"" + location: + row: 1 + column: 25 + end_location: + row: 1 + column: 47 + parent: ~ +- kind: + AvoidQuoteEscape: ~ + location: + row: 2 + column: 25 + end_location: + row: 2 + column: 52 + fix: + content: "\"This is \\\\ a \\\\'string'\"" + location: + row: 2 + column: 25 + end_location: + row: 2 + column: 52 parent: ~ diff --git a/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__doubles_doubles_multiline_string.py.snap b/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__doubles_doubles_multiline_string.py.snap index 382fab61f3..4363550694 100644 --- a/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__doubles_doubles_multiline_string.py.snap +++ b/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__doubles_doubles_multiline_string.py.snap @@ -1,6 +1,6 @@ --- source: src/flake8_quotes/mod.rs -expression: checks +expression: diagnostics --- - kind: BadQuotesMultilineString: single @@ -10,6 +10,13 @@ expression: checks end_location: row: 3 column: 12 - fix: ~ + fix: + content: "''' This \"should\"\nbe\n\"linted\" '''" + location: + row: 1 + column: 4 + end_location: + row: 3 + column: 12 parent: ~ diff --git a/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__single_docstring_docstring_doubles.py.snap b/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__single_docstring_docstring_doubles.py.snap index f87f7ebb3c..fe1ff22666 100644 --- a/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__single_docstring_docstring_doubles.py.snap +++ b/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__single_docstring_docstring_doubles.py.snap @@ -1,6 +1,6 @@ --- source: src/flake8_quotes/mod.rs -expression: checks +expression: diagnostics --- - kind: BadQuotesDocstring: single @@ -10,7 +10,14 @@ expression: checks end_location: row: 3 column: 3 - fix: ~ + fix: + content: "'''\nDouble quotes multiline module docstring\n'''" + location: + row: 1 + column: 0 + end_location: + row: 3 + column: 3 parent: ~ - kind: BadQuotesDocstring: single @@ -20,7 +27,14 @@ expression: checks end_location: row: 14 column: 7 - fix: ~ + fix: + content: "'''\n Double quotes multiline class docstring\n '''" + location: + row: 12 + column: 4 + end_location: + row: 14 + column: 7 parent: ~ - kind: BadQuotesDocstring: single @@ -30,6 +44,13 @@ expression: checks end_location: row: 26 column: 11 - fix: ~ + fix: + content: "'''\n Double quotes multiline function docstring\n '''" + location: + row: 24 + column: 8 + end_location: + row: 26 + column: 11 parent: ~ diff --git a/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__single_docstring_docstring_doubles_class.py.snap b/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__single_docstring_docstring_doubles_class.py.snap index ec22bcc676..4380b4b0f2 100644 --- a/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__single_docstring_docstring_doubles_class.py.snap +++ b/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__single_docstring_docstring_doubles_class.py.snap @@ -1,6 +1,6 @@ --- source: src/flake8_quotes/mod.rs -expression: checks +expression: diagnostics --- - kind: BadQuotesDocstring: single @@ -10,7 +10,14 @@ expression: checks end_location: row: 2 column: 53 - fix: ~ + fix: + content: "''' Double quotes single line class docstring '''" + location: + row: 2 + column: 4 + end_location: + row: 2 + column: 53 parent: ~ - kind: BadQuotesDocstring: single @@ -20,7 +27,14 @@ expression: checks end_location: row: 6 column: 57 - fix: ~ + fix: + content: "''' Double quotes single line method docstring'''" + location: + row: 6 + column: 8 + end_location: + row: 6 + column: 57 parent: ~ - kind: BadQuotesDocstring: single @@ -30,6 +44,13 @@ expression: checks end_location: row: 9 column: 52 - fix: ~ + fix: + content: "''' inline docstring '''" + location: + row: 9 + column: 28 + end_location: + row: 9 + column: 52 parent: ~ diff --git a/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__single_docstring_docstring_doubles_function.py.snap b/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__single_docstring_docstring_doubles_function.py.snap index 390eb5725e..0bd9aa16b9 100644 --- a/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__single_docstring_docstring_doubles_function.py.snap +++ b/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__single_docstring_docstring_doubles_function.py.snap @@ -10,7 +10,14 @@ expression: diagnostics end_location: row: 2 column: 56 - fix: ~ + fix: + content: "'''function without params, single line docstring'''" + location: + row: 2 + column: 4 + end_location: + row: 2 + column: 56 parent: ~ - kind: BadQuotesDocstring: single @@ -20,7 +27,14 @@ expression: diagnostics end_location: row: 10 column: 7 - fix: ~ + fix: + content: "'''\n function without params, multiline docstring\n '''" + location: + row: 8 + column: 4 + end_location: + row: 10 + column: 7 parent: ~ - kind: BadQuotesDocstring: single @@ -30,6 +44,13 @@ expression: diagnostics end_location: row: 27 column: 27 - fix: ~ + fix: + content: "'Single line docstring'" + location: + row: 27 + column: 4 + end_location: + row: 27 + column: 27 parent: ~ diff --git a/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__single_docstring_docstring_doubles_module_multiline.py.snap b/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__single_docstring_docstring_doubles_module_multiline.py.snap index 5f0a6c99fd..e78cc03d78 100644 --- a/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__single_docstring_docstring_doubles_module_multiline.py.snap +++ b/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__single_docstring_docstring_doubles_module_multiline.py.snap @@ -1,6 +1,6 @@ --- source: src/flake8_quotes/mod.rs -expression: checks +expression: diagnostics --- - kind: BadQuotesDocstring: single @@ -10,6 +10,13 @@ expression: checks end_location: row: 3 column: 3 - fix: ~ + fix: + content: "'''\nDouble quotes multiline module docstring\n'''" + location: + row: 1 + column: 0 + end_location: + row: 3 + column: 3 parent: ~ diff --git a/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__single_docstring_docstring_doubles_module_singleline.py.snap b/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__single_docstring_docstring_doubles_module_singleline.py.snap index 51dc16e36f..c51898a288 100644 --- a/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__single_docstring_docstring_doubles_module_singleline.py.snap +++ b/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__single_docstring_docstring_doubles_module_singleline.py.snap @@ -1,6 +1,6 @@ --- source: src/flake8_quotes/mod.rs -expression: checks +expression: diagnostics --- - kind: BadQuotesDocstring: single @@ -10,6 +10,13 @@ expression: checks end_location: row: 1 column: 49 - fix: ~ + fix: + content: "''' Double quotes singleline module docstring '''" + location: + row: 1 + column: 0 + end_location: + row: 1 + column: 49 parent: ~ diff --git a/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__single_docstring_docstring_singles.py.snap b/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__single_docstring_docstring_singles.py.snap index 8a332267f1..36cbcc0bca 100644 --- a/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__single_docstring_docstring_singles.py.snap +++ b/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__single_docstring_docstring_singles.py.snap @@ -1,6 +1,6 @@ --- source: src/flake8_quotes/mod.rs -expression: checks +expression: diagnostics --- - kind: BadQuotesMultilineString: double @@ -10,7 +10,14 @@ expression: checks end_location: row: 7 column: 3 - fix: ~ + fix: + content: "\"\"\"\nthis is not a docstring\n\"\"\"" + location: + row: 5 + column: 0 + end_location: + row: 7 + column: 3 parent: ~ - kind: BadQuotesMultilineString: double @@ -20,7 +27,14 @@ expression: checks end_location: row: 13 column: 3 - fix: ~ + fix: + content: "\"\"\"\n class params \\t not a docstring\n\"\"\"" + location: + row: 11 + column: 20 + end_location: + row: 13 + column: 3 parent: ~ - kind: BadQuotesMultilineString: double @@ -30,7 +44,14 @@ expression: checks end_location: row: 20 column: 7 - fix: ~ + fix: + content: "\"\"\"\n this is not a docstring\n \"\"\"" + location: + row: 18 + column: 4 + end_location: + row: 20 + column: 7 parent: ~ - kind: BadQuotesMultilineString: double @@ -40,7 +61,14 @@ expression: checks end_location: row: 24 column: 37 - fix: ~ + fix: + content: "\"\"\"\n definitely not a docstring\"\"\"" + location: + row: 23 + column: 20 + end_location: + row: 24 + column: 37 parent: ~ - kind: BadQuotesMultilineString: double @@ -50,7 +78,14 @@ expression: checks end_location: row: 34 column: 11 - fix: ~ + fix: + content: "\"\"\"\n this is not a docstring\n \"\"\"" + location: + row: 32 + column: 8 + end_location: + row: 34 + column: 11 parent: ~ - kind: BadQuotesMultilineString: double @@ -60,6 +95,13 @@ expression: checks end_location: row: 39 column: 15 - fix: ~ + fix: + content: "\"\"\"\n Looks like a docstring, but in reality it isn't - only modules, classes and functions\n \"\"\"" + location: + row: 37 + column: 12 + end_location: + row: 39 + column: 15 parent: ~ diff --git a/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__single_docstring_docstring_singles_class.py.snap b/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__single_docstring_docstring_singles_class.py.snap index a450e8d377..bcadfdcc8f 100644 --- a/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__single_docstring_docstring_singles_class.py.snap +++ b/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__single_docstring_docstring_singles_class.py.snap @@ -1,6 +1,6 @@ --- source: src/flake8_quotes/mod.rs -expression: checks +expression: diagnostics --- - kind: BadQuotesMultilineString: double @@ -10,7 +10,14 @@ expression: checks end_location: row: 3 column: 27 - fix: ~ + fix: + content: "\"\"\" Not a docstring \"\"\"" + location: + row: 3 + column: 4 + end_location: + row: 3 + column: 27 parent: ~ - kind: BadQuotesMultilineString: double @@ -20,6 +27,13 @@ expression: checks end_location: row: 5 column: 43 - fix: ~ + fix: + content: "\"\"\"not a docstring\"\"\"" + location: + row: 5 + column: 22 + end_location: + row: 5 + column: 43 parent: ~ diff --git a/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__single_docstring_docstring_singles_function.py.snap b/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__single_docstring_docstring_singles_function.py.snap index ff00475247..1221159987 100644 --- a/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__single_docstring_docstring_singles_function.py.snap +++ b/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__single_docstring_docstring_singles_function.py.snap @@ -10,7 +10,14 @@ expression: diagnostics end_location: row: 3 column: 26 - fix: ~ + fix: + content: "\"\"\" not a docstring\"\"\"" + location: + row: 3 + column: 4 + end_location: + row: 3 + column: 26 parent: ~ - kind: BadQuotesMultilineString: double @@ -20,7 +27,14 @@ expression: diagnostics end_location: row: 11 column: 26 - fix: ~ + fix: + content: "\"\"\" not a docstring\"\"\"" + location: + row: 11 + column: 4 + end_location: + row: 11 + column: 26 parent: ~ - kind: BadQuotesMultilineString: double @@ -30,7 +44,14 @@ expression: diagnostics end_location: row: 17 column: 3 - fix: ~ + fix: + content: "\"\"\"\n not a\n\"\"\"" + location: + row: 15 + column: 38 + end_location: + row: 17 + column: 3 parent: ~ - kind: BadQuotesMultilineString: double @@ -40,7 +61,14 @@ expression: diagnostics end_location: row: 17 column: 19 - fix: ~ + fix: + content: "\"\"\"docstring\"\"\"" + location: + row: 17 + column: 4 + end_location: + row: 17 + column: 19 parent: ~ - kind: BadQuotesMultilineString: double @@ -50,6 +78,13 @@ expression: diagnostics end_location: row: 22 column: 27 - fix: ~ + fix: + content: "\"\"\" not a docstring \"\"\"" + location: + row: 22 + column: 4 + end_location: + row: 22 + column: 27 parent: ~ diff --git a/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__single_docstring_docstring_singles_module_multiline.py.snap b/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__single_docstring_docstring_singles_module_multiline.py.snap index 3644ef4bda..dbf2a7547f 100644 --- a/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__single_docstring_docstring_singles_module_multiline.py.snap +++ b/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__single_docstring_docstring_singles_module_multiline.py.snap @@ -1,6 +1,6 @@ --- source: src/flake8_quotes/mod.rs -expression: checks +expression: diagnostics --- - kind: BadQuotesMultilineString: double @@ -10,7 +10,14 @@ expression: checks end_location: row: 6 column: 3 - fix: ~ + fix: + content: "\"\"\"\nthis is not a docstring\n\"\"\"" + location: + row: 4 + column: 0 + end_location: + row: 6 + column: 3 parent: ~ - kind: BadQuotesMultilineString: double @@ -20,6 +27,13 @@ expression: checks end_location: row: 11 column: 3 - fix: ~ + fix: + content: "\"\"\"\nthis is not a docstring\n\"\"\"" + location: + row: 9 + column: 0 + end_location: + row: 11 + column: 3 parent: ~ diff --git a/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__single_docstring_docstring_singles_module_singleline.py.snap b/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__single_docstring_docstring_singles_module_singleline.py.snap index 2f5933881f..6ddda69712 100644 --- a/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__single_docstring_docstring_singles_module_singleline.py.snap +++ b/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__single_docstring_docstring_singles_module_singleline.py.snap @@ -1,6 +1,6 @@ --- source: src/flake8_quotes/mod.rs -expression: checks +expression: diagnostics --- - kind: BadQuotesMultilineString: double @@ -10,7 +10,14 @@ expression: checks end_location: row: 2 column: 31 - fix: ~ + fix: + content: "\"\"\" this is not a docstring \"\"\"" + location: + row: 2 + column: 0 + end_location: + row: 2 + column: 31 parent: ~ - kind: BadQuotesMultilineString: double @@ -20,6 +27,13 @@ expression: checks end_location: row: 6 column: 31 - fix: ~ + fix: + content: "\"\"\" this is not a docstring \"\"\"" + location: + row: 6 + column: 0 + end_location: + row: 6 + column: 31 parent: ~ diff --git a/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__singles_singles.py.snap b/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__singles_singles.py.snap index cec9b0ac88..2e364842f7 100644 --- a/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__singles_singles.py.snap +++ b/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__singles_singles.py.snap @@ -1,6 +1,6 @@ --- source: src/flake8_quotes/mod.rs -expression: checks +expression: diagnostics --- - kind: BadQuotesInlineString: double @@ -10,7 +10,14 @@ expression: checks end_location: row: 1 column: 45 - fix: ~ + fix: + content: "\"single quote string\"" + location: + row: 1 + column: 24 + end_location: + row: 1 + column: 45 parent: ~ - kind: BadQuotesInlineString: double @@ -20,6 +27,13 @@ expression: checks end_location: row: 2 column: 46 - fix: ~ + fix: + content: "u\"double quote string\"" + location: + row: 2 + column: 24 + end_location: + row: 2 + column: 46 parent: ~ diff --git a/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__singles_singles_escaped.py.snap b/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__singles_singles_escaped.py.snap index a9dc42ea24..3421949288 100644 --- a/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__singles_singles_escaped.py.snap +++ b/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__singles_singles_escaped.py.snap @@ -1,6 +1,6 @@ --- source: src/flake8_quotes/mod.rs -expression: checks +expression: diagnostics --- - kind: AvoidQuoteEscape: ~ @@ -10,6 +10,13 @@ expression: checks end_location: row: 1 column: 47 - fix: ~ + fix: + content: "'This is a \"string\"'" + location: + row: 1 + column: 25 + end_location: + row: 1 + column: 47 parent: ~ diff --git a/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__singles_singles_multiline_string.py.snap b/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__singles_singles_multiline_string.py.snap index 5350455927..a48a344112 100644 --- a/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__singles_singles_multiline_string.py.snap +++ b/src/flake8_quotes/snapshots/ruff__flake8_quotes__tests__singles_singles_multiline_string.py.snap @@ -1,6 +1,6 @@ --- source: src/flake8_quotes/mod.rs -expression: checks +expression: diagnostics --- - kind: BadQuotesMultilineString: double @@ -10,6 +10,13 @@ expression: checks end_location: row: 3 column: 12 - fix: ~ + fix: + content: "\"\"\" This 'should'\nbe\n'linted' \"\"\"" + location: + row: 1 + column: 4 + end_location: + row: 3 + column: 12 parent: ~ diff --git a/src/violations.rs b/src/violations.rs index 7cf326a74b..789472169f 100644 --- a/src/violations.rs +++ b/src/violations.rs @@ -2334,7 +2334,7 @@ impl AlwaysAutofixableViolation for PPrintFound { define_violation!( pub struct BadQuotesInlineString(pub Quote); ); -impl Violation for BadQuotesInlineString { +impl AlwaysAutofixableViolation for BadQuotesInlineString { fn message(&self) -> String { let BadQuotesInlineString(quote) = self; match quote { @@ -2343,6 +2343,14 @@ impl Violation for BadQuotesInlineString { } } + fn autofix_title(&self) -> String { + let BadQuotesInlineString(quote) = self; + match quote { + Quote::Single => "Replace double quotes with single quotes".to_string(), + Quote::Double => "Replace single quotes with double quotes".to_string(), + } + } + fn placeholder() -> Self { BadQuotesInlineString(Quote::Double) } @@ -2351,7 +2359,7 @@ impl Violation for BadQuotesInlineString { define_violation!( pub struct BadQuotesMultilineString(pub Quote); ); -impl Violation for BadQuotesMultilineString { +impl AlwaysAutofixableViolation for BadQuotesMultilineString { fn message(&self) -> String { let BadQuotesMultilineString(quote) = self; match quote { @@ -2360,6 +2368,14 @@ impl Violation for BadQuotesMultilineString { } } + fn autofix_title(&self) -> String { + let BadQuotesMultilineString(quote) = self; + match quote { + Quote::Single => "Replace double multiline quotes with single quotes".to_string(), + Quote::Double => "Replace single multiline quotes with double quotes".to_string(), + } + } + fn placeholder() -> Self { BadQuotesMultilineString(Quote::Double) } @@ -2368,7 +2384,7 @@ impl Violation for BadQuotesMultilineString { define_violation!( pub struct BadQuotesDocstring(pub Quote); ); -impl Violation for BadQuotesDocstring { +impl AlwaysAutofixableViolation for BadQuotesDocstring { fn message(&self) -> String { let BadQuotesDocstring(quote) = self; match quote { @@ -2377,6 +2393,14 @@ impl Violation for BadQuotesDocstring { } } + fn autofix_title(&self) -> String { + let BadQuotesDocstring(quote) = self; + match quote { + Quote::Single => "Replace double quotes docstring with single quotes".to_string(), + Quote::Double => "Replace single quotes docstring with double quotes".to_string(), + } + } + fn placeholder() -> Self { BadQuotesDocstring(Quote::Double) } @@ -2385,11 +2409,15 @@ impl Violation for BadQuotesDocstring { define_violation!( pub struct AvoidQuoteEscape; ); -impl Violation for AvoidQuoteEscape { +impl AlwaysAutofixableViolation for AvoidQuoteEscape { fn message(&self) -> String { "Change outer quotes to avoid escaping inner quotes".to_string() } + fn autofix_title(&self) -> String { + "Change outer quotes to avoid escaping inner quotes".to_string() + } + fn placeholder() -> Self { AvoidQuoteEscape }