Skip to content

Commit 2dcb70f

Browse files
committed
Deny manual init() if #[class(init|no_init)] is present
Update one test that failed under this rule.
1 parent bc4d210 commit 2dcb70f

File tree

4 files changed

+41
-1
lines changed

4 files changed

+41
-1
lines changed

godot-macros/src/class/data_models/interface_trait_impl.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,8 +227,12 @@ fn handle_init<'a>(
227227
godot_init_impl, ..
228228
} = decls;
229229

230+
// If #[class(init)] or #[class(no_init)] is provided, deny overriding manual init().
231+
let deny_manual_init_macro = util::format_class_deny_manual_init_macro(class_name);
232+
230233
*godot_init_impl = quote! {
231234
#godot_init_impl
235+
#deny_manual_init_macro!();
232236

233237
#(#cfg_attrs)*
234238
impl ::godot::obj::cap::GodotDefault for #class_name {

godot-macros/src/class/derive_godot_class.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ pub fn derive_godot_class(item: venial::Item) -> ParseResult<TokenStream> {
148148
// Note: one limitation is that macros don't work for `impl nested::MyClass` blocks.
149149
let visibility_macro = make_visibility_macro(class_name, class.vis_marker.as_ref());
150150
let base_field_macro = make_base_field_macro(class_name, fields.base_field.is_some());
151+
let deny_manual_init_macro = make_deny_manual_init_macro(class_name, struct_cfg.init_strategy);
151152

152153
Ok(quote! {
153154
impl ::godot::obj::GodotClass for #class_name {
@@ -180,6 +181,7 @@ pub fn derive_godot_class(item: venial::Item) -> ParseResult<TokenStream> {
180181
#init_expecter
181182
#visibility_macro
182183
#base_field_macro
184+
#deny_manual_init_macro
183185
#( #deprecations )*
184186
#( #errors )*
185187

@@ -236,6 +238,35 @@ fn make_base_field_macro(class_name: &Ident, has_base_field: bool) -> TokenStrea
236238
}
237239
}
238240

241+
/// Generates code for a decl-macro that prevents manual `init()` for incompatible init strategies.
242+
fn make_deny_manual_init_macro(class_name: &Ident, init_strategy: InitStrategy) -> TokenStream {
243+
let macro_name = util::format_class_deny_manual_init_macro(class_name);
244+
245+
let class_attr = match init_strategy {
246+
InitStrategy::Absent => "#[class(no_init)]",
247+
InitStrategy::Generated => "#[class(init)]",
248+
InitStrategy::UserDefined => {
249+
// For classes that expect manual init, do nothing.
250+
return quote! {
251+
macro_rules! #macro_name {
252+
() => {};
253+
}
254+
};
255+
}
256+
};
257+
258+
let error_message =
259+
format!("Class `{class_name}` is marked with {class_attr} but provides an init() method.");
260+
261+
quote! {
262+
macro_rules! #macro_name {
263+
() => {
264+
compile_error!(#error_message);
265+
};
266+
}
267+
}
268+
}
269+
239270
/// Checks at compile time that a function with the given name exists on `Self`.
240271
#[must_use]
241272
pub fn make_existence_check(ident: &Ident) -> TokenStream {

godot-macros/src/util/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,3 +418,8 @@ pub fn format_class_visibility_macro(class_name: &Ident) -> Ident {
418418
pub fn format_class_base_field_macro(class_name: &Ident) -> Ident {
419419
format_ident!("__godot_{class_name}_has_base_field_macro")
420420
}
421+
422+
/// Returns the name of the macro used to deny manual `init()` for incompatible init strategies.
423+
pub fn format_class_deny_manual_init_macro(class_name: &Ident) -> Ident {
424+
format_ident!("__deny_manual_init_{class_name}")
425+
}

itest/rust/src/engine_tests/codegen_test.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ impl CodegenTest2 {
142142
macro_rules! make_class {
143143
($ClassName:ident, $BaseName:ident) => {
144144
#[derive(GodotClass)]
145-
#[class(no_init, base=$BaseName)]
145+
#[class(base=$BaseName)]
146146
pub struct $ClassName {
147147
base: Base<godot::classes::$BaseName>,
148148
}

0 commit comments

Comments
 (0)