diff --git a/crates/ruff/resources/test/fixtures/pyflakes/F541.py b/crates/ruff/resources/test/fixtures/pyflakes/F541.py index b0e4b5c0ca9545..4cdb02dd9aad87 100644 --- a/crates/ruff/resources/test/fixtures/pyflakes/F541.py +++ b/crates/ruff/resources/test/fixtures/pyflakes/F541.py @@ -33,3 +33,5 @@ # Errors f"{v:{f'0.2f'}}" f"{f''}" +f"{{test}}" +f'{{ 40 }}' diff --git a/crates/ruff/src/rules/pyflakes/rules/f_string_missing_placeholders.rs b/crates/ruff/src/rules/pyflakes/rules/f_string_missing_placeholders.rs index 2e7cf65c1ba941..57f4c89a2039da 100644 --- a/crates/ruff/src/rules/pyflakes/rules/f_string_missing_placeholders.rs +++ b/crates/ruff/src/rules/pyflakes/rules/f_string_missing_placeholders.rs @@ -2,6 +2,7 @@ use ruff_macros::{define_violation, derive_message_formats}; use rustpython_parser::ast::{Expr, ExprKind}; use crate::ast::helpers::find_useless_f_strings; +use crate::ast::types::Range; use crate::checkers::ast::Checker; use crate::fix::Fix; use crate::registry::Diagnostic; @@ -46,6 +47,26 @@ impl AlwaysAutofixableViolation for FStringMissingPlaceholders { } } +fn unescape_f_string(content: &str) -> String { + content.replace("{{", "{").replace("}}", "}") +} + +fn fix_f_string_missing_placeholders( + prefix_range: &Range, + tok_range: &Range, + checker: &mut Checker, +) -> Fix { + let content = checker.locator.slice(&Range::new( + prefix_range.end_location, + tok_range.end_location, + )); + Fix::replacement( + unescape_f_string(content), + prefix_range.location, + tok_range.end_location, + ) +} + /// F541 pub fn f_string_missing_placeholders(expr: &Expr, values: &[Expr], checker: &mut Checker) { if !values @@ -55,9 +76,10 @@ pub fn f_string_missing_placeholders(expr: &Expr, values: &[Expr], checker: &mut for (prefix_range, tok_range) in find_useless_f_strings(expr, checker.locator) { let mut diagnostic = Diagnostic::new(FStringMissingPlaceholders, tok_range); if checker.patch(diagnostic.kind.rule()) { - diagnostic.amend(Fix::deletion( - prefix_range.location, - prefix_range.end_location, + diagnostic.amend(fix_f_string_missing_placeholders( + &prefix_range, + &tok_range, + checker, )); } checker.diagnostics.push(diagnostic); diff --git a/crates/ruff/src/rules/pyflakes/snapshots/ruff__rules__pyflakes__tests__F541_F541.py.snap b/crates/ruff/src/rules/pyflakes/snapshots/ruff__rules__pyflakes__tests__F541_F541.py.snap index df9e8b6e107106..9ba8728e6caf21 100644 --- a/crates/ruff/src/rules/pyflakes/snapshots/ruff__rules__pyflakes__tests__F541_F541.py.snap +++ b/crates/ruff/src/rules/pyflakes/snapshots/ruff__rules__pyflakes__tests__F541_F541.py.snap @@ -1,5 +1,5 @@ --- -source: src/rules/pyflakes/mod.rs +source: crates/ruff/src/rules/pyflakes/mod.rs expression: diagnostics --- - kind: @@ -12,13 +12,13 @@ expression: diagnostics column: 10 fix: content: - - "" + - "\"def\"" location: row: 6 column: 4 end_location: row: 6 - column: 5 + column: 10 parent: ~ - kind: FStringMissingPlaceholders: ~ @@ -30,13 +30,13 @@ expression: diagnostics column: 10 fix: content: - - "" + - "\"def\"" location: row: 7 column: 4 end_location: row: 7 - column: 5 + column: 10 parent: ~ - kind: FStringMissingPlaceholders: ~ @@ -48,13 +48,13 @@ expression: diagnostics column: 10 fix: content: - - "" + - "\"def\"" location: row: 9 column: 4 end_location: row: 9 - column: 5 + column: 10 parent: ~ - kind: FStringMissingPlaceholders: ~ @@ -66,13 +66,13 @@ expression: diagnostics column: 8 fix: content: - - "" + - "\"a\"" location: row: 13 column: 4 end_location: row: 13 - column: 5 + column: 8 parent: ~ - kind: FStringMissingPlaceholders: ~ @@ -84,13 +84,13 @@ expression: diagnostics column: 8 fix: content: - - "" + - "\"b\"" location: row: 14 column: 4 end_location: row: 14 - column: 5 + column: 8 parent: ~ - kind: FStringMissingPlaceholders: ~ @@ -102,13 +102,13 @@ expression: diagnostics column: 9 fix: content: - - "" + - "\"d\"" location: row: 16 column: 5 end_location: row: 16 - column: 6 + column: 9 parent: ~ - kind: FStringMissingPlaceholders: ~ @@ -120,13 +120,13 @@ expression: diagnostics column: 9 fix: content: - - "" + - "r\"e\"" location: row: 17 column: 4 end_location: row: 17 - column: 5 + column: 9 parent: ~ - kind: FStringMissingPlaceholders: ~ @@ -138,13 +138,13 @@ expression: diagnostics column: 7 fix: content: - - "" + - "\"\"" location: row: 19 column: 4 end_location: row: 19 - column: 5 + column: 7 parent: ~ - kind: FStringMissingPlaceholders: ~ @@ -156,13 +156,13 @@ expression: diagnostics column: 16 fix: content: - - "" + - "\"z\"" location: row: 25 column: 12 end_location: row: 25 - column: 13 + column: 16 parent: ~ - kind: FStringMissingPlaceholders: ~ @@ -174,13 +174,13 @@ expression: diagnostics column: 13 fix: content: - - "" + - "'0.2f'" location: row: 34 column: 6 end_location: row: 34 - column: 7 + column: 13 parent: ~ - kind: FStringMissingPlaceholders: ~ @@ -192,12 +192,48 @@ expression: diagnostics column: 6 fix: content: - - "" + - "''" location: row: 35 column: 3 end_location: row: 35 - column: 4 + column: 6 + parent: ~ +- kind: + FStringMissingPlaceholders: ~ + location: + row: 36 + column: 0 + end_location: + row: 36 + column: 11 + fix: + content: + - "\"{test}\"" + location: + row: 36 + column: 0 + end_location: + row: 36 + column: 11 + parent: ~ +- kind: + FStringMissingPlaceholders: ~ + location: + row: 37 + column: 0 + end_location: + row: 37 + column: 11 + fix: + content: + - "'{ 40 }'" + location: + row: 37 + column: 0 + end_location: + row: 37 + column: 11 parent: ~