From 59ff82a7b921e589bc13affdf28480dfb64d5208 Mon Sep 17 00:00:00 2001 From: Googler Date: Mon, 6 Jul 2026 18:21:18 -0700 Subject: [PATCH] Replace field accesses in bindings generation with getters/setters on the Rust IR struct. Our end goal is to use ProtoViews directly in bindings generation instead of building an intermediate IR struct. To incrementally structure this change, a follow-up CL will replace the getter and setter implementations with their ProtoView equivalents. PiperOrigin-RevId: 943596886 --- .../generate_bindings/cpp_type_name.rs | 8 +- .../database/code_snippet.rs | 6 +- .../generate_bindings/database/db.rs | 41 +- .../generate_bindings/database/rs_snippet.rs | 74 +- .../generate_bindings_test.rs | 6 +- .../generate_bindings/generate_enum.rs | 26 +- .../generate_bindings/generate_function.rs | 50 +- .../generate_function_test.rs | 5 +- .../generate_function_thunk.rs | 36 +- .../generate_struct_and_union.rs | 208 ++-- .../generate_struct_and_union_test.rs | 10 +- .../generate_bindings/has_bindings.rs | 70 +- rs_bindings_from_cc/generate_bindings/lib.rs | 48 +- .../lifetime_defaults_transform.rs | 120 +- rs_bindings_from_cc/ir.rs | 1041 +++++++++++++++-- rs_bindings_from_cc/ir_from_cc_proto_test.rs | 92 +- rs_bindings_from_cc/ir_from_cc_test.rs | 116 +- rs_bindings_from_cc/ir_testing.rs | 12 +- 18 files changed, 1428 insertions(+), 541 deletions(-) diff --git a/rs_bindings_from_cc/generate_bindings/cpp_type_name.rs b/rs_bindings_from_cc/generate_bindings/cpp_type_name.rs index d209b70fa..670471563 100644 --- a/rs_bindings_from_cc/generate_bindings/cpp_type_name.rs +++ b/rs_bindings_from_cc/generate_bindings/cpp_type_name.rs @@ -40,7 +40,7 @@ pub fn cpp_tagless_type_name_for_record( record: &Record, db: &BindingsGenerator<'_>, ) -> Result { - let ident = expect_format_cc_type_name(record.cc_name.identifier.as_ref()); + let ident = expect_format_cc_type_name(record.cc_name().as_str()); let namespace_qualifier = db.namespace_qualifier(record).format_for_cc()?; Ok(quote! { #namespace_qualifier #ident }) } @@ -151,18 +151,18 @@ pub fn tagless_cpp_type_name_for_item( ) -> Result { match item { Item::IncompleteRecord(incomplete_record) => { - let ident = expect_format_cc_type_name(incomplete_record.cc_name.identifier.as_ref()); + let ident = expect_format_cc_type_name(incomplete_record.cc_name().as_str()); let namespace_qualifier = db.namespace_qualifier(incomplete_record).format_for_cc()?; Ok(quote! { #namespace_qualifier #ident }) } Item::Record(record) => cpp_tagless_type_name_for_record(record, db), Item::Enum(enum_) => { - let ident = expect_format_cc_type_name(&enum_.rs_name.identifier); + let ident = expect_format_cc_type_name(enum_.rs_name().as_str()); let namespace_qualifier = db.namespace_qualifier(item).format_for_cc()?; Ok(quote! { #namespace_qualifier #ident }) } Item::TypeAlias(type_alias) => { - let ident = expect_format_cc_type_name(&type_alias.cc_name.identifier); + let ident = expect_format_cc_type_name(type_alias.cc_name().as_str()); let namespace_qualifier = db.namespace_qualifier(item).format_for_cc()?; Ok(quote! { #namespace_qualifier #ident }) } diff --git a/rs_bindings_from_cc/generate_bindings/database/code_snippet.rs b/rs_bindings_from_cc/generate_bindings/database/code_snippet.rs index 9af24c5cd..4391ca227 100644 --- a/rs_bindings_from_cc/generate_bindings/database/code_snippet.rs +++ b/rs_bindings_from_cc/generate_bindings/database/code_snippet.rs @@ -221,11 +221,11 @@ pub fn missing_feature_descriptions(db: &BindingsGenerator, item: &Item) -> Resu if func.is_noreturn { missing_features.push("[[noreturn]] attribute".to_string()); } - for param in &func.params { + for param in func.params() { if let Some(unknown_attr) = ¶m.unknown_attr { missing_features.push(format!( "crubit.rs/errors/unknown_attribute: param {param} has unknown attribute(s): {unknown_attr}", - param = ¶m.identifier.identifier + param = param.identifier().as_str() )); } } @@ -803,7 +803,7 @@ pub fn generated_items_to_tokens<'db>( let canonical_namespace: &Rc = db .find_decl(current_namespace.canonical_namespace_id) .unwrap_or_else(|_| panic!("Namespace canonical_namespace_id {:?} not found as a valid Namespace item.", current_namespace.canonical_namespace_id)); - let name = make_rs_ident(&canonical_namespace.rs_name.identifier); + let name = make_rs_ident(canonical_namespace.rs_name().as_str()); quote! { #deprecated_attr diff --git a/rs_bindings_from_cc/generate_bindings/database/db.rs b/rs_bindings_from_cc/generate_bindings/database/db.rs index 386c6758d..4d7e496e8 100644 --- a/rs_bindings_from_cc/generate_bindings/database/db.rs +++ b/rs_bindings_from_cc/generate_bindings/database/db.rs @@ -260,13 +260,11 @@ impl<'db> BindingsGenerator<'db> { if let Some(parent_id) = f.enclosing_item_id && let Ok(record) = self.find_decl::>(parent_id) { - return self.defining_target(record.id); + return self.defining_target(record.id()); } None } - ir::Item::Record(r) => { - r.template_specialization.as_ref().map(|ts| ts.defining_target.clone()) - } + ir::Item::Record(r) => r.template_specialization().map(|ts| ts.defining_target.clone()), ir::Item::UnsupportedItem(ui) => ui.defining_target.clone(), _ => None, } @@ -286,9 +284,11 @@ impl<'db> BindingsGenerator<'db> { ir::Item::ExistingRustType(existing_rust_type) => { Some(existing_rust_type.cc_name.clone()) } - ir::Item::Record(record) => Some(record.cc_name.identifier.clone()), + ir::Item::Record(record) => { + Some(std::rc::Rc::from(record.cc_name().as_str())) + } ir::Item::IncompleteRecord(record) => { - Some(record.cc_name.identifier.clone()) + Some(std::rc::Rc::from(record.cc_name().as_str())) } _ => None, } @@ -298,7 +298,7 @@ impl<'db> BindingsGenerator<'db> { }; match &f.cc_name { ir::UnqualifiedIdentifier::Identifier(id) => { - name.push_str(&id.identifier); + name.push_str(id.as_str()); } ir::UnqualifiedIdentifier::Operator(op) => { name.push_str(&op.cc_name()); @@ -328,17 +328,17 @@ impl<'db> BindingsGenerator<'db> { .into() } ir::Item::UseMod(u) => { - return format!("<[internal] use mod {}::* = {}>", u.mod_name, u.path).into() + return format!("<[internal] use mod {}::* = {}>", u.mod_name(), u.path).into() } ir::Item::UnsupportedItem(ui) => return ui.name.clone(), ir::Item::ExistingRustType(e) => (e.id, e.cc_name.clone()), - ir::Item::Namespace(n) => (n.id, n.cc_name.identifier.clone()), - ir::Item::IncompleteRecord(r) => (r.id, r.cc_name.identifier.clone()), - ir::Item::Record(r) => (r.id, r.cc_name.identifier.clone()), - ir::Item::Enum(e) => (e.id, e.cc_name.identifier.clone()), - ir::Item::Constant(c) => (c.id, c.cc_name.identifier.clone()), - ir::Item::GlobalVar(g) => (g.id, g.cc_name.identifier.clone()), - ir::Item::TypeAlias(t) => (t.id, t.cc_name.identifier.clone()), + ir::Item::Namespace(n) => (n.id, std::rc::Rc::from(n.cc_name().as_str())), + ir::Item::IncompleteRecord(r) => (r.id, std::rc::Rc::from(r.cc_name().as_str())), + ir::Item::Record(r) => (r.id(), std::rc::Rc::from(r.cc_name().as_str())), + ir::Item::Enum(e) => (e.id, std::rc::Rc::from(e.cc_name().as_str())), + ir::Item::Constant(c) => (c.id, std::rc::Rc::from(c.cc_name().as_str())), + ir::Item::GlobalVar(g) => (g.id, std::rc::Rc::from(g.cc_name().as_str())), + ir::Item::TypeAlias(t) => (t.id, std::rc::Rc::from(t.cc_name().as_str())), }; let qualifier = self.namespace_qualifier_from_id(id).format_for_cc_debug(); return format! {"{qualifier}{name}"}.into(); @@ -540,7 +540,7 @@ impl<'db> BindingsGenerator<'db> { while let Some(parent_id) = enclosing_item_id { match self.find_untyped_decl(parent_id) { ir::Item::Namespace(ns) => { - namespaces.push(ns.rs_name.identifier.clone()); + namespaces.push(std::rc::Rc::from(ns.rs_name().as_str())); enclosing_item_id = ns.enclosing_item_id; } ir::Item::Record(parent_record) => { @@ -552,9 +552,9 @@ impl<'db> BindingsGenerator<'db> { self.record_to_associated_module_name(parent_record.clone()).unwrap(); nested_records.push(( module_name.to_string().into(), - parent_record.cc_name.identifier.clone(), + std::rc::Rc::from(parent_record.cc_name().as_str()), )); - enclosing_item_id = parent_record.enclosing_item_id; + enclosing_item_id = parent_record.enclosing_item_id(); } ir::Item::ExistingRustType(rust_type) => { assert!( @@ -590,7 +590,8 @@ impl<'db> BindingsGenerator<'db> { &self, record: Rc, ) -> Result { - let record_name: &str = record.rs_name.as_str(); + let rs_name = record.rs_name(); + let record_name: &str = rs_name.as_str(); let snake_case_name = record_name.to_snake_case(); // Add an `_items` suffix to distinguish the module name if the record name is already snake-case, // then distinguish by adding `_` suffixes until we find a name that is not in use. @@ -603,7 +604,7 @@ impl<'db> BindingsGenerator<'db> { let resolved_names = self.resolve_names(record.clone())?; let is_used = |n: &str| match resolved_names.get(n) { Some(ResolvedName::RecordNestedItems { parent_records_that_map_to_this_name }) => { - !parent_records_that_map_to_this_name.contains(&record.id) + !parent_records_that_map_to_this_name.contains(&record.id()) } Some(_) => true, None => false, diff --git a/rs_bindings_from_cc/generate_bindings/database/rs_snippet.rs b/rs_bindings_from_cc/generate_bindings/database/rs_snippet.rs index fa0a12494..219232399 100644 --- a/rs_bindings_from_cc/generate_bindings/database/rs_snippet.rs +++ b/rs_bindings_from_cc/generate_bindings/database/rs_snippet.rs @@ -238,10 +238,10 @@ pub fn format_generic_params_replacing_by_self<'db, 'a>( pub fn should_derive_clone(record: &Record) -> bool { // Thread-safe types wrap their fields in UnsafeCell<[MaybeUninit; N]>, // which prevents them from deriving Clone. - if record.is_thread_safe { + if record.is_thread_safe() { return false; } - match record.trait_derives.clone { + match record.trait_derives().clone { TraitImplPolarity::Positive => true, TraitImplPolarity::Negative => false, TraitImplPolarity::None => { @@ -250,7 +250,7 @@ pub fn should_derive_clone(record: &Record) -> bool { record.should_derive_copy() } else { record.is_unpin() - && record.copy_constructor == SpecialMemberFunc::Trivial + && record.copy_constructor() == SpecialMemberFunc::Trivial && record.check_by_value().is_ok() } } @@ -690,7 +690,7 @@ impl BridgeRsTypeKind { return Ok(Some(c9_co)); } - let Some(bridge_type) = &record.bridge_type else { + let Some(bridge_type) = record.bridge_type() else { return Ok(None); }; @@ -711,7 +711,7 @@ impl BridgeRsTypeKind { } else { return Err(anyhow!( "Internal error: template argument arity mismatch for bridge type `{}`", - record.rs_name.identifier.as_ref(), + record.rs_name().as_str(), )); } } @@ -735,20 +735,20 @@ impl BridgeRsTypeKind { Rc::new(db.rs_type_kind(t2)?), ), BridgeType::StdString => { - let in_cc_std = db.ir().is_current_target(&record.owning_target) - && record.owning_target.target_name_escaped() == "cc_std"; + let in_cc_std = db.ir().is_current_target(&record.owning_target()) + && record.owning_target().target_name_escaped() == "cc_std"; BridgeRsTypeKind::StdString { in_cc_std } } BridgeType::Callable { backing_type, fn_trait, return_type, param_types } => { - let target_identifier = record.owning_target.convert_to_cc_identifier(); + let target_identifier = record.owning_target().convert_to_cc_identifier(); BridgeRsTypeKind::Callable(Rc::new(Callable { backing_type: match backing_type { ir::BackingType::DynCallable => BackingType::DynCallable, ir::BackingType::AnyInvocable => BackingType::AnyInvocable { invoke_any_invocable_ident: format_ident!( "__crubit_invoke_any_invocable_{}{target_identifier}", - record.rs_name.identifier.as_ref(), + record.rs_name().as_str(), ), }, }, @@ -775,12 +775,12 @@ impl BridgeRsTypeKind { .collect::>()?, invoker_ident: format_ident!( "__crubit_invoker_{}{}", - record.rs_name.identifier.as_ref(), + record.rs_name().as_str(), target_identifier, ), manager_ident: format_ident!( "__crubit_manager_{}{}", - record.rs_name.identifier.as_ref(), + record.rs_name().as_str(), target_identifier, ), })) @@ -801,7 +801,7 @@ fn new_c9_co_record( let Some(TemplateSpecialization { kind: TemplateSpecializationKind::C9Co { raw_element_type }, .. - }) = record.template_specialization.as_ref() + }) = record.template_specialization() else { return Ok(None); }; @@ -897,7 +897,7 @@ impl RsTypeKind { // For example, perhaps the alias is to a forward declaration, and then later, we completed // the forward declaration. if let RsTypeKind::Record { record, .. } = &underlying_type - && record.owning_target != type_alias.owning_target + && (**record).owning_target() != type_alias.owning_target && db.defining_target(record.id()).as_ref() != Some(&type_alias.owning_target) { return Ok(underlying_type); @@ -932,22 +932,22 @@ impl RsTypeKind { let crate_path = Rc::new(CratePath::new( ir, db.namespace_qualifier(&record), - rs_imported_crate_name(&record.owning_target, ir), + rs_imported_crate_name(&(*record).owning_target(), ir), )); - let in_cc_std = db.ir().is_current_target(&record.owning_target) - && record.owning_target.target_name_escaped() == "cc_std"; + let in_cc_std = db.ir().is_current_target(&(*record).owning_target()) + && (*record).owning_target().target_name_escaped() == "cc_std"; Ok(RsTypeKind::Record { uniform_repr_template_type: UniformReprTemplateType::new( db, - record.template_specialization.as_ref().map(|ts| &ts.kind), + record.template_specialization().map(|ts| &ts.kind), options, template_args, lifetimes, in_cc_std, )?, - owned_ptr_type: record.owned_ptr_config.as_ref().map(|cfg| cfg.owned_ptr_type.clone()), + owned_ptr_type: record.owned_ptr_config().map(|cfg| cfg.owned_ptr_type.clone()), record, crate_path, lifetimes: lifetimes.to_vec(), @@ -1246,7 +1246,7 @@ impl RsTypeKind { match self.unalias() { RsTypeKind::IncompleteRecord { .. } => false, RsTypeKind::Record { record, .. } => { - record.move_constructor != ir::SpecialMemberFunc::Unavailable + record.move_constructor() != ir::SpecialMemberFunc::Unavailable } RsTypeKind::BridgeType { .. } => true, _ => true, @@ -1285,7 +1285,7 @@ impl RsTypeKind { RsTypeKind::IncompleteRecord { .. } => true, RsTypeKind::Record { record, .. } => { // Records that are bridged do not support being passed behind a pointer. - record.bridge_type.is_none() + record.bridge_type().is_none() } RsTypeKind::Enum { .. } => true, RsTypeKind::TypeAlias { .. } => unreachable!(), @@ -1468,7 +1468,7 @@ impl RsTypeKind { pub fn is_record(&self, expected_record: &Record) -> bool { match self.unalias() { RsTypeKind::Record { record: actual_record, .. } => { - actual_record.id == expected_record.id + actual_record.id() == expected_record.id() } _ => false, } @@ -1493,7 +1493,7 @@ impl RsTypeKind { pub fn is_destructible(&self) -> bool { match self.unalias() { RsTypeKind::Record { record, .. } => { - record.destructor != SpecialMemberFunc::Unavailable + record.destructor() != SpecialMemberFunc::Unavailable } RsTypeKind::IncompleteRecord { .. } => false, _ => true, @@ -1570,7 +1570,7 @@ impl RsTypeKind { ) }; - let owned_ptr_type = record.owned_ptr_config.as_ref().map(|cfg| cfg.owned_ptr_type.as_ref()).expect( + let owned_ptr_type = record.owned_ptr_config().map(|cfg| cfg.owned_ptr_type.as_ref()).expect( "CRUBIT_OWNED_POINTER annotated pointers should point to a struct with an associated CRUBIT_OWNED_POINTEE", ); @@ -1662,7 +1662,7 @@ impl RsTypeKind { pub fn overloads_operator_delete(&self) -> bool { match self.unalias() { - RsTypeKind::Record { record, .. } => record.overloads_operator_delete, + RsTypeKind::Record { record, .. } => record.overloads_operator_delete(), // Unlikely to come up (usually a compilation error to even consider it), but // we should imagine that an incomplete type _might_ implement operator delete? // This is going to go poorly either way. @@ -1673,7 +1673,7 @@ impl RsTypeKind { pub fn has_private_or_deleted_operator_delete(&self) -> bool { match self.unalias() { - RsTypeKind::Record { record, .. } => record.has_private_or_deleted_operator_delete, + RsTypeKind::Record { record, .. } => record.has_private_or_deleted_operator_delete(), RsTypeKind::IncompleteRecord { .. } => true, _ => false, } @@ -1922,7 +1922,7 @@ impl RsTypeKind { tokens } RsTypeKind::IncompleteRecord { incomplete_record, crate_path } => { - let record_ident = make_rs_ident(incomplete_record.rs_name.identifier.as_ref()); + let record_ident = make_rs_ident(incomplete_record.rs_name().as_str()); quote! { #crate_path #record_ident } } RsTypeKind::Record { @@ -1943,29 +1943,29 @@ impl RsTypeKind { } else { quote! { <#( #lifetimes ),* > } }; - let ident = make_rs_ident(record.rs_name.identifier.as_ref()); + let ident = make_rs_ident(record.rs_name().as_str()); quote! { #crate_path #ident #lts } } else { // Until we can get unsafe binders, the unsafe projection of a type with // lifetime parameters is that type instantiated at all 'static. let statics = std::iter::repeat_n(make_rs_lifetime_ident("static"), arity); - let ident = make_rs_ident(record.rs_name.identifier.as_ref()); + let ident = make_rs_ident(record.rs_name().as_str()); quote! { #crate_path #ident <#( #statics ),* > } } } RsTypeKind::Enum { enum_, crate_path } => { - let ident = make_rs_ident(&enum_.rs_name.identifier); + let ident = make_rs_ident(enum_.rs_name().as_str()); quote! { #crate_path #ident } } RsTypeKind::TypeAlias { type_alias, crate_path, lifetimes, .. } => { - let mut ident = make_rs_ident(&type_alias.rs_name.identifier); + let mut ident = make_rs_ident(type_alias.rs_name().as_str()); let mut crate_path = crate_path.clone(); // Check to see if the underlying type is a special template specialization kind // that we need to use an alternate name for if lifetimes are provided. if !lifetimes.is_empty() && let RsTypeKind::Record { record, .. } = self.unalias() && matches!( - record.template_specialization, + record.template_specialization(), Some(TemplateSpecialization { kind: TemplateSpecializationKind::StdStringView, .. @@ -2376,8 +2376,8 @@ mod tests { let enum_ = RsTypeKind::Enum { enum_: Rc::new(Enum { - cc_name: Identifier { identifier: "MyEnum".into() }, - rs_name: Identifier { identifier: "MyEnum".into() }, + cc_name: Identifier::new("MyEnum"), + rs_name: Identifier::new("MyEnum"), unique_name: "MyEnum".into(), id: ItemId::new_for_testing(0), owning_target: BazelLabel("//foo/bar".into()), @@ -2407,8 +2407,8 @@ mod tests { fn make_incomplete_record() -> RsTypeKind { RsTypeKind::IncompleteRecord { incomplete_record: Rc::new(IncompleteRecord { - cc_name: Identifier { identifier: "MyStruct".into() }, - rs_name: Identifier { identifier: "MyStruct".into() }, + cc_name: Identifier::new("MyStruct"), + rs_name: Identifier::new("MyStruct"), unique_name: "MyStruct".into(), id: ItemId::new_for_testing(0), owning_target: BazelLabel("//foo/bar".into()), @@ -2432,8 +2432,8 @@ mod tests { fn test_alias_incomplete_record_only_allowed_behind_single_element_ptr() { let alias_incomplete_record = RsTypeKind::TypeAlias { type_alias: Rc::new(TypeAlias { - cc_name: Identifier { identifier: "MyAlias".into() }, - rs_name: Identifier { identifier: "MyAlias".into() }, + cc_name: Identifier::new("MyAlias"), + rs_name: Identifier::new("MyAlias"), unique_name: "MyAlias".into(), id: ItemId::new_for_testing(1), owning_target: BazelLabel("//foo/bar".into()), diff --git a/rs_bindings_from_cc/generate_bindings/generate_bindings_test.rs b/rs_bindings_from_cc/generate_bindings/generate_bindings_test.rs index f56bdb458..e205050fc 100644 --- a/rs_bindings_from_cc/generate_bindings/generate_bindings_test.rs +++ b/rs_bindings_from_cc/generate_bindings/generate_bindings_test.rs @@ -586,7 +586,7 @@ fn test_rs_type_kind_is_shared_ref_to_with_lifetimes() -> Result<()> { // const-ref + lifetimes in C++ ===> shared-ref in Rust assert_eq!(foo_func.params.len(), 1); let foo_param = &foo_func.params[0]; - assert_eq!(foo_param.identifier.identifier.as_ref(), "foo_param"); + assert_eq!(foo_param.identifier.as_str(), "foo_param"); let foo_type = db.rs_type_kind(foo_param.type_.clone())?; assert!(foo_type.is_shared_ref_to(record)); assert!(matches!(foo_type, RsTypeKind::Reference { mutability: Mutability::Const, .. })); @@ -594,7 +594,7 @@ fn test_rs_type_kind_is_shared_ref_to_with_lifetimes() -> Result<()> { // non-const-ref + lifetimes in C++ ===> mutable-ref in Rust assert_eq!(bar_func.params.len(), 1); let bar_param = &bar_func.params[0]; - assert_eq!(bar_param.identifier.identifier.as_ref(), "bar_param"); + assert_eq!(bar_param.identifier.as_str(), "bar_param"); let bar_type = db.rs_type_kind(bar_param.type_.clone())?; assert!(!bar_type.is_shared_ref_to(record)); assert!(matches!(bar_type, RsTypeKind::Reference { mutability: Mutability::Mut, .. })); @@ -615,7 +615,7 @@ fn test_rs_type_kind_is_shared_ref_to_without_lifetimes() -> Result<()> { // const-ref + *no* lifetimes in C++ ===> const-pointer in Rust assert_eq!(foo_func.params.len(), 1); let foo_param = &foo_func.params[0]; - assert_eq!(foo_param.identifier.identifier.as_ref(), "foo_param"); + assert_eq!(foo_param.identifier.as_str(), "foo_param"); let foo_type = db.rs_type_kind(foo_param.type_.clone())?; assert!(!foo_type.is_shared_ref_to(record)); assert!(matches!(foo_type, RsTypeKind::Pointer { mutability: Mutability::Const, .. })); diff --git a/rs_bindings_from_cc/generate_bindings/generate_enum.rs b/rs_bindings_from_cc/generate_bindings/generate_enum.rs index 55919f51c..4fde8585a 100644 --- a/rs_bindings_from_cc/generate_bindings/generate_enum.rs +++ b/rs_bindings_from_cc/generate_bindings/generate_enum.rs @@ -21,47 +21,47 @@ use std::rc::Rc; /// Implementation of `BindingsGenerator::generate_enum`. pub fn generate_enum(db: &BindingsGenerator, enum_: Rc) -> Result { db.errors().add_category(error_report::Category::Type); - let ident = format_cc_ident(&enum_.cc_name.identifier)?; + let ident = format_cc_ident(enum_.cc_name().as_str())?; let namespace_qualifier = db.namespace_qualifier(&enum_).format_for_cc()?; let fully_qualified_cc_name = quote! { #namespace_qualifier #ident }; - let name = make_rs_ident(&enum_.rs_name.identifier); - let underlying_type = db.rs_type_kind(enum_.underlying_type.clone())?; + let name = make_rs_ident(enum_.rs_name().as_str()); + let underlying_type = db.rs_type_kind(enum_.underlying_type().clone())?; let enumerators: TokenStream = enum_ - .enumerators - .iter() + .enumerators() + .into_iter() .flatten() .map(|enumerator| { let omitting_bindings_comment = |reason: String| { let comment = format!( "Omitting bindings for {ident}\nreason: {reason}", - ident = &enumerator.identifier.identifier + ident = enumerator.identifier().as_str() ); quote! { __COMMENT__ #comment } }; - if let Some(unknown_attr) = &enumerator.unknown_attr { + if let Some(unknown_attr) = enumerator.unknown_attr() { return omitting_bindings_comment(format!("unknown attribute(s): {unknown_attr}")); } - let ident = make_rs_ident(&enumerator.identifier.identifier); + let ident = make_rs_ident(enumerator.identifier().as_str()); let value = - match integer_constant_to_token_stream(db, enumerator.value, &underlying_type) { + match integer_constant_to_token_stream(db, enumerator.value(), &underlying_type) { Ok(value) => value, Err(err) => return omitting_bindings_comment(err.to_string()), }; - let deprecated_attr = enumerator.deprecated.clone().map(DeprecatedAttr); + let deprecated_attr = enumerator.deprecated().map(DeprecatedAttr); quote! { #deprecated_attr pub const #ident: #name = #name(#value); } }) .collect(); let underlying_type_tokens = underlying_type.to_token_stream(db); let mut thunks: Vec = vec![]; let mut cc_details: Vec = vec![]; - let display_impl: TokenStream = if enum_.detected_formatter { + let display_impl: TokenStream = if enum_.detected_formatter() { let fmt_fn_name = make_rs_ident(&format!( "__crubit_fmt__{type_name}_{odr_suffix}", - type_name = enum_.cc_name, - odr_suffix = enum_.owning_target.convert_to_cc_identifier(), + type_name = enum_.cc_name().as_str(), + odr_suffix = enum_.owning_target().convert_to_cc_identifier(), )); let crate_root_path = db.ir().crate_root_path_tokens(); let namespace_qualifier = db.namespace_qualifier(&enum_).format_for_rs(); diff --git a/rs_bindings_from_cc/generate_bindings/generate_function.rs b/rs_bindings_from_cc/generate_bindings/generate_function.rs index 88aca3491..b50e8332a 100644 --- a/rs_bindings_from_cc/generate_bindings/generate_function.rs +++ b/rs_bindings_from_cc/generate_bindings/generate_function.rs @@ -131,7 +131,7 @@ fn trait_name_to_token_stream(db: &BindingsGenerator, trait_name: &TraitName) -> /// Returns whether an argument of this type causes ADL to include the `record`. fn adl_expands_to(record: &Record, rs_type_kind: &RsTypeKind) -> bool { match rs_type_kind { - RsTypeKind::Record { record: nested_record, .. } => record.id == nested_record.id, + RsTypeKind::Record { record: nested_record, .. } => record.id() == nested_record.id(), RsTypeKind::Reference { referent, .. } => adl_expands_to(record, referent), RsTypeKind::RvalueReference { referent, .. } => adl_expands_to(record, referent), _ => false, @@ -860,9 +860,9 @@ fn api_func_shape_for_identifier( SafetyAnnotation::DisableUnsafe => false, }; - let func_name = make_rs_ident(&id.identifier); + let func_name = make_rs_ident(id.as_str()); let Some(record) = maybe_record else { return (func_name, ImplKind::None { is_unsafe }) }; - let is_renamed_unpin_constructor = func.cc_name.is_constructor() && record.is_unpin(); + let is_renamed_unpin_constructor = func.cc_name().is_constructor() && record.is_unpin(); let format_first_param_as_self = if func.is_instance_method() { let Some(first_param) = param_types.first() else { panic!("Missing `__this` parameter in an instance method: {:?}", func); @@ -1143,7 +1143,7 @@ fn api_func_shape_for_conversion_operator( let (trait_name, func_name) = match return_type.unalias() { RsTypeKind::Record { record: dst_record, .. } => { - let is_dst_local = db.ir().is_current_target(&dst_record.owning_target); + let is_dst_local = db.ir().is_current_target(&(**dst_record).owning_target()); if !referent_type_kind.is_unpin() { return None; } @@ -1384,7 +1384,7 @@ fn materialize_ctor_in_caller(func: &Func, params: &mut [RsTypeKind]) { next_suffix += 1; } }; - for (func_param, param) in func.params.iter().zip(params.iter_mut()) { + for (func_param, param) in func.params().iter().zip(params.iter_mut()) { if param.is_unpin() { continue; } @@ -1392,7 +1392,7 @@ fn materialize_ctor_in_caller(func: &Func, params: &mut [RsTypeKind]) { *param = RsTypeKind::RvalueReference { referent: Rc::new(value), mutability: Mutability::Mut, - lifetime: new_lifetime_param(func_param.identifier.identifier.to_string()), + lifetime: new_lifetime_param(func_param.identifier().as_str().to_string()), }; } } @@ -1711,7 +1711,7 @@ fn rs_type_kinds_for_func( if i == 0 && func.is_instance_method() { if !func.cc_name.is_constructor() && !func.cc_name.is_destructor() && let Some(Item::Record(record)) = func.enclosing_item_id.map(|id| db.find_untyped_decl(id)) - && record.is_thread_safe + && record.is_thread_safe() && let CcTypeVariant::Pointer(ptr) = &mut param_type.variant { let mut new_pointee = (*ptr.pointee_type).clone(); new_pointee.is_const = true; @@ -1879,7 +1879,7 @@ pub fn generate_function( errors.consolidate()?; } let param_idents = - func.params.iter().map(|p| make_rs_ident(&p.identifier.identifier)).collect_vec(); + func.params().iter().map(|p| make_rs_ident(p.identifier().as_str())).collect_vec(); // Skip thunk generation if the function is a method on a public base class, // as the base class thunk will already have been generated. @@ -1887,7 +1887,7 @@ pub fn generate_function( || { let Some(derived) = &derived_record else { return false }; let Some(enclosing_id) = func.enclosing_item_id else { return false }; - if enclosing_id == derived.id { + if enclosing_id == derived.id() { return false; }; let Some(base_item) = db.ir().get_decl(enclosing_id) else { return false }; @@ -1943,7 +1943,7 @@ pub fn generate_function( if assume_lifetimes { let record = lifetime_defaults_transform_record(db, record)?; if let RsTypeKind::Record { ref mut lifetimes, .. } = self_type { - *lifetimes = record.lifetime_inputs.iter().map(|id| Lifetime::new(id)).collect(); + *lifetimes = record.lifetime_inputs().iter().map(|id| Lifetime::new(id)).collect(); } } quoted_return_type = quote! {}; @@ -1966,7 +1966,7 @@ pub fn generate_function( let failed = reportable_status.is_err(); let (derived_class_prefix, sep) = if let Some(ref derived_record) = derived_record { - (derived_record.mangled_cc_name.as_ref(), "_") + (derived_record.mangled_cc_name(), "_") } else { ("", "") }; @@ -2086,7 +2086,7 @@ pub fn generate_function( is_unsafe, } => { let record_name = make_rs_ident( - derived_record.as_deref().unwrap_or(record.as_ref()).rs_name.identifier.as_ref(), + derived_record.as_deref().unwrap_or(record.as_ref()).rs_name().as_str(), ); let fn_generic_params = format_generic_params(&lifetimes, std::iter::empty::()); @@ -2153,7 +2153,7 @@ pub fn generate_function( // Add the free method to the mapping, which we will extract and put into // snippets inside db later. free_functions_map.insert( - derived_record.as_deref().unwrap_or(record.as_ref()).id, + derived_record.as_deref().unwrap_or(record.as_ref()).id(), vec![quote! { #capture_tags #doc_comment @@ -2195,7 +2195,7 @@ pub fn generate_function( let mod_name = db.record_to_associated_module_name(target_record)?; member_functions_map.insert( - derived_record.as_deref().unwrap_or(record.as_ref()).id, + derived_record.as_deref().unwrap_or(record.as_ref()).id(), vec![quote! { #capture_tags #doc_comment @@ -2260,7 +2260,7 @@ pub fn generate_function( let assume_lifetimes = db .ir() - .target_crubit_features(&trait_record.owning_target) + .target_crubit_features(&(**trait_record).owning_target()) .contains(crubit_feature::CrubitFeature::AssumeLifetimes); // TODO(b/454627672): is it worth caching this? let transformed_trait_record; @@ -2274,11 +2274,11 @@ pub fn generate_function( let mut trait_lifetime_params: Vec = vec![]; if assume_lifetimes { trait_lifetime_params = - trait_record.lifetime_inputs.iter().map(|id| Lifetime::new(id)).collect(); + trait_record.lifetime_inputs().iter().map(|id| Lifetime::new(id)).collect(); } - let record_name = make_rs_ident(trait_record.rs_name.identifier.as_ref()); - let qualified_record_name = if Some(trait_record.id) == func.enclosing_item_id { + let record_name = make_rs_ident(trait_record.rs_name().as_str()); + let qualified_record_name = if Some(trait_record.id()) == func.enclosing_item_id { quote! { #record_name } } else { // If the trait is being implemented for a different record than its enclosing one @@ -2373,12 +2373,12 @@ pub fn generate_function( let mut trait_lifetime_params: Vec = vec![]; if assume_lifetimes { assumed_lifetime_params = trait_record - .lifetime_inputs + .lifetime_inputs() .iter() .map(|id| make_rs_lifetime_ident(id)) .collect(); trait_lifetime_params = - trait_record.lifetime_inputs.iter().map(|id| Lifetime::new(id)).collect(); + trait_record.lifetime_inputs().iter().map(|id| Lifetime::new(id)).collect(); } let trait_record_param_tokens = if !assumed_lifetime_params.is_empty() { quote! { < #( #assumed_lifetime_params ),* > } @@ -2625,11 +2625,11 @@ fn collect_parent_lifetime_bindings( if let Item::Record(r) = decl { let assume_lifetimes = db .ir() - .target_crubit_features(&r.owning_target) + .target_crubit_features(&(**r).owning_target()) .contains(crubit_feature::CrubitFeature::AssumeLifetimes); if assume_lifetimes { let r = lifetime_defaults_transform_record(db, r)?; - for lifetime in r.lifetime_inputs { + for lifetime in r.lifetime_inputs() { unordered_lifetimes.insert(lifetime.to_string()); } } @@ -2668,7 +2668,7 @@ fn function_signature( if let Some(derived_record) = derived_record.as_deref() { ensure!( db.ir() - .target_crubit_features(&derived_record.owning_target) + .target_crubit_features(&derived_record.owning_target()) .contains(crubit_feature::CrubitFeature::Experimental), "upcasting is currently experimental, see b/216195042" ); @@ -2709,7 +2709,7 @@ fn function_signature( if assume_lifetimes { let record = lifetime_defaults_transform_record(db, record)?; if let RsTypeKind::Record { ref mut lifetimes, .. } = t { - *lifetimes = record.lifetime_inputs.iter().map(|id| Lifetime::new(id)).collect(); + *lifetimes = record.lifetime_inputs().iter().map(|id| Lifetime::new(id)).collect(); } } Some(t) @@ -3176,7 +3176,7 @@ fn has_copy_assignment_operator_from_const_reference( return false; }; record - .children + .children() .iter() .filter_map(|item| match item { Item::Func(func) => Some(func.clone()), diff --git a/rs_bindings_from_cc/generate_bindings/generate_function_test.rs b/rs_bindings_from_cc/generate_bindings/generate_function_test.rs index a617d2979..d5de4441f 100644 --- a/rs_bindings_from_cc/generate_bindings/generate_function_test.rs +++ b/rs_bindings_from_cc/generate_bindings/generate_function_test.rs @@ -454,10 +454,7 @@ fn test_impl_clone_that_propagates_lifetime() -> Result<()> { }) .find(|f| { matches!(&f.rs_name, UnqualifiedIdentifier::Constructor) - && f.params - .get(1) - .map(|p| p.identifier.identifier.as_ref() == "i") - .unwrap_or_default() + && f.params.get(1).map(|p| p.identifier.as_str() == "i").unwrap_or_default() }) .unwrap(); { diff --git a/rs_bindings_from_cc/generate_bindings/generate_function_thunk.rs b/rs_bindings_from_cc/generate_bindings/generate_function_thunk.rs index f57b11e29..9b61eda35 100644 --- a/rs_bindings_from_cc/generate_bindings/generate_function_thunk.rs +++ b/rs_bindings_from_cc/generate_bindings/generate_function_thunk.rs @@ -300,7 +300,7 @@ fn generate_function_assertion_for_identifier( func: &Func, id: &Identifier, ) -> Result { - let fn_ident = format_cc_ident(&id.identifier)?; + let fn_ident = format_cc_ident(id.as_str())?; let mut namespace_qualifier = db.namespace_qualifier(func); // Keep goldens the same. namespace_qualifier.use_leading_colons = true; @@ -419,13 +419,13 @@ pub fn generate_function_thunk_impl( return Ok(None); } let thunk_ident = thunk_ident(db, func); - let implementation_function = match &func.cc_name { + let implementation_function = match func.cc_name() { UnqualifiedIdentifier::Operator(op) => { let name = syn::parse_str::(&op.name)?; quote! { operator #name } } UnqualifiedIdentifier::Identifier(id) => { - let fn_ident = format_cc_ident(&id.identifier)?; + let fn_ident = format_cc_ident(id.as_str())?; let namespace_qualifier = db.namespace_qualifier(func).format_for_cc()?; if func.instance_method_metadata.is_some() || func.adl_enclosing_record.is_some() { quote! {#fn_ident} @@ -442,12 +442,12 @@ pub fn generate_function_thunk_impl( UnqualifiedIdentifier::Constructor => { if let Some(parent_id) = func.enclosing_item_id { let record: &Rc = db.find_decl(parent_id)?; - if is_copy_constructor(func, record.id) - && record.copy_constructor == SpecialMemberFunc::Unavailable + if is_copy_constructor(func, record.id()) + && record.copy_constructor() == SpecialMemberFunc::Unavailable { bail!( "Would use an unavailable copy constructor for {}", - record.cc_name.identifier.as_ref() + record.cc_name().as_str() ); } } @@ -456,7 +456,7 @@ pub fn generate_function_thunk_impl( UnqualifiedIdentifier::Destructor => quote! {std::destroy_at}, UnqualifiedIdentifier::ConversionOperator => { let target_type_cpp = cpp_type_name::format_cpp_type_with_references( - &db.rs_type_kind(func.return_type.clone())?, + &db.rs_type_kind(func.return_type().clone())?, db, )?; quote! { operator #target_type_cpp } @@ -464,20 +464,20 @@ pub fn generate_function_thunk_impl( }; let mut param_idents = func - .params + .params() .iter() - .map(|p| format_cc_ident(&p.identifier.identifier)) + .map(|p| format_cc_ident(p.identifier().as_str())) .collect::>>()?; let mut conversion_stmts = quote! {}; let mut param_types = func - .params + .params() .iter() .map(|p| { - let arg_type = db.rs_type_kind(p.type_.clone())?; + let arg_type = db.rs_type_kind(p.type_().clone())?; let cpp_type = cpp_type_name::format_cpp_type(&arg_type, db)?; if arg_type.is_bridge_type() { - let ident = format_cc_ident(&p.identifier.identifier)?; + let ident = format_cc_ident(p.identifier().as_str())?; let crubit_abi_type = db.crubit_abi_type(arg_type)?; let crubit_abi_type_tokens = CrubitAbiTypeToCppTokens(&crubit_abi_type); let decoder = format_ident!("__{ident}_decoder"); @@ -495,11 +495,11 @@ pub fn generate_function_thunk_impl( .collect::>>()?; let arg_expressions = func - .params + .params() .iter() .map(|p| { - let ident = format_cc_ident(&p.identifier.identifier)?; - match &p.type_.variant { + let ident = format_cc_ident(p.identifier().as_str())?; + match &p.type_().variant { CcTypeVariant::Pointer(pointer) => match pointer.kind { PointerTypeKind::RValueRef => Ok(quote! { std::move(*#ident) }), PointerTypeKind::LValueRef => Ok(quote! { *#ident }), @@ -579,17 +579,17 @@ pub fn generate_function_thunk_impl( func.instance_method_metadata.as_ref().map(|meta| meta.reference) } }; - if func.cc_name.is_constructor() { + if func.cc_name().is_constructor() { this_ref_qualification = None; } let (implementation_function, arg_expressions) = if let Some(this_ref_qualification) = this_ref_qualification { let this_param = func - .params + .params() .first() .ok_or_else(|| anyhow!("Instance methods must have `__this` param."))?; - let this_arg = format_cc_ident(&this_param.identifier.identifier)?; + let this_arg = format_cc_ident(this_param.identifier().as_str())?; let this_dot = if this_ref_qualification == ir::ReferenceQualification::RValue { quote! {std::move(*#this_arg).} } else { diff --git a/rs_bindings_from_cc/generate_bindings/generate_struct_and_union.rs b/rs_bindings_from_cc/generate_bindings/generate_struct_and_union.rs index ff0c522ca..c1eb13315 100644 --- a/rs_bindings_from_cc/generate_bindings/generate_struct_and_union.rs +++ b/rs_bindings_from_cc/generate_bindings/generate_struct_and_union.rs @@ -64,14 +64,14 @@ pub fn generate_incomplete_record( .has_bindings(ir::Item::IncompleteRecord(incomplete_record.clone())) .unwrap_or_default() .visibility; - let cc_type = expect_format_cc_type_name(incomplete_record.cc_name.identifier.as_ref()); + let cc_type = expect_format_cc_type_name(incomplete_record.cc_name().as_str()); let namespace_qualifier = db.namespace_qualifier(&incomplete_record).format_for_cc()?; Ok(ApiSnippets { generated_items: HashMap::from([( - incomplete_record.id, + incomplete_record.id(), GeneratedItem::ForwardDeclare { visibility, - ident: make_rs_ident(incomplete_record.rs_name.identifier.as_ref()), + ident: make_rs_ident(incomplete_record.rs_name().as_str()), symbol: quote! {#namespace_qualifier #cc_type}.to_string(), }, )]), @@ -80,9 +80,9 @@ pub fn generate_incomplete_record( } fn make_rs_field_ident(field: &Field, field_index: usize) -> Ident { - match field.rust_identifier.as_ref() { + match field.rust_identifier() { None => make_rs_ident(&format!("__unnamed_field{}", field_index)), - Some(Identifier { identifier }) => make_rs_ident(identifier), + Some(ident) => make_rs_ident(ident.as_str()), } } @@ -105,18 +105,19 @@ fn get_field_rs_type_kind_for_layout( record: &Record, field: &Field, ) -> Result { - if field.is_no_unique_address { + let owning_target = record.owning_target(); + if field.is_no_unique_address() { bail!("`[[no_unique_address]]` attribute was present."); } let ir = db.ir(); - match &field.unknown_attr { + match field.unknown_attr() { Err(e) => bail!("{e}"), Ok(None) => (), Ok(Some(unknown_attr)) => { // Both the template definition and its instantiation should enable experimental // features. for target in - db.defining_target(record.id()).as_ref().into_iter().chain([&record.owning_target]) + db.defining_target(record.id()).as_ref().into_iter().chain([&owning_target]) { let enabled_features = ir.target_crubit_features(target); ensure!( @@ -128,7 +129,7 @@ fn get_field_rs_type_kind_for_layout( } } } - let type_kind = db.rs_type_kind(field.type_.clone())?; + let type_kind = db.rs_type_kind(field.type_().clone())?; if let RsTypeKind::Error { error, .. } = type_kind { return Err(error.clone()); @@ -139,9 +140,7 @@ fn get_field_rs_type_kind_for_layout( type_kind.display(db)) } - for target in - db.defining_target(record.id()).as_ref().into_iter().chain([&record.owning_target]) - { + for target in db.defining_target(record.id()).as_ref().into_iter().chain([&owning_target]) { let enabled_features = ir.target_crubit_features(target); let reasons = type_kind.missing_feature_descriptions_of_type(target, enabled_features); ensure!(reasons.is_empty(), reasons.join(", ")); @@ -153,9 +152,7 @@ fn get_field_rs_type_kind_for_layout( // // Users can still work around this with accessor functions. if record.should_implement_drop() && !record.is_union() && needs_manually_drop(&type_kind) { - for target in - db.defining_target(record.id()).as_ref().into_iter().chain([&record.owning_target]) - { + for target in db.defining_target(record.id()).as_ref().into_iter().chain([&owning_target]) { let enabled_features = ir.target_crubit_features(target); ensure!( enabled_features.contains(crubit_feature::CrubitFeature::Experimental), @@ -171,7 +168,7 @@ fn collect_unqualified_member_functions_from_all_bases( record: &Record, ) -> Rc<[Rc]> { record - .unambiguous_public_bases + .unambiguous_public_bases() .iter() .flat_map(|base_class| { let Ok(item) = db.find_decl::(base_class.base_record_id) else { @@ -190,11 +187,11 @@ fn collect_unqualified_member_functions_from_all_bases( /// Implementation of `BindingsGenerator::collect_unqualified_member_functions`. pub fn collect_unqualified_member_functions( - db: &BindingsGenerator, + _db: &BindingsGenerator, record: Rc, ) -> Rc<[Rc]> { record - .children + .children() .iter() .filter_map(|child_item| { if let Item::Func(member_function) = child_item @@ -297,12 +294,12 @@ fn field_definition( }); }; - let deprecated_attr = field.deprecated.clone().map(DeprecatedAttr); + let deprecated_attr = field.deprecated().map(DeprecatedAttr); let ident = make_rs_field_ident(field, field_index); let field_rs_type_kind = get_field_rs_type_kind_for_layout(db, record, field); let doc_comment = match &field_rs_type_kind { Ok(_) => generate_doc_comment( - field.doc_comment.as_deref(), + field.doc_comment(), None, None, db.is_golden_test(), @@ -312,8 +309,7 @@ fn field_definition( use std::fmt::Write; let mut new_text = field - .doc_comment - .as_deref() + .doc_comment() .map(|doc_comment| format!("{doc_comment}\n\n")) .unwrap_or_default(); let _ = write!( @@ -329,8 +325,8 @@ fn field_definition( ) } }; - let visibility = if field.access == AccessSpecifier::Public && field_rs_type_kind.is_ok() { - db.type_visibility(&record.owning_target, field_rs_type_kind.clone().unwrap()) + let visibility = if field.access() == AccessSpecifier::Public && field_rs_type_kind.is_ok() { + db.type_visibility(&record.owning_target(), field_rs_type_kind.clone().unwrap()) .unwrap_or_default() } else { Visibility::PubCrate @@ -340,7 +336,7 @@ fn field_definition( Err(_) => { *override_alignment = true; FieldType::Erased(BitPadding { - size: NonZeroUsize::new(end - field.offset) + size: NonZeroUsize::new(end - field.offset()) .expect("Bit padding should always be greater than 0"), internally_mutable: internally_mutable_unknown_fields, }) @@ -360,7 +356,7 @@ fn field_definition( }; FieldType::Type { needs_manually_drop: wrap_in_manually_drop, - needs_cell: field.is_mutable, + needs_cell: field.is_mutable(), ty, } } @@ -388,7 +384,7 @@ pub fn generate_record(db: &BindingsGenerator, record: Rc) -> Result) -> Result) -> Result = record - .fields + .fields() .iter() .filter_map(|field| { - let size = NonZeroUsize::new(field.size)?; + let size = NonZeroUsize::new(field.size())?; Some(FieldWithLayout { // We don't represent bitfields directly in Rust. We drop the field itself here // and only retain the offset information. Adjacent bitfields then get merged in // the next step. - ir: if field.is_bitfield { None } else { Some(field) }, - offset: field.offset, + ir: if field.is_bitfield() { None } else { Some(field) }, + offset: field.offset(), // We retain the end offset of fields only if we have a matching Rust type // to represent them. Otherwise we'll fill up all the space to the next field. // See: docs/design/struct_layout.md end: match get_field_rs_type_kind_for_layout(db, &record, field) { // Regular field - Ok(_rs_type) => Some(field.offset + field.size), + Ok(_rs_type) => Some(field.offset() + field.size()), // Opaque field Err(_error) => { if record.is_union() { - Some(field.size) + Some(field.size()) } else { None } } }, description: vec![BitfieldComment { - field_name: field.rust_identifier.as_ref().map(|i| i.identifier.clone()), + field_name: field.rust_identifier().map(|i| std::rc::Rc::from(i.as_str())), bits: size, }], }) @@ -472,7 +468,7 @@ pub fn generate_record(db: &BindingsGenerator, record: Rc) -> Result) -> Result) -> Result) -> Result) -> Result 0 || !allow_direct_init { Some(head_padding) } else { None }; @@ -621,7 +617,7 @@ pub fn generate_record(db: &BindingsGenerator, record: Rc) -> Result) -> Result) -> Result) -> Result>(); quote! { < #( #stubs ),* > } }; - let display_impl = if record.detected_formatter { + let display_impl = if record.detected_formatter() { let fmt_fn_name = make_rs_ident(&format!( "__crubit_fmt__{type_name}_{odr_suffix}", - type_name = record.mangled_cc_name, - odr_suffix = record.owning_target.convert_to_cc_identifier(), + type_name = record.mangled_cc_name(), + odr_suffix = (*record).owning_target().convert_to_cc_identifier(), )); let thunk = Thunk::Fmt { fmt_fn_name: fmt_fn_name.clone(), param_type: qualified_ident.clone() }; @@ -707,29 +703,31 @@ pub fn generate_record(db: &BindingsGenerator, record: Rc) -> Result; N]> body has alignment 1. - align: if (override_alignment || record.is_thread_safe) && record.size_align.alignment > 1 { - Some(record.size_align.alignment) + align: if (override_alignment || record.is_thread_safe()) + && record.size_align().alignment > 1 + { + Some(record.size_align().alignment) } else { None }, @@ -748,11 +746,11 @@ pub fn generate_record(db: &BindingsGenerator, record: Rc) -> Result) -> Result) -> Result) -> Result( record: &'a Record, db: &'a BindingsGenerator, ) -> impl Iterator + 'a { - record.children.iter().map(move |item| { + record.children().iter().map(move |item| { let is_nested = item.place_in_nested_module_if_nested_in_record() && db.has_bindings(item.clone()).is_ok(); ChildItem { is_nested, item: item.clone() } @@ -845,7 +845,7 @@ pub fn generate_derives(record: &Record) -> DeriveAttr { // Thread-safe types wrap their fields in UnsafeCell<[MaybeUninit; N]>. // This opaque byte array doesn't support useful standard derives, and Clone/Copy // are explicitly prevented to support interior mutability anyway. - if record.is_thread_safe { + if record.is_thread_safe() { return DeriveAttr(vec![]); } let mut derives = vec![]; @@ -854,16 +854,16 @@ pub fn generate_derives(record: &Record) -> DeriveAttr { } if record.should_derive_copy() { derives.push(quote! { Copy }); - if record.lifetime_inputs.is_empty() { + if record.lifetime_inputs().is_empty() { // TODO(b/491917803): Workaround for assume_lifetimes while MoveAndAssignViaCopy doesn't // support lifetime parameters. derives.push(quote! { ::ctor::MoveAndAssignViaCopy }); } } - if record.trait_derives.debug == TraitImplPolarity::Positive { + if record.trait_derives().debug == TraitImplPolarity::Positive { derives.push(quote! { Debug }); } - for custom_trait in &record.trait_derives.custom { + for custom_trait in &record.trait_derives().custom { // Breaks for paths right now... derives.push(make_rs_ident(custom_trait).to_token_stream()); } @@ -873,17 +873,17 @@ pub fn generate_derives(record: &Record) -> DeriveAttr { fn cc_struct_layout_assertion(db: &BindingsGenerator, record: &Record) -> Result { let namespace_qualifier = db.namespace_qualifier(record).format_for_cc()?; let fields_and_expected_offsets: Vec<(TokenStream, usize)> = record - .fields + .fields() .iter() .filter_map(|field| { - if field.access != AccessSpecifier::Public { + if field.access() != AccessSpecifier::Public { return None; } // https://en.cppreference.com/w/cpp/types/offsetof points out that "if member is [...] // a bit-field [...] the behavior [of `offsetof` macro] is undefined.". In such // scenario clang reports an error: cannot compute offset of bit-field 'field_name'. - if field.is_bitfield { + if field.is_bitfield() { return None; } @@ -891,29 +891,28 @@ fn cc_struct_layout_assertion(db: &BindingsGenerator, record: &Record) -> Result // offset in bytes, so we need to convert. We can assert that // `field.offset` is always at field boundaries, because the // bitfields have been filtered out earlier. - assert_eq!(field.offset % 8, 0); - let expected_offset = field.offset / 8; - let field_ident = - expect_format_cc_type_name(&field.cpp_identifier.as_ref()?.identifier); + assert_eq!(field.offset() % 8, 0); + let expected_offset = field.offset() / 8; + let field_ident = expect_format_cc_type_name(field.cpp_identifier()?.as_str()); Some((field_ident, expected_offset)) }) .collect(); // only use CRUBIT_SIZEOF for alignment > 1, so as to simplify the generated // code. - let sizeof_impl = if record.size_align.alignment > 1 { + let sizeof_impl = if record.size_align().alignment > 1 { SizeofImpl::RoundUpToAlignment } else { SizeofImpl::Builtin }; Ok(ThunkImpl::LayoutAssertion { - tag_kind: if record.is_canonical_alias { None } else { Some(record.record_type) }, + tag_kind: if record.is_canonical_alias() { None } else { Some(record.record_type()) }, namespace_qualifier, - record_ident: record.cc_name.identifier.clone(), + record_ident: std::rc::Rc::from(record.cc_name().as_str()), sizeof_impl, - size: record.size_align.size, - alignment: record.size_align.alignment, + size: record.size_align().size, + alignment: record.size_align().alignment, fields_and_expected_offsets, }) } @@ -924,26 +923,26 @@ fn cc_struct_no_unique_address_impl( record: &Record, ) -> Result> { let mut no_unique_address_accessors = vec![]; - for field in &record.fields { - if field.access != AccessSpecifier::Public || !field.is_no_unique_address { + for field in record.fields() { + if field.access() != AccessSpecifier::Public || !field.is_no_unique_address() { continue; } // `[[no_unique_address]]` cannot be applied to a bitfield. // See e.g. https://en.cppreference.com/w/cpp/language/attributes/no_unique_address // Indeed, this is a compilation error in Clang. - assert_eq!(field.offset % 8, 0, "invalid subobject: [[no_unique_address]] on a bitfield"); + assert_eq!(field.offset() % 8, 0, "invalid subobject: [[no_unique_address]] on a bitfield"); // Can't use `get_field_rs_type_kind_for_layout` here, because we want to dig // into no_unique_address fields, despite laying them out as opaque // blobs of bytes. - let type_ident = db.rs_type_kind(field.type_.clone()).with_context(|| { + let type_ident = db.rs_type_kind(field.type_().clone()).with_context(|| { format!("Failed to format type for field {field:?} on record {record:?}") })?; no_unique_address_accessors.push(NoUniqueAddressAccessor { - doc_comment: if field.size == 0 { + doc_comment: if field.size() == 0 { // These fields are not generated at all, so they need to be documented here. generate_doc_comment( - field.doc_comment.as_deref(), + field.doc_comment(), None, None, db.is_golden_test(), @@ -954,14 +953,13 @@ fn cc_struct_no_unique_address_impl( None }, field: make_rs_ident( - &field - .rust_identifier - .as_ref() + field + .rust_identifier() .expect("Unnamed fields can't be annotated with [[no_unique_address]]") - .identifier, + .as_str(), ), type_: type_ident.to_token_stream(db), - byte_offset: field.offset / 8, + byte_offset: field.offset() / 8, }); } Ok(no_unique_address_accessors) @@ -980,7 +978,7 @@ fn cc_struct_upcast_impl( let mut thunk_impls = vec![]; let mut upcast_impls = vec![]; let derived_name = db.rs_type_kind(record.as_ref().into())?.to_token_stream(db); - for base in &record.unambiguous_public_bases { + for base in record.unambiguous_public_bases() { let base_record: &Rc = db .find_decl(base.base_record_id) .with_context(|| format!("Can't find a base record of {:?}", record))?; @@ -988,8 +986,8 @@ fn cc_struct_upcast_impl( // The base type is unknown to Crubit, so don't generate upcast code for it. upcast_impls.push(Err(format!( "'{}' cannot be upcasted to '{}' because the base type doesn't have Crubit bindings.", - &record.cc_name, - &base_record.cc_name, + record.cc_name(), + base_record.cc_name(), ))); continue; }; @@ -1006,9 +1004,9 @@ fn cc_struct_upcast_impl( } else { let cast_fn_name = make_rs_ident(&format!( "__crubit_dynamic_upcast__{derived}__to__{base}_{odr_suffix}", - derived = record.mangled_cc_name, - base = base_record.mangled_cc_name, - odr_suffix = record.owning_target.convert_to_cc_identifier(), + derived = record.mangled_cc_name(), + base = base_record.mangled_cc_name(), + odr_suffix = (**record).owning_target().convert_to_cc_identifier(), )); let base_cc_name = cpp_type_name_for_record(base_record.as_ref(), db)?; let derived_cc_name = cpp_type_name_for_record(record.as_ref(), db)?; @@ -1050,8 +1048,8 @@ fn cc_struct_operator_delete_impl( let thunk_ident = make_rs_ident(&format!( "__crubit_operator_delete__{}_{}", - record.mangled_cc_name, - record.owning_target.convert_to_cc_identifier(), + record.mangled_cc_name(), + (**record).owning_target().convert_to_cc_identifier(), )); let thunk = Thunk::Function { diff --git a/rs_bindings_from_cc/generate_bindings/generate_struct_and_union_test.rs b/rs_bindings_from_cc/generate_bindings/generate_struct_and_union_test.rs index e7e5d4ee7..f06116b9d 100644 --- a/rs_bindings_from_cc/generate_bindings/generate_struct_and_union_test.rs +++ b/rs_bindings_from_cc/generate_bindings/generate_struct_and_union_test.rs @@ -608,28 +608,28 @@ fn test_copy_derives() { #[gtest] fn test_copy_derives_not_is_trivial_abi() { let mut record = ir_record("S"); - record.is_trivial_abi = false; + record.set_is_trivial_abi(false); assert_derives(&record, &[]); } #[gtest] fn test_copy_derives_ctor_deleted() { let mut record = ir_record("S"); - record.copy_constructor = ir::SpecialMemberFunc::Unavailable; + record.set_copy_constructor(ir::SpecialMemberFunc::Unavailable); assert_derives(&record, &[]); } #[gtest] fn test_copy_derives_ctor_nontrivial_members() { let mut record = ir_record("S"); - record.copy_constructor = ir::SpecialMemberFunc::NontrivialMembers; + record.set_copy_constructor(ir::SpecialMemberFunc::NontrivialMembers); assert_derives(&record, &[]); } #[gtest] fn test_copy_derives_ctor_nontrivial_self() { let mut record = ir_record("S"); - record.copy_constructor = ir::SpecialMemberFunc::NontrivialUserDefined; + record.set_copy_constructor(ir::SpecialMemberFunc::NontrivialUserDefined); assert_derives(&record, &[]); } @@ -640,7 +640,7 @@ fn test_copy_derives_dtor_nontrivial_self() { for definition in [ir::SpecialMemberFunc::NontrivialUserDefined, ir::SpecialMemberFunc::NontrivialMembers] { - record.destructor = definition; + record.set_destructor(definition); assert_derives(&record, &["Clone"]); } } diff --git a/rs_bindings_from_cc/generate_bindings/has_bindings.rs b/rs_bindings_from_cc/generate_bindings/has_bindings.rs index 2d141a359..70b0763a3 100644 --- a/rs_bindings_from_cc/generate_bindings/has_bindings.rs +++ b/rs_bindings_from_cc/generate_bindings/has_bindings.rs @@ -11,7 +11,7 @@ use database::rs_snippet::{LifetimeOptions, RsTypeKind}; use database::BindingsGenerator; use error_report::{anyhow, bail}; use heck::ToSnakeCase; -use ir::{BazelLabel, Func, GenericItem, Item, ItemId, Record}; +use ir::{BazelLabel, Func, GenericItem, Item, Record}; use std::collections::HashMap; use std::rc::Rc; @@ -46,7 +46,7 @@ pub fn has_bindings(db: &BindingsGenerator, item: Item) -> Result Result Result 1 { @@ -98,8 +98,8 @@ pub fn has_bindings(db: &BindingsGenerator, item: Item) -> Result>(parent_record_id) .unwrap() - .rs_name - .identifier + .rs_name() + .as_str() .to_string() }) .collect(), @@ -362,7 +362,8 @@ fn type_target_restriction_shallow( // All non-record types are `pub` if they receive bindings. return None; }; - let target = &record.owning_target; + let owning_target = (**record).owning_target(); + let target = &owning_target; // Template types (except for the special-cased ones like `[w]string_view`) // are the only types whose bindings have restrictions, and they do not have // unique owning targets. @@ -433,10 +434,11 @@ pub fn resolve_names( db: &BindingsGenerator, parent: Rc, ) -> Result, ResolvedName>>> { - let child_items = match parent.enclosing_item_id.map(|id| db.find_untyped_decl(id)) { + let parent_owning_target = (*parent).owning_target(); + let child_items = match parent.enclosing_item_id().map(|id| db.find_untyped_decl(id)) { Some(Item::Namespace(ns)) => ns.children.iter(), - Some(Item::Record(record)) => record.children.iter(), - None => db.ir().top_level_items_in_target(&parent.owning_target).iter(), + Some(Item::Record(record)) => record.children().iter(), + None => db.ir().top_level_items_in_target(&parent_owning_target).iter(), _ => bail!("not a parent namespace or record"), }; @@ -475,43 +477,59 @@ pub fn resolve_names( match item { Item::IncompleteRecord(incomplete_record) => { insert( - incomplete_record.rs_name.identifier.clone(), + std::rc::Rc::from(incomplete_record.rs_name().as_str()), ResolvedName::ExplicitItem(id), ); } Item::Record(record) => { - insert(record.rs_name.identifier.clone(), ResolvedName::ExplicitItem(id)); - } - Item::Enum(enum_) => { - insert(enum_.rs_name.identifier.clone(), ResolvedName::ExplicitItem(id)) + insert( + std::rc::Rc::from(record.rs_name().as_str()), + ResolvedName::ExplicitItem(id), + ); } + Item::Enum(enum_) => insert( + std::rc::Rc::from(enum_.rs_name().as_str()), + ResolvedName::ExplicitItem(id), + ), Item::TypeAlias(type_alias) => { - insert(type_alias.rs_name.identifier.clone(), ResolvedName::ExplicitItem(id)); + insert( + std::rc::Rc::from(type_alias.rs_name().as_str()), + ResolvedName::ExplicitItem(id), + ); } Item::Namespace(ns) => { insert( - ns.rs_name.identifier.clone(), + std::rc::Rc::from(ns.rs_name().as_str()), ResolvedName::Namespace { canonical_namespace_id: ns.canonical_namespace_id, }, ); } Item::UseMod(use_mod) => { - insert(use_mod.mod_name.identifier.clone(), ResolvedName::ExplicitItem(id)); + insert( + std::rc::Rc::from(use_mod.mod_name().as_str()), + ResolvedName::ExplicitItem(id), + ); } Item::ExistingRustType(existing_rust_type) => { insert(existing_rust_type.rs_name.clone(), ResolvedName::ExplicitItem(id)); } Item::Func(func) => { - if let ir::UnqualifiedIdentifier::Identifier(ident) = &func.rs_name { - insert(ident.identifier.clone(), ResolvedName::ValueItem(id)); + if let ir::UnqualifiedIdentifier::Identifier(ident) = func.rs_name() { + insert(std::rc::Rc::from(ident.as_str()), ResolvedName::ValueItem(id)); } } Item::Constant(constant) => { - insert(constant.rs_name.identifier.clone(), ResolvedName::ValueItem(id)); + insert( + std::rc::Rc::from(constant.rs_name().as_str()), + ResolvedName::ValueItem(id), + ); } Item::GlobalVar(global_var) => { - insert(global_var.rs_name.identifier.clone(), ResolvedName::ValueItem(id)); + insert( + std::rc::Rc::from(global_var.rs_name().as_str()), + ResolvedName::ValueItem(id), + ); } Item::Comment(_) | Item::UnsupportedItem(_) => {} } @@ -521,16 +539,16 @@ pub fn resolve_names( // Pass 2: Insert module names for records, checking for conflicts. for item in child_items { if let Item::Record(record) = item { - let id = record.id; + let id = record.id(); let make_module_for_nested_items = record - .children + .children() .iter() .any(|child| child.place_in_nested_module_if_nested_in_record()); if make_module_for_nested_items { - let mut name = record.rs_name.identifier.as_ref().to_snake_case(); + let mut name = record.rs_name().as_str().to_snake_case(); // Disambiguation logic - if name == record.rs_name.identifier.as_ref() { + if name == record.rs_name().as_str() { name = format!("{}_items", name); } diff --git a/rs_bindings_from_cc/generate_bindings/lib.rs b/rs_bindings_from_cc/generate_bindings/lib.rs index 8613dfbb2..a0fc9a703 100644 --- a/rs_bindings_from_cc/generate_bindings/lib.rs +++ b/rs_bindings_from_cc/generate_bindings/lib.rs @@ -180,7 +180,7 @@ fn generate_type_alias( db.kythe_annotations(), ), visibility: db.type_visibility(&type_alias.owning_target, rs_type_kind).unwrap_or_default(), - ident: make_rs_ident(&type_alias.rs_name.identifier), + ident: make_rs_ident(type_alias.rs_name().as_str()), underlying_type: underlying_type.to_token_stream(db), underlying_nested_module_path, deprecated_attr: type_alias.deprecated.clone().map(DeprecatedAttr), @@ -211,7 +211,7 @@ fn generate_constant(db: &BindingsGenerator, constant: &Constant) -> Result Result) -> Resul let mut api_snippets = ApiSnippets::default(); - for item in &namespace.children { + for item in namespace.children() { api_snippets.append(db.generate_item(item.clone())?); } @@ -342,8 +342,8 @@ fn generate_item_impl(db: &BindingsGenerator, item: &Item) -> Result generate_comment(comment.clone()), Item::Namespace(namespace) => generate_namespace(db, namespace.clone())?, Item::UseMod(use_mod) => { - let UseMod { path, mod_name, .. } = &**use_mod; - let mod_name = make_rs_ident(&mod_name.identifier); + let UseMod { path, .. } = &**use_mod; + let mod_name = make_rs_ident(use_mod.mod_name().as_str()); // TODO(b/308949532): Skip re-export if the module being used is empty // (transitively). ApiSnippets { @@ -713,7 +713,7 @@ fn rs_type_kind_safety(db: &BindingsGenerator, rs_type_kind: RsTypeKind) -> Opti if !record.is_raw_string_view() && db .ir() - .target_crubit_features(&record.owning_target) + .target_crubit_features(&(*record).owning_target()) .contains(crubit_feature::CrubitFeature::AssumeLifetimes) { match (db.codegen_functions().decl_lifetime_arity)(db, record.id()) { @@ -721,14 +721,14 @@ fn rs_type_kind_safety(db: &BindingsGenerator, rs_type_kind: RsTypeKind) -> Opti if arity != 0 && lifetimes.len() != arity { return Some(UnsafeReason(format!( "type {} has {} lifetime parameter{}, but {} {} provided; callers must ensure that arguments have the appropriate lifetime", - record.rs_name, arity, if arity == 1 { "" } else { "s" }, lifetimes.len(), if lifetimes.len() == 1 { "was" } else { "were" } + record.rs_name(), arity, if arity == 1 { "" } else { "s" }, lifetimes.len(), if lifetimes.len() == 1 { "was" } else { "were" } ).into())); } } _ => { return Some(UnsafeReason(format!( "unable to determine lifetime how many lifetime parameters {} accepts; callers must ensure that arguments have the appropriate lifetime", - record.rs_name + record.rs_name() ).into())); } } @@ -783,10 +783,10 @@ fn callable_safety( /// Implementation of `BindingsGenerator::record_field_safety`. fn record_field_safety(db: &BindingsGenerator, field: Field) -> Option { - if field.access != AccessSpecifier::Public { + if field.access() != AccessSpecifier::Public { return None; } - let field_rs_type_kind = match db.rs_type_kind(field.type_.clone()) { + let field_rs_type_kind = match db.rs_type_kind(field.type_().clone()) { Ok(field_rs_type_kind) => field_rs_type_kind, Err(err) => { // If we can't get the RsTypeKind for a public field, we assume it's unsafe. @@ -802,7 +802,7 @@ fn record_field_safety(db: &BindingsGenerator, field: Field) -> Option) -> Option { let mut doc = String::new(); - match record.safety_annotation { + match record.safety_annotation() { SafetyAnnotation::DisableUnsafe => { return None; } @@ -818,15 +818,14 @@ fn record_safety(db: &BindingsGenerator, record: Rc) -> Option = record - .fields + .fields() .iter() .filter_map(|field| { let reason = db.record_field_safety(field.clone())?; // TODO(nicholasbishop): handle unnamed better. let mut name = field - .rust_identifier - .as_ref() + .rust_identifier() .map(|i| format!("`{}`", i.as_str())) .unwrap_or("unnamed field".to_owned()); write!(name, ": {reason}").unwrap(); @@ -834,7 +833,7 @@ fn record_safety(db: &BindingsGenerator, record: Rc) -> Option Result { - let cpp_type = - make_cpp_type_from_item(enum_.as_ref(), enum_.cc_name.identifier.as_ref(), db)?; + let cpp_type = make_cpp_type_from_item(enum_.as_ref(), enum_.cc_name().as_str(), db)?; Ok(CrubitAbiType::Transmute { rust_type: rs_type_kind.to_token_stream(db), cpp_type }) } @@ -1260,7 +1258,7 @@ fn crubit_abi_type(db: &BindingsGenerator, rs_type_kind: RsTypeKind) -> Result Result Result Result Result { let item = db.find_untyped_decl(item_id); match item { - Item::TypeAlias(ta) if ta.rs_name == "raw_string_view" => Ok(1), + Item::TypeAlias(ta) if *ta.rs_name() == "raw_string_view" => Ok(1), // TODO(b/498977848): We seem to lose the typedef sugar if it's annotated. Note that we // explicitly only need to check for StdStringView here (and not the more general // rc.is_string_view()). - Item::Record(rc) => match rc.template_specialization { + Item::Record(rc) => match rc.template_specialization() { Some( ir::TemplateSpecialization { kind: ir::TemplateSpecializationKind::StdStringView, @@ -133,7 +133,7 @@ fn decl_lifetime_arity_impl( // Here and elsewhere in this function: change has_bindings.rs to check for additional // Item kinds when they are supported. // TODO(b/517949862): This needs to change once we add lifetime binders to type aliases. - lifetime_arity(db, &ta.underlying_type) + lifetime_arity(db, ta.underlying_type()) } Item::IncompleteRecord(_) => { bail!("Incomplete records unhandled for lifetimes: {:?}", item.cc_name_as_str()) @@ -189,10 +189,10 @@ impl BindingContext { } /// Returns a fresh variable name. - pub fn push_fresh_binding(&mut self, hint: Option<&Rc>) -> Rc { + pub fn push_fresh_binding(&mut self, hint: Option<&str>) -> Rc { let fresh_name = match hint { Some(id) => self.fresh_name_for(id), - None => self.fresh_name_for(&Rc::from("lt")), + None => self.fresh_name_for("lt"), }; self.push_new_binding(&fresh_name) } @@ -209,9 +209,9 @@ impl BindingContext { } /// Returns a fresh variable name based on `id`. - pub fn fresh_name_for(&self, id: &Rc) -> Rc { + pub fn fresh_name_for(&self, id: &str) -> Rc { if !self.names.contains(id) { - return id.clone(); + return Rc::from(id); } let mut ix = 0; loop { @@ -334,7 +334,7 @@ impl<'a, 'db> LifetimeDefaults<'a, 'db> { fn add_lifetime_to_input_type( &mut self, is_this: bool, - name_hint: Option<&Rc>, + name_hint: Option<&str>, new_bindings: &mut Vec>, ty: &CcType, ) -> Result { @@ -398,7 +398,7 @@ impl<'a, 'db> LifetimeDefaults<'a, 'db> { /// Returns the (raw) type argument applied to the decl `id`. fn type_arg_from_decl_id(&mut self, id: ItemId) -> Option { match self.db.find_untyped_decl(id) { - Item::Record(record) => match &record.template_specialization { + Item::Record(record) => match record.template_specialization() { Some(ir::TemplateSpecialization { kind: ir::TemplateSpecializationKind::StdVector { raw_element_type, .. }, .. @@ -551,17 +551,17 @@ impl<'a, 'db> LifetimeDefaults<'a, 'db> { // If a [[lifetimebound]] parameter already has a lifetime annotation and we // don't have a lifetime for the return value yet, use the parameter's // annotation. - return_lifetime = param.type_.explicit_lifetimes.clone(); - } else if !param.type_.explicit_lifetimes.is_empty() - && param.type_.explicit_lifetimes != return_lifetime + return_lifetime = param.type_().explicit_lifetimes().to_vec(); + } else if !param.type_().explicit_lifetimes().is_empty() + && param.type_().explicit_lifetimes() != return_lifetime { // If there's a conflict between what we believe is the [[lifetimebound]] // lifetime and the one annotated on a parameter, return a diagnostic. bail!( "lifetimebound: lifetime mismatch in function {:#?} between parameter {:#?} with lifetime {:#?} and return with lifetime {:#?}", - &func.cc_name, - ¶m.identifier.identifier, - ¶m.type_.explicit_lifetimes, + func.cc_name(), + param.identifier().as_str(), + param.type_().explicit_lifetimes(), &return_lifetime ); } @@ -572,7 +572,7 @@ impl<'a, 'db> LifetimeDefaults<'a, 'db> { return Ok(()); } // We have at least one parameter because `has_lifetimebound`. - let is_member_function = &func.params[0].identifier == "__this"; + let is_member_function = func.params()[0].identifier() == "__this"; if return_lifetime.is_empty() { // We still don't have any explicit annotations. // Below, `L(v)` returns the ordered list of lifetimes for the type of value `v`. @@ -634,13 +634,13 @@ impl<'a, 'db> LifetimeDefaults<'a, 'db> { } Item::Record(record) => { let arity = record_lifetime_arity(self.db, record)?; - if arity != record.lifetime_inputs.len() { + if arity != record.lifetime_inputs().len() { for _ in 0..arity { this_lifetimebound_names .push(self.bindings.push_new_binding(&Rc::from("__implicit"))); } } else { - record.lifetime_inputs.iter().for_each(|name| { + record.lifetime_inputs().iter().for_each(|name| { this_lifetimebound_names.push(self.bindings.push_new_binding(name)); }); } @@ -656,48 +656,55 @@ impl<'a, 'db> LifetimeDefaults<'a, 'db> { let mut state = LifetimeState::Unseen; let mut this_state = LifetimeState::Unseen; let mut had_this = false; - new_func.lifetime_inputs.clear(); + new_func.lifetime_inputs_mut().clear(); // Note that we generate a new LifetimeDefaults per Item that we're importing, so we don't // need to pop these bindings. (We *do* need to worry about unbinding names for internal // binders, like function types.) let this_lifetimebound_names = self.bind_lifetime_inputs(func.enclosing_item_id)?; // Rename local bindings (and remember how we've renamed them). - func.lifetime_inputs - .iter() - .for_each(|name| new_func.lifetime_inputs.push(self.bindings.push_new_binding(name))); + func.lifetime_inputs().iter().for_each(|name| { + new_func.lifetime_inputs_mut().push(self.bindings.push_new_binding(name)) + }); self.lower_clang_annotations(&mut new_func, &this_lifetimebound_names)?; - for (ix, param) in new_func.params.iter_mut().enumerate() { - let is_constructor = func.cc_name == ir::UnqualifiedIdentifier::Constructor; + + let mut params = std::mem::take(new_func.params_mut()); + let mut lifetime_inputs = std::mem::take(new_func.lifetime_inputs_mut()); + + for (ix, param) in params.iter_mut().enumerate() { + let is_constructor = *func.cc_name() == ir::UnqualifiedIdentifier::Constructor; // `this` in a constructor is strange. The !is_constructor restriction fixes some // situations where we would bind a `'__this` in a constructor and then not use it // (because the actual `__this` is a void*). - let is_this = ix == 0 && &*param.identifier.identifier == "__this" && !is_constructor; + let is_this = ix == 0 && param.identifier().as_str() == "__this" && !is_constructor; had_this |= is_this; let LifetimeResult { ty: new_type, state: new_state, this_state: new_this_state } = self.add_lifetime_to_input_type( is_this, - Some(¶m.identifier.identifier), - &mut new_func.lifetime_inputs, - ¶m.type_, + Some(param.identifier().as_str()), + &mut lifetime_inputs, + param.type_(), )?; state.update(&new_state); this_state.update(&new_this_state); - param.type_ = new_type; + *param.type_mut() = new_type; } + + *new_func.params_mut() = params; + let lifetime = match this_state { LifetimeState::Unseen => self.get_lifetime_for_state(&state), _ => self.get_lifetime_for_state(&this_state), }; - new_func.return_type = self.add_lifetime_to_output_type( - &lifetime, - &mut new_func.lifetime_inputs, - &new_func.return_type, - )?; + let return_type_arg = new_func.return_type().clone(); + let new_return_type = + self.add_lifetime_to_output_type(&lifetime, &mut lifetime_inputs, &return_type_arg)?; + *new_func.return_type_mut() = new_return_type; + *new_func.lifetime_inputs_mut() = lifetime_inputs; if had_this { // See if we can promote the type of `this` to a reference. - let this = new_func.params.get_mut(0).unwrap(); - if !this.type_.explicit_lifetimes.is_empty() - && let CcTypeVariant::Pointer(pty) = &mut this.type_.variant + let this = new_func.params_mut().get_mut(0).unwrap(); + if !this.type_().explicit_lifetimes().is_empty() + && let CcTypeVariant::Pointer(pty) = &mut this.type_mut().variant { pty.kind = PointerTypeKind::LValueRef; } @@ -708,20 +715,20 @@ impl<'a, 'db> LifetimeDefaults<'a, 'db> { /// Transforms a record to use default lifetime rules. fn add_lifetime_to_record(&mut self, record: &Record) -> Result { let mut new_record = record.clone(); - self.bind_lifetime_inputs(record.enclosing_item_id)?; - if new_record.lifetime_inputs.is_empty() { + self.bind_lifetime_inputs(record.enclosing_item_id())?; + if new_record.lifetime_inputs().is_empty() { // Record any implicit lifetime parameters. let arity = record_lifetime_arity(self.db, record)?; for _ in 0..arity { new_record - .lifetime_inputs + .lifetime_inputs_mut() .push(self.bindings.push_new_binding(&Rc::from("__implicit"))); } } else { - new_record.lifetime_inputs.clear(); + new_record.lifetime_inputs_mut().clear(); // Rename local bindings (and remember how we've renamed them). - record.lifetime_inputs.iter().for_each(|name| { - new_record.lifetime_inputs.push(self.bindings.push_new_binding(name)) + record.lifetime_inputs().iter().for_each(|name| { + new_record.lifetime_inputs_mut().push(self.bindings.push_new_binding(name)) }); } Ok(new_record) @@ -734,20 +741,23 @@ impl<'a, 'db> LifetimeDefaults<'a, 'db> { // TODO(b/517949862): Right now we don't allow users to explicitly bind lifetime parameters. // If the underlying type has any explicit lifetime arguments, we preserve those; otherwise, // we rebind all parameters. - if !type_alias.lifetime_inputs.is_empty() { + if !type_alias.lifetime_inputs().is_empty() { bail!( "b/517949862: type alias {} has explicit lifetime inputs: {:#?}", - type_alias.cc_name, - type_alias.lifetime_inputs + type_alias.cc_name(), + type_alias.lifetime_inputs() ); } - if type_alias.underlying_type.explicit_lifetimes.is_empty() - && let Ok(lifetime_arity) = self.get_lifetime_arity(&type_alias.underlying_type) + if type_alias.underlying_type().explicit_lifetimes().is_empty() + && let Ok(lifetime_arity) = self.get_lifetime_arity(type_alias.underlying_type()) { for it in 0..lifetime_arity { let new_name = self.bindings.push_new_binding(&Rc::from(format!("__alias{}", it))); - new_type_alias.lifetime_inputs.push(new_name.clone()); - new_type_alias.underlying_type.explicit_lifetimes.push(new_name.clone()); + new_type_alias.lifetime_inputs_mut().push(new_name.clone()); + new_type_alias + .underlying_type_mut() + .explicit_lifetimes_mut() + .push(new_name.clone()); } } Ok(new_type_alias) @@ -810,7 +820,7 @@ fn transform_item(db: &BindingsGenerator, item: &Item) -> Result { match &mut transformed { Item::Record(record) => { let mut record = Rc::as_ref(record).clone(); - record.children = transform_children(db, &record.children)?; + *record.children_mut() = transform_children(db, record.children())?; transformed = Item::Record(Rc::new(record)); } Item::Namespace(ns) => { diff --git a/rs_bindings_from_cc/ir.rs b/rs_bindings_from_cc/ir.rs index f23fa5c50..4d3f70021 100644 --- a/rs_bindings_from_cc/ir.rs +++ b/rs_bindings_from_cc/ir.rs @@ -148,7 +148,7 @@ impl<'a> Iterator for ItemsIterator<'a> { } match item { Item::Record(record) => { - self.stack.extend(record.children.iter().rev()); + self.stack.extend(record.children().iter().rev()); } Item::Namespace(ns) => { self.stack.extend(ns.children.iter().rev()); @@ -175,7 +175,7 @@ fn populate_item_id_to_item(item: &Item, item_id_to_item: &mut HashMap { - for child in &record.children { + for child in record.children() { populate_item_id_to_item(child, item_id_to_item); } } @@ -208,7 +208,7 @@ pub fn make_ir(tree_ir: TreeIR) -> IR { for item in ordered_items { let lifetime_params = match item { - Item::Record(record) => &record.lifetime_params[..], + Item::Record(record) => record.lifetime_params(), Item::Func(func) => &func.lifetime_params[..], _ => &[], }; @@ -284,6 +284,14 @@ pub struct CcType { } impl CcType { + pub fn explicit_lifetimes(&self) -> &[Rc] { + &self.explicit_lifetimes + } + + pub fn explicit_lifetimes_mut(&mut self) -> &mut Vec> { + &mut self.explicit_lifetimes + } + pub fn is_unit_type(&self) -> bool { matches!(&self.variant, CcTypeVariant::Primitive(Primitive::Void)) } @@ -292,7 +300,7 @@ impl CcType { impl From<&Record> for CcType { fn from(record: &Record) -> Self { CcType { - variant: CcTypeVariant::Decl { id: record.id, template_args: None }, + variant: CcTypeVariant::Decl { id: record.id(), template_args: None }, is_const: false, unknown_attr: Rc::default(), explicit_lifetimes: Vec::default(), @@ -588,33 +596,54 @@ impl TypeWithDeclId for CcType { } } -#[derive(PartialEq, Eq, Hash, Clone, Deserialize)] -#[serde(deny_unknown_fields)] -pub struct Identifier { - pub identifier: Rc, +#[derive(PartialEq, Eq, Hash, Clone)] +pub enum Identifier { + Static(&'static str), + Owned(Rc), } impl Identifier { + pub fn new(s: impl Into>) -> Self { + Self::Owned(s.into()) + } + pub fn as_str(&self) -> &str { - &self.identifier + match self { + Self::Static(s) => s, + Self::Owned(rc) => rc, + } + } +} + +impl<'de> Deserialize<'de> for Identifier { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + #[derive(Deserialize)] + struct IdentifierHelper { + identifier: Rc, + } + let helper = IdentifierHelper::deserialize(deserializer)?; + Ok(Self::Owned(helper.identifier)) } } impl Display for Identifier { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.identifier) + write!(f, "{}", self.as_str()) } } impl Debug for Identifier { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "\"{}\"", self.identifier) + write!(f, "\"{}\"", self.as_str()) } } impl PartialEq for Identifier { fn eq(&self, other: &str) -> bool { - self.identifier.as_ref() == other + self.as_str() == other } } @@ -834,7 +863,7 @@ impl UnqualifiedIdentifier { } } pub fn identifier_as_str(&self) -> Option<&str> { - self.as_identifier().map(|id| id.identifier.as_ref()) + self.as_identifier().map(|id| id.as_str()) } } @@ -853,7 +882,7 @@ impl Debug for UnqualifiedIdentifier { impl PartialEq for UnqualifiedIdentifier { fn eq(&self, other: &str) -> bool { if let UnqualifiedIdentifier::Identifier(identifier) = self { - &*identifier.identifier == other + identifier.as_str() == other } else { false } @@ -906,7 +935,21 @@ pub struct FuncParam { pub unknown_attr: Option>, } -#[derive(Debug, PartialEq, Eq, Hash, Clone, Deserialize)] +impl FuncParam { + pub fn type_(&self) -> &CcType { + &self.type_ + } + + pub fn type_mut(&mut self) -> &mut CcType { + &mut self.type_ + } + + pub fn identifier(&self) -> &Identifier { + &self.identifier + } +} + +#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone, Deserialize)] #[serde(deny_unknown_fields)] pub enum SafetyAnnotation { DisableUnsafe, @@ -1004,9 +1047,45 @@ impl GenericItem for Func { } impl Func { + pub fn cc_name(&self) -> &UnqualifiedIdentifier { + &self.cc_name + } + + pub fn rs_name(&self) -> &UnqualifiedIdentifier { + &self.rs_name + } + + pub fn params(&self) -> &[FuncParam] { + &self.params + } + + pub fn params_mut(&mut self) -> &mut Vec { + &mut self.params + } + + pub fn lifetime_params(&self) -> &[LifetimeName] { + &self.lifetime_params + } + + pub fn lifetime_inputs(&self) -> &[Rc] { + &self.lifetime_inputs + } + + pub fn lifetime_inputs_mut(&mut self) -> &mut Vec> { + &mut self.lifetime_inputs + } + pub fn is_instance_method(&self) -> bool { self.instance_method_metadata.is_some() } + + pub fn return_type(&self) -> &CcType { + &self.return_type + } + + pub fn return_type_mut(&mut self) -> &mut CcType { + &mut self.return_type + } } #[derive(Debug, PartialEq, Eq, Hash, Copy, Clone, Deserialize)] @@ -1018,7 +1097,7 @@ pub enum AccessSpecifier { #[derive(Debug, PartialEq, Eq, Hash, Clone, Deserialize)] #[serde(deny_unknown_fields)] -pub struct Field { +pub struct DeserializedField { pub rust_identifier: Option, pub cpp_identifier: Option, pub doc_comment: Option>, @@ -1027,25 +1106,186 @@ pub struct Field { pub access: AccessSpecifier, pub offset: usize, pub size: usize, - - /// A human-readable list of attributes that Crubit doesn't understand. pub unknown_attr: Result>, String>, - pub is_no_unique_address: bool, pub is_bitfield: bool, - - // TODO(kinuko): Consider removing this, it is a duplicate of the same information - // in `Record`. pub is_inheritable: bool, pub is_mutable: bool, - - /// The `[[deprecated("...")]]` string. If `[[deprecated]]`, then the empty - /// string is used. #[serde(default)] pub deprecated: Option>, } -#[derive(Debug, PartialEq, Eq, Hash, Clone, Deserialize)] +#[derive(Debug, Clone)] +pub struct ProtoField { + pub(crate) proto: ir_rust_proto::FieldView<'static>, + pub(crate) type_: CcType, + pub(crate) unknown_attr: Result>, String>, +} + +impl PartialEq for ProtoField { + fn eq(&self, other: &Self) -> bool { + self.proto.offset() == other.proto.offset() + && self.proto.size() == other.proto.size() + && self.type_ == other.type_ + } +} +impl Eq for ProtoField {} +impl Hash for ProtoField { + fn hash(&self, state: &mut H) { + self.proto.offset().hash(state); + self.proto.size().hash(state); + self.type_.hash(state); + } +} + +#[derive(Clone, PartialEq, Eq, Hash)] +pub enum Field { + Owned(DeserializedField), + Proto(ProtoField), +} + +impl<'de> Deserialize<'de> for Field { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let deserialized = DeserializedField::deserialize(deserializer)?; + Ok(Self::Owned(deserialized)) + } +} + +impl Field { + pub fn rust_identifier(&self) -> Option { + match self { + Self::Owned(f) => f.rust_identifier.clone(), + Self::Proto(f) => f + .proto + .rust_identifier_opt() + .map(|id| Identifier::Static(id.identifier().to_str().unwrap())), + } + } + + pub fn cpp_identifier(&self) -> Option { + match self { + Self::Owned(f) => f.cpp_identifier.clone(), + Self::Proto(f) => f + .proto + .cpp_identifier_opt() + .map(|id| Identifier::Static(id.identifier().to_str().unwrap())), + } + } + + pub fn doc_comment(&self) -> Option<&str> { + match self { + Self::Owned(f) => f.doc_comment.as_deref(), + Self::Proto(f) => f.proto.doc_comment_opt().map(|s| s.to_str().unwrap()), + } + } + + pub fn type_(&self) -> &CcType { + match self { + Self::Owned(f) => &f.type_, + Self::Proto(f) => &f.type_, + } + } + + pub fn type_mut(&mut self) -> &mut CcType { + match self { + Self::Owned(f) => &mut f.type_, + Self::Proto(f) => &mut f.type_, + } + } + + pub fn offset(&self) -> usize { + match self { + Self::Owned(f) => f.offset, + Self::Proto(f) => f.proto.offset() as usize, + } + } + + pub fn size(&self) -> usize { + match self { + Self::Owned(f) => f.size, + Self::Proto(f) => f.proto.size() as usize, + } + } + + pub fn is_bitfield(&self) -> bool { + match self { + Self::Owned(f) => f.is_bitfield, + Self::Proto(f) => f.proto.is_bitfield(), + } + } + + pub fn is_no_unique_address(&self) -> bool { + match self { + Self::Owned(f) => f.is_no_unique_address, + Self::Proto(f) => f.proto.is_no_unique_address(), + } + } + + pub fn access(&self) -> AccessSpecifier { + match self { + Self::Owned(f) => f.access, + Self::Proto(f) => match f.proto.access() { + ir_rust_proto::AccessSpecifier::Public => AccessSpecifier::Public, + ir_rust_proto::AccessSpecifier::Protected => AccessSpecifier::Protected, + ir_rust_proto::AccessSpecifier::Private => AccessSpecifier::Private, + _ => AccessSpecifier::Public, + }, + } + } + + pub fn is_mutable(&self) -> bool { + match self { + Self::Owned(f) => f.is_mutable, + Self::Proto(f) => f.proto.is_mutable(), + } + } + + pub fn unknown_attr(&self) -> &Result>, String> { + match self { + Self::Owned(f) => &f.unknown_attr, + Self::Proto(f) => &f.unknown_attr, + } + } + + pub fn deprecated(&self) -> Option> { + match self { + Self::Owned(f) => f.deprecated.clone(), + Self::Proto(f) => f.proto.deprecated_opt().map(|s| Rc::from(s.to_str().unwrap())), + } + } + + pub fn is_inheritable(&self) -> bool { + match self { + Self::Owned(f) => f.is_inheritable, + Self::Proto(f) => f.proto.is_inheritable(), + } + } +} + +impl Debug for Field { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut debug_struct = f.debug_struct("Field"); + debug_struct.field("rust_identifier", &self.rust_identifier()); + debug_struct.field("cpp_identifier", &self.cpp_identifier()); + debug_struct.field("doc_comment", &self.doc_comment()); + debug_struct.field("type_", self.type_()); + debug_struct.field("access", &self.access()); + debug_struct.field("offset", &self.offset()); + debug_struct.field("size", &self.size()); + debug_struct.field("unknown_attr", self.unknown_attr()); + debug_struct.field("is_no_unique_address", &self.is_no_unique_address()); + debug_struct.field("is_bitfield", &self.is_bitfield()); + debug_struct.field("is_inheritable", &self.is_inheritable()); + debug_struct.field("is_mutable", &self.is_mutable()); + debug_struct.field("deprecated", &self.deprecated()); + debug_struct.finish() + } +} + +#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone, Deserialize)] pub enum SpecialMemberFunc { Trivial, NontrivialMembers, @@ -1103,6 +1343,16 @@ impl GenericItem for IncompleteRecord { } } +impl IncompleteRecord { + pub fn cc_name(&self) -> &Identifier { + &self.cc_name + } + + pub fn rs_name(&self) -> &Identifier { + &self.rs_name + } +} + #[derive(Debug, PartialEq, Eq, Hash, Copy, Clone, Deserialize)] pub enum RecordType { Struct, @@ -1131,7 +1381,7 @@ impl ToTokens for RecordType { } } -#[derive(Debug, PartialEq, Eq, Hash, Clone, Deserialize)] +#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone, Deserialize)] #[serde(deny_unknown_fields)] pub struct SizeAlign { pub size: usize, @@ -1253,7 +1503,7 @@ pub struct OwnedPtrConfig { #[derive(Debug, PartialEq, Eq, Hash, Clone, Deserialize)] #[serde(deny_unknown_fields)] -pub struct Record { +pub struct DeserializedRecord { pub rs_name: Identifier, /// The C++ name of the record. If the record is a template specialization, the fully qualified /// name is used. Otherwise, the only the name of the record is used. @@ -1322,35 +1572,565 @@ pub struct Record { pub children: Vec, } +#[derive(Clone)] +pub struct ProtoRecord { + pub(crate) proto: ir_rust_proto::RecordView<'static>, + pub(crate) fields: Vec, + pub(crate) unambiguous_public_bases: Vec, + pub(crate) lifetime_params: Vec, + pub(crate) children: Vec, + pub(crate) lifetime_inputs: Vec>, + pub(crate) template_specialization: Option, + pub(crate) bridge_type: Option, + pub(crate) owned_ptr_config: Option, + pub(crate) trait_derives: TraitDerives, + pub(crate) size_align: SizeAlign, +} + +#[derive(Clone)] +pub enum Record { + Owned(DeserializedRecord), + Proto(ProtoRecord), +} + +impl<'de> Deserialize<'de> for Record { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let deserialized = DeserializedRecord::deserialize(deserializer)?; + Ok(Self::Owned(deserialized)) + } +} + impl GenericItem for Record { fn id(&self) -> ItemId { - self.id + self.id() } fn unique_name(&self) -> Option> { - Some(self.unique_name.clone()) + Some(Rc::from(self.unique_name())) } fn owning_target(&self) -> Option { - Some(self.owning_target.clone()) + Some(self.owning_target()) } fn unsupported_kind(&self) -> UnsupportedItemKind { - self.record_type.unsupported_item_kind() + self.record_type().unsupported_item_kind() } fn source_loc(&self) -> Option> { - Some(self.source_loc.clone()) + Some(Rc::from(self.source_loc())) } fn unknown_attr(&self) -> Option> { - self.unknown_attr.clone() + self.unknown_attr().map(Rc::from) } fn must_bind(&self) -> bool { - self.must_bind + self.must_bind() + } +} + +impl PartialEq for Record { + fn eq(&self, other: &Self) -> bool { + self.id() == other.id() + && self.rs_name() == other.rs_name() + && self.cc_name() == other.cc_name() + && self.unique_name() == other.unique_name() + && self.mangled_cc_name() == other.mangled_cc_name() + && self.owning_target() == other.owning_target() + && self.template_specialization() == other.template_specialization() + && self.unknown_attr() == other.unknown_attr() + && self.doc_comment() == other.doc_comment() + && self.bridge_type() == other.bridge_type() + && self.owned_ptr_config() == other.owned_ptr_config() + && self.source_loc() == other.source_loc() + && self.unambiguous_public_bases() == other.unambiguous_public_bases() + && self.fields() == other.fields() + && self.lifetime_params() == other.lifetime_params() + && self.size_align() == other.size_align() + && self.trait_derives() == other.trait_derives() + && self.is_derived_class() == other.is_derived_class() + && self.override_alignment() == other.override_alignment() + && self.safety_annotation() == other.safety_annotation() + && self.copy_constructor() == other.copy_constructor() + && self.move_constructor() == other.move_constructor() + && self.destructor() == other.destructor() + && self.is_trivial_abi() == other.is_trivial_abi() + && self.is_inheritable() == other.is_inheritable() + && self.is_abstract() == other.is_abstract() + && self.nodiscard() == other.nodiscard() + && self.record_type() == other.record_type() + && self.is_aggregate() == other.is_aggregate() + && self.is_canonical_alias() == other.is_canonical_alias() + && self.enclosing_item_id() == other.enclosing_item_id() + && self.must_bind() == other.must_bind() + && self.overloads_operator_delete() == other.overloads_operator_delete() + && self.has_private_or_deleted_operator_delete() + == other.has_private_or_deleted_operator_delete() + && self.lifetime_inputs() == other.lifetime_inputs() + && self.detected_formatter() == other.detected_formatter() + && self.deprecated() == other.deprecated() + && self.is_thread_safe() == other.is_thread_safe() + && self.is_explicit_class_template_instantiation_definition() + == other.is_explicit_class_template_instantiation_definition() + && self.children() == other.children() + } +} + +impl Eq for Record {} + +impl Hash for Record { + fn hash(&self, state: &mut H) { + self.id().hash(state); + } +} + +impl Debug for Record { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut debug_struct = f.debug_struct("Record"); + debug_struct.field("rs_name", &self.rs_name()); + debug_struct.field("cc_name", &self.cc_name()); + debug_struct.field("unique_name", &self.unique_name()); + debug_struct.field("mangled_cc_name", &self.mangled_cc_name()); + debug_struct.field("id", &self.id()); + debug_struct.field("owning_target", &self.owning_target()); + debug_struct.field("template_specialization", &self.template_specialization()); + debug_struct.field("unknown_attr", &self.unknown_attr()); + debug_struct.field("doc_comment", &self.doc_comment()); + debug_struct.field("bridge_type", &self.bridge_type()); + debug_struct.field("owned_ptr_config", &self.owned_ptr_config()); + debug_struct.field("source_loc", &self.source_loc()); + debug_struct.field("unambiguous_public_bases", &self.unambiguous_public_bases()); + debug_struct.field("fields", &self.fields()); + debug_struct.field("lifetime_params", &self.lifetime_params()); + debug_struct.field("size_align", &self.size_align()); + debug_struct.field("trait_derives", &self.trait_derives()); + debug_struct.field("is_derived_class", &self.is_derived_class()); + debug_struct.field("override_alignment", &self.override_alignment()); + debug_struct.field("safety_annotation", &self.safety_annotation()); + debug_struct.field("copy_constructor", &self.copy_constructor()); + debug_struct.field("move_constructor", &self.move_constructor()); + debug_struct.field("destructor", &self.destructor()); + debug_struct.field("is_trivial_abi", &self.is_trivial_abi()); + debug_struct.field("is_inheritable", &self.is_inheritable()); + debug_struct.field("is_abstract", &self.is_abstract()); + debug_struct.field("nodiscard", &self.nodiscard()); + debug_struct.field("record_type", &self.record_type()); + debug_struct.field("is_aggregate", &self.is_aggregate()); + debug_struct.field("is_canonical_alias", &self.is_canonical_alias()); + debug_struct.field("enclosing_item_id", &self.enclosing_item_id()); + debug_struct.field("must_bind", &self.must_bind()); + debug_struct.field("overloads_operator_delete", &self.overloads_operator_delete()); + debug_struct.field( + "has_private_or_deleted_operator_delete", + &self.has_private_or_deleted_operator_delete(), + ); + debug_struct.field("lifetime_inputs", &self.lifetime_inputs()); + debug_struct.field("detected_formatter", &self.detected_formatter()); + debug_struct.field("deprecated", &self.deprecated()); + debug_struct.field("is_thread_safe", &self.is_thread_safe()); + debug_struct.field( + "is_explicit_class_template_instantiation_definition", + &self.is_explicit_class_template_instantiation_definition(), + ); + debug_struct.field("children", &self.children()); + debug_struct.finish() } } impl Record { + pub fn rs_name(&self) -> Identifier { + match self { + Self::Owned(r) => r.rs_name.clone(), + Self::Proto(r) => Identifier::Static(r.proto.rs_name().identifier().to_str().unwrap()), + } + } + + pub fn rs_name_as_str(&self) -> &str { + match self { + Self::Owned(r) => r.rs_name.as_str(), + Self::Proto(r) => r.proto.rs_name().identifier().to_str().unwrap(), + } + } + + pub fn cc_name(&self) -> Identifier { + match self { + Self::Owned(r) => r.cc_name.clone(), + Self::Proto(r) => Identifier::Static(r.proto.cc_name().identifier().to_str().unwrap()), + } + } + + pub fn cc_name_as_str(&self) -> &str { + match self { + Self::Owned(r) => r.cc_name.as_str(), + Self::Proto(r) => r.proto.cc_name().identifier().to_str().unwrap(), + } + } + + pub fn unique_name(&self) -> &str { + match self { + Self::Owned(r) => &r.unique_name, + Self::Proto(r) => r.proto.unique_name().to_str().unwrap(), + } + } + + pub fn mangled_cc_name(&self) -> &str { + match self { + Self::Owned(r) => &r.mangled_cc_name, + Self::Proto(r) => r.proto.mangled_cc_name().to_str().unwrap(), + } + } + + pub fn id(&self) -> ItemId { + match self { + Self::Owned(r) => r.id, + Self::Proto(r) => ItemId(r.proto.id() as usize), + } + } + + pub fn owning_target(&self) -> BazelLabel { + match self { + Self::Owned(r) => r.owning_target.clone(), + Self::Proto(r) => BazelLabel::from(r.proto.owning_target().to_str().unwrap()), + } + } + + pub fn template_specialization(&self) -> Option<&TemplateSpecialization> { + match self { + Self::Owned(r) => r.template_specialization.as_ref(), + Self::Proto(r) => r.template_specialization.as_ref(), + } + } + + pub fn bridge_type(&self) -> Option<&BridgeType> { + match self { + Self::Owned(r) => r.bridge_type.as_ref(), + Self::Proto(r) => r.bridge_type.as_ref(), + } + } + + pub fn is_thread_safe(&self) -> bool { + match self { + Self::Owned(r) => r.is_thread_safe, + Self::Proto(r) => r.proto.is_thread_safe(), + } + } + + pub fn trait_derives(&self) -> &TraitDerives { + match self { + Self::Owned(r) => &r.trait_derives, + Self::Proto(r) => &r.trait_derives, + } + } + + pub fn safety_annotation(&self) -> SafetyAnnotation { + match self { + Self::Owned(r) => r.safety_annotation, + Self::Proto(r) => match r.proto.safety_annotation() { + ir_rust_proto::SafetyAnnotation::DisableUnsafe => SafetyAnnotation::DisableUnsafe, + ir_rust_proto::SafetyAnnotation::Unsafe => SafetyAnnotation::Unsafe, + ir_rust_proto::SafetyAnnotation::Unannotated => SafetyAnnotation::Unannotated, + _ => SafetyAnnotation::Unannotated, + }, + } + } + + pub fn fields(&self) -> &[Field] { + match self { + Self::Owned(r) => &r.fields, + Self::Proto(r) => &r.fields, + } + } + + pub fn children(&self) -> &[Item] { + match self { + Self::Owned(r) => &r.children, + Self::Proto(r) => &r.children, + } + } + + pub fn size_align(&self) -> &SizeAlign { + match self { + Self::Owned(r) => &r.size_align, + Self::Proto(r) => &r.size_align, + } + } + + pub fn is_trivial_abi(&self) -> bool { + match self { + Self::Owned(r) => r.is_trivial_abi, + Self::Proto(r) => r.proto.is_trivial_abi(), + } + } + + pub fn is_inheritable(&self) -> bool { + match self { + Self::Owned(r) => r.is_inheritable, + Self::Proto(r) => r.proto.is_inheritable(), + } + } + + pub fn is_abstract(&self) -> bool { + match self { + Self::Owned(r) => r.is_abstract, + Self::Proto(r) => r.proto.is_abstract(), + } + } + + pub fn record_type(&self) -> RecordType { + match self { + Self::Owned(r) => r.record_type, + Self::Proto(r) => match r.proto.record_type() { + ir_rust_proto::RecordType::Struct => RecordType::Struct, + ir_rust_proto::RecordType::Union => RecordType::Union, + ir_rust_proto::RecordType::Class => RecordType::Class, + _ => RecordType::Struct, + }, + } + } + + pub fn is_canonical_alias(&self) -> bool { + match self { + Self::Owned(r) => r.is_canonical_alias, + Self::Proto(r) => r.proto.is_canonical_alias(), + } + } + + pub fn enclosing_item_id(&self) -> Option { + match self { + Self::Owned(r) => r.enclosing_item_id, + Self::Proto(r) => r.proto.enclosing_item_id_opt().map(|id| ItemId(id as usize)), + } + } + + pub fn must_bind(&self) -> bool { + match self { + Self::Owned(r) => r.must_bind, + Self::Proto(r) => r.proto.must_bind(), + } + } + + pub fn copy_constructor(&self) -> SpecialMemberFunc { + match self { + Self::Owned(r) => r.copy_constructor, + Self::Proto(r) => match r.proto.copy_constructor() { + ir_rust_proto::SpecialMemberFunc::Trivial => SpecialMemberFunc::Trivial, + ir_rust_proto::SpecialMemberFunc::NontrivialMembers => { + SpecialMemberFunc::NontrivialMembers + } + ir_rust_proto::SpecialMemberFunc::NontrivialUserDefined => { + SpecialMemberFunc::NontrivialUserDefined + } + ir_rust_proto::SpecialMemberFunc::Unavailable => SpecialMemberFunc::Unavailable, + _ => SpecialMemberFunc::Trivial, + }, + } + } + + pub fn move_constructor(&self) -> SpecialMemberFunc { + match self { + Self::Owned(r) => r.move_constructor, + Self::Proto(r) => match r.proto.move_constructor() { + ir_rust_proto::SpecialMemberFunc::Trivial => SpecialMemberFunc::Trivial, + ir_rust_proto::SpecialMemberFunc::NontrivialMembers => { + SpecialMemberFunc::NontrivialMembers + } + ir_rust_proto::SpecialMemberFunc::NontrivialUserDefined => { + SpecialMemberFunc::NontrivialUserDefined + } + ir_rust_proto::SpecialMemberFunc::Unavailable => SpecialMemberFunc::Unavailable, + _ => SpecialMemberFunc::Trivial, + }, + } + } + + pub fn destructor(&self) -> SpecialMemberFunc { + match self { + Self::Owned(r) => r.destructor, + Self::Proto(r) => match r.proto.destructor() { + ir_rust_proto::SpecialMemberFunc::Trivial => SpecialMemberFunc::Trivial, + ir_rust_proto::SpecialMemberFunc::NontrivialMembers => { + SpecialMemberFunc::NontrivialMembers + } + ir_rust_proto::SpecialMemberFunc::NontrivialUserDefined => { + SpecialMemberFunc::NontrivialUserDefined + } + ir_rust_proto::SpecialMemberFunc::Unavailable => SpecialMemberFunc::Unavailable, + _ => SpecialMemberFunc::Trivial, + }, + } + } + + pub fn is_derived_class(&self) -> bool { + match self { + Self::Owned(r) => r.is_derived_class, + Self::Proto(r) => r.proto.is_derived_class(), + } + } + + pub fn override_alignment(&self) -> bool { + match self { + Self::Owned(r) => r.override_alignment, + Self::Proto(r) => r.proto.override_alignment(), + } + } + + pub fn source_loc(&self) -> &str { + match self { + Self::Owned(r) => &r.source_loc, + Self::Proto(r) => r.proto.source_loc().to_str().unwrap(), + } + } + + pub fn lifetime_params(&self) -> &[LifetimeName] { + match self { + Self::Owned(r) => &r.lifetime_params, + Self::Proto(r) => &r.lifetime_params, + } + } + + pub fn doc_comment(&self) -> Option<&str> { + match self { + Self::Owned(r) => r.doc_comment.as_deref(), + Self::Proto(r) => r.proto.doc_comment_opt().map(|s| s.to_str().unwrap()), + } + } + + pub fn deprecated(&self) -> Option> { + match self { + Self::Owned(r) => r.deprecated.clone(), + Self::Proto(r) => r.proto.deprecated_opt().map(|s| Rc::from(s.to_str().unwrap())), + } + } + + // Setters for test mutation + pub fn set_is_trivial_abi(&mut self, val: bool) { + match self { + Self::Owned(r) => r.is_trivial_abi = val, + Self::Proto(_) => panic!("Cannot mutate Proto-backed Record"), + } + } + + pub fn set_copy_constructor(&mut self, val: SpecialMemberFunc) { + match self { + Self::Owned(r) => r.copy_constructor = val, + Self::Proto(_) => panic!("Cannot mutate Proto-backed Record"), + } + } + + pub fn set_destructor(&mut self, val: SpecialMemberFunc) { + match self { + Self::Owned(r) => r.destructor = val, + Self::Proto(_) => panic!("Cannot mutate Proto-backed Record"), + } + } + + pub fn set_rs_name(&mut self, val: Identifier) { + match self { + Self::Owned(r) => r.rs_name = val, + Self::Proto(_) => panic!("Cannot mutate Proto-backed Record"), + } + } + + pub fn set_cc_name(&mut self, val: Identifier) { + match self { + Self::Owned(r) => r.cc_name = val, + Self::Proto(_) => panic!("Cannot mutate Proto-backed Record"), + } + } + + pub fn set_id(&mut self, val: ItemId) { + match self { + Self::Owned(r) => r.id = val, + Self::Proto(_) => panic!("Cannot mutate Proto-backed Record"), + } + } + + pub fn children_mut(&mut self) -> &mut Vec { + match self { + Self::Owned(r) => &mut r.children, + Self::Proto(_) => panic!("Cannot mutate Proto-backed Record"), + } + } + + pub fn lifetime_inputs_mut(&mut self) -> &mut Vec> { + match self { + Self::Owned(r) => &mut r.lifetime_inputs, + Self::Proto(_) => panic!("Cannot mutate Proto-backed Record"), + } + } + + pub fn unambiguous_public_bases(&self) -> &[BaseClass] { + match self { + Self::Owned(r) => &r.unambiguous_public_bases, + Self::Proto(r) => &r.unambiguous_public_bases, + } + } + + pub fn owned_ptr_config(&self) -> Option<&OwnedPtrConfig> { + match self { + Self::Owned(r) => r.owned_ptr_config.as_ref(), + Self::Proto(r) => r.owned_ptr_config.as_ref(), + } + } + + pub fn overloads_operator_delete(&self) -> bool { + match self { + Self::Owned(r) => r.overloads_operator_delete, + Self::Proto(r) => r.proto.overloads_operator_delete(), + } + } + + pub fn has_private_or_deleted_operator_delete(&self) -> bool { + match self { + Self::Owned(r) => r.has_private_or_deleted_operator_delete, + Self::Proto(r) => r.proto.has_private_or_deleted_operator_delete(), + } + } + + pub fn detected_formatter(&self) -> bool { + match self { + Self::Owned(r) => r.detected_formatter, + Self::Proto(r) => r.proto.detected_formatter(), + } + } + + pub fn is_explicit_class_template_instantiation_definition(&self) -> bool { + match self { + Self::Owned(r) => r.is_explicit_class_template_instantiation_definition, + Self::Proto(r) => r.proto.is_explicit_class_template_instantiation_definition(), + } + } + + pub fn is_aggregate(&self) -> bool { + match self { + Self::Owned(r) => r.is_aggregate, + Self::Proto(r) => r.proto.is_aggregate(), + } + } + + pub fn unknown_attr(&self) -> Option<&str> { + match self { + Self::Owned(r) => r.unknown_attr.as_deref(), + Self::Proto(r) => r.proto.unknown_attr_opt().map(|s| s.to_str().unwrap()), + } + } + + pub fn nodiscard(&self) -> Option<&str> { + match self { + Self::Owned(r) => r.nodiscard.as_deref(), + Self::Proto(r) => r.proto.nodiscard_opt().map(|s| s.to_str().unwrap()), + } + } + + pub fn lifetime_inputs(&self) -> &[Rc] { + match self { + Self::Owned(r) => &r.lifetime_inputs, + Self::Proto(r) => &r.lifetime_inputs, + } + } + /// Whether this type has Rust-like object semantics for mutating /// assignment, and can be passed by mut reference as a result. /// - /// If a type `T` is mut reference safe, it can be possed as a `&mut T` + /// If a type `T` is mut reference safe, it can be passed as a `&mut T` /// safely. Otherwise, mutable references must use `Pin<&mut T>`. /// /// In C++, this is called "trivially relocatable". Such types can be passed @@ -1359,7 +2139,7 @@ impl Record { /// /// Described in more detail at: docs/design/unpin.md pub fn is_unpin(&self) -> bool { - self.is_trivial_abi + self.is_trivial_abi() } // TODO(b/498977848): The record with cc_name @@ -1368,7 +2148,7 @@ impl Record { // TemplateSpecialization kind NonSpecial. This is unfortunate, since we want to exclude all // flavors of string_view because of our special-casing. pub fn is_string_view(&self) -> bool { - match &self.template_specialization { + match self.template_specialization() { Some(TemplateSpecialization { defining_target, kind, .. }) => { let is_in_cc_std = *defining_target == BazelLabel("//support/cc_std:cc_std".into()) @@ -1383,7 +2163,7 @@ impl Record { if is_string_view { return true; }; - self.cc_name.as_str().starts_with("std::basic_string_view<") + self.cc_name().as_str().starts_with("std::basic_string_view<") } else { false } @@ -1396,13 +2176,13 @@ impl Record { /// special-case this. pub fn is_raw_string_view(&self) -> bool { matches!( - self.template_specialization, + self.template_specialization(), Some(TemplateSpecialization { kind: TemplateSpecializationKind::StdStringView, .. }) - ) && self.rs_name.identifier.as_ref() == "raw_string_view" + ) && self.rs_name().as_str() == "raw_string_view" } pub fn is_union(&self) -> bool { - match self.record_type { + match self.record_type() { RecordType::Union => true, RecordType::Struct | RecordType::Class => false, } @@ -1414,15 +2194,15 @@ impl Record { /// to a record type. (For example, typedefs to anonymous records, or template specializations /// with a `preferred_name`.) pub fn cc_tag_kind(&self) -> TokenStream { - if self.is_canonical_alias { + if self.is_canonical_alias() { quote! {} } else { - self.record_type.into_token_stream() + self.record_type().into_token_stream() } } pub fn should_implement_drop(&self) -> bool { - match self.destructor { + match self.destructor() { SpecialMemberFunc::Trivial => false, // TODO(jeanpierreda): b/212690698 - Avoid calling into the C++ destructor @@ -1446,21 +2226,21 @@ impl Record { pub fn should_derive_copy(&self) -> bool { // Thread-safe types wrap their fields in UnsafeCell<[MaybeUninit; N]>, // which prevents them from deriving Copy. - if self.is_thread_safe { + if self.is_thread_safe() { return false; } - match self.trait_derives.copy { + match self.trait_derives().copy { TraitImplPolarity::Positive => true, TraitImplPolarity::Negative => false, TraitImplPolarity::None => { self.is_unpin() - && self.copy_constructor == SpecialMemberFunc::Trivial - && self.destructor == SpecialMemberFunc::Trivial + && self.copy_constructor() == SpecialMemberFunc::Trivial + && self.destructor() == SpecialMemberFunc::Trivial && self.check_by_value().is_ok() - && self.trait_derives.clone != TraitImplPolarity::Negative + && self.trait_derives().clone != TraitImplPolarity::Negative // Mutable fields become `Cell` in Rust, which prevents // the struct from deriving `Copy`. - && self.fields.iter().all(|f| !f.is_mutable) + && self.fields().iter().all(|f| !f.is_mutable()) } } } @@ -1470,14 +2250,14 @@ impl Record { /// This does not necessarily imply that the type is Rust-movable, e.g. trivially relocatable. pub fn check_by_value(&self) -> Result<()> { ensure!( - self.destructor != SpecialMemberFunc::Unavailable, + self.destructor() != SpecialMemberFunc::Unavailable, "`{}` can't be used by-value because it has a non-public or deleted destructor", - self.cc_name + self.cc_name() ); ensure!( - !self.is_abstract, + !self.is_abstract(), "`{}` can be used by-value because it has pure virtual functions that are not overridden", - self.cc_name + self.cc_name() ); Ok(()) } @@ -1487,7 +2267,7 @@ impl Record { /// Notably, all records that have a unique owning target are supported, e.g. `std::string`, but /// not all supported records have a unique owning target, e.g. `std::vector`. pub fn has_unique_owning_target(self: &Record) -> bool { - self.template_specialization.is_none() || self.is_canonical_alias + self.template_specialization().is_none() || self.is_canonical_alias() } } @@ -1538,6 +2318,16 @@ impl GenericItem for Constant { } } +impl Constant { + pub fn cc_name(&self) -> &Identifier { + &self.cc_name + } + + pub fn rs_name(&self) -> &Identifier { + &self.rs_name + } +} + #[derive(Debug, PartialEq, Eq, Hash, Clone, Deserialize)] #[serde(deny_unknown_fields)] pub struct GlobalVar { @@ -1586,6 +2376,16 @@ impl GenericItem for GlobalVar { } } +impl GlobalVar { + pub fn cc_name(&self) -> &Identifier { + &self.cc_name + } + + pub fn rs_name(&self) -> &Identifier { + &self.rs_name + } +} + #[derive(Debug, PartialEq, Eq, Hash, Clone, Deserialize)] #[serde(deny_unknown_fields)] pub struct Enum { @@ -1643,6 +2443,32 @@ impl GenericItem for Enum { } } +impl Enum { + pub fn cc_name(&self) -> &Identifier { + &self.cc_name + } + + pub fn rs_name(&self) -> &Identifier { + &self.rs_name + } + + pub fn enumerators(&self) -> Option<&[Enumerator]> { + self.enumerators.as_deref() + } + + pub fn underlying_type(&self) -> &CcType { + &self.underlying_type + } + + pub fn detected_formatter(&self) -> bool { + self.detected_formatter + } + + pub fn owning_target(&self) -> &BazelLabel { + &self.owning_target + } +} + #[derive(Debug, PartialEq, Eq, Hash, Clone, Deserialize)] #[serde(deny_unknown_fields)] pub struct Enumerator { @@ -1658,6 +2484,24 @@ pub struct Enumerator { pub doc_comment: Option>, } +impl Enumerator { + pub fn identifier(&self) -> &Identifier { + &self.identifier + } + + pub fn value(&self) -> IntegerConstant { + self.value + } + + pub fn unknown_attr(&self) -> Option<&str> { + self.unknown_attr.as_deref() + } + + pub fn deprecated(&self) -> Option> { + self.deprecated.clone() + } +} + #[derive(Debug, PartialEq, Eq, Hash, Clone, Deserialize)] #[serde(deny_unknown_fields)] pub struct TypeAlias { @@ -1706,6 +2550,32 @@ impl GenericItem for TypeAlias { } } +impl TypeAlias { + pub fn cc_name(&self) -> &Identifier { + &self.cc_name + } + + pub fn rs_name(&self) -> &Identifier { + &self.rs_name + } + + pub fn lifetime_inputs(&self) -> &[Rc] { + &self.lifetime_inputs + } + + pub fn lifetime_inputs_mut(&mut self) -> &mut Vec> { + &mut self.lifetime_inputs + } + + pub fn underlying_type(&self) -> &CcType { + &self.underlying_type + } + + pub fn underlying_type_mut(&mut self) -> &mut CcType { + &mut self.underlying_type + } +} + impl Display for TypeAlias { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{} ({}, {})", self.rs_name, self.owning_target, self.source_loc) @@ -1957,6 +2827,24 @@ impl GenericItem for Namespace { } } +impl Namespace { + pub fn cc_name(&self) -> &Identifier { + &self.cc_name + } + + pub fn rs_name(&self) -> &Identifier { + &self.rs_name + } + + pub fn children(&self) -> &[Item] { + &self.children + } + + pub fn children_mut(&mut self) -> &mut Vec { + &mut self.children + } +} + #[derive(Debug, PartialEq, Eq, Hash, Clone, Deserialize)] #[serde(deny_unknown_fields)] pub struct UseMod { @@ -1990,6 +2878,12 @@ impl GenericItem for UseMod { } } +impl UseMod { + pub fn mod_name(&self) -> &Identifier { + &self.mod_name + } +} + /// A C++ type annotated with CRUBIT_INTERNAL_RUST_TYPE, indicating that Crubit should use the /// existing Rust type instead of generating a new Rust type. Note that this corresponds to concrete /// types, meaning non-template types or template instantiations, but not uninstantiated template @@ -2127,7 +3021,7 @@ impl GenericItem for Item { impl Item { pub fn enclosing_item_id(&self) -> Option { match self { - Item::Record(record) => record.enclosing_item_id, + Item::Record(record) => record.enclosing_item_id(), Item::IncompleteRecord(record) => record.enclosing_item_id, Item::Enum(enum_) => enum_.enclosing_item_id, Item::Constant(constant) => constant.enclosing_item_id, @@ -2164,27 +3058,23 @@ impl Item { } /// Returns the C++ identifier for this item, if it has one. - pub fn cc_name_as_str(&self) -> Option> { + pub fn cc_name_as_str(&self) -> Option<&str> { match self { - Item::Func(func) => match &func.cc_name { - UnqualifiedIdentifier::Identifier(identifier) => { - Some(identifier.identifier.clone()) - } + Item::Func(func) => match func.cc_name() { + UnqualifiedIdentifier::Identifier(identifier) => Some(identifier.as_str()), _ => None, }, - Item::IncompleteRecord(incomplete_record) => { - Some(incomplete_record.cc_name.identifier.clone()) - } - Item::Record(record) => Some(record.cc_name.identifier.clone()), - Item::Enum(enum_) => Some(enum_.cc_name.identifier.clone()), - Item::Constant(constant) => Some(constant.cc_name.identifier.clone()), - Item::GlobalVar(global_var) => Some(global_var.cc_name.identifier.clone()), - Item::TypeAlias(type_alias) => Some(type_alias.cc_name.identifier.clone()), - Item::Namespace(namespace) => Some(namespace.cc_name.identifier.clone()), + Item::IncompleteRecord(incomplete_record) => Some(incomplete_record.cc_name().as_str()), + Item::Record(record) => Some(record.cc_name_as_str()), + Item::Enum(enum_) => Some(enum_.cc_name().as_str()), + Item::Constant(constant) => Some(constant.cc_name().as_str()), + Item::GlobalVar(global_var) => Some(global_var.cc_name().as_str()), + Item::TypeAlias(type_alias) => Some(type_alias.cc_name().as_str()), + Item::Namespace(namespace) => Some(namespace.cc_name().as_str()), Item::UnsupportedItem(_) => None, Item::Comment(_) => None, Item::UseMod(_) => None, - Item::ExistingRustType(existing_rust_type) => Some(existing_rust_type.cc_name.clone()), + Item::ExistingRustType(existing_rust_type) => Some(&*existing_rust_type.cc_name), } } @@ -2590,16 +3480,13 @@ mod tests { #[gtest] fn test_identifier_debug_print() { - assert_eq!(format!("{:?}", Identifier { identifier: "hello".into() }), "\"hello\""); + assert_eq!(format!("{:?}", Identifier::new("hello")), "\"hello\""); } #[gtest] fn test_unqualified_identifier_debug_print() { assert_eq!( - format!( - "{:?}", - UnqualifiedIdentifier::Identifier(Identifier { identifier: "hello".into() }) - ), + format!("{:?}", UnqualifiedIdentifier::Identifier(Identifier::new("hello"))), "\"hello\"" ); assert_eq!(format!("{:?}", UnqualifiedIdentifier::Constructor), "Constructor"); diff --git a/rs_bindings_from_cc/ir_from_cc_proto_test.rs b/rs_bindings_from_cc/ir_from_cc_proto_test.rs index 3dcbd8b6c..3d3c5a843 100644 --- a/rs_bindings_from_cc/ir_from_cc_proto_test.rs +++ b/rs_bindings_from_cc/ir_from_cc_proto_test.rs @@ -15,16 +15,10 @@ fn test_func_proto() -> Result<()> { let ir = get_ir("int f(int a, int b);")?; let func = ir.functions().find(|f| f.rs_name == "f").expect("should find func f from the source code"); - assert_eq!(func.cc_name.as_identifier().unwrap().identifier.as_ref(), "f"); + assert_eq!(func.cc_name.as_identifier().unwrap().as_str(), "f"); assert_eq!(func.params.len(), 2); - assert_eq!( - func.params.first().expect("should have parameter 'a'").identifier.identifier.as_ref(), - "a" - ); - assert_eq!( - func.params.get(1).expect("should have parameter 'b'").identifier.identifier.as_ref(), - "b" - ); + assert_eq!(func.params.first().expect("should have parameter 'a'").identifier.as_str(), "a"); + assert_eq!(func.params.get(1).expect("should have parameter 'b'").identifier.as_str(), "b"); Ok(()) } @@ -33,20 +27,12 @@ fn test_record_proto() -> Result<()> { let ir = get_ir("struct MyStruct { int a; };")?; let record = ir .records() - .find(|r| r.cc_name == "MyStruct") + .find(|r| r.cc_name_as_str() == "MyStruct") .expect("should find struct MyStruct from the source code"); - assert_eq!(record.cc_name.identifier.as_ref(), "MyStruct"); - assert_eq!(record.fields.len(), 1); + assert_eq!(record.cc_name_as_str(), "MyStruct"); + assert_eq!(record.fields().len(), 1); assert_eq!( - record - .fields - .first() - .expect("should have field 'a'") - .cpp_identifier - .as_ref() - .unwrap() - .identifier - .as_ref(), + record.fields().first().expect("should have field 'a'").cpp_identifier().unwrap().as_str(), "a" ); Ok(()) @@ -57,8 +43,8 @@ fn test_function_with_asm_label_proto() -> Result<()> { let ir = get_ir("int f(int a, int b) asm(\"foo\");")?; let func = ir.functions().find(|f| f.rs_name == "f").expect("should find func f from the source code"); - assert_eq!(func.cc_name.as_identifier().unwrap().identifier.as_ref(), "f"); - assert_eq!(func.rs_name.as_identifier().unwrap().identifier.as_ref(), "f"); + assert_eq!(func.cc_name.as_identifier().unwrap().as_str(), "f"); + assert_eq!(func.rs_name.as_identifier().unwrap().as_str(), "f"); match multiplatform_testing::test_platform() { multiplatform_testing::Platform::ArmMacOS | multiplatform_testing::Platform::X86MacOS => { @@ -78,11 +64,11 @@ fn test_function_with_unnamed_parameters_proto() -> Result<()> { ir.functions().find(|f| f.rs_name == "f").expect("should find func f from the source code"); assert_eq!(func.params.len(), 2); assert_eq!( - func.params.first().expect("should have parameter 0").identifier.identifier.as_ref(), + func.params.first().expect("should have parameter 0").identifier.as_str(), "__param_0" ); assert_eq!( - func.params.get(1).expect("should have parameter 1").identifier.identifier.as_ref(), + func.params.get(1).expect("should have parameter 1").identifier.as_str(), "__param_1" ); Ok(()) @@ -95,15 +81,15 @@ fn test_unescapable_rust_keywords_in_function_parameters_proto() -> Result<()> { ir.functions().find(|f| f.rs_name == "f").expect("should find func f from the source code"); assert_eq!(func.params.len(), 3); assert_eq!( - func.params.first().expect("should have parameter 0").identifier.identifier.as_ref(), + func.params.first().expect("should have parameter 0").identifier.as_str(), "__param_0" ); assert_eq!( - func.params.get(1).expect("should have parameter 1").identifier.identifier.as_ref(), + func.params.get(1).expect("should have parameter 1").identifier.as_str(), "__param_1" ); assert_eq!( - func.params.get(2).expect("should have parameter 2").identifier.identifier.as_ref(), + func.params.get(2).expect("should have parameter 2").identifier.as_str(), "__param_2" ); Ok(()) @@ -149,35 +135,35 @@ fn test_record_member_variable_access_specifiers_proto() -> Result<()> { let some_struct = ir .records() - .find(|r| r.cc_name == "SomeStruct") + .find(|r| r.cc_name_as_str() == "SomeStruct") .expect("should find struct SomeStruct from the source code"); - assert_eq!(some_struct.fields.len(), 4); + assert_eq!(some_struct.fields().len(), 4); - let f0 = some_struct.fields.first().expect("should have field 'default_access_int'"); - assert_eq!(f0.rust_identifier.as_ref().unwrap().identifier.as_ref(), "default_access_int"); - assert_eq!(f0.access, ir::AccessSpecifier::Public); + let f0 = some_struct.fields().first().expect("should have field 'default_access_int'"); + assert_eq!(f0.rust_identifier().unwrap().as_str(), "default_access_int"); + assert_eq!(f0.access(), ir::AccessSpecifier::Public); - let f1 = some_struct.fields.get(1).expect("should have field 'public_int'"); - assert_eq!(f1.rust_identifier.as_ref().unwrap().identifier.as_ref(), "public_int"); - assert_eq!(f1.access, ir::AccessSpecifier::Public); + let f1 = some_struct.fields().get(1).expect("should have field 'public_int'"); + assert_eq!(f1.rust_identifier().unwrap().as_str(), "public_int"); + assert_eq!(f1.access(), ir::AccessSpecifier::Public); - let f2 = some_struct.fields.get(2).expect("should have field 'protected_int'"); - assert_eq!(f2.rust_identifier.as_ref().unwrap().identifier.as_ref(), "protected_int"); - assert_eq!(f2.access, ir::AccessSpecifier::Protected); + let f2 = some_struct.fields().get(2).expect("should have field 'protected_int'"); + assert_eq!(f2.rust_identifier().unwrap().as_str(), "protected_int"); + assert_eq!(f2.access(), ir::AccessSpecifier::Protected); - let f3 = some_struct.fields.get(3).expect("should have field 'private_int'"); - assert_eq!(f3.rust_identifier.as_ref().unwrap().identifier.as_ref(), "private_int"); - assert_eq!(f3.access, ir::AccessSpecifier::Private); + let f3 = some_struct.fields().get(3).expect("should have field 'private_int'"); + assert_eq!(f3.rust_identifier().unwrap().as_str(), "private_int"); + assert_eq!(f3.access(), ir::AccessSpecifier::Private); let some_class = ir .records() - .find(|r| r.cc_name == "SomeClass") + .find(|r| r.cc_name_as_str() == "SomeClass") .expect("should find class SomeClass from the source code"); - assert_eq!(some_class.fields.len(), 1); - let cf0 = some_class.fields.first().expect("should have field 'default_access_int'"); - assert_eq!(cf0.rust_identifier.as_ref().unwrap().identifier.as_ref(), "default_access_int"); - assert_eq!(cf0.access, ir::AccessSpecifier::Private); + assert_eq!(some_class.fields().len(), 1); + let cf0 = some_class.fields().first().expect("should have field 'default_access_int'"); + assert_eq!(cf0.rust_identifier().unwrap().as_str(), "default_access_int"); + assert_eq!(cf0.access(), ir::AccessSpecifier::Private); Ok(()) } @@ -188,16 +174,16 @@ fn test_enum_proto() -> Result<()> { .enums() .find(|r| r.cc_name == "MyEnum") .expect("should find enum MyEnum from the source code"); - assert_eq!(enum_decl.cc_name.identifier.as_ref(), "MyEnum"); - assert_eq!(enum_decl.rs_name.identifier.as_ref(), "MyEnum"); + assert_eq!(enum_decl.cc_name.as_str(), "MyEnum"); + assert_eq!(enum_decl.rs_name.as_str(), "MyEnum"); let k_a = enum_decl.enumerators.as_ref().unwrap().first().expect("should have enumerator 'kA'"); - assert_eq!(k_a.identifier.identifier.as_ref(), "kA"); + assert_eq!(k_a.identifier.as_str(), "kA"); assert_eq!(k_a.value.wrapped_value, 42); assert!(!k_a.value.is_negative); let k_b = enum_decl.enumerators.as_ref().unwrap().get(1).expect("should have enumerator 'kB'"); - assert_eq!(k_b.identifier.identifier.as_ref(), "kB"); + assert_eq!(k_b.identifier.as_str(), "kB"); // In proto, wrapped_value is int64, so -1 cast to int64 is -1. assert_eq!(k_b.value.wrapped_value as i64, -1); assert!(k_b.value.is_negative); @@ -211,8 +197,8 @@ fn test_type_alias_proto() -> Result<()> { .type_aliases() .find(|t| t.cc_name == "MyInt") .expect("should find type alias MyInt from the source code"); - assert_eq!(type_alias.cc_name.identifier.as_ref(), "MyInt"); - assert_eq!(type_alias.rs_name.identifier.as_ref(), "MyInt"); + assert_eq!(type_alias.cc_name.as_str(), "MyInt"); + assert_eq!(type_alias.rs_name.as_str(), "MyInt"); Ok(()) } diff --git a/rs_bindings_from_cc/ir_from_cc_test.rs b/rs_bindings_from_cc/ir_from_cc_test.rs index fa6b57ff6..53a943515 100644 --- a/rs_bindings_from_cc/ir_from_cc_test.rs +++ b/rs_bindings_from_cc/ir_from_cc_test.rs @@ -276,11 +276,13 @@ fn test_unescapable_rust_keywords_in_anonymous_struct_type_alias() { #[gtest] fn test_unescapable_rust_keywords_in_field_name() { let ir = ir_from_cc("struct SomeStruct { int self; };").unwrap(); - let record = ir.records().find(|record| record.rs_name == "SomeStruct").unwrap(); - assert_eq!(record.fields.len(), 1); - let field = &record.fields[0]; - assert_eq!(field.rust_identifier.as_ref().map(|x| x.as_str()), Some("__field_0")); - assert_eq!(field.cpp_identifier.as_ref().map(|x| x.as_str()), Some("self")); + let record = ir.records().find(|record| record.rs_name() == "SomeStruct").unwrap(); + assert_eq!(record.fields().len(), 1); + let field = &record.fields()[0]; + let rust_id = field.rust_identifier(); + assert_eq!(rust_id.as_ref().map(|x| x.as_str()), Some("__field_0")); + let cpp_id = field.cpp_identifier(); + assert_eq!(cpp_id.as_ref().map(|x| x.as_str()), Some("self")); } #[gtest] @@ -655,8 +657,8 @@ fn test_struct_with_owned_ptr_type_annotation() -> googletest::Result<()> { .expect("Failed to generate IR from CC"); let record = - ir.records().find(|record| record.rs_name == "RecordWithOwnedPtrType").or_fail()?; - let owned_ptr_config = record.owned_ptr_config.as_ref().or_fail()?; + ir.records().find(|record| record.rs_name() == "RecordWithOwnedPtrType").or_fail()?; + let owned_ptr_config = record.owned_ptr_config().or_fail()?; expect_that!(&*owned_ptr_config.owned_ptr_type, eq("SomeOwnedPtrType")); Ok(()) } @@ -1134,10 +1136,8 @@ fn test_doc_comment() -> Result<()> { struct MultilineOneStar {}; "#, )?; - let comments: HashMap<_, _> = ir - .records() - .map(|r| (r.rs_name.identifier.as_ref(), r.doc_comment.as_ref().unwrap().as_ref())) - .collect(); + let comments: HashMap<_, _> = + ir.records().map(|r| (r.rs_name_as_str(), r.doc_comment().unwrap())).collect(); assert_eq!(comments["DocCommentSlashes"], "Doc comment\n\n * with three slashes"); assert_eq!(comments["DocCommentBang"], "Doc comment\n\n * with slashes and bang"); @@ -1188,7 +1188,7 @@ fn test_doc_comment_vs_tooling_directives() -> Result<()> { .functions() .map(|f| { if let UnqualifiedIdentifier::Identifier(id) = &f.rs_name { - (id.identifier.as_ref(), f.doc_comment.as_deref()) + (id.as_str(), f.doc_comment.as_deref()) } else { panic!("No constructors/destructors expected in this test.") } @@ -1210,8 +1210,8 @@ fn test_doc_comment_vs_tooling_directives() -> Result<()> { #[gtest] fn test_must_bind_annotation_on_record() -> googletest::Result<()> { let ir = ir_from_cc(r#"struct [[clang::annotate("crubit_must_bind")]] S {};"#).or_fail()?; - let record = ir.records().find(|record| record.rs_name == "S").or_fail()?; - expect_that!(&**record, field!(&Record.must_bind, eq(true))); + let record = ir.records().find(|record| record.rs_name() == "S").or_fail()?; + expect_eq!(record.must_bind(), true); Ok(()) } @@ -1395,7 +1395,7 @@ fn test_typedef_of_full_template_specialization() -> Result<()> { } } ); - let record_id = retrieve_record(&ir, "test_namespace_bindings::MyStruct").id; + let record_id = retrieve_record(&ir, "test_namespace_bindings::MyStruct").id(); // Make sure the instantiation of the class template appears exactly once in the // `top_level_items`. assert_eq!(1, ir.top_level_items().iter().filter(|item| item.id() == record_id).count()); @@ -1497,7 +1497,7 @@ fn test_typedef_for_explicit_template_specialization() -> Result<()> { } } ); - let record_id = retrieve_record(&ir, "test_namespace_bindings::MyStruct").id; + let record_id = retrieve_record(&ir, "test_namespace_bindings::MyStruct").id(); // TODO(b/200067826) This assertion worked because the template specialization // was top level already. @@ -1542,14 +1542,8 @@ fn test_multiple_typedefs_to_same_specialization() -> Result<()> { )?; // Verify that there is only 1 record for each specialization. - assert_eq!( - 1, - ir.records().filter(|r| r.cc_name.identifier.as_ref() == "MyStruct").count() - ); - assert_eq!( - 1, - ir.records().filter(|r| r.cc_name.identifier.as_ref() == "MyStruct").count() - ); + assert_eq!(1, ir.records().filter(|r| r.cc_name_as_str() == "MyStruct").count()); + assert_eq!(1, ir.records().filter(|r| r.cc_name_as_str() == "MyStruct").count()); let functions = ir .functions() .filter(|f| f.rs_name == UnqualifiedIdentifier::Identifier(ir_id("MyMethod"))) @@ -1589,8 +1583,8 @@ fn test_implicit_specialization_items_are_deterministically_ordered() -> Result< .top_level_items() .iter() .filter_map(|item| match item { - ir::Item::Record(r) if r.rs_name.identifier.contains("__CcTemplateInst") => { - Some(r.rs_name.identifier.as_ref()) + ir::Item::Record(r) if r.rs_name_as_str().contains("__CcTemplateInst") => { + Some(r.rs_name_as_str()) } _ => None, }) @@ -1609,7 +1603,7 @@ fn test_implicit_specialization_items_are_deterministically_ordered() -> Result< let method_mangled_names = ir .functions() .filter_map(|f| match &f.rs_name { - UnqualifiedIdentifier::Identifier(id) if id.identifier.as_ref() == "MyMethod" => { + UnqualifiedIdentifier::Identifier(id) if id.as_str() == "MyMethod" => { Some(f.mangled_name.as_ref()) } _ => None, @@ -1664,14 +1658,14 @@ fn test_templates_inheritance() -> Result<()> { assert_eq!( 1, ir.records() - .filter(|r| r.cc_name.identifier.contains("ClassTemplateDerivedFromClassTemplate")) + .filter(|r| r.cc_name_as_str().contains("ClassTemplateDerivedFromClassTemplate")) .count() ); // BaseTemplate is *not* instantiated in the generated bindings/IR. The derived // class's bindings work fine without the bindings for the base class (this // is also true for non-templated base/derived classes). - assert_eq!(0, ir.records().filter(|r| r.cc_name.identifier.contains("BaseTemplate")).count()); + assert_eq!(0, ir.records().filter(|r| r.cc_name_as_str().contains("BaseTemplate")).count()); Ok(()) } @@ -1809,7 +1803,7 @@ fn test_fully_instantiated_template_in_function_return_type() -> Result<()> { } } ); - let record_id = retrieve_record(&ir, "MyStruct").id; + let record_id = retrieve_record(&ir, "MyStruct").id(); // Function that used the class template as a return type. assert_ir_matches!( ir, @@ -1853,7 +1847,7 @@ fn test_fully_instantiated_template_in_function_param_type() -> Result<()> { } } ); - let record_id = retrieve_record(&ir, "MyStruct").id; + let record_id = retrieve_record(&ir, "MyStruct").id(); // Function that used the class template as a param type: assert_ir_matches!( ir, @@ -1911,7 +1905,7 @@ fn test_fully_instantiated_template_in_public_field() -> Result<()> { } } ); - let record_id = retrieve_record(&ir, "MyTemplate").id; + let record_id = retrieve_record(&ir, "MyTemplate").id(); // Struct that used the class template as a type of a public field: assert_ir_matches!( ir, @@ -2693,8 +2687,7 @@ fn test_do_not_import_nonstatic_member_functions_when_record_not_supported_yet() #[gtest] fn test_dont_import_injected_class_name() { let ir = ir_from_cc("struct SomeStruct {};").unwrap(); - let names = - ir.records().map(|r| r.rs_name.identifier.as_ref()).filter(|n| n.contains("SomeStruct")); + let names = ir.records().map(|r| r.rs_name_as_str()).filter(|n| n.contains("SomeStruct")); // we support nested structs, so we should not emit record for injected class name assert_eq!(names.count(), 1); } @@ -2787,7 +2780,7 @@ fn test_class() { #[gtest] fn test_struct_forward_declaration() { let ir = ir_from_cc("struct Struct;").unwrap(); - assert!(!ir.records().any(|r| r.rs_name.identifier.as_ref() == "Struct")); + assert!(!ir.records().any(|r| r.rs_name_as_str() == "Struct")); } #[gtest] @@ -2802,7 +2795,7 @@ fn test_struct_forward_declaration_in_namespace() -> Result<()> { assert_eq!(1, ir.namespaces().count()); let ns = ir.namespaces().next().unwrap(); - assert_eq!("MyNamespace", ns.rs_name.identifier.as_ref()); + assert_eq!("MyNamespace", ns.rs_name.as_str()); assert_eq!(1, ns.children.len()); let ns_id = ns.id; @@ -2917,8 +2910,7 @@ fn test_member_function_params() { .functions() .find(|f| f.rs_name == UnqualifiedIdentifier::Identifier(ir_id("Foo"))) .unwrap(); - let param_names: Vec<_> = - foo_func.params.iter().map(|p| p.identifier.identifier.as_ref()).collect(); + let param_names: Vec<_> = foo_func.params.iter().map(|p| p.identifier.as_str()).collect(); assert_eq!(param_names, vec!["__this", "x", "y"]); } @@ -2928,12 +2920,10 @@ fn assert_member_function_with_predicate_has_instance_method_metadata, ) { - let record = ir - .records() - .find(|r| r.rs_name.identifier.as_ref() == record_name) - .expect("Struct not found"); + let record = + ir.records().find(|r| r.rs_name_as_str() == record_name).expect("record not found"); let function = ir.functions().find(|f| func_predicate(f)).expect("Function not found"); - assert_eq!(function.enclosing_item_id, Some(record.id)); + assert_eq!(function.enclosing_item_id, Some(record.id())); assert_eq!(&function.instance_method_metadata, expected_metadata); } @@ -3119,9 +3109,7 @@ fn get_func_names(definition: &str) -> Vec { fn test_identifier_function_name() { assert_eq!( get_func_names("void Function();"), - vec![ir::UnqualifiedIdentifier::Identifier(ir::Identifier { - identifier: "Function".into() - })], + vec![ir::UnqualifiedIdentifier::Identifier(ir::Identifier::new("Function"))], ); } @@ -3237,8 +3225,8 @@ fn test_elided_lifetimes() { fn verify_elided_lifetimes_in_default_constructor(ir: &IR) { let r = ir.records().next().expect("IR should contain `struct S`"); - assert_eq!(r.rs_name.identifier.as_ref(), "S"); - assert!(r.is_trivial_abi); + assert_eq!(r.rs_name_as_str(), "S"); + assert!(r.is_trivial_abi()); let f = ir .functions() @@ -3274,7 +3262,7 @@ fn test_operator_names() { .filter_map(|f| { // Only SomeStruct member functions (excluding stddef.h stuff). let r = ir.find_decl::>(f.enclosing_item_id?).ok()?; - if r.rs_name.identifier.as_ref() != "SomeStruct" { + if r.rs_name_as_str() != "SomeStruct" { return None; } @@ -3561,8 +3549,8 @@ fn test_record_items() { ) .unwrap(); - let record = ir.records().find(|i| i.rs_name == "TopLevelStruct").unwrap(); - let record_items = record.children.iter().collect_vec(); + let record = ir.records().find(|i| i.rs_name() == "TopLevelStruct").unwrap(); + let record_items = record.children().iter().collect_vec(); assert_items_match!( record_items, @@ -3748,14 +3736,18 @@ fn test_enclosing_item_ids() { .iter() .all(|item| item.enclosing_item_id() == Some(inner_namespace.id))); - let record = ir.records().find(|r| r.rs_name.identifier.as_ref() == "S").unwrap(); - let record_items: Vec<&Item> = record.children.iter().collect_vec(); - for item in record_items.iter() { + let record = ir.records().find(|r| r.rs_name_as_str() == "S").unwrap(); + let record_items: Vec<&Item> = record.children().iter().collect_vec(); + for item in &record_items { match item { - Item::UnsupportedItem(_) => {} - Item::Comment(_) => {} + Item::Func(func) => { + assert!(func.enclosing_item_id == Some(record.id())); + } + Item::Constant(constant) => { + assert!(constant.enclosing_item_id == Some(record.id())); + } _ => { - assert!(item.enclosing_item_id() == Some(record.id)); + assert!(item.enclosing_item_id() == Some(record.id())); } } } @@ -4917,7 +4909,7 @@ fn test_anonymous_enum_in_record() { let ir = ir_from_cc("struct S { enum { kFoo = 1 }; };").unwrap(); let record = retrieve_record(&ir, "S"); let constant = ir.constants().find(|c| c.cc_name == "kFoo").unwrap(); - assert_eq!(constant.enclosing_item_id, Some(record.id)); + assert_eq!(constant.enclosing_item_id, Some(record.id())); assert_eq!(constant.value.wrapped_value, 1); } @@ -4933,11 +4925,11 @@ fn test_has_private_or_deleted_operator_delete() { ) .unwrap(); let s1 = retrieve_record(&ir, "S1"); - assert!(s1.has_private_or_deleted_operator_delete); + assert!(s1.has_private_or_deleted_operator_delete()); let s2 = retrieve_record(&ir, "S2"); - assert!(s2.has_private_or_deleted_operator_delete); + assert!(s2.has_private_or_deleted_operator_delete()); let s3 = retrieve_record(&ir, "S3"); - assert!(!s3.has_private_or_deleted_operator_delete); + assert!(!s3.has_private_or_deleted_operator_delete()); let s4 = retrieve_record(&ir, "S4"); - assert!(s4.has_private_or_deleted_operator_delete); + assert!(s4.has_private_or_deleted_operator_delete()); } diff --git a/rs_bindings_from_cc/ir_testing.rs b/rs_bindings_from_cc/ir_testing.rs index b4ba70114..8be852cff 100644 --- a/rs_bindings_from_cc/ir_testing.rs +++ b/rs_bindings_from_cc/ir_testing.rs @@ -149,7 +149,7 @@ pub fn ir_from_cc_dependency( /// Creates an identifier pub fn ir_id(name: &str) -> Identifier { - Identifier { identifier: name.into() } + Identifier::new(name) } /// Creates a simple `Item::Record` with a given name. @@ -158,8 +158,8 @@ pub fn ir_record(platform: multiplatform_testing::Platform, name: &str) -> Recor for item in ir.items() { if let Item::Record(record) = item { let mut record = (**record).clone(); - record.rs_name = Identifier { identifier: name.into() }; - record.cc_name = Identifier { identifier: name.into() }; + record.set_rs_name(Identifier::new(name)); + record.set_cc_name(Identifier::new(name)); return record; } } @@ -190,7 +190,7 @@ pub fn retrieve_func<'a>(ir: &'a IR, name: &str) -> &'a Func { /// Panics if no such record could be found. pub fn retrieve_record<'a>(ir: &'a IR, cc_name: &str) -> &'a Record { for record in ir.records() { - if record.cc_name == cc_name { + if record.cc_name() == cc_name { return record; } } @@ -238,9 +238,9 @@ mod tests { #[should_panic(expected = "Duplicate decl_id found in")] fn test_duplicate_decl_ids_err() { let mut r1 = ir_record(Platform::X86Linux, "R1"); - r1.id = ItemId::new_for_testing(42); + r1.set_id(ItemId::new_for_testing(42)); let mut r2 = ir_record(Platform::X86Linux, "R2"); - r2.id = ItemId::new_for_testing(42); + r2.set_id(ItemId::new_for_testing(42)); let _ = make_ir_from_items([r1.into(), r2.into()]); } }