Skip to content

Commit

Permalink
Update proc macro to preserve attributes that are common across all c…
Browse files Browse the repository at this point in the history
…hild codes
  • Loading branch information
zanieb committed Feb 1, 2024
1 parent 052edbd commit 8247b85
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 20 deletions.
20 changes: 11 additions & 9 deletions crates/ruff_macros/src/map_codes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),`
Expand Down Expand Up @@ -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)
});
}

Expand All @@ -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(),
});
}

Expand Down
40 changes: 29 additions & 11 deletions crates/ruff_macros/src/rule_code_prefix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,21 +89,39 @@ 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 remove all of the items that are not present in each of the
// remaining slices
while let Some(slice) = slices.next() {
let mut mismatches = Vec::with_capacity(slice.len());
for (idx, item) in intersection.iter().enumerate() {
if !slice.contains(item) {
mismatches.push(idx)
}
}
for idx in mismatches {
intersection.remove(idx);
}
}
intersection
} else {
None
Vec::new()
}
}

Expand Down

0 comments on commit 8247b85

Please sign in to comment.