mirror of
				https://github.com/godotengine/godot.git
				synced 2025-11-03 23:21:15 +00:00 
			
		
		
		
	Allow readonly and writeonly C# properties to be accessed from GDScript
This commit is contained in:
		
							parent
							
								
									7ba79d68bd
								
							
						
					
					
						commit
						41cf94e8b6
					
				
					 6 changed files with 69 additions and 33 deletions
				
			
		| 
						 | 
					@ -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; }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -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; }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -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; }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -303,11 +303,6 @@ namespace Godot.SourceGenerators
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            foreach (var property in properties)
 | 
					            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);
 | 
					                var marshalType = MarshalUtils.ConvertManagedTypeToMarshalType(property.Type, typeCache);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if (marshalType == null)
 | 
					                if (marshalType == null)
 | 
				
			||||||
| 
						 | 
					@ -325,10 +320,6 @@ namespace Godot.SourceGenerators
 | 
				
			||||||
            foreach (var field in fields)
 | 
					            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.
 | 
					                // 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);
 | 
					                var marshalType = MarshalUtils.ConvertManagedTypeToMarshalType(field.Type, typeCache);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if (marshalType == null)
 | 
					                if (marshalType == null)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -212,7 +212,10 @@ namespace Godot.SourceGenerators
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                // Generate GetGodotClassPropertyValue
 | 
					                // Generate GetGodotClassPropertyValue
 | 
				
			||||||
 | 
					                bool allPropertiesAreWriteOnly = godotClassFields.Length == 0 && godotClassProperties.All(pi => pi.PropertySymbol.IsWriteOnly);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (!allPropertiesAreWriteOnly)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
                    source.Append("    /// <inheritdoc/>\n");
 | 
					                    source.Append("    /// <inheritdoc/>\n");
 | 
				
			||||||
                    source.Append("    [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]\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("    protected override bool GetGodotClassPropertyValue(in godot_string_name name, ");
 | 
				
			||||||
| 
						 | 
					@ -221,6 +224,9 @@ namespace Godot.SourceGenerators
 | 
				
			||||||
                    isFirstEntry = true;
 | 
					                    isFirstEntry = true;
 | 
				
			||||||
                    foreach (var property in godotClassProperties)
 | 
					                    foreach (var property in godotClassProperties)
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
 | 
					                        if (property.PropertySymbol.IsWriteOnly)
 | 
				
			||||||
 | 
					                            continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        GeneratePropertyGetter(property.PropertySymbol.Name,
 | 
					                        GeneratePropertyGetter(property.PropertySymbol.Name,
 | 
				
			||||||
                            property.PropertySymbol.Type, property.Type, source, isFirstEntry);
 | 
					                            property.PropertySymbol.Type, property.Type, source, isFirstEntry);
 | 
				
			||||||
                        isFirstEntry = false;
 | 
					                        isFirstEntry = false;
 | 
				
			||||||
| 
						 | 
					@ -236,7 +242,7 @@ namespace Godot.SourceGenerators
 | 
				
			||||||
                    source.Append("        return base.GetGodotClassPropertyValue(name, out value);\n");
 | 
					                    source.Append("        return base.GetGodotClassPropertyValue(name, out value);\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    source.Append("    }\n");
 | 
					                    source.Append("    }\n");
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
                // Generate GetGodotPropertyList
 | 
					                // Generate GetGodotPropertyList
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                const string dictionaryType = "global::System.Collections.Generic.List<global::Godot.Bridge.PropertyInfo>";
 | 
					                const string dictionaryType = "global::System.Collections.Generic.List<global::Godot.Bridge.PropertyInfo>";
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -119,8 +119,14 @@ namespace Godot.SourceGenerators
 | 
				
			||||||
                .Where(s => !s.IsStatic && s.Kind == SymbolKind.Field && !s.IsImplicitlyDeclared)
 | 
					                .Where(s => !s.IsStatic && s.Kind == SymbolKind.Field && !s.IsImplicitlyDeclared)
 | 
				
			||||||
                .Cast<IFieldSymbol>();
 | 
					                .Cast<IFieldSymbol>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var godotClassProperties = propertySymbols.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.
 | 
				
			||||||
            var godotClassFields = fieldSymbols.WhereIsGodotCompatibleType(typeCache).ToArray();
 | 
					            // 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
 | 
					            var signalDelegateSymbols = members
 | 
				
			||||||
                .Where(s => s.Kind == SymbolKind.NamedType)
 | 
					                .Where(s => s.Kind == SymbolKind.NamedType)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue