From 4278d3a2fece5bebab129c8bee2219e8c264ec7a Mon Sep 17 00:00:00 2001 From: Thaddeus Crews Date: Wed, 14 Feb 2024 14:12:30 -0600 Subject: [PATCH] C#: Enable nullability for generated & compatibility code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit • Specify explicit references to GodotObject as nullable in Variant --- modules/mono/editor/bindings_generator.cpp | 128 +++++++++--------- modules/mono/editor/bindings_generator.h | 7 + .../mono/glue/GodotSharp/GodotSharp/Compat.cs | 18 +-- .../glue/GodotSharp/GodotSharp/Core/Array.cs | 2 +- .../Core/NativeInterop/VariantUtils.cs | 2 +- .../GodotSharp/GodotSharp/Core/Variant.cs | 12 +- .../GodotSharp/GodotSharpEditor/Compat.cs | 5 +- 7 files changed, 90 insertions(+), 84 deletions(-) diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp index 5cb177676c1f..417b3996d002 100644 --- a/modules/mono/editor/bindings_generator.cpp +++ b/modules/mono/editor/bindings_generator.cpp @@ -66,6 +66,7 @@ StringBuilder &operator<<(StringBuilder &r_sb, const char *p_cstring) { #define OPEN_BLOCK "{\n" #define CLOSE_BLOCK "}\n" +#define EMPTY_BLOCK " { }\n" #define OPEN_BLOCK_L1 INDENT1 OPEN_BLOCK #define OPEN_BLOCK_L2 INDENT2 OPEN_BLOCK @@ -1122,6 +1123,7 @@ void BindingsGenerator::_append_xml_method(StringBuilder &p_xml_output, const Ty if (iarg.def_param_mode == ArgumentInterface::NULLABLE_VAL) { p_xml_output.append("}"); } + // Documentation accounts for nullable refs automatically, no need to append "?" } p_xml_output.append(")\"/>"); } else { @@ -1486,6 +1488,7 @@ Error BindingsGenerator::_populate_method_icalls_table(const TypeInterface &p_it void BindingsGenerator::_generate_array_extensions(StringBuilder &p_output) { p_output.append("namespace " BINDINGS_NAMESPACE ";\n\n"); p_output.append("using System;\n\n"); + p_output.append("#nullable enable\n\n"); // The class where we put the extensions doesn't matter, so just use "GD". p_output.append("public static partial class " BINDINGS_GLOBAL_SCOPE_CLASS "\n{"); @@ -1498,7 +1501,7 @@ void BindingsGenerator::_generate_array_extensions(StringBuilder &p_output) { p_output.append(INDENT1 "public static bool IsEmpty(this " #m_type "[] instance)\n"); \ p_output.append(OPEN_BLOCK_L1); \ p_output.append(INDENT2 "return instance == null || instance.Length == 0;\n"); \ - p_output.append(INDENT1 CLOSE_BLOCK); + p_output.append(CLOSE_BLOCK_L1); #define ARRAY_JOIN(m_type) \ p_output.append("\n" INDENT1 "/// \n"); \ @@ -1509,8 +1512,8 @@ void BindingsGenerator::_generate_array_extensions(StringBuilder &p_output) { p_output.append(INDENT1 "/// A single string with all items.\n"); \ p_output.append(INDENT1 "public static string Join(this " #m_type "[] instance, string delimiter = \", \")\n"); \ p_output.append(OPEN_BLOCK_L1); \ - p_output.append(INDENT2 "return String.Join(delimiter, instance);\n"); \ - p_output.append(INDENT1 CLOSE_BLOCK); + p_output.append(INDENT2 "return String.Join(delimiter, instance ?? Array.Empty<" #m_type ">());\n"); \ + p_output.append(CLOSE_BLOCK_L1); #define ARRAY_STRINGIFY(m_type) \ p_output.append("\n" INDENT1 "/// \n"); \ @@ -1521,7 +1524,7 @@ void BindingsGenerator::_generate_array_extensions(StringBuilder &p_output) { p_output.append(INDENT1 "public static string Stringify(this " #m_type "[] instance)\n"); \ p_output.append(OPEN_BLOCK_L1); \ p_output.append(INDENT2 "return \"[\" + instance.Join() + \"]\";\n"); \ - p_output.append(INDENT1 CLOSE_BLOCK); + p_output.append(CLOSE_BLOCK_L1); #define ARRAY_ALL(m_type) \ ARRAY_IS_EMPTY(m_type) \ @@ -1554,7 +1557,7 @@ void BindingsGenerator::_generate_global_constants(StringBuilder &p_output) { // Constants (in partial GD class) p_output.append("namespace " BINDINGS_NAMESPACE ";\n\n"); - + p_output.append("#nullable enable\n\n"); p_output.append("public static partial class " BINDINGS_GLOBAL_SCOPE_CLASS "\n" OPEN_BLOCK); for (const ConstantInterface &iconstant : global_constants) { @@ -1727,8 +1730,8 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_proj_dir) { cs_icalls_content.append("using System;\n" "using System.Diagnostics.CodeAnalysis;\n" "using System.Runtime.InteropServices;\n" - "using Godot.NativeInterop;\n" - "\n"); + "using Godot.NativeInterop;\n\n" + "#nullable enable\n\n"); cs_icalls_content.append("[SuppressMessage(\"ReSharper\", \"InconsistentNaming\")]\n"); cs_icalls_content.append("[SuppressMessage(\"ReSharper\", \"RedundantUnsafeContext\")]\n"); cs_icalls_content.append("[SuppressMessage(\"ReSharper\", \"RedundantNameQualifier\")]\n"); @@ -1834,8 +1837,8 @@ Error BindingsGenerator::generate_cs_editor_project(const String &p_proj_dir) { cs_icalls_content.append("using System;\n" "using System.Diagnostics.CodeAnalysis;\n" "using System.Runtime.InteropServices;\n" - "using Godot.NativeInterop;\n" - "\n"); + "using Godot.NativeInterop;\n\n" + "#nullable enable\n\n"); cs_icalls_content.append("[SuppressMessage(\"ReSharper\", \"InconsistentNaming\")]\n"); cs_icalls_content.append("[SuppressMessage(\"ReSharper\", \"RedundantUnsafeContext\")]\n"); cs_icalls_content.append("[SuppressMessage(\"ReSharper\", \"RedundantNameQualifier\")]\n"); @@ -1964,9 +1967,9 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str output.append("using System;\n"); // IntPtr output.append("using System.ComponentModel;\n"); // EditorBrowsable output.append("using System.Diagnostics;\n"); // DebuggerBrowsable - output.append("using Godot.NativeInterop;\n"); + output.append("using Godot.NativeInterop;\n\n"); - output.append("\n#nullable disable\n"); + output.append("#nullable enable\n\n"); const DocData::ClassDoc *class_doc = itype.class_doc; @@ -2148,7 +2151,7 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str instance_type_name = itype.proxy_name; } - output.append(MEMBER_BEGIN "private static " + instance_type_name + " singleton;\n"); + output.append(MEMBER_BEGIN "private static " + instance_type_name + "? singleton;\n"); output << MEMBER_BEGIN "public static " + instance_type_name + " " CS_PROPERTY_SINGLETON " =>\n" << INDENT2 "singleton \?\?= (" + instance_type_name + ")" @@ -2173,29 +2176,19 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str if (is_derived_type) { // Add default constructor - if (itype.is_instantiable) { - output << MEMBER_BEGIN "public " << itype.proxy_name << "() : this(" - << (itype.memory_own ? "true" : "false") << ")\n" OPEN_BLOCK_L1 - << INDENT2 "unsafe\n" INDENT2 OPEN_BLOCK - << INDENT3 "ConstructAndInitialize(" CS_STATIC_FIELD_NATIVE_CTOR ", " - << BINDINGS_NATIVE_NAME_FIELD ", CachedType, refCounted: " - << (itype.is_ref_counted ? "true" : "false") << ");\n" - << CLOSE_BLOCK_L2 CLOSE_BLOCK_L1; - } else { - // Hide the constructor - output << MEMBER_BEGIN "internal " << itype.proxy_name << "() : this(" - << (itype.memory_own ? "true" : "false") << ")\n" OPEN_BLOCK_L1 - << INDENT2 "unsafe\n" INDENT2 OPEN_BLOCK - << INDENT3 "ConstructAndInitialize(null, " - << BINDINGS_NATIVE_NAME_FIELD ", CachedType, refCounted: " - << (itype.is_ref_counted ? "true" : "false") << ");\n" - << CLOSE_BLOCK_L2 CLOSE_BLOCK_L1; - } + output << MEMBER_BEGIN << (itype.is_instantiable ? "public" : "internal") << " " + << itype.proxy_name << "() : this(" << (itype.memory_own ? "true" : "false") + << ")\n" OPEN_BLOCK_L1 INDENT2 "unsafe\n" + << INDENT2 OPEN_BLOCK INDENT3 "ConstructAndInitialize(" + << (itype.is_instantiable ? CS_STATIC_FIELD_NATIVE_CTOR : "null") + << ", " << BINDINGS_NATIVE_NAME_FIELD ", CachedType, refCounted: " + << (itype.is_ref_counted ? "true" : "false") << ");\n" + << CLOSE_BLOCK_L2 CLOSE_BLOCK_L1; // Add.. em.. trick constructor. Sort of. output.append(MEMBER_BEGIN "internal "); output.append(itype.proxy_name); - output.append("(bool " CS_PARAM_MEMORYOWN ") : base(" CS_PARAM_MEMORYOWN ") { }\n"); + output.append("(bool " CS_PARAM_MEMORYOWN ") : base(" CS_PARAM_MEMORYOWN ")" EMPTY_BLOCK); } } @@ -2317,7 +2310,7 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str ERR_FAIL_NULL_V(return_type, ERR_BUG); // Return type not found output << INDENT3 "ret = " - << sformat(return_type->cs_managed_to_variant, "callRet", return_type->cs_type, return_type->name) + << sformat(return_type->cs_managed_to_variant, "callRet", return_type->cs_type + (return_type->is_object_type ? "?" : ""), return_type->name) << ";\n" << INDENT3 "return true;\n"; } else { @@ -2576,14 +2569,13 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte String prop_cs_type = prop_itype->cs_type + _get_generic_type_parameters(*prop_itype, proptype_name.generic_type_parameters); p_output.append(prop_cs_type); - p_output.append(" "); + p_output.append(prop_itype->is_object_type ? "? " : " "); p_output.append(p_iprop.proxy_name); p_output.append("\n" OPEN_BLOCK_L1); if (getter) { - p_output.append(INDENT2 "get\n" OPEN_BLOCK_L2 INDENT3); + p_output.append(INDENT2 "get => "); - p_output.append("return "); p_output.append(getter->proxy_name + "("); if (p_iprop.index != -1) { const ArgumentInterface &idx_arg = getter->arguments.front()->get(); @@ -2596,11 +2588,11 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte p_output.append(itos(p_iprop.index)); } } - p_output.append(");\n" CLOSE_BLOCK_L2); + p_output.append(");\n"); } if (setter) { - p_output.append(INDENT2 "set\n" OPEN_BLOCK_L2 INDENT3); + p_output.append(INDENT2 "set => "); p_output.append(setter->proxy_name + "("); if (p_iprop.index != -1) { @@ -2614,7 +2606,7 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte p_output.append(itos(p_iprop.index) + ", "); } } - p_output.append("value);\n" CLOSE_BLOCK_L2); + p_output.append("value);\n"); } p_output.append(CLOSE_BLOCK_L1); @@ -2696,6 +2688,8 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf if (iarg.def_param_mode == ArgumentInterface::NULLABLE_VAL) { arguments_sig += "> "; + } else if (iarg.def_param_mode == ArgumentInterface::NULLABLE_REF || arg_type->is_object_type) { + arguments_sig += "? "; } else { arguments_sig += " "; } @@ -2713,27 +2707,13 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf icall_params += ", "; - if (iarg.default_argument.size() && iarg.def_param_mode != ArgumentInterface::CONSTANT) { + if (iarg.default_argument.size() && iarg.def_param_mode != ArgumentInterface::CONSTANT && iarg.default_argument != "null") { // The default value of an argument must be constant. Otherwise we make it Nullable and do the following: - // Type arg_in = arg.HasValue ? arg.Value : ; + // Type arg_in = arg ?? ; String arg_or_defval_local = iarg.name; arg_or_defval_local += "OrDefVal"; - cs_in_statements << INDENT2 << arg_cs_type << " " << arg_or_defval_local << " = " << iarg.name; - - if (iarg.def_param_mode == ArgumentInterface::NULLABLE_VAL) { - cs_in_statements << ".HasValue ? "; - } else { - cs_in_statements << " != null ? "; - } - - cs_in_statements << iarg.name; - - if (iarg.def_param_mode == ArgumentInterface::NULLABLE_VAL) { - cs_in_statements << ".Value : "; - } else { - cs_in_statements << " : "; - } + cs_in_statements << INDENT2 << arg_cs_type << " " << arg_or_defval_local << " = " << iarg.name << " ?? "; String cs_type = arg_cs_type; if (cs_type.ends_with("[]")) { @@ -2760,7 +2740,7 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf // Escape < and > in the attribute default value String param_def_arg = def_arg.replacen("<", "<").replacen(">", ">"); - default_args_doc.append(MEMBER_BEGIN "/// If the parameter is null, then the default value is " + param_def_arg + "."); + default_args_doc.append(MEMBER_BEGIN "/// If the parameter is , then the default value is " + param_def_arg + "."); } else { if (arg_type->cs_in.size()) { cs_in_statements << sformat(arg_type->cs_in, arg_type->c_type, iarg.name, @@ -2840,23 +2820,30 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf } String return_cs_type = return_type->cs_type + _get_generic_type_parameters(*return_type, p_imethod.return_type.generic_type_parameters); + if (return_type->is_object_type) { + return_cs_type += "?"; + } p_output.append(return_cs_type + " "); p_output.append(p_imethod.proxy_name + "("); - p_output.append(arguments_sig + ")\n" OPEN_BLOCK_L1); + p_output.append(arguments_sig + ")"); if (p_imethod.is_virtual) { // Godot virtual method must be overridden, therefore we return a default value by default. if (return_type->cname == name_cache.type_void) { - p_output.append(CLOSE_BLOCK_L1); + p_output << EMPTY_BLOCK; } else { - p_output.append(INDENT2 "return default;\n" CLOSE_BLOCK_L1); + p_output << "\n" OPEN_BLOCK_L1 + << INDENT2 "return " << return_type->cs_default << ";\n" + << CLOSE_BLOCK_L1; } return OK; // Won't increment method bind count } + p_output << "\n" OPEN_BLOCK_L1; + if (p_imethod.requires_object_call) { // Fallback to Godot's object.Call(string, params) @@ -2936,7 +2923,7 @@ Error BindingsGenerator::_generate_cs_signal(const BindingsGenerator::TypeInterf } arguments_sig += arg_type->cs_type; - arguments_sig += " "; + arguments_sig += arg_type->is_object_type ? "? " : " "; arguments_sig += iarg.name; delegate_type_params += arg_type->cs_type; @@ -3374,6 +3361,9 @@ const String BindingsGenerator::_get_generic_type_parameters(const TypeInterface } params += param_itype->cs_type; + if (param_itype->is_object_type) { + params += "?"; + } if (i < p_generic_type_parameters.size() - 1) { params += ", "; } @@ -3612,7 +3602,7 @@ bool BindingsGenerator::_populate_object_type_interfaces() { itype.c_arg_in = "&%s"; itype.c_type = "IntPtr"; itype.c_type_in = itype.c_type; - itype.c_type_out = "GodotObject"; + itype.c_type_out = "GodotObject?"; // Populate properties @@ -4138,11 +4128,11 @@ bool BindingsGenerator::_arg_default_value_from_variant(const Variant &p_val, Ar if (r_iarg.type.cname == name_cache.type_StringName || r_iarg.type.cname == name_cache.type_NodePath) { if (r_iarg.default_argument.length() > 0) { r_iarg.default_argument = "(%s)\"" + r_iarg.default_argument + "\""; - r_iarg.def_param_mode = ArgumentInterface::NULLABLE_REF; } else { // No need for a special `in` statement to change `null` to `""`. Marshaling takes care of this already. r_iarg.default_argument = "null"; } + r_iarg.def_param_mode = ArgumentInterface::NULLABLE_REF; } else { CRASH_COND(r_iarg.type.cname != name_cache.type_String); r_iarg.default_argument = "\"" + r_iarg.default_argument + "\""; @@ -4173,9 +4163,6 @@ bool BindingsGenerator::_arg_default_value_from_variant(const Variant &p_val, Ar case Variant::VECTOR2I: case Variant::VECTOR3: case Variant::VECTOR3I: - r_iarg.default_argument = "new %s" + r_iarg.default_argument; - r_iarg.def_param_mode = ArgumentInterface::NULLABLE_VAL; - break; case Variant::VECTOR4: case Variant::VECTOR4I: r_iarg.default_argument = "new %s" + r_iarg.default_argument; @@ -4186,13 +4173,14 @@ bool BindingsGenerator::_arg_default_value_from_variant(const Variant &p_val, Ar "Parameter of type '" + String(r_iarg.type.cname) + "' can only have null/zero as the default value."); r_iarg.default_argument = "null"; + r_iarg.def_param_mode = ArgumentInterface::NULLABLE_REF; break; case Variant::DICTIONARY: ERR_FAIL_COND_V_MSG(!p_val.operator Dictionary().is_empty(), false, "Default value of type 'Dictionary' must be an empty dictionary."); // The [cs_in] expression already interprets null values as empty dictionaries. r_iarg.default_argument = "null"; - r_iarg.def_param_mode = ArgumentInterface::CONSTANT; + r_iarg.def_param_mode = ArgumentInterface::NULLABLE_REF; break; case Variant::RID: ERR_FAIL_COND_V_MSG(r_iarg.type.cname != name_cache.type_RID, false, @@ -4208,7 +4196,7 @@ bool BindingsGenerator::_arg_default_value_from_variant(const Variant &p_val, Ar "Default value of type 'Array' must be an empty array."); // The [cs_in] expression already interprets null values as empty arrays. r_iarg.default_argument = "null"; - r_iarg.def_param_mode = ArgumentInterface::CONSTANT; + r_iarg.def_param_mode = ArgumentInterface::NULLABLE_REF; break; case Variant::PACKED_BYTE_ARRAY: case Variant::PACKED_INT32_ARRAY: @@ -4412,6 +4400,7 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { itype.cname = itype.name; itype.proxy_name = "string"; itype.cs_type = itype.proxy_name; + itype.cs_default = "string.Empty"; itype.c_in = "%5using %0 %1_in = " C_METHOD_MONOSTR_TO_GODOT "(%1);\n"; itype.c_out = "%5return " C_METHOD_MONOSTR_FROM_GODOT "(%1);\n"; itype.c_arg_in = "&%s_in"; @@ -4428,6 +4417,7 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { itype.cname = itype.name; itype.proxy_name = "StringName"; itype.cs_type = itype.proxy_name; + itype.cs_default = "new()"; itype.cs_in_expr = "(%1)(%0?.NativeValue ?? default)"; // Cannot pass null StringName to ptrcall itype.c_out = "%5return %0.CreateTakingOwnershipOfDisposableValue(%1);\n"; @@ -4446,6 +4436,7 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { itype.cname = itype.name; itype.proxy_name = "NodePath"; itype.cs_type = itype.proxy_name; + itype.cs_default = "new()"; itype.cs_in_expr = "(%1)(%0?.NativeValue ?? default)"; // Cannot pass null NodePath to ptrcall itype.c_out = "%5return %0.CreateTakingOwnershipOfDisposableValue(%1);\n"; @@ -4533,6 +4524,7 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { itype.cname = itype.name; \ itype.proxy_name = #m_proxy_t "[]"; \ itype.cs_type = itype.proxy_name; \ + itype.cs_default = "Array.Empty<" #m_proxy_t ">()"; \ itype.c_in = "%5using %0 %1_in = " C_METHOD_MONOARRAY_TO(m_type) "(%1);\n"; \ itype.c_out = "%5return " C_METHOD_MONOARRAY_FROM(m_type) "(%1);\n"; \ itype.c_arg_in = "&%s_in"; \ @@ -4567,6 +4559,7 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { itype.proxy_name = itype.name; itype.type_parameter_count = 1; itype.cs_type = BINDINGS_NAMESPACE_COLLECTIONS "." + itype.proxy_name; + itype.cs_default = "new()"; itype.cs_in_expr = "(%1)(%0 ?? new()).NativeValue"; itype.c_out = "%5return %0.CreateTakingOwnershipOfDisposableValue(%1);\n"; itype.c_arg_in = "&%s"; @@ -4594,6 +4587,7 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { itype.proxy_name = itype.name; itype.type_parameter_count = 2; itype.cs_type = BINDINGS_NAMESPACE_COLLECTIONS "." + itype.proxy_name; + itype.cs_default = "new()"; itype.cs_in_expr = "(%1)(%0 ?? new()).NativeValue"; itype.c_out = "%5return %0.CreateTakingOwnershipOfDisposableValue(%1);\n"; itype.c_arg_in = "&%s"; diff --git a/modules/mono/editor/bindings_generator.h b/modules/mono/editor/bindings_generator.h index bb0ba0cb0096..23f9e709021f 100644 --- a/modules/mono/editor/bindings_generator.h +++ b/modules/mono/editor/bindings_generator.h @@ -415,6 +415,11 @@ class BindingsGenerator { */ String cs_type; + /** + * Value used when returning a default argument. Usually 'default'. + */ + String cs_default; + /** * Formatting elements: * %0: input expression of type `in godot_variant` @@ -600,8 +605,10 @@ class BindingsGenerator { TypeInterface() { static String default_cs_variant_to_managed = "VariantUtils.ConvertTo<%1>(%0)"; static String default_cs_managed_to_variant = "VariantUtils.CreateFrom<%1>(%0)"; + static String default_cs_default = "default"; cs_variant_to_managed = default_cs_variant_to_managed; cs_managed_to_variant = default_cs_managed_to_variant; + cs_default = default_cs_default; } }; diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Compat.cs b/modules/mono/glue/GodotSharp/GodotSharp/Compat.cs index 4e80afc4a595..5d5c3dfeef2f 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Compat.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Compat.cs @@ -7,6 +7,8 @@ namespace Godot; +#nullable enable + #pragma warning disable CS1734 // XML comment on 'X' has a paramref tag for 'Y', but there is no parameter by that name. // TODO: This is currently disabled because of https://github.com/dotnet/roslyn/issues/52904 #pragma warning disable IDE0040 // Add accessibility modifiers. @@ -70,7 +72,7 @@ partial class CodeEdit { /// [EditorBrowsable(EditorBrowsableState.Never)] - public void AddCodeCompletionOption(CodeCompletionKind type, string displayText, string insertText, Nullable textColor, Resource icon, Nullable value) + public void AddCodeCompletionOption(CodeCompletionKind type, string displayText, string insertText, Nullable textColor, Resource? icon, Nullable value) { AddCodeCompletionOption(type, displayText, insertText, textColor, icon, value, location: 1024); } @@ -98,7 +100,7 @@ public bool ArrangeNodesButtonHidden /// [EditorBrowsable(EditorBrowsableState.Never)] - public HBoxContainer GetZoomHBox() + public HBoxContainer? GetZoomHBox() { return GetMenuHBox(); } @@ -134,7 +136,7 @@ partial class ImporterMesh { /// [EditorBrowsable(EditorBrowsableState.Never)] - public void AddSurface(Mesh.PrimitiveType primitive, Godot.Collections.Array arrays, Godot.Collections.Array blendShapes, Godot.Collections.Dictionary lods, Material material, string name, uint flags) + public void AddSurface(Mesh.PrimitiveType primitive, Godot.Collections.Array arrays, Godot.Collections.Array? blendShapes, Godot.Collections.Dictionary? lods, Material? material, string name, uint flags) { AddSurface(primitive, arrays, blendShapes, lods, material, name, (ulong)flags); } @@ -172,9 +174,9 @@ partial class RenderingDevice { /// [EditorBrowsable(EditorBrowsableState.Never)] - public long DrawListBegin(Rid framebuffer, InitialAction initialColorAction, FinalAction finalColorAction, InitialAction initialDepthAction, FinalAction finalDepthAction, Color[] clearColorValues, float clearDepth, uint clearStencil, Nullable region, Godot.Collections.Array storageTextures) + public long DrawListBegin(Rid framebuffer, InitialAction initialColorAction, FinalAction finalColorAction, InitialAction initialDepthAction, FinalAction finalDepthAction, Color[]? clearColorValues, float clearDepth, uint clearStencil, Nullable region, Godot.Collections.Array? storageTextures) { - return DrawListBegin(framebuffer, initialColorAction, finalColorAction, initialDepthAction, finalDepthAction, clearColorValues, clearDepth, clearStencil, region, new Godot.Collections.Array(storageTextures)); + return DrawListBegin(framebuffer, initialColorAction, finalColorAction, initialDepthAction, finalDepthAction, clearColorValues, clearDepth, clearStencil, region, new Godot.Collections.Array(storageTextures ?? new())); } } @@ -199,14 +201,14 @@ partial class SurfaceTool { /// [EditorBrowsable(EditorBrowsableState.Never)] - public void AddTriangleFan(Vector3[] vertices, Vector2[] uvs, Color[] colors, Vector2[] uv2S, Vector3[] normals, Godot.Collections.Array tangents) + public void AddTriangleFan(Vector3[] vertices, Vector2[]? uvs, Color[]? colors, Vector2[]? uv2S, Vector3[]? normals, Godot.Collections.Array? tangents) { - AddTriangleFan(vertices, uvs, colors, uv2S, normals, new Godot.Collections.Array(tangents)); + AddTriangleFan(vertices, uvs, colors, uv2S, normals, new Godot.Collections.Array(tangents ?? new())); } /// [EditorBrowsable(EditorBrowsableState.Never)] - public ArrayMesh Commit(ArrayMesh existing, uint flags) + public ArrayMesh? Commit(ArrayMesh existing, uint flags) { return Commit(existing, (ulong)flags); } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs index 9b5aec7031cc..858cec6ef433 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs @@ -158,7 +158,7 @@ public Array(Span array) /// The is . /// /// A new Godot Array. - public Array(ReadOnlySpan array) + public Array(ReadOnlySpan array) { if (array == null) throw new ArgumentNullException(nameof(array)); diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs index 464b5174281a..e33c7b43b4f9 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs @@ -243,7 +243,7 @@ public static godot_variant CreateFromSystemArrayOfNodePath(Span from) public static godot_variant CreateFromSystemArrayOfRid(Span from) => CreateFromArray(new Collections.Array(from)); - public static godot_variant CreateFromSystemArrayOfGodotObject(GodotObject[]? from) + public static godot_variant CreateFromSystemArrayOfGodotObject(GodotObject?[]? from) { if (from == null) return default; // Nil diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Variant.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Variant.cs index 036a26328a79..22970ba94761 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Variant.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Variant.cs @@ -346,7 +346,7 @@ public Rid[] AsSystemArrayOfRid() => VariantUtils.ConvertToSystemArrayOfRid((godot_variant)NativeVar); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public GodotObject AsGodotObject() => + public GodotObject? AsGodotObject() => VariantUtils.ConvertToGodotObject((godot_variant)NativeVar); [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -501,7 +501,7 @@ public Collections.Array AsGodotArray() => public static explicit operator Rid[](Variant from) => from.AsSystemArrayOfRid(); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static explicit operator GodotObject(Variant from) => from.AsGodotObject(); + public static explicit operator GodotObject?(Variant from) => from.AsGodotObject(); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator StringName(Variant from) => from.AsStringName(); @@ -642,7 +642,7 @@ public Collections.Array AsGodotArray() => public static Variant CreateFrom(Span from) => from; [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Variant CreateFrom(GodotObject[] from) => from; + public static Variant CreateFrom(GodotObject?[] from) => from; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Variant CreateFrom<[MustBeVariant] TKey, [MustBeVariant] TValue>(Collections.Dictionary from) => @@ -662,7 +662,7 @@ public static Variant CreateFrom<[MustBeVariant] T>(Collections.Array from) = public static Variant CreateFrom(Span from) => from; [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Variant CreateFrom(GodotObject from) => from; + public static Variant CreateFrom(GodotObject? from) => from; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Variant CreateFrom(StringName from) => from; @@ -842,7 +842,7 @@ public static implicit operator Variant(Color[] from) => (Variant)from.AsSpan(); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator Variant(GodotObject[] from) => + public static implicit operator Variant(GodotObject?[] from) => CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromSystemArrayOfGodotObject(from)); [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -906,7 +906,7 @@ public static implicit operator Variant(Span from) => CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromSystemArrayOfRid(from)); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator Variant(GodotObject from) => + public static implicit operator Variant(GodotObject? from) => CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromGodotObject(from)); [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/modules/mono/glue/GodotSharp/GodotSharpEditor/Compat.cs b/modules/mono/glue/GodotSharp/GodotSharpEditor/Compat.cs index d1289ee6ba8d..b2ef4fbceb9b 100644 --- a/modules/mono/glue/GodotSharp/GodotSharpEditor/Compat.cs +++ b/modules/mono/glue/GodotSharp/GodotSharpEditor/Compat.cs @@ -7,6 +7,9 @@ namespace Godot; +#nullable enable + +#pragma warning disable CS1734 // XML comment on 'X' has a paramref tag for 'Y', but there is no parameter by that name. // TODO: This is currently disabled because of https://github.com/dotnet/roslyn/issues/52904 #pragma warning disable IDE0040 // Add accessibility modifiers. @@ -14,7 +17,7 @@ partial class EditorUndoRedoManager { /// [EditorBrowsable(EditorBrowsableState.Never)] - public void CreateAction(string name, UndoRedo.MergeMode mergeMode, GodotObject customContext) + public void CreateAction(string name, UndoRedo.MergeMode mergeMode, GodotObject? customContext) { CreateAction(name, mergeMode, customContext, backwardUndoOps: false); }