Skip to content

Commit 2b9b41b

Browse files
committed
refactor merge_cfg_attributes pass
1 parent c854516 commit 2b9b41b

File tree

1 file changed

+111
-121
lines changed

1 file changed

+111
-121
lines changed

bindgen/codegen/postprocessing/merge_cfg_attributes.rs

Lines changed: 111 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,124 @@
11
use proc_macro2::Span;
22
use quote::{quote, ToTokens};
3-
use std::collections::HashMap;
43
use syn::{
5-
parse_quote,
6-
visit_mut::{visit_file_mut, VisitMut},
7-
Attribute, File, ForeignItem, Ident, Item, ItemConst, ItemEnum, ItemFn,
8-
ItemForeignMod, ItemImpl, ItemMod, ItemStatic, ItemStruct, ItemType,
9-
ItemUnion, ItemUse,
4+
Attribute, File, ForeignItem, Ident, Item, ItemConst, ItemEnum, ItemFn, ItemForeignMod,
5+
ItemImpl, ItemMod, ItemStatic, ItemStruct, ItemType, ItemUnion, ItemUse,
106
};
11-
7+
use itertools::Itertools;
8+
use crate::HashMap;
129
use crate::HashSet;
1310

1411
pub fn merge_cfg_attributes(file: &mut File) {
15-
let mut visitor = Visitor;
16-
visitor.visit_file_mut(file);
12+
let mut visitor = Visitor::new();
13+
visitor.visit_file(file);
1714
}
1815

19-
struct Visitor;
16+
struct Visitor {
17+
synthetic_mods: HashMap<Ident, (AttributeSet, Vec<Item>)>,
18+
new_items: Vec<Item>,
19+
}
2020

21-
impl VisitMut for Visitor {
22-
fn visit_file_mut(&mut self, file: &mut File) {
23-
process_items(&mut file.items);
21+
impl Visitor {
22+
fn new() -> Self {
23+
Self {
24+
synthetic_mods: HashMap::default(),
25+
new_items: Vec::new(),
26+
}
27+
}
28+
29+
fn visit_file(&mut self, file: &mut File) {
30+
self.visit_items(&mut file.items);
31+
32+
for (ident, (attr_set, items)) in self.synthetic_mods.drain() {
33+
let cfg_attrs: Vec<_> = attr_set.cfg_attrs.iter().collect();
34+
let cc_attrs: Vec<_> = attr_set.cc_attrs.iter().collect();
35+
let block = if cc_attrs.is_empty() {
36+
quote! {
37+
#(#items)*
38+
}
39+
} else {
40+
quote! {
41+
#(#cc_attrs)*
42+
unsafe extern "C" {
43+
#(#items)*
44+
}
45+
}
46+
};
47+
48+
self.new_items.push(Item::Verbatim(quote! {
49+
#(#cfg_attrs)*
50+
pub mod #ident {
51+
#block
52+
}
53+
54+
#(#cfg_attrs)*
55+
pub use #ident::*;
56+
}));
57+
}
58+
59+
file.items = std::mem::take(&mut self.new_items);
60+
}
61+
62+
fn visit_items(&mut self, items: &mut Vec<Item>) {
63+
for mut item in std::mem::take(items) {
64+
match &mut item {
65+
Item::Const(ItemConst { ref mut attrs, .. })
66+
| Item::Struct(ItemStruct { ref mut attrs, .. })
67+
| Item::Enum(ItemEnum { ref mut attrs, .. })
68+
| Item::Fn(ItemFn { ref mut attrs, .. })
69+
| Item::Union(ItemUnion { ref mut attrs, .. })
70+
| Item::Type(ItemType { ref mut attrs, .. })
71+
| Item::Impl(ItemImpl { ref mut attrs, .. })
72+
| Item::Mod(ItemMod { ref mut attrs, .. })
73+
| Item::Use(ItemUse { ref mut attrs, .. })
74+
| Item::Static(ItemStatic { ref mut attrs, .. }) => {
75+
let attr_set = partition_attributes(attrs);
76+
*attrs = attr_set.other_attrs.iter().cloned().collect();
77+
self.insert_item_into_mod(attr_set, item);
78+
}
79+
Item::ForeignMod(foreign_mod) => {
80+
self.visit_foreign_mod(foreign_mod);
81+
}
82+
_ => {
83+
self.new_items.push(item);
84+
}
85+
}
86+
}
87+
}
88+
89+
fn visit_foreign_mod(&mut self, foreign_mod: &mut ItemForeignMod) {
90+
for mut foreign_item in std::mem::take(&mut foreign_mod.items) {
91+
let mut attr_set = partition_attributes(&foreign_mod.attrs);
92+
let inner_attrs = match &mut foreign_item {
93+
ForeignItem::Fn(f) => &mut f.attrs,
94+
ForeignItem::Static(s) => &mut s.attrs,
95+
ForeignItem::Type(t) => &mut t.attrs,
96+
ForeignItem::Macro(m) => &mut m.attrs,
97+
_ => &mut Vec::new(),
98+
};
99+
100+
let inner_attr_set = partition_attributes(inner_attrs);
101+
attr_set.other_attrs.extend(inner_attr_set.other_attrs);
102+
attr_set.cfg_attrs.extend(inner_attr_set.cfg_attrs);
103+
attr_set.cc_attrs.extend(inner_attr_set.cc_attrs);
104+
*inner_attrs = attr_set.other_attrs.iter().cloned().collect();
105+
106+
self.insert_item_into_mod(
107+
attr_set,
108+
Item::Verbatim(quote! { #foreign_item }),
109+
);
110+
}
111+
}
112+
113+
fn insert_item_into_mod(&mut self, attr_set: AttributeSet, item: Item) {
114+
if !attr_set.cfg_attrs.is_empty() || !attr_set.cc_attrs.is_empty() {
115+
let (_, items) = self.synthetic_mods
116+
.entry(attr_set.ident())
117+
.or_insert_with(|| (attr_set, Vec::new()));
118+
items.push(item);
119+
} else {
120+
self.new_items.push(item);
121+
}
24122
}
25123
}
26124

@@ -30,7 +128,6 @@ struct AttributeSet {
30128
cc_attrs: HashSet<Attribute>,
31129
other_attrs: HashSet<Attribute>,
32130
}
33-
use itertools::Itertools;
34131

35132
impl AttributeSet {
36133
fn ident(&self) -> Ident {
@@ -64,113 +161,6 @@ impl AttributeSet {
64161
}
65162
}
66163

67-
fn process_items(items: &mut Vec<Item>) {
68-
let mut synthetic_mods: HashMap<Ident, (AttributeSet, Vec<Item>)> =
69-
HashMap::new();
70-
let mut new_items = Vec::new();
71-
72-
for mut item in std::mem::take(items) {
73-
match &mut item {
74-
Item::Const(ItemConst { ref mut attrs, .. }) |
75-
Item::Struct(ItemStruct { ref mut attrs, .. }) |
76-
Item::Enum(ItemEnum { ref mut attrs, .. }) |
77-
Item::Fn(ItemFn { ref mut attrs, .. }) |
78-
Item::Union(ItemUnion { ref mut attrs, .. }) |
79-
Item::Type(ItemType { ref mut attrs, .. }) |
80-
Item::Impl(ItemImpl { ref mut attrs, .. }) |
81-
Item::Mod(ItemMod { ref mut attrs, .. }) |
82-
Item::Use(ItemUse { ref mut attrs, .. }) |
83-
Item::Static(ItemStatic { ref mut attrs, .. }) => {
84-
let attr_set = partition_attributes(attrs);
85-
*attrs = attr_set.other_attrs.iter().cloned().collect();
86-
87-
let items = if !attr_set.cfg_attrs.is_empty() || !attr_set.cc_attrs.is_empty() {
88-
&mut synthetic_mods
89-
.entry(attr_set.ident())
90-
.or_insert_with(|| (attr_set, vec![]))
91-
.1
92-
} else {
93-
&mut new_items
94-
};
95-
items.push(item);
96-
}
97-
98-
Item::ForeignMod(ItemForeignMod {
99-
ref mut attrs,
100-
ref mut items,
101-
..
102-
}) => {
103-
for foreign_item in items.iter_mut() {
104-
let mut attr_set = partition_attributes(&attrs);
105-
let inner_attrs = match foreign_item {
106-
ForeignItem::Fn(ref mut foreign_fn) => {
107-
&mut foreign_fn.attrs
108-
}
109-
ForeignItem::Static(ref mut foreign_static) => {
110-
&mut foreign_static.attrs
111-
}
112-
_ => &mut vec![],
113-
};
114-
115-
let inner_attr_set = partition_attributes(inner_attrs);
116-
attr_set
117-
.other_attrs
118-
.extend(inner_attr_set.other_attrs.clone());
119-
attr_set.cfg_attrs.extend(inner_attr_set.cfg_attrs);
120-
attr_set.cc_attrs.extend(inner_attr_set.cc_attrs);
121-
*inner_attrs =
122-
inner_attr_set.other_attrs.into_iter().collect();
123-
124-
let items = if !attr_set.cfg_attrs.is_empty() || !attr_set.cc_attrs.is_empty() {
125-
&mut synthetic_mods
126-
.entry(attr_set.ident())
127-
.or_insert_with(|| (attr_set, vec![]))
128-
.1
129-
} else {
130-
&mut new_items
131-
};
132-
items.push(Item::Verbatim(quote! {
133-
#foreign_item
134-
}));
135-
}
136-
}
137-
_ => {
138-
new_items.push(item);
139-
}
140-
}
141-
}
142-
143-
for (ident, (attr_set, items)) in synthetic_mods {
144-
let cfg_attrs: Vec<_> = attr_set.cfg_attrs.iter().collect();
145-
let cc_attrs: Vec<_> = attr_set.cc_attrs.iter().collect();
146-
let block = if cc_attrs.is_empty() {
147-
quote! {
148-
#(#items)*
149-
}
150-
} else {
151-
// TODO: include unsafe and abi from original items
152-
quote! {
153-
#(#cc_attrs)*
154-
unsafe extern "C" {
155-
#(#items)*
156-
}
157-
}
158-
};
159-
160-
new_items.push(Item::Verbatim(quote! {
161-
#(#cfg_attrs)*
162-
pub mod #ident {
163-
#block
164-
}
165-
166-
#(#cfg_attrs)*
167-
pub use #ident::*;
168-
}));
169-
}
170-
171-
items.extend(new_items);
172-
}
173-
174164
fn partition_attributes(attrs: &[Attribute]) -> AttributeSet {
175165
let mut attribute_set = AttributeSet::default();
176166

0 commit comments

Comments
 (0)