Skip to content

Commit a0d5799

Browse files
authored
Merge pull request #918 from godot-rust/bugfix/script-virtual-registered-name
Display script-virtual methods as `_method` instead of `method` in Godot docs
2 parents 8ad9cb0 + 49cd1aa commit a0d5799

File tree

5 files changed

+46
-23
lines changed

5 files changed

+46
-23
lines changed

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ impl GetterSetterImpl {
202202
// Ideally, we'd be able to place #[cfg_attr] on #[var(get)] and #[var(set)] to be able to match a
203203
// #[cfg()] (for instance) placed on the getter/setter function, but that is not currently supported.
204204
external_attributes: Vec::new(),
205-
rename: None,
205+
registered_name: None,
206206
is_script_virtual: false,
207207
rpc_info: None,
208208
},

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

+10-3
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,18 @@ use quote::{format_ident, quote};
1515
pub struct FuncDefinition {
1616
/// Refined signature, with higher level info and renamed parameters.
1717
pub signature_info: SignatureInfo,
18+
1819
/// The function's non-gdext attributes (all except #[func]).
1920
pub external_attributes: Vec<venial::Attribute>,
21+
2022
/// The name the function will be exposed as in Godot. If `None`, the Rust function name is used.
21-
pub rename: Option<String>,
23+
///
24+
/// This can differ from the name in [`signature_info`] if the user has used `#[func(rename)]` or for script-virtual functions.
25+
pub registered_name: Option<String>,
26+
27+
/// True for script-virtual functions.
2228
pub is_script_virtual: bool,
29+
2330
/// Information about the RPC configuration, if provided.
2431
pub rpc_info: Option<RpcAttr>,
2532
}
@@ -84,8 +91,8 @@ pub fn make_method_registration(
8491
// String literals
8592
let method_name = &signature_info.method_name;
8693
let class_name_str = class_name.to_string();
87-
let method_name_str = if let Some(rename) = func_definition.rename {
88-
rename
94+
let method_name_str = if let Some(updated_name) = func_definition.registered_name {
95+
updated_name
8996
} else {
9097
method_name.to_string()
9198
};

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

+33-17
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use crate::class::{
99
make_signal_registrations, ConstDefinition, FuncDefinition, RpcAttr, RpcMode, SignalDefinition,
1010
SignatureInfo, TransferMode,
1111
};
12-
use crate::util::{bail, ident, require_api_version, KvParser};
12+
use crate::util::{bail, c_str, ident, require_api_version, KvParser};
1313
use crate::{handle_mutually_exclusive_keys, util, ParseResult};
1414

1515
use proc_macro2::{Delimiter, Group, Ident, TokenStream};
@@ -89,7 +89,7 @@ pub fn transform_inherent_impl(mut impl_block: venial::Impl) -> ParseResult<Toke
8989
let method_registrations: Vec<TokenStream> = funcs
9090
.into_iter()
9191
.map(|func_def| make_method_registration(&class_name, func_def))
92-
.collect::<ParseResult<Vec<TokenStream>>>()?; // <- FIXME transpose this
92+
.collect::<ParseResult<Vec<TokenStream>>>()?;
9393

9494
let constant_registration = make_constant_registration(consts, &class_name, &class_name_obj)?;
9595

@@ -196,21 +196,25 @@ fn process_godot_fns(
196196

197197
// For virtual methods, rename/mangle existing user method and create a new method with the original name,
198198
// which performs a dynamic dispatch.
199-
if func.is_virtual {
200-
add_virtual_script_call(
199+
let registered_name = if func.is_virtual {
200+
let registered_name = add_virtual_script_call(
201201
&mut virtual_functions,
202202
function,
203203
&signature_info,
204204
class_name,
205205
&func.rename,
206206
gd_self_parameter,
207207
);
208+
209+
Some(registered_name)
210+
} else {
211+
func.rename
208212
};
209213

210214
func_definitions.push(FuncDefinition {
211215
signature_info,
212216
external_attributes,
213-
rename: func.rename,
217+
registered_name,
214218
is_script_virtual: func.is_virtual,
215219
rpc_info,
216220
});
@@ -295,7 +299,7 @@ fn add_virtual_script_call(
295299
class_name: &Ident,
296300
rename: &Option<String>,
297301
gd_self_parameter: Option<Ident>,
298-
) {
302+
) -> String {
299303
assert!(cfg!(since_api = "4.3"));
300304

301305
// Update parameter names, so they can be forwarded (e.g. a "_" declared by the user cannot).
@@ -311,9 +315,12 @@ fn add_virtual_script_call(
311315

312316
let class_name_str = class_name.to_string();
313317
let early_bound_name = format_ident!("__earlybound_{}", &function.name);
314-
let method_name_str = rename
315-
.clone()
316-
.unwrap_or_else(|| format!("_{}", function.name));
318+
319+
let method_name_str = match rename {
320+
Some(rename) => rename.clone(),
321+
None => format!("_{}", function.name),
322+
};
323+
let method_name_cstr = c_str(&method_name_str);
317324

318325
let sig_tuple = signature_info.tuple_type();
319326
let arg_names = &signature_info.param_idents;
@@ -329,7 +336,7 @@ fn add_virtual_script_call(
329336

330337
let code = quote! {
331338
let object_ptr = #object_ptr;
332-
let method_sname = ::godot::builtin::StringName::from(#method_name_str);
339+
let method_sname = ::godot::builtin::StringName::from(#method_name_cstr);
333340
let method_sname_ptr = method_sname.string_sys();
334341
let has_virtual_override = unsafe { ::godot::private::has_virtual_script_method(object_ptr, method_sname_ptr) };
335342

@@ -360,6 +367,8 @@ fn add_virtual_script_call(
360367

361368
std::mem::swap(&mut function.body, &mut early_bound_function.body);
362369
virtual_functions.push(early_bound_function);
370+
371+
method_name_str
363372
}
364373

365374
fn extract_attributes<T>(item: &mut T) -> ParseResult<Option<ItemAttr>>
@@ -377,7 +386,7 @@ where
377386
index += 1;
378387

379388
let Some(attr_name) = attr.get_single_path_segment() else {
380-
// Attribute of the form #[segmented::path] can't be what we are looking for
389+
// Attribute of the form #[segmented::path] can't be what we are looking for.
381390
continue;
382391
};
383392

@@ -412,7 +421,7 @@ where
412421

413422
// #[rpc]
414423
name if name == "rpc" => {
415-
// Safe unwrap since #[rpc] must be present if we got to this point
424+
// Safe unwrap, since #[rpc] must be present if we got to this point.
416425
let mut parser = KvParser::parse(attributes, "rpc")?.unwrap();
417426

418427
let rpc_mode = handle_mutually_exclusive_keys(
@@ -445,9 +454,14 @@ where
445454
let rpc_attr = match (config_expr, (&rpc_mode, &transfer_mode, &call_local, &channel)) {
446455
// Ok: Only `config = [expr]` is present.
447456
(Some(expr), (None, None, None, None)) => RpcAttr::Expression(expr),
457+
448458
// Err: `config = [expr]` is present along other parameters, which is not allowed.
449-
(Some(_), _) => return bail!(&*item, "`#[rpc(config = ...)]` is mutually exclusive with any other parameters(`any_peer`, `reliable`, `call_local`, `channel = 0`)"),
450-
// Ok: `config` is not present, any combination of the other parameters is allowed..
459+
(Some(_), _) => return bail!(
460+
&*item,
461+
"`#[rpc(config = ...)]` is mutually exclusive with any other parameters(`any_peer`, `reliable`, `call_local`, `channel = 0`)"
462+
),
463+
464+
// Ok: `config` is not present, any combination of the other parameters is allowed.
451465
_ => RpcAttr::SeparatedArgs {
452466
rpc_mode,
453467
transfer_mode,
@@ -476,19 +490,21 @@ where
476490

477491
let attr_name = attr_name.clone();
478492

479-
// Remaining code no longer has attribute -- rest stays
480-
attributes.remove(index - 1); // -1 because we bumped the index at the beginning of the loop
493+
// Remaining code no longer has attribute -- rest stays.
494+
attributes.remove(index - 1); // -1 because we bumped the index at the beginning of the loop.
481495
index -= 1;
482496

483497
let (new_name, new_attr) = match (found, parsed_attr) {
484-
// First attribute
498+
// First attribute.
485499
(None, parsed) => (attr_name, parsed),
500+
486501
// Regardless of the order, if we found both `#[func]` and `#[rpc]`, we can just merge them.
487502
(Some((found_name, AttrParseResult::Func(func))), AttrParseResult::Rpc(rpc))
488503
| (Some((found_name, AttrParseResult::Rpc(rpc))), AttrParseResult::Func(func)) => (
489504
ident(&format!("{found_name}_{attr_name}")),
490505
AttrParseResult::FuncRpc(func, rpc),
491506
),
507+
492508
// We found two incompatible attributes.
493509
(Some((found_name, _)), _) => {
494510
return bail!(&*item, "The attributes `{found_name}` and `{attr_name}` cannot be used in the same declaration")?;

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ fn make_rpc_registration(func_def: &FuncDefinition) -> Option<TokenStream> {
145145
}
146146
};
147147

148-
let method_name_str = if let Some(rename) = &func_def.rename {
148+
let method_name_str = if let Some(rename) = &func_def.registered_name {
149149
rename.to_string()
150150
} else {
151151
func_def.signature_info.method_name.to_string()

godot-macros/src/docs.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ pub fn make_virtual_method_docs(method: Function) -> Option<String> {
247247
pub fn make_method_docs(method: &FuncDefinition) -> Option<String> {
248248
let desc = make_docs_from_attributes(&method.external_attributes)?;
249249
let name = method
250-
.rename
250+
.registered_name
251251
.clone()
252252
.unwrap_or_else(|| method.signature_info.method_name.to_string());
253253
let ret = method.signature_info.ret_type.to_token_stream().to_string();

0 commit comments

Comments
 (0)