diff --git a/crates/ruff_linter/src/checkers/ast/analyze/expression.rs b/crates/ruff_linter/src/checkers/ast/analyze/expression.rs index d21dc3ccb1..cf9713f515 100644 --- a/crates/ruff_linter/src/checkers/ast/analyze/expression.rs +++ b/crates/ruff_linter/src/checkers/ast/analyze/expression.rs @@ -1197,9 +1197,11 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) { op: Operator::Add, .. }) => { if checker.enabled(Rule::ExplicitStringConcatenation) { - if let Some(diagnostic) = - flake8_implicit_str_concat::rules::explicit(expr, checker.locator) - { + if let Some(diagnostic) = flake8_implicit_str_concat::rules::explicit( + expr, + checker.locator, + checker.settings, + ) { checker.diagnostics.push(diagnostic); } } diff --git a/crates/ruff_linter/src/checkers/tokens.rs b/crates/ruff_linter/src/checkers/tokens.rs index e144df16f2..68dda9bd4e 100644 --- a/crates/ruff_linter/src/checkers/tokens.rs +++ b/crates/ruff_linter/src/checkers/tokens.rs @@ -125,9 +125,9 @@ pub(crate) fn check_tokens( flake8_implicit_str_concat::rules::implicit( &mut diagnostics, tokens, - settings, locator, indexer, + settings, ); } diff --git a/crates/ruff_linter/src/rules/flake8_implicit_str_concat/rules/explicit.rs b/crates/ruff_linter/src/rules/flake8_implicit_str_concat/rules/explicit.rs index 2853e02c1a..e726067824 100644 --- a/crates/ruff_linter/src/rules/flake8_implicit_str_concat/rules/explicit.rs +++ b/crates/ruff_linter/src/rules/flake8_implicit_str_concat/rules/explicit.rs @@ -1,5 +1,6 @@ use ruff_python_ast::{self as ast, Expr, Operator}; +use crate::settings::LinterSettings; use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; use ruff_source_file::Locator; @@ -40,7 +41,19 @@ impl Violation for ExplicitStringConcatenation { } /// ISC003 -pub(crate) fn explicit(expr: &Expr, locator: &Locator) -> Option { +pub(crate) fn explicit( + expr: &Expr, + locator: &Locator, + settings: &LinterSettings, +) -> Option { + // If the user sets `allow-multiline` to `false`, then we should allow explicitly concatenated + // strings that span multiple lines even if this rule is enabled. Otherwise, there's no way + // for the user to write multiline strings, and that setting is "more explicit" than this rule + // being enabled. + if !settings.flake8_implicit_str_concat.allow_multiline { + return None; + } + if let Expr::BinOp(ast::ExprBinOp { left, op, diff --git a/crates/ruff_linter/src/rules/flake8_implicit_str_concat/rules/implicit.rs b/crates/ruff_linter/src/rules/flake8_implicit_str_concat/rules/implicit.rs index 35e893e069..7d67980b59 100644 --- a/crates/ruff_linter/src/rules/flake8_implicit_str_concat/rules/implicit.rs +++ b/crates/ruff_linter/src/rules/flake8_implicit_str_concat/rules/implicit.rs @@ -93,9 +93,9 @@ impl Violation for MultiLineImplicitStringConcatenation { pub(crate) fn implicit( diagnostics: &mut Vec, tokens: &Tokens, - settings: &LinterSettings, locator: &Locator, indexer: &Indexer, + settings: &LinterSettings, ) { for (a_token, b_token) in tokens .iter() diff --git a/crates/ruff_linter/src/rules/flake8_implicit_str_concat/snapshots/ruff_linter__rules__flake8_implicit_str_concat__tests__multiline_ISC003_ISC.py.snap b/crates/ruff_linter/src/rules/flake8_implicit_str_concat/snapshots/ruff_linter__rules__flake8_implicit_str_concat__tests__multiline_ISC003_ISC.py.snap index e168bae223..1858d1d7e1 100644 --- a/crates/ruff_linter/src/rules/flake8_implicit_str_concat/snapshots/ruff_linter__rules__flake8_implicit_str_concat__tests__multiline_ISC003_ISC.py.snap +++ b/crates/ruff_linter/src/rules/flake8_implicit_str_concat/snapshots/ruff_linter__rules__flake8_implicit_str_concat__tests__multiline_ISC003_ISC.py.snap @@ -1,55 +1,4 @@ --- source: crates/ruff_linter/src/rules/flake8_implicit_str_concat/mod.rs --- -ISC.py:9:3: ISC003 Explicitly concatenated string should be implicitly concatenated - | - 8 | _ = ( - 9 | "abc" + - | ___^ -10 | | "def" - | |_______^ ISC003 -11 | ) - | - -ISC.py:14:3: ISC003 Explicitly concatenated string should be implicitly concatenated - | -13 | _ = ( -14 | f"abc" + - | ___^ -15 | | "def" - | |_______^ ISC003 -16 | ) - | - -ISC.py:19:3: ISC003 Explicitly concatenated string should be implicitly concatenated - | -18 | _ = ( -19 | b"abc" + - | ___^ -20 | | b"def" - | |________^ ISC003 -21 | ) - | - -ISC.py:78:10: ISC003 Explicitly concatenated string should be implicitly concatenated - | -77 | # Explicitly concatenated nested f-strings -78 | _ = f"a {f"first" - | __________^ -79 | | + f"second"} d" - | |_______________^ ISC003 -80 | _ = f"a {f"first {f"middle"}" -81 | + f"second"} d" - | - -ISC.py:80:10: ISC003 Explicitly concatenated string should be implicitly concatenated - | -78 | _ = f"a {f"first" -79 | + f"second"} d" -80 | _ = f"a {f"first {f"middle"}" - | __________^ -81 | | + f"second"} d" - | |_______________^ ISC003 - | - diff --git a/crates/ruff_workspace/src/options.rs b/crates/ruff_workspace/src/options.rs index c8eb6ad248..f9efa45f6f 100644 --- a/crates/ruff_workspace/src/options.rs +++ b/crates/ruff_workspace/src/options.rs @@ -1260,10 +1260,11 @@ pub struct Flake8ImplicitStrConcatOptions { /// allowed (but continuation lines, delimited with a backslash, are /// prohibited). /// - /// Note that setting `allow-multiline = false` should typically be coupled - /// with disabling `explicit-string-concatenation` (`ISC003`). Otherwise, - /// both explicit and implicit multiline string concatenations will be seen - /// as violations. + /// Setting `allow-multiline = false` will automatically disable the + /// `explicit-string-concatenation` (`ISC003`) rule. Otherwise, both + /// implicit and explicit multiline string concatenations would be seen + /// as violations, making it impossible to write a linter-compliant multiline + /// string. #[option( default = r#"true"#, value_type = "bool", diff --git a/ruff.schema.json b/ruff.schema.json index 71bf642a01..7d84ccae8e 100644 --- a/ruff.schema.json +++ b/ruff.schema.json @@ -1033,7 +1033,7 @@ "type": "object", "properties": { "allow-multiline": { - "description": "Whether to allow implicit string concatenations for multiline strings. By default, implicit concatenations of multiline strings are allowed (but continuation lines, delimited with a backslash, are prohibited).\n\nNote that setting `allow-multiline = false` should typically be coupled with disabling `explicit-string-concatenation` (`ISC003`). Otherwise, both explicit and implicit multiline string concatenations will be seen as violations.", + "description": "Whether to allow implicit string concatenations for multiline strings. By default, implicit concatenations of multiline strings are allowed (but continuation lines, delimited with a backslash, are prohibited).\n\nSetting `allow-multiline = false` will automatically disable the `explicit-string-concatenation` (`ISC003`) rule. Otherwise, both implicit and explicit multiline string concatenations would be seen as violations, making it impossible to write a linter-compliant multiline string.", "type": [ "boolean", "null"