You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-11-06 12:20:30 +00:00
fix https://github.com/godotengine/godot/issues/104135 Generator for C# makes illegal code for a GodotObject with a primary ctor
Co-authored-by: Raul Santos <raulsntos@gmail.com>
This commit is contained in:
committed by
Ivan Shakhov
parent
49cc57a75d
commit
724c0021c7
@@ -22,6 +22,13 @@ public class ScriptPropertyDefValGeneratorTests
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async void ExportedProperties2()
|
||||||
|
{
|
||||||
|
await CSharpSourceGeneratorVerifier<ScriptPropertyDefValGenerator>.Verify(
|
||||||
|
"ExportedProperties2.cs", "ExportedProperties2_ScriptPropertyDefVal.generated.cs");
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async void ExportedComplexStrings()
|
public async void ExportedComplexStrings()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
partial class ExportedProperties2
|
||||||
|
{
|
||||||
|
#pragma warning disable CS0109 // Disable warning about redundant 'new' keyword
|
||||||
|
#if TOOLS
|
||||||
|
/// <summary>
|
||||||
|
/// Get the default values for all properties declared in this class.
|
||||||
|
/// This method is used by Godot to determine the value that will be
|
||||||
|
/// used by the inspector when resetting properties.
|
||||||
|
/// Do not call this method.
|
||||||
|
/// </summary>
|
||||||
|
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
|
||||||
|
internal new static global::System.Collections.Generic.Dictionary<global::Godot.StringName, global::Godot.Variant> GetGodotPropertyDefaultValues()
|
||||||
|
{
|
||||||
|
var values = new global::System.Collections.Generic.Dictionary<global::Godot.StringName, global::Godot.Variant>(3);
|
||||||
|
int __Health_default_value = default;
|
||||||
|
values.Add(PropertyName.@Health, global::Godot.Variant.From<int>(__Health_default_value));
|
||||||
|
global::Godot.Resource __SubResource_default_value = default;
|
||||||
|
values.Add(PropertyName.@SubResource, global::Godot.Variant.From<global::Godot.Resource>(__SubResource_default_value));
|
||||||
|
string[] __Strings_default_value = default;
|
||||||
|
values.Add(PropertyName.@Strings, global::Godot.Variant.From<string[]>(__Strings_default_value));
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
#endif // TOOLS
|
||||||
|
#pragma warning restore CS0109
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
using Godot;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
[GlobalClass]
|
||||||
|
public partial class ExportedProperties2(int health, Resource subResource, string[] strings) : Resource
|
||||||
|
{
|
||||||
|
[Export]
|
||||||
|
public int Health { get; set; } = health;
|
||||||
|
[Export]
|
||||||
|
public Resource SubResource { get; set; } = subResource;
|
||||||
|
[Export]
|
||||||
|
public string[] Strings { get; set; } = strings ?? System.Array.Empty<string>();
|
||||||
|
}
|
||||||
@@ -215,6 +215,10 @@ namespace Godot.SourceGenerators
|
|||||||
if (propertyDeclarationSyntax.Initializer != null)
|
if (propertyDeclarationSyntax.Initializer != null)
|
||||||
{
|
{
|
||||||
var sm = context.Compilation.GetSemanticModel(propertyDeclarationSyntax.Initializer.SyntaxTree);
|
var sm = context.Compilation.GetSemanticModel(propertyDeclarationSyntax.Initializer.SyntaxTree);
|
||||||
|
var initializerValue = propertyDeclarationSyntax.Initializer.Value;
|
||||||
|
if (!IsStaticallyResolvable(initializerValue, sm))
|
||||||
|
value = "default";
|
||||||
|
else
|
||||||
value = propertyDeclarationSyntax.Initializer.Value.FullQualifiedSyntax(sm);
|
value = propertyDeclarationSyntax.Initializer.Value.FullQualifiedSyntax(sm);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -418,6 +422,106 @@ namespace Godot.SourceGenerators
|
|||||||
context.AddSource(uniqueHint, SourceText.From(source.ToString(), Encoding.UTF8));
|
context.AddSource(uniqueHint, SourceText.From(source.ToString(), Encoding.UTF8));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static bool IsStaticallyResolvable(ExpressionSyntax expression, SemanticModel semanticModel)
|
||||||
|
{
|
||||||
|
// Handle literals (e.g., `10`, `"string"`, `true`, etc.)
|
||||||
|
if (expression is LiteralExpressionSyntax)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle identifiers (e.g., variable names)
|
||||||
|
if (expression is IdentifierNameSyntax identifier)
|
||||||
|
{
|
||||||
|
var symbolInfo = semanticModel.GetSymbolInfo(identifier).Symbol;
|
||||||
|
|
||||||
|
// Ensure it's a static member
|
||||||
|
return symbolInfo is { IsStatic: true };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle member access (e.g., `MyClass.StaticValue`)
|
||||||
|
if (expression is MemberAccessExpressionSyntax memberAccess)
|
||||||
|
{
|
||||||
|
var symbolInfo = semanticModel.GetSymbolInfo(memberAccess).Symbol;
|
||||||
|
|
||||||
|
// Ensure it's referring to a static member
|
||||||
|
return symbolInfo is { IsStatic: true };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle object creation expressions (e.g., `new Vector2(1.0f, 2.0f)`)
|
||||||
|
if (expression is ObjectCreationExpressionSyntax objectCreation)
|
||||||
|
{
|
||||||
|
// Recursively ensure all its arguments are self-contained
|
||||||
|
if (objectCreation.ArgumentList == null)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
foreach (var argument in objectCreation.ArgumentList.Arguments)
|
||||||
|
{
|
||||||
|
if (!IsStaticallyResolvable(argument.Expression, semanticModel))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expression is ImplicitObjectCreationExpressionSyntax)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expression is InvocationExpressionSyntax invocationExpression)
|
||||||
|
{
|
||||||
|
// Resolve the method being invoked
|
||||||
|
var symbolInfo = semanticModel.GetSymbolInfo(invocationExpression).Symbol;
|
||||||
|
|
||||||
|
if (symbolInfo is IMethodSymbol methodSymbol)
|
||||||
|
{
|
||||||
|
// Ensure the method is static
|
||||||
|
if (methodSymbol.IsStatic)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expression is InterpolatedStringExpressionSyntax interpolatedString)
|
||||||
|
{
|
||||||
|
foreach (var content in interpolatedString.Contents)
|
||||||
|
{
|
||||||
|
if (content is not InterpolationSyntax interpolation)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Analyze the expression inside `${...}`
|
||||||
|
var interpolatedExpression = interpolation.Expression;
|
||||||
|
|
||||||
|
if (!IsStaticallyResolvable(interpolatedExpression, semanticModel))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expression is InitializerExpressionSyntax initializerExpressionSyntax)
|
||||||
|
{
|
||||||
|
foreach (var content in initializerExpressionSyntax.Expressions)
|
||||||
|
{
|
||||||
|
if (!IsStaticallyResolvable(content, semanticModel))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle other expressions conservatively (e.g., method calls, instance references, etc.)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private static bool MemberHasNodeType(ITypeSymbol memberType, MarshalType marshalType)
|
private static bool MemberHasNodeType(ITypeSymbol memberType, MarshalType marshalType)
|
||||||
{
|
{
|
||||||
if (marshalType == MarshalType.GodotObjectOrDerived)
|
if (marshalType == MarshalType.GodotObjectOrDerived)
|
||||||
|
|||||||
Reference in New Issue
Block a user