diff --git a/frb_codegen/src/library/codegen/parser/function_parser/argument.rs b/frb_codegen/src/library/codegen/parser/function_parser/argument.rs index 5a3b28feae..2b45b0a40d 100644 --- a/frb_codegen/src/library/codegen/parser/function_parser/argument.rs +++ b/frb_codegen/src/library/codegen/parser/function_parser/argument.rs @@ -2,6 +2,7 @@ use crate::codegen::ir::field::{IrField, IrFieldSettings}; use crate::codegen::ir::func::{IrFuncMode, IrFuncOwnerInfo}; use crate::codegen::ir::ident::IrIdent; use crate::codegen::ir::ty::boxed::IrTypeBoxed; +use crate::codegen::ir::ty::rust_auto_opaque::OwnershipMode; use crate::codegen::ir::ty::IrType; use crate::codegen::ir::ty::IrType::Boxed; use crate::codegen::parser::attribute_parser::FrbAttributes; @@ -11,7 +12,7 @@ use crate::codegen::parser::function_parser::{ use crate::codegen::parser::type_parser::misc::parse_comments; use crate::codegen::parser::type_parser::TypeParserParsingContext; use crate::if_then_some; -use anyhow::{bail, Context}; +use anyhow::{bail, ensure, Context}; use syn::*; impl<'a, 'b> FunctionParser<'a, 'b> { @@ -76,6 +77,11 @@ impl<'a, 'b> FunctionParser<'a, 'b> { ..Default::default() }); } + + ensure!( + parse_receiver_ownership_mode(receiver) == OwnershipMode::Ref, + "If you want to use `self`/`&mut self`, please make the struct opaque (by adding `#[frb(opaque)]` on the struct)." + ); } partial_info_for_normal_type_raw(ty, &receiver.attrs, name) @@ -184,13 +190,21 @@ fn parse_name_from_pat_type(pat_type: &PatType) -> anyhow::Result { } fn generate_ref_type_considering_reference(raw: &str, receiver: &Receiver) -> String { + match parse_receiver_ownership_mode(receiver) { + OwnershipMode::Owned => raw.to_owned(), + OwnershipMode::RefMut => format!("&mut {raw}"), + OwnershipMode::Ref => format!("&{raw}"), + } +} + +fn parse_receiver_ownership_mode(receiver: &Receiver) -> OwnershipMode { if receiver.reference.is_some() { if receiver.mutability.is_some() { - format!("&mut {raw}") + OwnershipMode::RefMut } else { - format!("&{raw}") + OwnershipMode::Ref } } else { - raw.to_owned() + OwnershipMode::Owned } } diff --git a/frb_codegen/src/library/codegen/parser/mod.rs b/frb_codegen/src/library/codegen/parser/mod.rs index dbd65a51bf..18b7e23d93 100644 --- a/frb_codegen/src/library/codegen/parser/mod.rs +++ b/frb_codegen/src/library/codegen/parser/mod.rs @@ -145,13 +145,14 @@ mod tests { use crate::codegen::parser::parse; use crate::codegen::parser::reader::CachedRustReader; use crate::codegen::parser::source_graph::crates::Crate; + use crate::codegen::parser::IrPack; use crate::utils::logs::configure_opinionated_test_logging; use crate::utils::test_utils::{ create_path_sanitizers, get_test_fixture_dir, json_golden_test, }; use log::info; use serial_test::serial; - use std::path::Path; + use std::path::{Path, PathBuf}; #[test] #[serial] @@ -204,11 +205,35 @@ mod tests { body("library/codegen/parser/mod/generics", None) } + #[test] + #[serial] + fn test_error_non_opaque_mut() -> anyhow::Result<()> { + let result = execute_parse("library/codegen/parser/mod/error_non_opaque_mut", None); + assert!(format!("{:#?}", result.err().unwrap()) + .contains("If you want to use `self`/`&mut self`")); + Ok(()) + } + #[allow(clippy::type_complexity)] fn body( fixture_name: &str, rust_input_path_pack: Option RustInputPathPack>>, ) -> anyhow::Result<()> { + let (actual_ir, rust_crate_dir) = execute_parse(fixture_name, rust_input_path_pack)?; + json_golden_test( + &serde_json::to_value(actual_ir)?, + &rust_crate_dir.join("expect_ir.json"), + &[], + )?; + + Ok(()) + } + + #[allow(clippy::type_complexity)] + fn execute_parse( + fixture_name: &str, + rust_input_path_pack: Option RustInputPathPack>>, + ) -> anyhow::Result<(IrPack, PathBuf)> { configure_opinionated_test_logging(); let test_fixture_dir = get_test_fixture_dir(fixture_name); let rust_crate_dir = test_fixture_dir.clone(); @@ -223,9 +248,10 @@ mod tests { &serde_json::to_value(crate_map)?, &rust_crate_dir.join("expect_source_graph.json"), &create_path_sanitizers(&test_fixture_dir), - )?; + ) + .unwrap(); - let actual_ir = parse( + let pack = parse( &ParserInternalConfig { rust_input_path_pack: rust_input_path_pack.map(|f| f(&rust_crate_dir)).unwrap_or( RustInputPathPack { @@ -240,12 +266,7 @@ mod tests { &Dumper(&Default::default()), &GeneratorProgressBarPack::new(), )?; - json_golden_test( - &serde_json::to_value(actual_ir)?, - &rust_crate_dir.join("expect_ir.json"), - &[], - )?; - Ok(()) + Ok((pack, rust_crate_dir)) } } diff --git a/frb_codegen/test_fixtures/library/codegen/parser/mod/error_non_opaque_mut/Cargo.toml b/frb_codegen/test_fixtures/library/codegen/parser/mod/error_non_opaque_mut/Cargo.toml new file mode 100644 index 0000000000..9e90ef45b3 --- /dev/null +++ b/frb_codegen/test_fixtures/library/codegen/parser/mod/error_non_opaque_mut/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "example" +version = "0.1.0" +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] + +[workspace] diff --git a/frb_codegen/test_fixtures/library/codegen/parser/mod/error_non_opaque_mut/expect_source_graph.json b/frb_codegen/test_fixtures/library/codegen/parser/mod/error_non_opaque_mut/expect_source_graph.json new file mode 100644 index 0000000000..8ccbd3f4bc --- /dev/null +++ b/frb_codegen/test_fixtures/library/codegen/parser/mod/error_non_opaque_mut/expect_source_graph.json @@ -0,0 +1,47 @@ +{ + "manifest_path": "{the-working-directory}/Cargo.toml", + "name": "example", + "root_module": { + "info": { + "file_path": "{the-working-directory}/src/lib.rs", + "module_path": [ + "crate" + ], + "visibility": "Public" + }, + "scope": { + "enums": [], + "modules": [ + { + "info": { + "file_path": "{the-working-directory}/src/api.rs", + "module_path": [ + "crate", + "api" + ], + "visibility": "Inherited" + }, + "scope": { + "enums": [], + "modules": [], + "structs": [ + { + "ident": "MyStruct", + "mirror": false, + "path": [ + "crate", + "api", + "MyStruct" + ], + "visibility": "Public" + } + ], + "type_alias": [] + } + } + ], + "structs": [], + "type_alias": [] + } + } +} \ No newline at end of file diff --git a/frb_codegen/test_fixtures/library/codegen/parser/mod/error_non_opaque_mut/src/api.rs b/frb_codegen/test_fixtures/library/codegen/parser/mod/error_non_opaque_mut/src/api.rs new file mode 100644 index 0000000000..e616514929 --- /dev/null +++ b/frb_codegen/test_fixtures/library/codegen/parser/mod/error_non_opaque_mut/src/api.rs @@ -0,0 +1,7 @@ +pub struct MyStruct { + my_field: String, +} + +impl MyStruct { + pub fn my_mut_method(&mut self) {} +} diff --git a/frb_codegen/test_fixtures/library/codegen/parser/mod/error_non_opaque_mut/src/lib.rs b/frb_codegen/test_fixtures/library/codegen/parser/mod/error_non_opaque_mut/src/lib.rs new file mode 100644 index 0000000000..b32f9e29f1 --- /dev/null +++ b/frb_codegen/test_fixtures/library/codegen/parser/mod/error_non_opaque_mut/src/lib.rs @@ -0,0 +1 @@ +mod api;