mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-03 18:28:24 +00:00
Update rule selection to respect preview mode (#7195)
## Summary <!-- What's the purpose of the change? What does it do, and why? --> Extends work in #7046 (some relevant discussion there) Changes: - All nursery rules are now referred to as preview rules - Documentation for the nursery is updated to describe preview - Adds a "PREVIEW" selector for preview rules - This is primarily to allow `--preview --ignore PREVIEW --extend-select FOO001,BAR200` - Using `--preview` enables preview rules that match selectors Notable decisions: - Preview rules are not selectable by their rule code without enabling preview - Retains the "NURSERY" selector for backwards compatibility - Nursery rules are selectable by their rule code for backwards compatiblity Additional work: - Selection of preview rules without the "--preview" flag should display a warning - Use of deprecated nursery selection behavior should display a warning - Nursery selection should be removed after some time ## Test Plan <!-- How was it tested? --> Manual confirmation (i.e. we don't have an preview rules yet just nursery rules so I added a preview rule for manual testing) New unit tests --------- Co-authored-by: Charlie Marsh <charlie.r.marsh@gmail.com>
This commit is contained in:
parent
7c9bbcf4e2
commit
6566d00295
15 changed files with 607 additions and 233 deletions
|
@ -8,7 +8,7 @@ use syn::{
|
|||
Ident, ItemFn, LitStr, Pat, Path, Stmt, Token,
|
||||
};
|
||||
|
||||
use crate::rule_code_prefix::{get_prefix_ident, if_all_same, is_nursery};
|
||||
use crate::rule_code_prefix::{get_prefix_ident, if_all_same};
|
||||
|
||||
/// A rule entry in the big match statement such a
|
||||
/// `(Pycodestyle, "E112") => (RuleGroup::Nursery, rules::pycodestyle::rules::logical_lines::NoIndentedBlock),`
|
||||
|
@ -113,9 +113,23 @@ pub(crate) fn map_codes(func: &ItemFn) -> syn::Result<TokenStream> {
|
|||
Self::#linter(linter)
|
||||
}
|
||||
}
|
||||
|
||||
// Rust doesn't yet support `impl const From<RuleCodePrefix> for RuleSelector`
|
||||
// See https://github.com/rust-lang/rust/issues/67792
|
||||
impl From<#linter> for crate::rule_selector::RuleSelector {
|
||||
fn from(linter: #linter) -> Self {
|
||||
Self::Prefix{prefix: RuleCodePrefix::#linter(linter), redirected_from: None}
|
||||
let prefix = RuleCodePrefix::#linter(linter);
|
||||
if is_single_rule_selector(&prefix) {
|
||||
Self::Rule {
|
||||
prefix,
|
||||
redirected_from: None,
|
||||
}
|
||||
} else {
|
||||
Self::Prefix {
|
||||
prefix,
|
||||
redirected_from: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -156,7 +170,7 @@ pub(crate) fn map_codes(func: &ItemFn) -> syn::Result<TokenStream> {
|
|||
|
||||
output.extend(quote! {
|
||||
impl #linter {
|
||||
pub fn rules(self) -> ::std::vec::IntoIter<Rule> {
|
||||
pub fn rules(&self) -> ::std::vec::IntoIter<Rule> {
|
||||
match self { #prefix_into_iter_match_arms }
|
||||
}
|
||||
}
|
||||
|
@ -172,7 +186,7 @@ pub(crate) fn map_codes(func: &ItemFn) -> syn::Result<TokenStream> {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn rules(self) -> ::std::vec::IntoIter<Rule> {
|
||||
pub fn rules(&self) -> ::std::vec::IntoIter<Rule> {
|
||||
match self {
|
||||
#(RuleCodePrefix::#linter_idents(prefix) => prefix.clone().rules(),)*
|
||||
}
|
||||
|
@ -195,26 +209,12 @@ fn rules_by_prefix(
|
|||
// TODO(charlie): Why do we do this here _and_ in `rule_code_prefix::expand`?
|
||||
let mut rules_by_prefix = BTreeMap::new();
|
||||
|
||||
for (code, rule) in rules {
|
||||
// Nursery rules have to be explicitly selected, so we ignore them when looking at
|
||||
// prefix-level selectors (e.g., `--select SIM10`), but add the rule itself under
|
||||
// its fully-qualified code (e.g., `--select SIM101`).
|
||||
if is_nursery(&rule.group) {
|
||||
rules_by_prefix.insert(code.clone(), vec![(rule.path.clone(), rule.attrs.clone())]);
|
||||
continue;
|
||||
}
|
||||
|
||||
for code in rules.keys() {
|
||||
for i in 1..=code.len() {
|
||||
let prefix = code[..i].to_string();
|
||||
let rules: Vec<_> = rules
|
||||
.iter()
|
||||
.filter_map(|(code, rule)| {
|
||||
// Nursery rules have to be explicitly selected, so we ignore them when
|
||||
// looking at prefixes.
|
||||
if is_nursery(&rule.group) {
|
||||
return None;
|
||||
}
|
||||
|
||||
if code.starts_with(&prefix) {
|
||||
Some((rule.path.clone(), rule.attrs.clone()))
|
||||
} else {
|
||||
|
@ -311,6 +311,11 @@ See also https://github.com/astral-sh/ruff/issues/2186.
|
|||
}
|
||||
}
|
||||
|
||||
pub fn is_preview(&self) -> bool {
|
||||
matches!(self.group(), RuleGroup::Preview)
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
pub fn is_nursery(&self) -> bool {
|
||||
matches!(self.group(), RuleGroup::Nursery)
|
||||
}
|
||||
|
@ -336,12 +341,10 @@ fn generate_iter_impl(
|
|||
let mut linter_rules_match_arms = quote!();
|
||||
let mut linter_all_rules_match_arms = quote!();
|
||||
for (linter, map) in linter_to_rules {
|
||||
let rule_paths = map.values().filter(|rule| !is_nursery(&rule.group)).map(
|
||||
|Rule { attrs, path, .. }| {
|
||||
let rule_name = path.segments.last().unwrap();
|
||||
quote!(#(#attrs)* Rule::#rule_name)
|
||||
},
|
||||
);
|
||||
let rule_paths = map.values().map(|Rule { attrs, path, .. }| {
|
||||
let rule_name = path.segments.last().unwrap();
|
||||
quote!(#(#attrs)* Rule::#rule_name)
|
||||
});
|
||||
linter_rules_match_arms.extend(quote! {
|
||||
Linter::#linter => vec![#(#rule_paths,)*].into_iter(),
|
||||
});
|
||||
|
|
|
@ -12,22 +12,14 @@ pub(crate) fn expand<'a>(
|
|||
let mut prefix_to_codes: BTreeMap<String, BTreeSet<String>> = BTreeMap::default();
|
||||
let mut code_to_attributes: BTreeMap<String, &[Attribute]> = BTreeMap::default();
|
||||
|
||||
for (variant, group, attr) in variants {
|
||||
for (variant, .., attr) in variants {
|
||||
let code_str = variant.to_string();
|
||||
// Nursery rules have to be explicitly selected, so we ignore them when looking at prefixes.
|
||||
if is_nursery(group) {
|
||||
for i in 1..=code_str.len() {
|
||||
let prefix = code_str[..i].to_string();
|
||||
prefix_to_codes
|
||||
.entry(code_str.clone())
|
||||
.entry(prefix)
|
||||
.or_default()
|
||||
.insert(code_str.clone());
|
||||
} else {
|
||||
for i in 1..=code_str.len() {
|
||||
let prefix = code_str[..i].to_string();
|
||||
prefix_to_codes
|
||||
.entry(prefix)
|
||||
.or_default()
|
||||
.insert(code_str.clone());
|
||||
}
|
||||
}
|
||||
|
||||
code_to_attributes.insert(code_str, attr);
|
||||
|
@ -125,14 +117,3 @@ pub(crate) fn get_prefix_ident(prefix: &str) -> Ident {
|
|||
};
|
||||
Ident::new(&prefix, Span::call_site())
|
||||
}
|
||||
|
||||
/// Returns true if the given group is the "nursery" group.
|
||||
pub(crate) fn is_nursery(group: &Path) -> bool {
|
||||
let group = group
|
||||
.segments
|
||||
.iter()
|
||||
.map(|segment| segment.ident.to_string())
|
||||
.collect::<Vec<String>>()
|
||||
.join("::");
|
||||
group == "RuleGroup::Nursery"
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue