Skip to content

Commit 2be739e

Browse files
committed
Add rule removal infrastructure
Removes PLR1706 for testing
1 parent c2da5bd commit 2be739e

File tree

5 files changed

+55
-1
lines changed

5 files changed

+55
-1
lines changed

crates/ruff/tests/integration_test.rs

+15
Original file line numberDiff line numberDiff line change
@@ -1049,6 +1049,21 @@ fn preview_enabled_group_ignore() {
10491049
"###);
10501050
}
10511051

1052+
#[test]
1053+
fn removed_direct() {
1054+
// Selection of a removed rule should fail
1055+
let mut cmd = RuffCheck::default().args(["--select", "PLR1706"]).build();
1056+
assert_cmd_snapshot!(cmd, @r###"
1057+
success: false
1058+
exit_code: 2
1059+
----- stdout -----
1060+
1061+
----- stderr -----
1062+
ruff failed
1063+
Cause: Rule `PLR1706` was removed and cannot be selected.
1064+
"###);
1065+
}
1066+
10521067
#[test]
10531068
fn deprecated_direct() {
10541069
// Selection of a deprecated rule without preview enabled should still work

crates/ruff_linter/src/codes.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ pub enum RuleGroup {
5555
/// The rule has been deprecated, warnings will be displayed during selection in stable
5656
/// and errors will be raised if used with preview mode enabled.
5757
Deprecated,
58+
/// The rule has been removed, errors will be displayed on use.
59+
Removed,
5860
/// Legacy category for unstable rules, supports backwards compatible selection.
5961
#[deprecated(note = "Use `RuleGroup::Preview` for new rules instead")]
6062
Nursery,
@@ -268,7 +270,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
268270
(Pylint, "R1704") => (RuleGroup::Preview, rules::pylint::rules::RedefinedArgumentFromLocal),
269271
(Pylint, "R1711") => (RuleGroup::Stable, rules::pylint::rules::UselessReturn),
270272
(Pylint, "R1714") => (RuleGroup::Stable, rules::pylint::rules::RepeatedEqualityComparison),
271-
(Pylint, "R1706") => (RuleGroup::Preview, rules::pylint::rules::AndOrTernary),
273+
(Pylint, "R1706") => (RuleGroup::Removed, rules::pylint::rules::AndOrTernary),
272274
(Pylint, "R1722") => (RuleGroup::Stable, rules::pylint::rules::SysExitAlias),
273275
(Pylint, "R1733") => (RuleGroup::Preview, rules::pylint::rules::UnnecessaryDictIndexLookup),
274276
(Pylint, "R1736") => (RuleGroup::Preview, rules::pylint::rules::UnnecessaryListIndexLookup),

crates/ruff_linter/src/rule_selector.rs

+2
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,8 @@ impl RuleSelector {
213213
|| (preview_enabled && (matches!(self, RuleSelector::Rule { .. }) || !preview_require_explicit))
214214
// Deprecated rules are excluded in preview mode unless explicitly selected
215215
|| (rule.is_deprecated() && (!preview_enabled || matches!(self, RuleSelector::Rule { .. })))
216+
// Removed rules are included if explicitly selected but will error downstream
217+
|| (rule.is_removed() && matches!(self, RuleSelector::Rule { .. }))
216218
})
217219
}
218220
}

crates/ruff_macros/src/map_codes.rs

+4
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,10 @@ See also https://github.com/astral-sh/ruff/issues/2186.
327327
pub fn is_deprecated(&self) -> bool {
328328
matches!(self.group(), RuleGroup::Deprecated)
329329
}
330+
331+
pub fn is_removed(&self) -> bool {
332+
matches!(self.group(), RuleGroup::Removed)
333+
}
330334
}
331335

332336
impl Linter {

crates/ruff_workspace/src/configuration.rs

+31
Original file line numberDiff line numberDiff line change
@@ -732,6 +732,7 @@ impl LintConfiguration {
732732
let mut redirects = FxHashMap::default();
733733
let mut deprecated_nursery_selectors = FxHashSet::default();
734734
let mut deprecated_selectors = FxHashSet::default();
735+
let mut removed_selectors = FxHashSet::default();
735736
let mut ignored_preview_selectors = FxHashSet::default();
736737

737738
// Track which docstring rules are specifically enabled
@@ -896,6 +897,13 @@ impl LintConfiguration {
896897
}
897898
}
898899

900+
// Removed rules
901+
if let RuleSelector::Rule { prefix, .. } = selector {
902+
if prefix.rules().any(|rule| rule.is_removed()) {
903+
removed_selectors.insert(selector);
904+
}
905+
}
906+
899907
// Redirected rules
900908
if let RuleSelector::Prefix {
901909
prefix,
@@ -907,6 +915,29 @@ impl LintConfiguration {
907915
}
908916
}
909917

918+
let removed_selectors = removed_selectors.iter().collect::<Vec<_>>();
919+
match removed_selectors.as_slice() {
920+
[] => (),
921+
[selection] => {
922+
let (prefix, code) = selection.prefix_and_code();
923+
return Err(anyhow!(
924+
"Rule `{prefix}{code}` was removed and cannot be selected."
925+
));
926+
}
927+
[..] => {
928+
let mut message =
929+
"The following rules have been removed and cannot be selected:".to_string();
930+
for selection in removed_selectors {
931+
let (prefix, code) = selection.prefix_and_code();
932+
message.push_str("\n\t- ");
933+
message.push_str(prefix);
934+
message.push_str(code);
935+
}
936+
message.push('\n');
937+
return Err(anyhow!(message));
938+
}
939+
}
940+
910941
for (from, target) in redirects {
911942
// TODO(martin): This belongs into the ruff crate.
912943
warn_user_once_by_id!(

0 commit comments

Comments
 (0)