summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Pepyakin <s.pepyakin@gmail.com>2017-10-04 16:36:54 +0300
committerSergey Pepyakin <s.pepyakin@gmail.com>2017-10-05 11:55:57 +0300
commitc4c4ae27483970092476ae50738e3f7040672bf2 (patch)
tree1c149ea4c1969834c8ad5c417506b59f0676580f
parent8387c7f5888e4e9b17828cfc6803dbbbd4fb6e47 (diff)
Eagerly generate bitfield accessor names
Also clean a bit.
-rw-r--r--src/codegen/mod.rs60
-rw-r--r--src/ir/comp.rs145
-rw-r--r--src/ir/context.rs46
3 files changed, 176 insertions, 75 deletions
diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs
index 5e4bb5fe..ea9fec41 100644
--- a/src/codegen/mod.rs
+++ b/src/codegen/mod.rs
@@ -1202,7 +1202,7 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit {
(&unit_field_name, unit_field_int_ty.clone()),
);
- let param_name = bitfield_getter_name(ctx, parent, bf.name().unwrap());
+ let param_name = bitfield_getter_name(ctx, bf);
let bitfield_ty_item = ctx.resolve_item(bf.ty());
let bitfield_ty = bitfield_ty_item.expect_type();
let bitfield_ty =
@@ -1236,59 +1236,21 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit {
}
}
-fn parent_has_method(
- ctx: &BindgenContext,
- parent: &CompInfo,
- name: &str,
-) -> bool {
- parent.methods().iter().any(|method| {
- let method_name = match *ctx.resolve_item(method.signature()).kind() {
- ItemKind::Function(ref func) => func.name(),
- ref otherwise => {
- panic!(
- "a method's signature should always be a \
- item of kind ItemKind::Function, found: \
- {:?}",
- otherwise
- )
- }
- };
-
- method_name == name || ctx.rust_mangle(&method_name) == name
- })
-}
-
fn bitfield_getter_name(
ctx: &BindgenContext,
- parent: &CompInfo,
- bitfield_name: &str,
+ bitfield: &Bitfield,
) -> quote::Tokens {
- let name = ctx.rust_mangle(bitfield_name);
-
- if parent_has_method(ctx, parent, &name) {
- let mut name = name.to_string();
- name.push_str("_bindgen_bitfield");
- let name = ctx.rust_ident(name);
- return quote! { #name };
- }
-
- let name = ctx.rust_ident(name);
+ let name = bitfield.getter_name();
+ let name = ctx.rust_ident_raw(name);
quote! { #name }
}
fn bitfield_setter_name(
ctx: &BindgenContext,
- parent: &CompInfo,
- bitfield_name: &str,
+ bitfield: &Bitfield,
) -> quote::Tokens {
- let setter = format!("set_{}", bitfield_name);
- let mut setter = ctx.rust_mangle(&setter).to_string();
-
- if parent_has_method(ctx, parent, &setter) {
- setter.push_str("_bindgen_bitfield");
- }
-
- let setter = ctx.rust_ident(setter);
+ let setter = bitfield.setter_name();
+ let setter = ctx.rust_ident_raw(setter);
quote! { #setter }
}
@@ -1301,7 +1263,7 @@ impl<'a> FieldCodegen<'a> for Bitfield {
_fields_should_be_private: bool,
_codegen_depth: usize,
_accessor_kind: FieldAccessorKind,
- parent: &CompInfo,
+ _parent: &CompInfo,
_result: &mut CodegenResult,
_struct_layout: &mut StructLayoutTracker,
_fields: &mut F,
@@ -1311,11 +1273,9 @@ impl<'a> FieldCodegen<'a> for Bitfield {
F: Extend<quote::Tokens>,
M: Extend<quote::Tokens>,
{
- // Should never be called with name() as None, as codegen can't be done
- // on an anonymous bitfield
let prefix = ctx.trait_prefix();
- let getter_name = bitfield_getter_name(ctx, parent, self.name().unwrap());
- let setter_name = bitfield_setter_name(ctx, parent, self.name().unwrap());
+ let getter_name = bitfield_getter_name(ctx, self);
+ let setter_name = bitfield_setter_name(ctx, self);
let unit_field_ident = quote::Ident::new(unit_field_name);
let bitfield_ty_item = ctx.resolve_item(self.ty());
diff --git a/src/ir/comp.rs b/src/ir/comp.rs
index 80c2bde1..91f29a51 100644
--- a/src/ir/comp.rs
+++ b/src/ir/comp.rs
@@ -292,6 +292,16 @@ pub struct Bitfield {
/// The field data for this bitfield.
data: FieldData,
+
+ /// Name of the generated Rust getter for this bitfield.
+ ///
+ /// Should be assigned before codegen.
+ getter_name: Option<String>,
+
+ /// Name of the generated Rust setter for this bitfield.
+ ///
+ /// Should be assigned before codegen.
+ setter_name: Option<String>,
}
impl Bitfield {
@@ -302,6 +312,8 @@ impl Bitfield {
Bitfield {
offset_into_unit: offset_into_unit,
data: raw.0,
+ getter_name: None,
+ setter_name: None,
}
}
@@ -331,6 +343,35 @@ impl Bitfield {
pub fn width(&self) -> u32 {
self.data.bitfield().unwrap()
}
+
+ /// Get the name of this bitfield.
+ fn name(&self) -> Option<&str> {
+ self.data.name()
+ }
+
+ /// Name of the generated Rust getter for this bitfield.
+ ///
+ /// Panics if called before assigning bitfield accessor names or if
+ /// this bitfield have no name.
+ pub fn getter_name(&self) -> &str {
+ assert!(self.name().is_some(), "`Bitfield::getter_name` called on anonymous field");
+ self.getter_name.as_ref().expect(
+ "`Bitfield::getter_name` should only be called after\
+ assigning bitfield accessor names",
+ )
+ }
+
+ /// Name of the generated Rust setter for this bitfield.
+ ///
+ /// Panics if called before assigning bitfield accessor names or if
+ /// this bitfield have no name.
+ pub fn setter_name(&self) -> &str {
+ assert!(self.name().is_some(), "`Bitfield::setter_name` called on anonymous field");
+ self.setter_name.as_ref().expect(
+ "`Bitfield::setter_name` should only be called\
+ after assigning bitfield accessor names",
+ )
+ }
}
impl FieldMethods for Bitfield {
@@ -661,30 +702,102 @@ impl CompFields {
);
}
- fn deanonymize_fields(&mut self) {
+ fn deanonymize_fields(&mut self, ctx: &BindgenContext, methods: &[Method]) {
+ use std::collections::HashMap;
+
let fields = match *self {
- CompFields::AfterComputingBitfieldUnits(ref mut fields) => {
- fields
- }
+ CompFields::AfterComputingBitfieldUnits(ref mut fields) => fields,
CompFields::BeforeComputingBitfieldUnits(_) => {
panic!("Not yet computed bitfield units.");
}
};
+ fn has_method(
+ methods: &[Method],
+ ctx: &BindgenContext,
+ name: &str,
+ ) -> bool {
+ methods.iter().any(|method| {
+ let method_name = ctx.resolve_func(method.signature()).name();
+ method_name == name || ctx.rust_mangle(&method_name) == name
+ })
+ }
+
+ struct AccessorNamesPair {
+ getter: String,
+ setter: String,
+ }
+
+ let mut accessor_names: HashMap<String, AccessorNamesPair> = fields
+ .iter()
+ .flat_map(|field| match *field {
+ Field::Bitfields(ref bu) => &*bu.bitfields,
+ Field::DataMember(_) => &[],
+ })
+ .filter_map(|bitfield| bitfield.name())
+ .map(|bitfield_name| {
+ let bitfield_name = bitfield_name.to_string();
+ let getter = {
+ let mut getter =
+ ctx.rust_mangle(&bitfield_name).to_string();
+ if has_method(methods, ctx, &getter) {
+ getter.push_str("_bindgen_bitfield");
+ }
+ getter
+ };
+ let setter = {
+ let setter = format!("set_{}", bitfield_name);
+ let mut setter = ctx.rust_mangle(&setter).to_string();
+ if has_method(methods, ctx, &setter) {
+ setter.push_str("_bindgen_bitfield");
+ }
+ setter
+ };
+ (
+ bitfield_name,
+ AccessorNamesPair {
+ getter,
+ setter,
+ },
+ )
+ })
+ .collect();
+
let mut anon_field_counter = 0;
for field in fields.iter_mut() {
- let field_data = match *field {
- Field::DataMember(ref mut fd) => fd,
- Field::Bitfields(_) => continue,
- };
+ match *field {
+ Field::DataMember(FieldData {
+ ref mut name, ..
+ }) => {
+ if let Some(_) = *name {
+ continue;
+ }
- if let Some(_) = field_data.name {
- continue;
- }
+ anon_field_counter += 1;
+ let generated_name =
+ format!("__bindgen_anon_{}", anon_field_counter);
+ *name = Some(generated_name);
+ }
+ Field::Bitfields(ref mut bu) => for bitfield in
+ &mut bu.bitfields
+ {
+ if bitfield.name().is_none() {
+ continue;
+ }
+
+ let (getter, setter) =
+ match accessor_names.remove(bitfield.name().unwrap()) {
+ Some(AccessorNamesPair {
+ getter,
+ setter,
+ }) => (getter, setter),
+ None => continue,
+ };
- anon_field_counter += 1;
- let name = format!("__bindgen_anon_{}", anon_field_counter);
- field_data.name = Some(name);
+ bitfield.getter_name = Some(getter);
+ bitfield.setter_name = Some(setter);
+ },
+ }
}
}
}
@@ -1397,8 +1510,8 @@ impl CompInfo {
}
/// Assign for each anonymous field a generated name.
- pub fn deanonymize_fields(&mut self) {
- self.fields.deanonymize_fields();
+ pub fn deanonymize_fields(&mut self, ctx: &BindgenContext) {
+ self.fields.deanonymize_fields(ctx, &self.methods);
}
/// Returns whether the current union can be represented as a Rust `union`
diff --git a/src/ir/context.rs b/src/ir/context.rs
index e9a9b504..706531ef 100644
--- a/src/ir/context.rs
+++ b/src/ir/context.rs
@@ -15,6 +15,7 @@ use super::module::{Module, ModuleKind};
use super::template::{TemplateInstantiation, TemplateParameters};
use super::traversal::{self, Edge, ItemTraversal};
use super::ty::{FloatKind, Type, TypeKind};
+use super::function::Function;
use super::super::time::Timer;
use BindgenOptions;
use callbacks::ParseCallbacks;
@@ -994,12 +995,31 @@ impl BindgenContext {
/// Assign a new generated name for each anonymous field.
fn deanonymize_fields(&mut self) {
let _t = self.timer("deanonymize_fields");
- let comp_types = self.items
- .values_mut()
- .filter_map(|item| item.kind_mut().as_type_mut())
- .filter_map(Type::as_comp_mut);
- for comp_info in comp_types {
- comp_info.deanonymize_fields();
+
+ let comp_item_ids: Vec<ItemId> = self.items
+ .iter()
+ .filter_map(|(id, item)| {
+ if let Some(ty) = item.kind().as_type() {
+ if let Some(_comp) = ty.as_comp() {
+ return Some(id);
+ }
+ }
+ None
+ })
+ .cloned()
+ .collect();
+
+ for id in comp_item_ids {
+ let mut item = self.items.remove(&id).unwrap();
+
+ item.kind_mut()
+ .as_type_mut()
+ .unwrap()
+ .as_comp_mut()
+ .unwrap()
+ .deanonymize_fields(self);
+
+ self.items.insert(id, item);
}
}
@@ -1391,12 +1411,20 @@ impl BindgenContext {
self.root_module
}
- /// Resolve the given `ItemId` as a type.
+ /// Resolve a type with the given id.
///
- /// Panics if there is no item for the given `ItemId` or if the resolved
+ /// Panics if there is no item for the given `TypeId` or if the resolved
/// item is not a `Type`.
pub fn resolve_type(&self, type_id: TypeId) -> &Type {
- self.items.get(&type_id.into()).unwrap().kind().expect_type()
+ self.resolve_item(type_id).kind().expect_type()
+ }
+
+ /// Resolve a function with the given id.
+ ///
+ /// Panics if there is no item for the given `FunctionId` or if the resolved
+ /// item is not a `Function`.
+ pub fn resolve_func(&self, func_id: FunctionId) -> &Function {
+ self.resolve_item(func_id).kind().expect_function()
}
/// Resolve the given `ItemId` as a type, or `None` if there is no item with