diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/OneWayProperties/AllReadOnly.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/OneWayProperties/AllReadOnly.cs new file mode 100644 index 000000000000..0c374169b9c5 --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/OneWayProperties/AllReadOnly.cs @@ -0,0 +1,10 @@ +namespace Godot.SourceGenerators.Sample +{ + public partial class AllReadOnly : GodotObject + { + public readonly string readonly_field = "foo"; + public string readonly_auto_property { get; } = "foo"; + public string readonly_property { get => "foo"; } + public string initonly_auto_property { get; init; } + } +} diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/OneWayProperties/AllWriteOnly.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/OneWayProperties/AllWriteOnly.cs new file mode 100644 index 000000000000..14a1802330b3 --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/OneWayProperties/AllWriteOnly.cs @@ -0,0 +1,10 @@ +using System; + +namespace Godot.SourceGenerators.Sample +{ + public partial class AllWriteOnly : GodotObject + { + bool writeonly_backing_field = false; + public bool writeonly_property { set => writeonly_backing_field = value; } + } +} diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/OneWayProperties/MixedReadOnlyWriteOnly.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/OneWayProperties/MixedReadOnlyWriteOnly.cs new file mode 100644 index 000000000000..f556bdc7e407 --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/OneWayProperties/MixedReadOnlyWriteOnly.cs @@ -0,0 +1,13 @@ +namespace Godot.SourceGenerators.Sample +{ + public partial class MixedReadonlyWriteOnly : GodotObject + { + public readonly string readonly_field = "foo"; + public string readonly_auto_property { get; } = "foo"; + public string readonly_property { get => "foo"; } + public string initonly_auto_property { get; init; } + + bool writeonly_backing_field = false; + public bool writeonly_property { set => writeonly_backing_field = value; } + } +} diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs index b6ea4b8e88e3..5866db5144f9 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs @@ -303,11 +303,6 @@ namespace Godot.SourceGenerators { foreach (var property in properties) { - // TODO: We should still restore read-only properties after reloading assembly. Two possible ways: reflection or turn RestoreGodotObjectData into a constructor overload. - // Ignore properties without a getter, without a setter or with an init-only setter. Godot properties must be both readable and writable. - if (property.IsWriteOnly || property.IsReadOnly || property.SetMethod!.IsInitOnly) - continue; - var marshalType = MarshalUtils.ConvertManagedTypeToMarshalType(property.Type, typeCache); if (marshalType == null) @@ -325,10 +320,6 @@ namespace Godot.SourceGenerators foreach (var field in fields) { // TODO: We should still restore read-only fields after reloading assembly. Two possible ways: reflection or turn RestoreGodotObjectData into a constructor overload. - // Ignore properties without a getter or without a setter. Godot properties must be both readable and writable. - if (field.IsReadOnly) - continue; - var marshalType = MarshalUtils.ConvertManagedTypeToMarshalType(field.Type, typeCache); if (marshalType == null) diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs index 94d869671795..219ab7aa440c 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs @@ -212,31 +212,37 @@ namespace Godot.SourceGenerators } // Generate GetGodotClassPropertyValue + bool allPropertiesAreWriteOnly = godotClassFields.Length == 0 && godotClassProperties.All(pi => pi.PropertySymbol.IsWriteOnly); - source.Append(" /// \n"); - source.Append(" [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]\n"); - source.Append(" protected override bool GetGodotClassPropertyValue(in godot_string_name name, "); - source.Append("out godot_variant value)\n {\n"); - - isFirstEntry = true; - foreach (var property in godotClassProperties) + if (!allPropertiesAreWriteOnly) { - GeneratePropertyGetter(property.PropertySymbol.Name, - property.PropertySymbol.Type, property.Type, source, isFirstEntry); - isFirstEntry = false; + source.Append(" /// \n"); + source.Append(" [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]\n"); + source.Append(" protected override bool GetGodotClassPropertyValue(in godot_string_name name, "); + source.Append("out godot_variant value)\n {\n"); + + isFirstEntry = true; + foreach (var property in godotClassProperties) + { + if (property.PropertySymbol.IsWriteOnly) + continue; + + GeneratePropertyGetter(property.PropertySymbol.Name, + property.PropertySymbol.Type, property.Type, source, isFirstEntry); + isFirstEntry = false; + } + + foreach (var field in godotClassFields) + { + GeneratePropertyGetter(field.FieldSymbol.Name, + field.FieldSymbol.Type, field.Type, source, isFirstEntry); + isFirstEntry = false; + } + + source.Append(" return base.GetGodotClassPropertyValue(name, out value);\n"); + + source.Append(" }\n"); } - - foreach (var field in godotClassFields) - { - GeneratePropertyGetter(field.FieldSymbol.Name, - field.FieldSymbol.Type, field.Type, source, isFirstEntry); - isFirstEntry = false; - } - - source.Append(" return base.GetGodotClassPropertyValue(name, out value);\n"); - - source.Append(" }\n"); - // Generate GetGodotPropertyList const string dictionaryType = "global::System.Collections.Generic.List"; diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSerializationGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSerializationGenerator.cs index 231a7be021eb..9de99414b6b3 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSerializationGenerator.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSerializationGenerator.cs @@ -119,8 +119,14 @@ namespace Godot.SourceGenerators .Where(s => !s.IsStatic && s.Kind == SymbolKind.Field && !s.IsImplicitlyDeclared) .Cast(); - var godotClassProperties = propertySymbols.WhereIsGodotCompatibleType(typeCache).ToArray(); - var godotClassFields = fieldSymbols.WhereIsGodotCompatibleType(typeCache).ToArray(); + // TODO: We should still restore read-only properties after reloading assembly. Two possible ways: reflection or turn RestoreGodotObjectData into a constructor overload. + // Ignore properties without a getter, without a setter or with an init-only setter. Godot properties must be both readable and writable. + var godotClassProperties = propertySymbols.Where(property => !(property.IsReadOnly || property.IsWriteOnly || property.SetMethod!.IsInitOnly)) + .WhereIsGodotCompatibleType(typeCache) + .ToArray(); + var godotClassFields = fieldSymbols.Where(property => !property.IsReadOnly) + .WhereIsGodotCompatibleType(typeCache) + .ToArray(); var signalDelegateSymbols = members .Where(s => s.Kind == SymbolKind.NamedType)