Skip to content

Commit 17dbb68

Browse files
committed
fix: normalize attributes, unified callback dispatch
1 parent c769d52 commit 17dbb68

File tree

3 files changed

+138
-104
lines changed

3 files changed

+138
-104
lines changed

bindgen/callbacks.rs

+1
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,7 @@ pub enum AttributeItemKind {
255255
Var,
256256
/// The item is a Rust `fn`.
257257
Function(FunctionKind),
258+
// TODO: Add `Alias` variant and more information about other items
258259
}
259260

260261
#[derive(Debug, Clone, Copy, PartialEq, Eq)]

bindgen/codegen/mod.rs

+132-102
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,9 @@ use crate::ir::var::Var;
5757

5858
use proc_macro2::{Ident, Span, TokenStream};
5959
use quote::{ToTokens, TokenStreamExt};
60-
use syn::{parse_quote, Attribute};
60+
use syn::parse::ParseStream;
61+
use syn::token::Pound;
62+
use syn::{parse, parse2, parse_quote, parse_str, Attribute, Block};
6163

6264
use crate::{Entry, HashMap, HashSet};
6365
use std::borrow::Cow;
@@ -500,6 +502,51 @@ trait CodeGenerator {
500502
) -> Self::Return;
501503
}
502504

505+
fn normalize_attributes(attrs: HashSet<String>) -> HashSet<String> {
506+
attrs
507+
.iter()
508+
.map(|attr| {
509+
let mut in_quotes = None;
510+
attr.chars()
511+
.filter_map(|c| match c {
512+
'"' | '\'' if in_quotes.is_none() => {
513+
in_quotes = Some(c);
514+
Some(c)
515+
}
516+
c if in_quotes == Some(c) => {
517+
in_quotes = None;
518+
Some(c)
519+
}
520+
c if in_quotes.is_some() => Some(c),
521+
c if !c.is_whitespace() => Some(c),
522+
_ => None,
523+
})
524+
.collect()
525+
})
526+
.collect()
527+
}
528+
529+
fn process_attributes(
530+
result: &mut CodegenResult,
531+
item: &Item,
532+
ctx: &BindgenContext,
533+
attrs: HashSet<String>,
534+
kind: AttributeItemKind,
535+
) -> Vec<TokenStream> {
536+
let mut attrs = normalize_attributes(attrs);
537+
ctx.options().for_each_callback_mut(|cb| {
538+
cb.process_attributes(
539+
&AttributeInfo {
540+
name: &item.canonical_name(ctx),
541+
kind,
542+
},
543+
&mut attrs,
544+
);
545+
});
546+
result.set_attributes(item.id(), attrs.clone());
547+
parse_tokens(normalize_attributes(attrs))
548+
}
549+
503550
impl Item {
504551
fn process_before_codegen(
505552
&self,
@@ -703,17 +750,24 @@ impl CodeGenerator for Var {
703750
let ty = var_ty.to_rust_ty_or_opaque(ctx, &());
704751

705752
if let Some(val) = self.val() {
706-
ctx.options().for_each_callback_mut(|cb| {
707-
cb.process_attributes(
708-
&AttributeInfo {
709-
name: &canonical_name,
710-
kind: AttributeItemKind::Var,
711-
},
712-
&mut attrs,
713-
);
714-
});
715-
result.set_attributes(item.id(), attrs.clone());
716-
let attrs = parse_tokens(attrs);
753+
/*if let Item::Fn(func) = item {
754+
for attr in func.attrs {
755+
// Process the attribute and extract key-value pairs
756+
if let Ok(Meta::NameValue(meta)) = attr.parse_meta() {
757+
// Check if the value of the attribute is a string literal
758+
if let Lit::Str(value) = meta.lit {
759+
attrs.insert(meta.path.get_ident().unwrap().to_string(), value.value());
760+
}
761+
}
762+
}
763+
}*/
764+
let attrs = process_attributes(
765+
result,
766+
item,
767+
ctx,
768+
attrs,
769+
AttributeItemKind::Var,
770+
);
717771

718772
match *val {
719773
VarType::Bool(val) => {
@@ -829,17 +883,13 @@ impl CodeGenerator for Var {
829883
}
830884
}
831885

832-
ctx.options().for_each_callback_mut(|cb| {
833-
cb.process_attributes(
834-
&AttributeInfo {
835-
name: &canonical_name,
836-
kind: AttributeItemKind::Var,
837-
},
838-
&mut attrs,
839-
);
840-
});
841-
result.set_attributes(item.id(), attrs.clone());
842-
let attrs = parse_tokens(attrs);
886+
let attrs = process_attributes(
887+
result,
888+
item,
889+
ctx,
890+
attrs,
891+
AttributeItemKind::Var,
892+
);
843893

844894
let maybe_mut = if self.is_const() {
845895
quote! {}
@@ -1068,15 +1118,17 @@ impl CodeGenerator for Type {
10681118
// Only apply attributes through type aliases when they are relevant to compilation
10691119
attrs.extend(
10701120
parse_tokens(inner_attrs)
1071-
.into_iter()
1072-
.map(|attr| parse_quote!{ #attr })
1073-
.filter_map(|attr: Attribute|{
1074-
if attr.path().is_ident("cfg") || attr.path().is_ident("link"){
1075-
Some(attr.to_token_stream().to_string())
1076-
} else {
1077-
None
1078-
}
1079-
})
1121+
.into_iter()
1122+
.map(|attr| parse_quote! { #attr })
1123+
.filter_map(|attr: Attribute| {
1124+
if attr.path().is_ident("cfg") ||
1125+
attr.path().is_ident("link")
1126+
{
1127+
Some(attr.to_token_stream().to_string())
1128+
} else {
1129+
None
1130+
}
1131+
}),
10801132
);
10811133
}
10821134

@@ -1088,28 +1140,18 @@ impl CodeGenerator for Type {
10881140
attrs.insert(attributes::doc(comment).to_string());
10891141
}
10901142

1091-
// Allow the callbacks to process our attributes
1092-
ctx.options().for_each_callback_mut(|cb| {
1093-
cb.process_attributes(
1094-
&AttributeInfo {
1095-
name: &name,
1096-
// FIXME: Introduce a TypeAlias variant with extra information similar
1097-
// to DiscoveredItem::Alias, indicating this is merely an alias
1098-
// and not a new type definition.
1099-
kind: AttributeItemKind::Struct,
1100-
},
1101-
&mut attrs,
1102-
);
1103-
});
1104-
1105-
// Store the final attributes of this item
1106-
result.set_attributes(item.id(), attrs.clone());
1143+
let attrs = process_attributes(
1144+
result,
1145+
item,
1146+
ctx,
1147+
attrs,
1148+
AttributeItemKind::Struct,
1149+
);
11071150

1108-
let attrs = parse_tokens(attrs);
11091151
let mut tokens = quote! {
11101152
#( #attrs )*
11111153
};
1112-
1154+
11131155
// We prefer using `pub use` over `pub type` because of:
11141156
// https://github.com/rust-lang/rust/issues/26264
11151157
if matches!(inner_rust_type, syn::Type::Path(_)) &&
@@ -2608,21 +2650,18 @@ impl CodeGenerator for CompInfo {
26082650
}
26092651

26102652
attrs.extend(item.annotations().attributes().iter().cloned());
2611-
ctx.options().for_each_callback_mut(|cb| {
2612-
cb.process_attributes(
2613-
&AttributeInfo {
2614-
name: &canonical_name,
2615-
kind: if is_rust_union {
2616-
AttributeItemKind::Union
2617-
} else {
2618-
AttributeItemKind::Struct
2619-
},
2620-
},
2621-
&mut attrs,
2622-
);
2623-
});
2624-
result.set_attributes(item.id(), attrs.clone());
2625-
let attrs = parse_tokens(attrs);
2653+
2654+
let attrs = process_attributes(
2655+
result,
2656+
item,
2657+
ctx,
2658+
attrs,
2659+
if is_rust_union {
2660+
AttributeItemKind::Union
2661+
} else {
2662+
AttributeItemKind::Struct
2663+
},
2664+
);
26262665

26272666
let mut tokens = if is_rust_union {
26282667
quote! {
@@ -3234,19 +3273,13 @@ impl Method {
32343273
attrs.insert(attributes::must_use().to_string());
32353274
}
32363275

3237-
ctx.options().for_each_callback_mut(|cb| {
3238-
cb.process_attributes(
3239-
&AttributeInfo {
3240-
name: &canonical_name,
3241-
kind: AttributeItemKind::Function(FunctionKind::Method(
3242-
self.kind(),
3243-
)),
3244-
},
3245-
&mut attrs,
3246-
);
3247-
});
3248-
result.set_attributes(function_item.id(), attrs.clone());
3249-
let attrs = parse_tokens(attrs);
3276+
let attrs = process_attributes(
3277+
result,
3278+
function_item,
3279+
ctx,
3280+
attrs,
3281+
AttributeItemKind::Function(FunctionKind::Method(self.kind())),
3282+
);
32503283

32513284
let name = ctx.rust_ident(&name);
32523285
methods.push(quote! {
@@ -3859,20 +3892,21 @@ impl CodeGenerator for Enum {
38593892
// add them to the end of the list.
38603893
attrs.extend(item.annotations().attributes().iter().cloned());
38613894

3862-
ctx.options().for_each_callback_mut(|cb| {
3863-
cb.process_attributes(
3864-
&AttributeInfo {
3865-
name: &name,
3866-
kind: AttributeItemKind::Enum,
3867-
},
3868-
&mut attrs,
3869-
);
3870-
});
3871-
result.set_attributes(item.id(), attrs.clone());
3895+
let attrs = process_attributes(
3896+
result,
3897+
item,
3898+
ctx,
3899+
attrs,
3900+
AttributeItemKind::Enum,
3901+
);
38723902

3873-
let attrs = parse_tokens(attrs);
3874-
let mut builder =
3875-
EnumBuilder::new(&name, attrs.clone(), repr, variation, has_typedef);
3903+
let mut builder = EnumBuilder::new(
3904+
&name,
3905+
attrs.clone(),
3906+
repr,
3907+
variation,
3908+
has_typedef,
3909+
);
38763910

38773911
// A map where we keep a value -> variant relation.
38783912
let mut seen_values = HashMap::<_, Ident>::default();
@@ -4820,18 +4854,14 @@ impl CodeGenerator for Function {
48204854
.unsafe_extern_blocks
48214855
.then(|| quote!(unsafe));
48224856

4823-
ctx.options().for_each_callback_mut(|cb| {
4824-
cb.process_attributes(
4825-
&AttributeInfo {
4826-
name: &name,
4827-
kind: AttributeItemKind::Function(self.kind()),
4828-
},
4829-
&mut attrs,
4830-
);
4831-
});
4832-
result.set_attributes(item.id(), attrs.clone());
4857+
let attrs = process_attributes(
4858+
result,
4859+
item,
4860+
ctx,
4861+
attrs,
4862+
AttributeItemKind::Function(FunctionKind::Function),
4863+
);
48334864

4834-
let attrs = parse_tokens(attrs);
48354865
let tokens = quote! {
48364866
#wasm_link_attribute
48374867
#safety extern #abi {

bindgen/codegen/postprocessing/mod.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,11 @@ macro_rules! pass {
2828
};
2929
}
3030

31-
const PASSES: &[PostProcessingPass] =
32-
&[pass!(merge_cfg_attributes), pass!(merge_extern_blocks), pass!(sort_semantically)];
31+
const PASSES: &[PostProcessingPass] = &[
32+
pass!(merge_cfg_attributes),
33+
pass!(merge_extern_blocks),
34+
pass!(sort_semantically),
35+
];
3336

3437
pub(crate) fn postprocessing(
3538
items: Vec<TokenStream>,

0 commit comments

Comments
 (0)