Merge pull request #91375 from paulloz/dotnet/prevent-generator-crash-on-exported-unconstructed-generic-arrays

C#: Fix generator crash w/ generic arrays
This commit is contained in:
Rémi Verschelde 2024-05-02 12:46:42 +02:00
commit 4eaafc8fa8
No known key found for this signature in database
GPG Key ID: C3336907360768E1
4 changed files with 69 additions and 1 deletions

View File

@ -57,4 +57,13 @@ public class ScriptPropertiesGeneratorTests
"ScriptBoilerplate_ScriptProperties.generated.cs", "OuterClass.NestedClass_ScriptProperties.generated.cs"
);
}
[Fact]
public async void AbstractGenericNode()
{
await CSharpSourceGeneratorVerifier<ScriptPropertiesGenerator>.Verify(
"AbstractGenericNode.cs",
"AbstractGenericNode(Of T)_ScriptProperties.generated.cs"
);
}
}

View File

@ -0,0 +1,49 @@
using Godot;
using Godot.NativeInterop;
partial class AbstractGenericNode<T>
{
#pragma warning disable CS0109 // Disable warning about redundant 'new' keyword
/// <summary>
/// Cached StringNames for the properties and fields contained in this class, for fast lookup.
/// </summary>
public new class PropertyName : global::Godot.Node.PropertyName {
/// <summary>
/// Cached name for the 'MyArray' property.
/// </summary>
public new static readonly global::Godot.StringName MyArray = "MyArray";
}
/// <inheritdoc/>
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
protected override bool SetGodotClassPropertyValue(in godot_string_name name, in godot_variant value)
{
if (name == PropertyName.MyArray) {
this.MyArray = global::Godot.NativeInterop.VariantUtils.ConvertToArray<T>(value);
return true;
}
return base.SetGodotClassPropertyValue(name, value);
}
/// <inheritdoc/>
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
protected override bool GetGodotClassPropertyValue(in godot_string_name name, out godot_variant value)
{
if (name == PropertyName.MyArray) {
value = global::Godot.NativeInterop.VariantUtils.CreateFromArray(this.MyArray);
return true;
}
return base.GetGodotClassPropertyValue(name, out value);
}
/// <summary>
/// Get the property information for all the properties declared in this class.
/// This method is used by Godot to register the available properties in the editor.
/// Do not call this method.
/// </summary>
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
internal new static global::System.Collections.Generic.List<global::Godot.Bridge.PropertyInfo> GetGodotPropertyList()
{
var properties = new global::System.Collections.Generic.List<global::Godot.Bridge.PropertyInfo>();
properties.Add(new(type: (global::Godot.Variant.Type)28, name: PropertyName.MyArray, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true));
return properties;
}
#pragma warning restore CS0109
}

View File

@ -0,0 +1,7 @@
using Godot;
public abstract partial class AbstractGenericNode<[MustBeVariant] T> : Node
{
[Export] // This should be included, but without type hints.
public Godot.Collections.Array<T> MyArray { get; set; } = new();
}

View File

@ -658,7 +658,10 @@ namespace Godot.SourceGenerators
var elementType = MarshalUtils.GetArrayElementType(type);
if (elementType == null)
return false; // Non-generic Array, so there's no hint to add
return false; // Non-generic Array, so there's no hint to add.
if (elementType.TypeKind == TypeKind.TypeParameter)
return false; // The generic is not constructed, we can't really hint anything.
var elementMarshalType = MarshalUtils.ConvertManagedTypeToMarshalType(elementType, typeCache)!.Value;
var elementVariantType = MarshalUtils.ConvertMarshalTypeToVariantType(elementMarshalType)!.Value;