Merge pull request #67304 from wscalf/master

Allow readonly and writeonly C# properties to be accessed from GDScript
This commit is contained in:
Rémi Verschelde 2023-09-26 16:36:33 +02:00
commit 4410b0b0e1
No known key found for this signature in database
GPG key ID: C3336907360768E1
6 changed files with 69 additions and 33 deletions

View file

@ -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; }
}
}

View file

@ -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; }
}
}

View file

@ -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; }
}
}

View file

@ -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)

View file

@ -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");
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<global::Godot.Bridge.PropertyInfo>";

View file

@ -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)