Skip to content

Commit cf3cebd

Browse files
committed
added warning messages for when negative bitfields are encountered
1 parent 1e8fbf7 commit cf3cebd

File tree

8 files changed

+60
-15
lines changed

8 files changed

+60
-15
lines changed

godot-codegen/src/context.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ pub struct Context<'a> {
2828
notification_enum_names_by_class: HashMap<TyName, NotificationEnum>,
2929
method_table_indices: HashMap<MethodTableKey, usize>,
3030
method_table_next_index: HashMap<String, usize>,
31+
warnings: Vec<String>,
3132
}
3233

3334
impl<'a> Context<'a> {
@@ -269,6 +270,14 @@ impl<'a> Context<'a> {
269270
let prev = self.cached_rust_types.insert(godot_ty, resolved);
270271
assert!(prev.is_none(), "no overwrites of RustTy");
271272
}
273+
274+
pub fn warnings(&self) -> &Vec<String> {
275+
&self.warnings
276+
}
277+
278+
pub fn warnings_mut(&mut self) -> &mut Vec<String> {
279+
&mut self.warnings
280+
}
272281
}
273282

274283
// ----------------------------------------------------------------------------------------------------------------------------------------------

godot-codegen/src/generator/builtins.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ fn make_builtin_class(class: &BuiltinClass, ctx: &mut Context) -> GeneratedBuilt
101101
} = make_builtin_methods(class, &class.methods, ctx);
102102

103103
let imports = util::make_imports();
104-
let enums = enums::make_enums(&class.enums);
104+
let enums = enums::make_enums(&class.enums, ctx);
105105
let special_constructors = make_special_builtin_methods(class.name(), ctx);
106106

107107
// mod re_export needed, because class should not appear inside the file module, and we can't re-export private struct as pub

godot-codegen/src/generator/central_files.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ pub fn make_core_central_code(api: &ExtensionApi, ctx: &mut Context) -> TokenStr
108108
..
109109
} = make_variant_enums(api, ctx);
110110

111-
let global_enum_defs = make_global_enums(api);
111+
let global_enum_defs = make_global_enums(api, ctx);
112112

113113
// TODO impl Clone, Debug, PartialEq, PartialOrd, Hash for VariantDispatch
114114
// TODO could use try_to().unwrap_unchecked(), since type is already verified. Also directly overload from_variant().
@@ -256,7 +256,7 @@ fn make_variant_enums(api: &ExtensionApi, ctx: &mut Context) -> VariantEnums {
256256
result
257257
}
258258

259-
fn make_global_enums(api: &ExtensionApi) -> Vec<TokenStream> {
259+
fn make_global_enums(api: &ExtensionApi, ctx: &mut Context) -> Vec<TokenStream> {
260260
let mut global_enum_defs = vec![];
261261

262262
for enum_ in api.global_enums.iter() {
@@ -265,7 +265,7 @@ fn make_global_enums(api: &ExtensionApi) -> Vec<TokenStream> {
265265
continue;
266266
}
267267

268-
let def = enums::make_enum_definition(enum_);
268+
let def = enums::make_enum_definition(enum_, ctx);
269269
global_enum_defs.push(def);
270270
}
271271

godot-codegen/src/generator/classes.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ fn make_class(class: &Class, ctx: &mut Context, view: &ApiView) -> GeneratedClas
9898
builders,
9999
} = make_class_methods(class, &class.methods, ctx);
100100

101-
let enums = enums::make_enums(&class.enums);
101+
let enums = enums::make_enums(&class.enums, ctx);
102102
let constants = constants::make_constants(&class.constants);
103103
let inherits_macro = format_ident!("unsafe_inherits_transitive_{}", class_name.rust_ty);
104104
let deref_impl = make_deref_impl(class_name, &base_ty);

godot-codegen/src/generator/enums.rs

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,21 @@
55
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
66
*/
77

8+
use crate::context::Context;
89
use crate::models::domain::{Enum, Enumerator, EnumeratorValue};
910
use crate::util;
1011
use proc_macro2::{Literal, TokenStream};
1112
use quote::quote;
1213

13-
pub fn make_enums(enums: &[Enum]) -> TokenStream {
14-
let definitions = enums.iter().map(make_enum_definition);
14+
pub fn make_enums(enums: &[Enum], ctx: &mut Context) -> TokenStream {
15+
let definitions = enums.iter().map(|enum_| make_enum_definition(enum_, ctx));
1516

1617
quote! {
1718
#( #definitions )*
1819
}
1920
}
2021

21-
pub fn make_enum_definition(enum_: &Enum) -> TokenStream {
22+
pub fn make_enum_definition(enum_: &Enum, ctx: &mut Context) -> TokenStream {
2223
// TODO enums which have unique ords could be represented as Rust enums
2324
// This would allow exhaustive matches (or at least auto-completed matches + #[non_exhaustive]). But even without #[non_exhaustive],
2425
// this might be a forward compatibility hazard, if Godot deprecates enumerators and adds new ones with existing ords.
@@ -39,7 +40,7 @@ pub fn make_enum_definition(enum_: &Enum) -> TokenStream {
3940
let mut unique_ords = Vec::with_capacity(rust_enumerators.len());
4041

4142
for enumerator in rust_enumerators.iter() {
42-
let def = make_enumerator_definition(enumerator);
43+
let def = make_enumerator_definition(enumerator, ctx);
4344
enumerators.push(def);
4445

4546
if let EnumeratorValue::Enum(ord) = enumerator.value {
@@ -176,10 +177,20 @@ fn make_bitfield_flag_ord(ord: i64) -> Literal {
176177
Literal::i64_suffixed(ord)
177178
}
178179

179-
fn make_enumerator_definition(enumerator: &Enumerator) -> TokenStream {
180+
fn make_enumerator_definition(enumerator: &Enumerator, ctx: &mut Context) -> TokenStream {
180181
let ordinal_lit = match enumerator.value {
181182
EnumeratorValue::Enum(ord) => make_enumerator_ord(ord),
182-
EnumeratorValue::Bitfield(ord) => make_bitfield_flag_ord(ord),
183+
EnumeratorValue::Bitfield(ord) => {
184+
if ord < 0 {
185+
ctx.warnings_mut().push(format!(
186+
"Encountered negative bitfield. {} = {}. This is currently being discussed in the following issues: https://github.com/godotengine/godot/issues/88962, https://github.com/CoaguCo-Industries/GodotSteam/issues/424",
187+
enumerator.godot_name,
188+
ord
189+
))
190+
}
191+
192+
make_bitfield_flag_ord(ord)
193+
}
183194
};
184195

185196
let rust_ident = &enumerator.name;

godot-codegen/src/generator/mod.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ pub fn generate_core_mod_file(gen_path: &Path, submit_fn: &mut SubmitFn) {
100100
pub mod builtin_classes;
101101
pub mod utilities;
102102
pub mod native;
103+
pub mod warn;
103104
};
104105

105106
submit_fn(gen_path.join("mod.rs"), code);
@@ -115,3 +116,15 @@ pub fn generate_core_central_file(
115116

116117
submit_fn(gen_path.join("central.rs"), core_code);
117118
}
119+
120+
pub fn generate_core_warn_file(ctx: &mut Context, gen_path: &Path, submit_fn: &mut SubmitFn) {
121+
// When invoked by another crate during unit-test (not integration test), don't run generator.
122+
123+
let warnings = ctx.warnings();
124+
125+
let code = quote! {
126+
pub fn warnings() -> Vec<&'static str> { vec![#(#warnings),*] }
127+
};
128+
129+
submit_fn(gen_path.join("warn.rs"), code);
130+
}

godot-codegen/src/lib.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@ use crate::generator::extension_interface::generate_sys_interface_file;
2525
use crate::generator::native_structures::generate_native_structures_files;
2626
use crate::generator::utility_functions::generate_utilities_file;
2727
use crate::generator::{
28-
generate_core_central_file, generate_core_mod_file, generate_sys_builtin_lifecycle_file,
29-
generate_sys_builtin_methods_file, generate_sys_central_file, generate_sys_classes_file,
30-
generate_sys_utilities_file,
28+
generate_core_central_file, generate_core_mod_file, generate_core_warn_file,
29+
generate_sys_builtin_lifecycle_file, generate_sys_builtin_methods_file,
30+
generate_sys_central_file, generate_sys_classes_file, generate_sys_utilities_file,
3131
};
3232
use crate::models::domain::{ApiView, ExtensionApi};
3333
use crate::models::json::{load_extension_api, JsonExtensionApi};
@@ -142,5 +142,8 @@ pub fn generate_core_files(core_gen_path: &Path) {
142142
);
143143
watch.record("generate_native_structures_files");
144144

145+
generate_core_warn_file(&mut ctx, core_gen_path, &mut submit_fn);
146+
watch.record("generate_warn_file");
147+
145148
watch.write_stats_to(&core_gen_path.join("codegen-stats.txt"));
146149
}

godot-core/src/init/mod.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ use godot_ffi as sys;
1010
use sys::GodotFfi;
1111

1212
use crate::builtin::{GString, StringName};
13-
use crate::out;
13+
use crate::gen::warn;
14+
use crate::{godot_warn, out};
1415

1516
pub use sys::GdextBuild;
1617

@@ -44,6 +45,12 @@ pub unsafe fn __gdext_load_library<E: ExtensionLibrary>(
4445

4546
*init = godot_init_params;
4647

48+
if !E::ignore_codegen_warnings() {
49+
for warning in warn::warnings() {
50+
godot_warn!("{warning}");
51+
}
52+
}
53+
4754
success as u8
4855
};
4956

@@ -168,6 +175,8 @@ pub unsafe trait ExtensionLibrary {
168175
fn on_level_deinit(_level: InitLevel) {
169176
// Nothing by default.
170177
}
178+
179+
fn ignore_codegen_warnings() -> bool { false }
171180
}
172181

173182
/// Determines if and how an extension's code is run in the editor.

0 commit comments

Comments
 (0)