diff --git a/crates/ruff_linter/resources/test/fixtures/pylint/duplicate_bases.py b/crates/ruff_linter/resources/test/fixtures/pylint/duplicate_bases.py index e59b561ec7..829791f762 100644 --- a/crates/ruff_linter/resources/test/fixtures/pylint/duplicate_bases.py +++ b/crates/ruff_linter/resources/test/fixtures/pylint/duplicate_bases.py @@ -70,3 +70,9 @@ class D(C): class E(A, C): ... + +# https://github.com/astral-sh/ruff/issues/18814 +class Bar(Foo, # 1 + Foo # 2 +): + pass diff --git a/crates/ruff_linter/src/rules/pylint/rules/duplicate_bases.rs b/crates/ruff_linter/src/rules/pylint/rules/duplicate_bases.rs index 9be4a8c628..e195b3f11a 100644 --- a/crates/ruff_linter/src/rules/pylint/rules/duplicate_bases.rs +++ b/crates/ruff_linter/src/rules/pylint/rules/duplicate_bases.rs @@ -1,3 +1,4 @@ +use ruff_diagnostics::Applicability; use ruff_python_ast::{self as ast, Arguments, Expr}; use rustc_hash::{FxBuildHasher, FxHashSet}; @@ -34,6 +35,23 @@ use crate::{Fix, FixAvailability, Violation}; /// pass /// ``` /// +/// ## Fix safety +/// This rule's fix is marked as unsafe if there's comments in the +/// base classes, as comments may be removed.. +/// +/// For example, the fix would be marked as unsafe in the following case: +/// ```python +/// class Foo: +/// pass +/// +/// +/// class Bar( +/// Foo, # comment +/// Foo, +/// ): +/// pass +/// ``` +/// /// ## References /// - [Python documentation: Class definitions](https://docs.python.org/3/reference/compound_stmts.html#class-definitions) #[derive(ViolationMetadata)] @@ -82,7 +100,16 @@ pub(crate) fn duplicate_bases(checker: &Checker, name: &str, arguments: Option<& checker.locator().contents(), checker.comment_ranges(), ) - .map(Fix::safe_edit) + .map(|edit| { + Fix::applicable_edit( + edit, + if checker.comment_ranges().intersects(arguments.range()) { + Applicability::Unsafe + } else { + Applicability::Safe + }, + ) + }) }); } } diff --git a/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLE0241_duplicate_bases.py.snap b/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLE0241_duplicate_bases.py.snap index ca3062908b..7848ac3fb6 100644 --- a/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLE0241_duplicate_bases.py.snap +++ b/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLE0241_duplicate_bases.py.snap @@ -1,6 +1,5 @@ --- source: crates/ruff_linter/src/rules/pylint/mod.rs -snapshot_kind: text --- duplicate_bases.py:13:13: PLE0241 [*] Duplicate base `A` for class `F1` | @@ -155,3 +154,24 @@ duplicate_bases.py:54:5: PLE0241 [*] Duplicate base `A` for class `G4` 55 54 | B, 56 55 | ): 57 56 | ... + +duplicate_bases.py:76:5: PLE0241 [*] Duplicate base `Foo` for class `Bar` + | +74 | # https://github.com/astral-sh/ruff/issues/18814 +75 | class Bar(Foo, # 1 +76 | Foo # 2 + | ^^^ PLE0241 +77 | ): +78 | pass + | + = help: Remove duplicate base + +ℹ Unsafe fix +72 72 | ... +73 73 | +74 74 | # https://github.com/astral-sh/ruff/issues/18814 +75 |-class Bar(Foo, # 1 +76 |- Foo # 2 + 75 |+class Bar(Foo # 2 +77 76 | ): +78 77 | pass