diff options
author | William Scalf <wscalf@gmail.com> | 2023-08-13 18:35:10 -0400 |
---|---|---|
committer | William Scalf <wscalf@gmail.com> | 2023-08-13 18:35:10 -0400 |
commit | 41cf94e8b61ee81fc0e682f2ee4ea2c6df893d37 (patch) | |
tree | df51a5d8f0f871b6d765c29f439cbde572ac2d9b | |
parent | 7ba79d68bd0f97797d7cb37452da6a036ba7c7c9 (diff) | |
download | redot-engine-41cf94e8b61ee81fc0e682f2ee4ea2c6df893d37.tar.gz |
Allow readonly and writeonly C# properties to be accessed from GDScript
6 files changed, 66 insertions, 30 deletions
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 0000000000..0c374169b9 --- /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 0000000000..14a1802330 --- /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 0000000000..f556bdc7e4 --- /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 b6ea4b8e88..5866db5144 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 94d8696717..219ab7aa44 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(" /// <inheritdoc/>\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(" /// <inheritdoc/>\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"); - foreach (var field in godotClassFields) - { - GeneratePropertyGetter(field.FieldSymbol.Name, - field.FieldSymbol.Type, field.Type, source, isFirstEntry); - isFirstEntry = false; - } + isFirstEntry = true; + foreach (var property in godotClassProperties) + { + if (property.PropertySymbol.IsWriteOnly) + continue; - source.Append(" return base.GetGodotClassPropertyValue(name, out value);\n"); + GeneratePropertyGetter(property.PropertySymbol.Name, + property.PropertySymbol.Type, property.Type, source, isFirstEntry); + isFirstEntry = false; + } - 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<global::Godot.Bridge.PropertyInfo>"; 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 231a7be021..9de99414b6 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<IFieldSymbol>(); - 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) |