Skip to content

Commit affb64d

Browse files
authored
Merge pull request #884 from godot-rust/qol/redundant-class-attrs
`#[class]` attribute: rename `hidden` -> `internal`, deprecate `editor_plugin`
2 parents 0c91b8a + 773e42e commit affb64d

File tree

6 files changed

+57
-52
lines changed

6 files changed

+57
-52
lines changed

godot-core/src/deprecated.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,14 @@ pub use crate::emit_deprecated_warning;
4141
More information on https://github.com/godot-rust/gdext/pull/844."]
4242
pub const fn init_default() {}
4343

44+
#[deprecated = "\nThe attribute key #[class(editor_plugin)] is now implied by #[class(base = EditorPlugin)]. It is ignored.\n\
45+
More information on https://github.com/godot-rust/gdext/pull/884."]
46+
pub const fn class_editor_plugin() {}
47+
48+
#[deprecated = "\nThe attribute key #[class(hidden)] has been renamed to #[class(internal)], following Godot terminology.\n\
49+
More information on https://github.com/godot-rust/gdext/pull/884."]
50+
pub const fn class_hidden() {}
51+
4452
// ----------------------------------------------------------------------------------------------------------------------------------------------
4553
// Godot-side deprecations
4654

godot-core/src/registry/class.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ fn fill_class_info(item: PluginItem, c: &mut ClassRegistrationInfo) {
229229
default_get_virtual_fn,
230230
is_tool,
231231
is_editor_plugin,
232-
is_hidden,
232+
is_internal,
233233
is_instantiable,
234234
#[cfg(all(since_api = "4.3", feature = "docs"))]
235235
docs: _,
@@ -257,7 +257,7 @@ fn fill_class_info(item: PluginItem, c: &mut ClassRegistrationInfo) {
257257
.expect("duplicate: create_instance_func (def)");
258258

259259
#[cfg(before_api = "4.2")]
260-
let _ = is_hidden; // mark used
260+
let _ = is_internal; // mark used
261261
#[cfg(since_api = "4.2")]
262262
{
263263
fill_into(
@@ -266,7 +266,7 @@ fn fill_class_info(item: PluginItem, c: &mut ClassRegistrationInfo) {
266266
)
267267
.expect("duplicate: recreate_instance_func (def)");
268268

269-
c.godot_params.is_exposed = sys::conv::bool_to_sys(!is_hidden);
269+
c.godot_params.is_exposed = sys::conv::bool_to_sys(!is_internal);
270270
}
271271

272272
#[cfg(before_api = "4.2")]

godot-core/src/registry/plugin.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,11 +89,11 @@ pub enum PluginItem {
8989
/// Whether `#[class(tool)]` was used.
9090
is_tool: bool,
9191

92-
/// Whether `#[class(editor_plugin)]` was used.
92+
/// Whether the base class is an `EditorPlugin`.
9393
is_editor_plugin: bool,
9494

95-
/// Whether `#[class(hidden)]` was used.
96-
is_hidden: bool,
95+
/// Whether `#[class(internal)]` was used.
96+
is_internal: bool,
9797

9898
/// Whether the class has a default constructor.
9999
is_instantiable: bool,

godot-macros/src/class/derive_godot_class.rs

Lines changed: 40 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,12 @@ pub fn derive_godot_class(item: venial::Item) -> ParseResult<TokenStream> {
2121
.ok_or_else(|| venial::Error::new("Not a valid struct"))?;
2222

2323
let named_fields = named_fields(class)?;
24-
let struct_cfg = parse_struct_attributes(class)?;
25-
let fields = parse_fields(named_fields, struct_cfg.init_strategy)?;
24+
let mut struct_cfg = parse_struct_attributes(class)?;
25+
let mut fields = parse_fields(named_fields, struct_cfg.init_strategy)?;
26+
let is_editor_plugin = struct_cfg.is_editor_plugin();
27+
28+
let mut deprecations = std::mem::take(&mut struct_cfg.deprecations);
29+
deprecations.append(&mut fields.deprecations);
2630

2731
let class_name = &class.name;
2832
let class_name_str: String = struct_cfg
@@ -33,8 +37,7 @@ pub fn derive_godot_class(item: venial::Item) -> ParseResult<TokenStream> {
3337
let class_name_cstr = util::c_str(&class_name_str);
3438
let class_name_obj = util::class_name_obj(class_name);
3539

36-
let is_editor_plugin = struct_cfg.is_editor_plugin;
37-
let is_hidden = struct_cfg.is_hidden;
40+
let is_internal = struct_cfg.is_internal;
3841
let base_ty = &struct_cfg.base_ty;
3942
#[cfg(all(feature = "docs", since_api = "4.3"))]
4043
let docs = crate::docs::make_definition_docs(
@@ -75,7 +78,6 @@ pub fn derive_godot_class(item: venial::Item) -> ParseResult<TokenStream> {
7578
let mut create_fn = quote! { None };
7679
let mut recreate_fn = quote! { None };
7780
let mut is_instantiable = true;
78-
let deprecations = &fields.deprecations;
7981

8082
match struct_cfg.init_strategy {
8183
InitStrategy::Generated => {
@@ -153,7 +155,7 @@ pub fn derive_godot_class(item: venial::Item) -> ParseResult<TokenStream> {
153155
default_get_virtual_fn: #default_get_virtual_fn,
154156
is_tool: #is_tool,
155157
is_editor_plugin: #is_editor_plugin,
156-
is_hidden: #is_hidden,
158+
is_internal: #is_internal,
157159
is_instantiable: #is_instantiable,
158160
#docs
159161
},
@@ -201,9 +203,15 @@ struct ClassAttributes {
201203
base_ty: Ident,
202204
init_strategy: InitStrategy,
203205
is_tool: bool,
204-
is_editor_plugin: bool,
205-
is_hidden: bool,
206+
is_internal: bool,
206207
rename: Option<Ident>,
208+
deprecations: Vec<TokenStream>,
209+
}
210+
211+
impl ClassAttributes {
212+
fn is_editor_plugin(&self) -> bool {
213+
self.base_ty == ident("EditorPlugin")
214+
}
207215
}
208216

209217
fn make_godot_init_impl(class_name: &Ident, fields: &Fields) -> TokenStream {
@@ -310,9 +318,9 @@ fn parse_struct_attributes(class: &venial::Struct) -> ParseResult<ClassAttribute
310318
let mut base_ty = ident("RefCounted");
311319
let mut init_strategy = InitStrategy::UserDefined;
312320
let mut is_tool = false;
313-
let mut is_editor_plugin = false;
314-
let mut is_hidden = false;
321+
let mut is_internal = false;
315322
let mut rename: Option<Ident> = None;
323+
let mut deprecations = vec![];
316324

317325
// #[class] attribute on struct
318326
if let Some(mut parser) = KvParser::parse(&class.attributes, "class")? {
@@ -333,50 +341,45 @@ fn parse_struct_attributes(class: &venial::Struct) -> ParseResult<ClassAttribute
333341
is_tool = true;
334342
}
335343

336-
// #[class(editor_plugin)]
337-
if let Some(attr_key) = parser.handle_alone_with_span("editor_plugin")? {
338-
is_editor_plugin = true;
339-
340-
// Requires #[class(tool, base=EditorPlugin)].
341-
// The base=EditorPlugin check should come first to create the best compile errors since it's more complex to resolve.
342-
// See https://github.com/godot-rust/gdext/pull/773
343-
if base_ty != ident("EditorPlugin") {
344-
return bail!(
345-
attr_key,
346-
"#[class(editor_plugin)] requires additional key-value `base=EditorPlugin`"
347-
);
348-
}
349-
if !is_tool {
350-
return bail!(
351-
attr_key,
352-
"#[class(editor_plugin)] requires additional key `tool`"
353-
);
354-
}
344+
// Deprecated #[class(editor_plugin)]
345+
if let Some(_attr_key) = parser.handle_alone_with_span("editor_plugin")? {
346+
deprecations.push(quote! {
347+
::godot::__deprecated::emit_deprecated_warning!(class_editor_plugin);
348+
});
355349
}
356350

357351
// #[class(rename = NewName)]
358352
rename = parser.handle_ident("rename")?;
359353

360-
// #[class(hidden)]
361-
// TODO consider naming this "internal"; godot-cpp uses that terminology:
362-
// https://github.com/godotengine/godot-cpp/blob/master/include/godot_cpp/core/class_db.hpp#L327
354+
// #[class(internal)]
355+
// Named "internal" following Godot terminology: https://github.com/godotengine/godot-cpp/blob/master/include/godot_cpp/core/class_db.hpp#L327
356+
if let Some(span) = parser.handle_alone_with_span("internal")? {
357+
require_api_version!("4.2", span, "#[class(internal)]")?;
358+
is_internal = true;
359+
}
360+
361+
// Deprecated #[class(hidden)]
363362
if let Some(span) = parser.handle_alone_with_span("hidden")? {
364363
require_api_version!("4.2", span, "#[class(hidden)]")?;
365-
is_hidden = true;
364+
is_internal = true;
365+
366+
deprecations.push(quote! {
367+
::godot::__deprecated::emit_deprecated_warning!(class_hidden);
368+
});
366369
}
367370

368371
parser.finish()?;
369372
}
370373

371-
post_validate(&base_ty, is_tool, is_editor_plugin)?;
374+
post_validate(&base_ty, is_tool)?;
372375

373376
Ok(ClassAttributes {
374377
base_ty,
375378
init_strategy,
376379
is_tool,
377-
is_editor_plugin,
378-
is_hidden,
380+
is_internal,
379381
rename,
382+
deprecations,
380383
})
381384
}
382385

@@ -561,7 +564,7 @@ fn handle_opposite_keys(
561564
}
562565

563566
/// Checks more logical combinations of attributes.
564-
fn post_validate(base_ty: &Ident, is_tool: bool, is_editor_plugin: bool) -> ParseResult<()> {
567+
fn post_validate(base_ty: &Ident, is_tool: bool) -> ParseResult<()> {
565568
// TODO: this should be delegated to either:
566569
// a) the type system: have a trait IsTool which is implemented when #[class(tool)] is set.
567570
// Then, for certain base classes, require a tool bound (e.g. generate method `fn type_check<T: IsTool>()`).
@@ -579,12 +582,6 @@ fn post_validate(base_ty: &Ident, is_tool: bool, is_editor_plugin: bool) -> Pars
579582
"Base class `{}` is a virtual extension class, which runs in the editor and thus requires #[class(tool)].",
580583
base_ty
581584
);
582-
} else if class_name == "EditorPlugin" && !is_editor_plugin {
583-
return bail!(
584-
base_ty,
585-
"Classes extending `{}` require #[class(editor_plugin)] to get registered as a plugin in the editor. See: https://godot-rust.github.io/book/recipes/editor-plugin/index.html",
586-
base_ty
587-
);
588585
} else if is_class_editor && !is_tool {
589586
return bail!(
590587
base_ty,

godot-macros/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -400,12 +400,12 @@ use crate::util::ident;
400400
///
401401
/// ## Class hiding
402402
///
403-
/// If you want to register a class with Godot, but not have it show up in the editor then you can use `#[class(hidden)]`.
403+
/// If you want to register a class with Godot, but not have it show up in the editor then you can use `#[class(internal)]`.
404404
///
405405
/// ```
406406
/// # use godot::prelude::*;
407407
/// #[derive(GodotClass)]
408-
/// #[class(base=Node, init, hidden)]
408+
/// #[class(base=Node, init, internal)]
409409
/// pub struct Foo {}
410410
/// ```
411411
///

itest/rust/src/object_tests/virtual_methods_test.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -779,7 +779,7 @@ impl GetSetTest {
779779
// There isn't a good way to test editor plugins, but we can at least declare one to ensure that the macro
780780
// compiles.
781781
#[derive(GodotClass)]
782-
#[class(no_init, base = EditorPlugin, editor_plugin, tool)]
782+
#[class(no_init, base = EditorPlugin, tool)]
783783
struct CustomEditorPlugin;
784784

785785
// Just override EditorPlugin::edit() to verify method is declared with Option<T>.

0 commit comments

Comments
 (0)