mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-19 01:51:30 +00:00
Add internal hidden rules for testing (#9747)
Updated implementation of https://github.com/astral-sh/ruff/pull/7369 which was left out in the cold. This was motivated again following changes in #9691 and #9689 where we could not test the changes without actually deprecating or removing rules. --- Follow-up to discussion in https://github.com/astral-sh/ruff/pull/7210 Moves integration tests from using rules that are transitively in nursery / preview groups to dedicated test rules that only exist during development. These rules always raise violations (they do not require specific file behavior). The rules are not available in production or in the documentation. Uses features instead of `cfg(test)` for cross-crate support per https://github.com/rust-lang/cargo/issues/8379
This commit is contained in:
parent
2cc8acb0b7
commit
f18e7d40ac
13 changed files with 541 additions and 196 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};
|
||||
use crate::rule_code_prefix::{get_prefix_ident, intersection_all};
|
||||
|
||||
/// A rule entry in the big match statement such a
|
||||
/// `(Pycodestyle, "E112") => (RuleGroup::Nursery, rules::pycodestyle::rules::logical_lines::NoIndentedBlock),`
|
||||
|
@ -142,12 +142,13 @@ pub(crate) fn map_codes(func: &ItemFn) -> syn::Result<TokenStream> {
|
|||
|
||||
for (prefix, rules) in &rules_by_prefix {
|
||||
let prefix_ident = get_prefix_ident(prefix);
|
||||
let attr = match if_all_same(rules.iter().map(|(.., attrs)| attrs)) {
|
||||
Some(attr) => quote!(#(#attr)*),
|
||||
None => quote!(),
|
||||
let attrs = intersection_all(rules.iter().map(|(.., attrs)| attrs.as_slice()));
|
||||
let attrs = match attrs.as_slice() {
|
||||
[] => quote!(),
|
||||
[..] => quote!(#(#attrs)*),
|
||||
};
|
||||
all_codes.push(quote! {
|
||||
#attr Self::#linter(#linter::#prefix_ident)
|
||||
#attrs Self::#linter(#linter::#prefix_ident)
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -159,12 +160,13 @@ pub(crate) fn map_codes(func: &ItemFn) -> syn::Result<TokenStream> {
|
|||
quote!(#(#attrs)* Rule::#rule_name)
|
||||
});
|
||||
let prefix_ident = get_prefix_ident(&prefix);
|
||||
let attr = match if_all_same(rules.iter().map(|(.., attrs)| attrs)) {
|
||||
Some(attr) => quote!(#(#attr)*),
|
||||
None => quote!(),
|
||||
let attrs = intersection_all(rules.iter().map(|(.., attrs)| attrs.as_slice()));
|
||||
let attrs = match attrs.as_slice() {
|
||||
[] => quote!(),
|
||||
[..] => quote!(#(#attrs)*),
|
||||
};
|
||||
prefix_into_iter_match_arms.extend(quote! {
|
||||
#attr #linter::#prefix_ident => vec![#(#rule_paths,)*].into_iter(),
|
||||
#attrs #linter::#prefix_ident => vec![#(#rule_paths,)*].into_iter(),
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -89,21 +89,30 @@ fn attributes_for_prefix(
|
|||
codes: &BTreeSet<String>,
|
||||
attributes: &BTreeMap<String, &[Attribute]>,
|
||||
) -> proc_macro2::TokenStream {
|
||||
match if_all_same(codes.iter().map(|code| attributes[code])) {
|
||||
Some(attr) => quote!(#(#attr)*),
|
||||
None => quote!(),
|
||||
let attrs = intersection_all(codes.iter().map(|code| attributes[code]));
|
||||
match attrs.as_slice() {
|
||||
[] => quote!(),
|
||||
[..] => quote!(#(#attrs)*),
|
||||
}
|
||||
}
|
||||
|
||||
/// If all values in an iterator are the same, return that value. Otherwise,
|
||||
/// return `None`.
|
||||
pub(crate) fn if_all_same<T: PartialEq>(iter: impl Iterator<Item = T>) -> Option<T> {
|
||||
let mut iter = iter.peekable();
|
||||
let first = iter.next()?;
|
||||
if iter.all(|x| x == first) {
|
||||
Some(first)
|
||||
/// Collect all the items from an iterable of slices that are present in all slices.
|
||||
pub(crate) fn intersection_all<'a, T: PartialEq>(
|
||||
mut slices: impl Iterator<Item = &'a [T]>,
|
||||
) -> Vec<&'a T> {
|
||||
if let Some(slice) = slices.next() {
|
||||
// Collect all the items in the first slice
|
||||
let mut intersection = Vec::with_capacity(slice.len());
|
||||
for item in slice {
|
||||
intersection.push(item);
|
||||
}
|
||||
// Then only keep items that are present in each of the remaining slices
|
||||
for slice in slices {
|
||||
intersection.retain(|item| slice.contains(item));
|
||||
}
|
||||
intersection
|
||||
} else {
|
||||
None
|
||||
Vec::new()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue