mirror of
				https://github.com/godotengine/godot.git
				synced 2025-10-31 21:51:22 +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,31 +212,37 @@ namespace Godot.SourceGenerators | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 // Generate GetGodotClassPropertyValue |                 // Generate GetGodotClassPropertyValue | ||||||
|  |                 bool allPropertiesAreWriteOnly = godotClassFields.Length == 0 && godotClassProperties.All(pi => pi.PropertySymbol.IsWriteOnly); | ||||||
| 
 | 
 | ||||||
|                 source.Append("    /// <inheritdoc/>\n"); |                 if (!allPropertiesAreWriteOnly) | ||||||
|                 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) |  | ||||||
|                 { |                 { | ||||||
|                     GeneratePropertyGetter(property.PropertySymbol.Name, |                     source.Append("    /// <inheritdoc/>\n"); | ||||||
|                         property.PropertySymbol.Type, property.Type, source, isFirstEntry); |                     source.Append("    [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]\n"); | ||||||
|                     isFirstEntry = false; |                     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 |                 // 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
	
	 William Scalf
						William Scalf