Skip to content

Commit 8247b85

Browse files
committed
Update proc macro to preserve attributes that are common across all child codes
1 parent 052edbd commit 8247b85

File tree

2 files changed

+40
-20
lines changed

2 files changed

+40
-20
lines changed

crates/ruff_macros/src/map_codes.rs

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use syn::{
88
Ident, ItemFn, LitStr, Pat, Path, Stmt, Token,
99
};
1010

11-
use crate::rule_code_prefix::{get_prefix_ident, if_all_same};
11+
use crate::rule_code_prefix::{get_prefix_ident, intersection_all};
1212

1313
/// A rule entry in the big match statement such a
1414
/// `(Pycodestyle, "E112") => (RuleGroup::Nursery, rules::pycodestyle::rules::logical_lines::NoIndentedBlock),`
@@ -142,12 +142,13 @@ pub(crate) fn map_codes(func: &ItemFn) -> syn::Result<TokenStream> {
142142

143143
for (prefix, rules) in &rules_by_prefix {
144144
let prefix_ident = get_prefix_ident(prefix);
145-
let attr = match if_all_same(rules.iter().map(|(.., attrs)| attrs)) {
146-
Some(attr) => quote!(#(#attr)*),
147-
None => quote!(),
145+
let attrs = intersection_all(rules.iter().map(|(.., attrs)| attrs.as_slice()));
146+
let attrs = match attrs.as_slice() {
147+
[] => quote!(),
148+
[..] => quote!(#(#attrs)*),
148149
};
149150
all_codes.push(quote! {
150-
#attr Self::#linter(#linter::#prefix_ident)
151+
#attrs Self::#linter(#linter::#prefix_ident)
151152
});
152153
}
153154

@@ -159,12 +160,13 @@ pub(crate) fn map_codes(func: &ItemFn) -> syn::Result<TokenStream> {
159160
quote!(#(#attrs)* Rule::#rule_name)
160161
});
161162
let prefix_ident = get_prefix_ident(&prefix);
162-
let attr = match if_all_same(rules.iter().map(|(.., attrs)| attrs)) {
163-
Some(attr) => quote!(#(#attr)*),
164-
None => quote!(),
163+
let attrs = intersection_all(rules.iter().map(|(.., attrs)| attrs.as_slice()));
164+
let attrs = match attrs.as_slice() {
165+
[] => quote!(),
166+
[..] => quote!(#(#attrs)*),
165167
};
166168
prefix_into_iter_match_arms.extend(quote! {
167-
#attr #linter::#prefix_ident => vec![#(#rule_paths,)*].into_iter(),
169+
#attrs #linter::#prefix_ident => vec![#(#rule_paths,)*].into_iter(),
168170
});
169171
}
170172

crates/ruff_macros/src/rule_code_prefix.rs

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -89,21 +89,39 @@ fn attributes_for_prefix(
8989
codes: &BTreeSet<String>,
9090
attributes: &BTreeMap<String, &[Attribute]>,
9191
) -> proc_macro2::TokenStream {
92-
match if_all_same(codes.iter().map(|code| attributes[code])) {
93-
Some(attr) => quote!(#(#attr)*),
94-
None => quote!(),
92+
let attrs = intersection_all(codes.iter().map(|code| attributes[code]));
93+
match attrs.as_slice() {
94+
[] => quote!(),
95+
[..] => quote!(#(#attrs)*),
9596
}
9697
}
9798

98-
/// If all values in an iterator are the same, return that value. Otherwise,
99-
/// return `None`.
100-
pub(crate) fn if_all_same<T: PartialEq>(iter: impl Iterator<Item = T>) -> Option<T> {
101-
let mut iter = iter.peekable();
102-
let first = iter.next()?;
103-
if iter.all(|x| x == first) {
104-
Some(first)
99+
/// Collect all the items from an iterable of slices that are present in all slices.
100+
pub(crate) fn intersection_all<'a, T: PartialEq>(
101+
mut slices: impl Iterator<Item = &'a [T]>,
102+
) -> Vec<&'a T> {
103+
if let Some(slice) = slices.next() {
104+
// Collect all the items in the first slice
105+
let mut intersection = Vec::with_capacity(slice.len());
106+
for item in slice {
107+
intersection.push(item);
108+
}
109+
// Then remove all of the items that are not present in each of the
110+
// remaining slices
111+
while let Some(slice) = slices.next() {
112+
let mut mismatches = Vec::with_capacity(slice.len());
113+
for (idx, item) in intersection.iter().enumerate() {
114+
if !slice.contains(item) {
115+
mismatches.push(idx)
116+
}
117+
}
118+
for idx in mismatches {
119+
intersection.remove(idx);
120+
}
121+
}
122+
intersection
105123
} else {
106-
None
124+
Vec::new()
107125
}
108126
}
109127

0 commit comments

Comments
 (0)