summaryrefslogtreecommitdiff
path: root/modules/mono/editor
diff options
context:
space:
mode:
Diffstat (limited to 'modules/mono/editor')
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedFields.cs5
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedProperties.cs89
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/MoreExportedFields.cs19
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Common.cs4
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/EventHandlerSuffixSuppressor.cs53
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs70
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotEnums.cs48
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotMemberData.cs8
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotPluginsInitializerGenerator.cs2
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalUtils.cs42
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MethodInfo.cs2
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/PropertyInfo.cs2
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs26
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPathAttributeGenerator.cs10
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs24
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs86
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSerializationGenerator.cs8
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs35
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.IdeMessaging/Utils/SemaphoreExtensions.cs2
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs70
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs2
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs118
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/PlaySettings.cs2
-rw-r--r--modules/mono/editor/bindings_generator.cpp124
-rw-r--r--modules/mono/editor/code_completion.cpp2
-rw-r--r--modules/mono/editor/editor_internal_calls.cpp2
26 files changed, 616 insertions, 239 deletions
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedFields.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedFields.cs
index ac8d6473a6..9a46b7d164 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedFields.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedFields.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
#pragma warning disable CS0169
@@ -83,6 +84,10 @@ namespace Godot.SourceGenerators.Sample
[Export] private StringName[] field_StringNameArray = { "foo", "bar" };
[Export] private NodePath[] field_NodePathArray = { "foo", "bar" };
[Export] private RID[] field_RIDArray = { default, default, default };
+ // Note we use Array and not System.Array. This tests the generated namespace qualification.
+ [Export] private Int32[] field_empty_Int32Array = Array.Empty<Int32>();
+ // Note we use List and not System.Collections.Generic.
+ [Export] private int[] field_array_from_list = new List<int>(Array.Empty<int>()).ToArray();
// Variant
[Export] private Variant field_Variant = "foo";
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedProperties.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedProperties.cs
index 3020cfbc50..eb83833b40 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedProperties.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedProperties.cs
@@ -12,6 +12,95 @@ namespace Godot.SourceGenerators.Sample
[SuppressMessage("ReSharper", "InconsistentNaming")]
public partial class ExportedProperties : Godot.Object
{
+ // Do not generate default value
+ private String _notGenerate_Property_String = new string("not generate");
+ [Export]
+ public String NotGenerate_Complex_Lamda_Property
+ {
+ get => _notGenerate_Property_String + Convert.ToInt32("1");
+ set => _notGenerate_Property_String = value;
+ }
+
+ [Export]
+ public String NotGenerate_Lamda_NoField_Property
+ {
+ get => new string("not generate");
+ set => _notGenerate_Property_String = value;
+ }
+
+ [Export]
+ public String NotGenerate_Complex_Return_Property
+ {
+ get
+ {
+ return _notGenerate_Property_String + Convert.ToInt32("1");
+ }
+ set
+ {
+ _notGenerate_Property_String = value;
+ }
+ }
+
+ private int _notGenerate_Property_Int = 1;
+ [Export]
+ public string NotGenerate_Returns_Property
+ {
+ get
+ {
+ if (_notGenerate_Property_Int == 1)
+ {
+ return "a";
+ }
+ else
+ {
+ return "b";
+ }
+ }
+ set
+ {
+ _notGenerate_Property_Int = value == "a" ? 1 : 2;
+ }
+ }
+
+ // Full Property
+ private String _fullProperty_String = "FullProperty_String";
+ [Export]
+ public String FullProperty_String
+ {
+ get
+ {
+ return _fullProperty_String;
+ }
+ set
+ {
+ _fullProperty_String = value;
+ }
+ }
+
+ private String _fullProperty_String_Complex = new string("FullProperty_String_Complex") + Convert.ToInt32("1");
+ [Export]
+ public String FullProperty_String_Complex
+ {
+ get
+ {
+ return _fullProperty_String_Complex;
+ }
+ set
+ {
+ _fullProperty_String_Complex = value;
+ }
+ }
+
+ // Lamda Property
+ private String _lamdaProperty_String = "LamdaProperty_String";
+ [Export]
+ public String LamdaProperty_String
+ {
+ get => _lamdaProperty_String;
+ set => _lamdaProperty_String = value;
+ }
+
+ // Auto Property
[Export] private Boolean property_Boolean { get; set; } = true;
[Export] private Char property_Char { get; set; } = 'f';
[Export] private SByte property_SByte { get; set; } = 10;
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/MoreExportedFields.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/MoreExportedFields.cs
new file mode 100644
index 0000000000..a6c8e52667
--- /dev/null
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/MoreExportedFields.cs
@@ -0,0 +1,19 @@
+using System;
+using System.Diagnostics.CodeAnalysis;
+
+#pragma warning disable CS0169
+#pragma warning disable CS0414
+
+namespace Godot.SourceGenerators.Sample
+{
+ [SuppressMessage("ReSharper", "BuiltInTypeReferenceStyle")]
+ [SuppressMessage("ReSharper", "RedundantNameQualifier")]
+ [SuppressMessage("ReSharper", "ArrangeObjectCreationWhenTypeEvident")]
+ [SuppressMessage("ReSharper", "InconsistentNaming")]
+ // We split the definition of ExportedFields to verify properties work across multiple files.
+ public partial class ExportedFields : Godot.Object
+ {
+ // Note we use Array and not System.Array. This tests the generated namespace qualification.
+ [Export] private Int64[] field_empty_Int64Array = Array.Empty<Int64>();
+ }
+}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Common.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Common.cs
index e28788ec0b..4eed2d7b7b 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Common.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Common.cs
@@ -14,7 +14,7 @@ namespace Godot.SourceGenerators
{
string message =
"Missing partial modifier on declaration of type '" +
- $"{symbol.FullQualifiedName()}' which is a subclass of '{GodotClasses.Object}'";
+ $"{symbol.FullQualifiedNameOmitGlobal()}' which is a subclass of '{GodotClasses.Object}'";
string description = $"{message}. Subclasses of '{GodotClasses.Object}' " +
"must be declared with the partial modifier.";
@@ -41,7 +41,7 @@ namespace Godot.SourceGenerators
.GetDeclaredSymbol(outerTypeDeclSyntax);
string fullQualifiedName = outerSymbol is INamedTypeSymbol namedTypeSymbol ?
- namedTypeSymbol.FullQualifiedName() :
+ namedTypeSymbol.FullQualifiedNameOmitGlobal() :
"type not found";
string message =
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/EventHandlerSuffixSuppressor.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/EventHandlerSuffixSuppressor.cs
new file mode 100644
index 0000000000..ddde730fa2
--- /dev/null
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/EventHandlerSuffixSuppressor.cs
@@ -0,0 +1,53 @@
+using System.Collections.Immutable;
+using System.Linq;
+using System.Threading;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Diagnostics;
+
+namespace Godot.SourceGenerators
+{
+ [DiagnosticAnalyzer(LanguageNames.CSharp)]
+ public class EventHandlerSuffixSuppressor : DiagnosticSuppressor
+ {
+ private static readonly SuppressionDescriptor _descriptor = new(
+ id: "GDSP0001",
+ suppressedDiagnosticId: "CA1711",
+ justification: "Signal delegates are used in events so the naming follows the guidelines.");
+
+ public override ImmutableArray<SuppressionDescriptor> SupportedSuppressions =>
+ ImmutableArray.Create(_descriptor);
+
+ public override void ReportSuppressions(SuppressionAnalysisContext context)
+ {
+ foreach (var diagnostic in context.ReportedDiagnostics)
+ {
+ AnalyzeDiagnostic(context, diagnostic, context.CancellationToken);
+ }
+ }
+
+ private static void AnalyzeDiagnostic(SuppressionAnalysisContext context, Diagnostic diagnostic, CancellationToken cancellationToken = default)
+ {
+ var location = diagnostic.Location;
+ var root = location.SourceTree?.GetRoot(cancellationToken);
+ var dds = root?
+ .FindNode(location.SourceSpan)
+ .DescendantNodesAndSelf()
+ .OfType<DelegateDeclarationSyntax>()
+ .FirstOrDefault();
+
+ if (dds == null)
+ return;
+
+ var semanticModel = context.GetSemanticModel(dds.SyntaxTree);
+ var delegateSymbol = semanticModel.GetDeclaredSymbol(dds, cancellationToken);
+ if (delegateSymbol == null)
+ return;
+
+ if (delegateSymbol.GetAttributes().Any(a => a.AttributeClass?.IsGodotSignalAttribute() ?? false))
+ {
+ context.ReportSuppression(Suppression.Create(_descriptor, diagnostic));
+ }
+ }
+ }
+}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs
index de3b6c862a..7008fb638f 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs
@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
+using System.Text;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
@@ -29,7 +30,7 @@ namespace Godot.SourceGenerators
{
while (symbol != null)
{
- if (symbol.ContainingAssembly.Name == assemblyName &&
+ if (symbol.ContainingAssembly?.Name == assemblyName &&
symbol.ToString() == typeFullName)
{
return true;
@@ -47,7 +48,7 @@ namespace Godot.SourceGenerators
while (symbol != null)
{
- if (symbol.ContainingAssembly.Name == "GodotSharp")
+ if (symbol.ContainingAssembly?.Name == "GodotSharp")
return symbol;
symbol = symbol.BaseType;
@@ -148,22 +149,73 @@ namespace Godot.SourceGenerators
};
}
+ public static string NameWithTypeParameters(this INamedTypeSymbol symbol)
+ {
+ return symbol.IsGenericType ?
+ string.Concat(symbol.Name, "<", string.Join(", ", symbol.TypeParameters), ">") :
+ symbol.Name;
+ }
+
private static SymbolDisplayFormat FullyQualifiedFormatOmitGlobal { get; } =
SymbolDisplayFormat.FullyQualifiedFormat
.WithGlobalNamespaceStyle(SymbolDisplayGlobalNamespaceStyle.Omitted);
- public static string FullQualifiedName(this ITypeSymbol symbol)
+ private static SymbolDisplayFormat FullyQualifiedFormatIncludeGlobal { get; } =
+ SymbolDisplayFormat.FullyQualifiedFormat
+ .WithGlobalNamespaceStyle(SymbolDisplayGlobalNamespaceStyle.Included);
+
+ public static string FullQualifiedNameOmitGlobal(this ITypeSymbol symbol)
=> symbol.ToDisplayString(NullableFlowState.NotNull, FullyQualifiedFormatOmitGlobal);
- public static string NameWithTypeParameters(this INamedTypeSymbol symbol)
+ public static string FullQualifiedNameOmitGlobal(this INamespaceSymbol namespaceSymbol)
+ => namespaceSymbol.ToDisplayString(FullyQualifiedFormatOmitGlobal);
+
+ public static string FullQualifiedNameIncludeGlobal(this ITypeSymbol symbol)
+ => symbol.ToDisplayString(NullableFlowState.NotNull, FullyQualifiedFormatIncludeGlobal);
+
+ public static string FullQualifiedNameIncludeGlobal(this INamespaceSymbol namespaceSymbol)
+ => namespaceSymbol.ToDisplayString(FullyQualifiedFormatIncludeGlobal);
+
+ public static string FullQualifiedSyntax(this SyntaxNode node, SemanticModel sm)
{
- return symbol.IsGenericType ?
- string.Concat(symbol.Name, "<", string.Join(", ", symbol.TypeParameters), ">") :
- symbol.Name;
+ StringBuilder sb = new();
+ FullQualifiedSyntax(node, sm, sb, true);
+ return sb.ToString();
}
- public static string FullQualifiedName(this INamespaceSymbol namespaceSymbol)
- => namespaceSymbol.ToDisplayString(FullyQualifiedFormatOmitGlobal);
+ private static void FullQualifiedSyntax(SyntaxNode node, SemanticModel sm, StringBuilder sb, bool isFirstNode)
+ {
+ if (node is NameSyntax ns && isFirstNode)
+ {
+ SymbolInfo nameInfo = sm.GetSymbolInfo(ns);
+ sb.Append(nameInfo.Symbol?.ToDisplayString(FullyQualifiedFormatIncludeGlobal) ?? ns.ToString());
+ return;
+ }
+
+ bool innerIsFirstNode = true;
+ foreach (var child in node.ChildNodesAndTokens())
+ {
+ if (child.HasLeadingTrivia)
+ {
+ sb.Append(child.GetLeadingTrivia());
+ }
+
+ if (child.IsNode)
+ {
+ FullQualifiedSyntax(child.AsNode()!, sm, sb, isFirstNode: innerIsFirstNode);
+ innerIsFirstNode = false;
+ }
+ else
+ {
+ sb.Append(child);
+ }
+
+ if (child.HasTrailingTrivia)
+ {
+ sb.Append(child.GetTrailingTrivia());
+ }
+ }
+ }
public static string SanitizeQualifiedNameForUniqueHint(this string qualifiedName)
=> qualifiedName
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotEnums.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotEnums.cs
index 1a25d684a0..88c0e71155 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotEnums.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotEnums.cs
@@ -71,29 +71,29 @@ namespace Godot.SourceGenerators
Expression = 19,
PlaceholderText = 20,
ColorNoAlpha = 21,
- ImageCompressLossy = 22,
- ImageCompressLossless = 23,
- ObjectId = 24,
- TypeString = 25,
- NodePathToEditedNode = 26,
- MethodOfVariantType = 27,
- MethodOfBaseType = 28,
- MethodOfInstance = 29,
- MethodOfScript = 30,
- PropertyOfVariantType = 31,
- PropertyOfBaseType = 32,
- PropertyOfInstance = 33,
- PropertyOfScript = 34,
- ObjectTooBig = 35,
- NodePathValidTypes = 36,
- SaveFile = 37,
- GlobalSaveFile = 38,
- IntIsObjectid = 39,
- IntIsPointer = 41,
- ArrayType = 40,
- LocaleId = 42,
- LocalizableString = 43,
- NodeType = 44,
+ ObjectId = 22,
+ TypeString = 23,
+ NodePathToEditedNode = 24,
+ MethodOfVariantType = 25,
+ MethodOfBaseType = 26,
+ MethodOfInstance = 27,
+ MethodOfScript = 28,
+ PropertyOfVariantType = 29,
+ PropertyOfBaseType = 30,
+ PropertyOfInstance = 31,
+ PropertyOfScript = 32,
+ ObjectTooBig = 33,
+ NodePathValidTypes = 34,
+ SaveFile = 35,
+ GlobalSaveFile = 36,
+ IntIsObjectid = 37,
+ IntIsPointer = 38,
+ ArrayType = 39,
+ LocaleId = 40,
+ LocalizableString = 41,
+ NodeType = 42,
+ HideQuaternionEdit = 43,
+ Password = 44,
Max = 45
}
@@ -128,12 +128,14 @@ namespace Godot.SourceGenerators
DeferredSetResource = 33554432,
EditorInstantiateObject = 67108864,
EditorBasicSetting = 134217728,
+ ReadOnly = 268435456,
Array = 536870912,
Default = 6,
DefaultIntl = 38,
NoEditor = 2
}
+ [Flags]
public enum MethodFlags
{
Normal = 1,
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotMemberData.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotMemberData.cs
index db395e21cb..abd8079922 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotMemberData.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotMemberData.cs
@@ -3,7 +3,7 @@ using Microsoft.CodeAnalysis;
namespace Godot.SourceGenerators
{
- public struct GodotMethodData
+ public readonly struct GodotMethodData
{
public GodotMethodData(IMethodSymbol method, ImmutableArray<MarshalType> paramTypes,
ImmutableArray<ITypeSymbol> paramTypeSymbols, MarshalType? retType, ITypeSymbol? retSymbol)
@@ -22,7 +22,7 @@ namespace Godot.SourceGenerators
public ITypeSymbol? RetSymbol { get; }
}
- public struct GodotSignalDelegateData
+ public readonly struct GodotSignalDelegateData
{
public GodotSignalDelegateData(string name, INamedTypeSymbol delegateSymbol, GodotMethodData invokeMethodData)
{
@@ -36,7 +36,7 @@ namespace Godot.SourceGenerators
public GodotMethodData InvokeMethodData { get; }
}
- public struct GodotPropertyData
+ public readonly struct GodotPropertyData
{
public GodotPropertyData(IPropertySymbol propertySymbol, MarshalType type)
{
@@ -48,7 +48,7 @@ namespace Godot.SourceGenerators
public MarshalType Type { get; }
}
- public struct GodotFieldData
+ public readonly struct GodotFieldData
{
public GodotFieldData(IFieldSymbol fieldSymbol, MarshalType type)
{
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotPluginsInitializerGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotPluginsInitializerGenerator.cs
index 7ec3f88e5d..19fdd51dab 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotPluginsInitializerGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotPluginsInitializerGenerator.cs
@@ -56,7 +56,7 @@ namespace GodotPlugins.Game
}
";
- context.AddSource("GodotPlugins.Game_Generated",
+ context.AddSource("GodotPlugins.Game.generated",
SourceText.From(source, Encoding.UTF8));
}
}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalUtils.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalUtils.cs
index efdd50098e..4fdd40f638 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalUtils.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalUtils.cs
@@ -124,8 +124,8 @@ namespace Godot.SourceGenerators
if (typeKind == TypeKind.Struct)
{
- if (type.ContainingAssembly.Name == "GodotSharp" &&
- type.ContainingNamespace.Name == "Godot")
+ if (type.ContainingAssembly?.Name == "GodotSharp" &&
+ type.ContainingNamespace?.Name == "Godot")
{
return type switch
{
@@ -156,6 +156,10 @@ namespace Godot.SourceGenerators
else if (typeKind == TypeKind.Array)
{
var arrayType = (IArrayTypeSymbol)type;
+
+ if (arrayType.Rank != 1)
+ return null;
+
var elementType = arrayType.ElementType;
switch (elementType.SpecialType)
@@ -177,8 +181,8 @@ namespace Godot.SourceGenerators
if (elementType.SimpleDerivesFrom(typeCache.GodotObjectType))
return MarshalType.GodotObjectOrDerivedArray;
- if (elementType.ContainingAssembly.Name == "GodotSharp" &&
- elementType.ContainingNamespace.Name == "Godot")
+ if (elementType.ContainingAssembly?.Name == "GodotSharp" &&
+ elementType.ContainingNamespace?.Name == "Godot")
{
switch (elementType)
{
@@ -204,9 +208,9 @@ namespace Godot.SourceGenerators
if (type.SimpleDerivesFrom(typeCache.GodotObjectType))
return MarshalType.GodotObjectOrDerived;
- if (type.ContainingAssembly.Name == "GodotSharp")
+ if (type.ContainingAssembly?.Name == "GodotSharp")
{
- switch (type.ContainingNamespace.Name)
+ switch (type.ContainingNamespace?.Name)
{
case "Godot":
return type switch
@@ -216,7 +220,7 @@ namespace Godot.SourceGenerators
_ => null
};
case "Collections"
- when type.ContainingNamespace.FullQualifiedName() == "Godot.Collections":
+ when type.ContainingNamespace?.FullQualifiedNameOmitGlobal() == "Godot.Collections":
return type switch
{
{ Name: "Dictionary" } =>
@@ -363,7 +367,7 @@ namespace Godot.SourceGenerators
MarshalType.SignalInfo =>
source.Append(VariantUtils, ".ConvertToSignalInfo(", inputExpr, ")"),
MarshalType.Enum =>
- source.Append("(", typeSymbol.FullQualifiedName(),
+ source.Append("(", typeSymbol.FullQualifiedNameIncludeGlobal(),
")", VariantUtils, ".ConvertToInt32(", inputExpr, ")"),
MarshalType.ByteArray =>
source.Append(VariantUtils, ".ConvertAsPackedByteArrayToSystemArray(", inputExpr, ")"),
@@ -385,7 +389,7 @@ namespace Godot.SourceGenerators
source.Append(VariantUtils, ".ConvertAsPackedColorArrayToSystemArray(", inputExpr, ")"),
MarshalType.GodotObjectOrDerivedArray =>
source.Append(VariantUtils, ".ConvertToSystemArrayOfGodotObject<",
- ((IArrayTypeSymbol)typeSymbol).ElementType.FullQualifiedName(), ">(", inputExpr, ")"),
+ ((IArrayTypeSymbol)typeSymbol).ElementType.FullQualifiedNameIncludeGlobal(), ">(", inputExpr, ")"),
MarshalType.SystemArrayOfStringName =>
source.Append(VariantUtils, ".ConvertToSystemArrayOfStringName(", inputExpr, ")"),
MarshalType.SystemArrayOfNodePath =>
@@ -395,7 +399,7 @@ namespace Godot.SourceGenerators
MarshalType.Variant =>
source.Append("global::Godot.Variant.CreateCopyingBorrowed(", inputExpr, ")"),
MarshalType.GodotObjectOrDerived =>
- source.Append("(", typeSymbol.FullQualifiedName(),
+ source.Append("(", typeSymbol.FullQualifiedNameIncludeGlobal(),
")", VariantUtils, ".ConvertToGodotObject(", inputExpr, ")"),
MarshalType.StringName =>
source.Append(VariantUtils, ".ConvertToStringNameObject(", inputExpr, ")"),
@@ -409,11 +413,11 @@ namespace Godot.SourceGenerators
source.Append(VariantUtils, ".ConvertToArrayObject(", inputExpr, ")"),
MarshalType.GodotGenericDictionary =>
source.Append(VariantUtils, ".ConvertToDictionaryObject<",
- ((INamedTypeSymbol)typeSymbol).TypeArguments[0].FullQualifiedName(), ", ",
- ((INamedTypeSymbol)typeSymbol).TypeArguments[1].FullQualifiedName(), ">(", inputExpr, ")"),
+ ((INamedTypeSymbol)typeSymbol).TypeArguments[0].FullQualifiedNameIncludeGlobal(), ", ",
+ ((INamedTypeSymbol)typeSymbol).TypeArguments[1].FullQualifiedNameIncludeGlobal(), ">(", inputExpr, ")"),
MarshalType.GodotGenericArray =>
source.Append(VariantUtils, ".ConvertToArrayObject<",
- ((INamedTypeSymbol)typeSymbol).TypeArguments[0].FullQualifiedName(), ">(", inputExpr, ")"),
+ ((INamedTypeSymbol)typeSymbol).TypeArguments[0].FullQualifiedNameIncludeGlobal(), ">(", inputExpr, ")"),
_ => throw new ArgumentOutOfRangeException(nameof(marshalType), marshalType,
"Received unexpected marshal type")
};
@@ -574,7 +578,7 @@ namespace Godot.SourceGenerators
MarshalType.Callable => source.Append(inputExpr, ".AsCallable()"),
MarshalType.SignalInfo => source.Append(inputExpr, ".AsSignalInfo()"),
MarshalType.Enum =>
- source.Append("(", typeSymbol.FullQualifiedName(), ")", inputExpr, ".AsInt64()"),
+ source.Append("(", typeSymbol.FullQualifiedNameIncludeGlobal(), ")", inputExpr, ".AsInt64()"),
MarshalType.ByteArray => source.Append(inputExpr, ".AsByteArray()"),
MarshalType.Int32Array => source.Append(inputExpr, ".AsInt32Array()"),
MarshalType.Int64Array => source.Append(inputExpr, ".AsInt64Array()"),
@@ -585,23 +589,23 @@ namespace Godot.SourceGenerators
MarshalType.Vector3Array => source.Append(inputExpr, ".AsVector3Array()"),
MarshalType.ColorArray => source.Append(inputExpr, ".AsColorArray()"),
MarshalType.GodotObjectOrDerivedArray => source.Append(inputExpr, ".AsGodotObjectArray<",
- ((IArrayTypeSymbol)typeSymbol).ElementType.FullQualifiedName(), ">()"),
+ ((IArrayTypeSymbol)typeSymbol).ElementType.FullQualifiedNameIncludeGlobal(), ">()"),
MarshalType.SystemArrayOfStringName => source.Append(inputExpr, ".AsSystemArrayOfStringName()"),
MarshalType.SystemArrayOfNodePath => source.Append(inputExpr, ".AsSystemArrayOfNodePath()"),
MarshalType.SystemArrayOfRID => source.Append(inputExpr, ".AsSystemArrayOfRID()"),
MarshalType.Variant => source.Append(inputExpr),
MarshalType.GodotObjectOrDerived => source.Append("(",
- typeSymbol.FullQualifiedName(), ")", inputExpr, ".AsGodotObject()"),
+ typeSymbol.FullQualifiedNameIncludeGlobal(), ")", inputExpr, ".AsGodotObject()"),
MarshalType.StringName => source.Append(inputExpr, ".AsStringName()"),
MarshalType.NodePath => source.Append(inputExpr, ".AsNodePath()"),
MarshalType.RID => source.Append(inputExpr, ".AsRID()"),
MarshalType.GodotDictionary => source.Append(inputExpr, ".AsGodotDictionary()"),
MarshalType.GodotArray => source.Append(inputExpr, ".AsGodotArray()"),
MarshalType.GodotGenericDictionary => source.Append(inputExpr, ".AsGodotDictionary<",
- ((INamedTypeSymbol)typeSymbol).TypeArguments[0].FullQualifiedName(), ", ",
- ((INamedTypeSymbol)typeSymbol).TypeArguments[1].FullQualifiedName(), ">()"),
+ ((INamedTypeSymbol)typeSymbol).TypeArguments[0].FullQualifiedNameIncludeGlobal(), ", ",
+ ((INamedTypeSymbol)typeSymbol).TypeArguments[1].FullQualifiedNameIncludeGlobal(), ">()"),
MarshalType.GodotGenericArray => source.Append(inputExpr, ".AsGodotArray<",
- ((INamedTypeSymbol)typeSymbol).TypeArguments[0].FullQualifiedName(), ">()"),
+ ((INamedTypeSymbol)typeSymbol).TypeArguments[0].FullQualifiedNameIncludeGlobal(), ">()"),
_ => throw new ArgumentOutOfRangeException(nameof(marshalType), marshalType,
"Received unexpected marshal type")
};
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MethodInfo.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MethodInfo.cs
index 81c6f2b7d5..bb9be862c4 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MethodInfo.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MethodInfo.cs
@@ -2,7 +2,7 @@ using System.Collections.Generic;
namespace Godot.SourceGenerators
{
- internal struct MethodInfo
+ internal readonly struct MethodInfo
{
public MethodInfo(string name, PropertyInfo returnVal, MethodFlags flags,
List<PropertyInfo>? arguments,
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/PropertyInfo.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/PropertyInfo.cs
index b345f5f84d..2b89633ef6 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/PropertyInfo.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/PropertyInfo.cs
@@ -1,6 +1,6 @@
namespace Godot.SourceGenerators
{
- internal struct PropertyInfo
+ internal readonly struct PropertyInfo
{
public PropertyInfo(VariantType type, string name, PropertyHint hint,
string? hintString, PropertyUsageFlags usage, bool exported)
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs
index 1ee31eb1a9..2f51018293 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs
@@ -80,14 +80,14 @@ namespace Godot.SourceGenerators
{
INamespaceSymbol namespaceSymbol = symbol.ContainingNamespace;
string classNs = namespaceSymbol != null && !namespaceSymbol.IsGlobalNamespace ?
- namespaceSymbol.FullQualifiedName() :
+ namespaceSymbol.FullQualifiedNameOmitGlobal() :
string.Empty;
bool hasNamespace = classNs.Length != 0;
bool isInnerClass = symbol.ContainingType != null;
- string uniqueHint = symbol.FullQualifiedName().SanitizeQualifiedNameForUniqueHint()
- + "_ScriptMethods_Generated";
+ string uniqueHint = symbol.FullQualifiedNameOmitGlobal().SanitizeQualifiedNameForUniqueHint()
+ + "_ScriptMethods.generated";
var source = new StringBuilder();
@@ -135,7 +135,7 @@ namespace Godot.SourceGenerators
source.Append("#pragma warning disable CS0109 // Disable warning about redundant 'new' keyword\n");
- source.Append($" public new class MethodName : {symbol.BaseType.FullQualifiedName()}.MethodName {{\n");
+ source.Append($" public new class MethodName : {symbol.BaseType.FullQualifiedNameIncludeGlobal()}.MethodName {{\n");
// Generate cached StringNames for methods and properties, for fast lookup
@@ -146,7 +146,7 @@ namespace Godot.SourceGenerators
foreach (string methodName in distinctMethodNames)
{
- source.Append(" public new static readonly StringName ");
+ source.Append(" public new static readonly global::Godot.StringName ");
source.Append(methodName);
source.Append(" = \"");
source.Append(methodName);
@@ -159,7 +159,7 @@ namespace Godot.SourceGenerators
if (godotClassMethods.Length > 0)
{
- const string listType = "System.Collections.Generic.List<global::Godot.Bridge.MethodInfo>";
+ const string listType = "global::System.Collections.Generic.List<global::Godot.Bridge.MethodInfo>";
source.Append(" internal new static ")
.Append(listType)
@@ -188,14 +188,14 @@ namespace Godot.SourceGenerators
if (godotClassMethods.Length > 0)
{
source.Append(" protected override bool InvokeGodotClassMethod(in godot_string_name method, ");
- source.Append("NativeVariantPtrArgs args, int argCount, out godot_variant ret)\n {\n");
+ source.Append("NativeVariantPtrArgs args, out godot_variant ret)\n {\n");
foreach (var method in godotClassMethods)
{
GenerateMethodInvoker(method, source);
}
- source.Append(" return base.InvokeGodotClassMethod(method, args, argCount, out ret);\n");
+ source.Append(" return base.InvokeGodotClassMethod(method, args, out ret);\n");
source.Append(" }\n");
}
@@ -248,7 +248,7 @@ namespace Godot.SourceGenerators
AppendPropertyInfo(source, methodInfo.ReturnVal);
- source.Append(", flags: (Godot.MethodFlags)")
+ source.Append(", flags: (global::Godot.MethodFlags)")
.Append((int)methodInfo.Flags)
.Append(", arguments: ");
@@ -276,15 +276,15 @@ namespace Godot.SourceGenerators
private static void AppendPropertyInfo(StringBuilder source, PropertyInfo propertyInfo)
{
- source.Append("new(type: (Godot.Variant.Type)")
+ source.Append("new(type: (global::Godot.Variant.Type)")
.Append((int)propertyInfo.Type)
.Append(", name: \"")
.Append(propertyInfo.Name)
- .Append("\", hint: (Godot.PropertyHint)")
+ .Append("\", hint: (global::Godot.PropertyHint)")
.Append((int)propertyInfo.Hint)
.Append(", hintString: \"")
.Append(propertyInfo.HintString)
- .Append("\", usage: (Godot.PropertyUsageFlags)")
+ .Append("\", usage: (global::Godot.PropertyUsageFlags)")
.Append((int)propertyInfo.Usage)
.Append(", exported: ")
.Append(propertyInfo.Exported ? "true" : "false")
@@ -364,7 +364,7 @@ namespace Godot.SourceGenerators
source.Append(" if (method == MethodName.");
source.Append(methodName);
- source.Append(" && argCount == ");
+ source.Append(" && args.Count == ");
source.Append(method.ParamTypes.Length);
source.Append(") {\n");
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPathAttributeGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPathAttributeGenerator.cs
index e8a9e28d0c..fb32f6192f 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPathAttributeGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPathAttributeGenerator.cs
@@ -92,12 +92,12 @@ namespace Godot.SourceGenerators
INamespaceSymbol namespaceSymbol = symbol.ContainingNamespace;
string classNs = namespaceSymbol != null && !namespaceSymbol.IsGlobalNamespace ?
- namespaceSymbol.FullQualifiedName() :
+ namespaceSymbol.FullQualifiedNameOmitGlobal() :
string.Empty;
bool hasNamespace = classNs.Length != 0;
- var uniqueHint = symbol.FullQualifiedName().SanitizeQualifiedNameForUniqueHint()
- + "_ScriptPath_Generated";
+ string uniqueHint = symbol.FullQualifiedNameOmitGlobal().SanitizeQualifiedNameForUniqueHint()
+ + "_ScriptPath.generated";
var source = new StringBuilder();
@@ -126,7 +126,7 @@ namespace Godot.SourceGenerators
source.Append("\n}\n");
}
- context.AddSource(uniqueHint.ToString(), SourceText.From(source.ToString(), Encoding.UTF8));
+ context.AddSource(uniqueHint, SourceText.From(source.ToString(), Encoding.UTF8));
}
private static void AddScriptTypesAssemblyAttr(GeneratorExecutionContext context,
@@ -157,7 +157,7 @@ namespace Godot.SourceGenerators
sourceBuilder.Append("})]\n");
- context.AddSource("AssemblyScriptTypes_Generated",
+ context.AddSource("AssemblyScriptTypes.generated",
SourceText.From(sourceBuilder.ToString(), Encoding.UTF8));
}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs
index b331e2e794..252f162b0c 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs
@@ -66,14 +66,14 @@ namespace Godot.SourceGenerators
{
INamespaceSymbol namespaceSymbol = symbol.ContainingNamespace;
string classNs = namespaceSymbol != null && !namespaceSymbol.IsGlobalNamespace ?
- namespaceSymbol.FullQualifiedName() :
+ namespaceSymbol.FullQualifiedNameOmitGlobal() :
string.Empty;
bool hasNamespace = classNs.Length != 0;
bool isInnerClass = symbol.ContainingType != null;
- string uniqueHint = symbol.FullQualifiedName().SanitizeQualifiedNameForUniqueHint()
- + "_ScriptProperties_Generated";
+ string uniqueHint = symbol.FullQualifiedNameOmitGlobal().SanitizeQualifiedNameForUniqueHint()
+ + "_ScriptProperties.generated";
var source = new StringBuilder();
@@ -124,14 +124,14 @@ namespace Godot.SourceGenerators
source.Append("#pragma warning disable CS0109 // Disable warning about redundant 'new' keyword\n");
- source.Append($" public new class PropertyName : {symbol.BaseType.FullQualifiedName()}.PropertyName {{\n");
+ source.Append($" public new class PropertyName : {symbol.BaseType.FullQualifiedNameIncludeGlobal()}.PropertyName {{\n");
// Generate cached StringNames for methods and properties, for fast lookup
foreach (var property in godotClassProperties)
{
string propertyName = property.PropertySymbol.Name;
- source.Append(" public new static readonly StringName ");
+ source.Append(" public new static readonly global::Godot.StringName ");
source.Append(propertyName);
source.Append(" = \"");
source.Append(propertyName);
@@ -141,7 +141,7 @@ namespace Godot.SourceGenerators
foreach (var field in godotClassFields)
{
string fieldName = field.FieldSymbol.Name;
- source.Append(" public new static readonly StringName ");
+ source.Append(" public new static readonly global::Godot.StringName ");
source.Append(fieldName);
source.Append(" = \"");
source.Append(fieldName);
@@ -216,7 +216,7 @@ namespace Godot.SourceGenerators
// Generate GetGodotPropertyList
- string dictionaryType = "System.Collections.Generic.List<global::Godot.Bridge.PropertyInfo>";
+ string dictionaryType = "global::System.Collections.Generic.List<global::Godot.Bridge.PropertyInfo>";
source.Append(" internal new static ")
.Append(dictionaryType)
@@ -292,7 +292,7 @@ namespace Godot.SourceGenerators
source.Append("if (name == PropertyName.")
.Append(propertyMemberName)
.Append(") {\n")
- .Append(" ")
+ .Append(" this.")
.Append(propertyMemberName)
.Append(" = ")
.AppendNativeVariantToManagedExpr("value", propertyTypeSymbol, propertyMarshalType)
@@ -317,7 +317,7 @@ namespace Godot.SourceGenerators
.Append(propertyMemberName)
.Append(") {\n")
.Append(" value = ")
- .AppendManagedToNativeVariantExpr(propertyMemberName, propertyMarshalType)
+ .AppendManagedToNativeVariantExpr("this." + propertyMemberName, propertyMarshalType)
.Append(";\n")
.Append(" return true;\n")
.Append(" }\n");
@@ -340,15 +340,15 @@ namespace Godot.SourceGenerators
private static void AppendPropertyInfo(StringBuilder source, PropertyInfo propertyInfo)
{
- source.Append(" properties.Add(new(type: (Godot.Variant.Type)")
+ source.Append(" properties.Add(new(type: (global::Godot.Variant.Type)")
.Append((int)propertyInfo.Type)
.Append(", name: PropertyName.")
.Append(propertyInfo.Name)
- .Append(", hint: (Godot.PropertyHint)")
+ .Append(", hint: (global::Godot.PropertyHint)")
.Append((int)propertyInfo.Hint)
.Append(", hintString: \"")
.Append(propertyInfo.HintString)
- .Append("\", usage: (Godot.PropertyUsageFlags)")
+ .Append("\", usage: (global::Godot.PropertyUsageFlags)")
.Append((int)propertyInfo.Usage)
.Append(", exported: ")
.Append(propertyInfo.Exported ? "true" : "false")
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs
index 65dadcb801..3f588a4c90 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs
@@ -2,6 +2,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
@@ -66,14 +67,14 @@ namespace Godot.SourceGenerators
{
INamespaceSymbol namespaceSymbol = symbol.ContainingNamespace;
string classNs = namespaceSymbol != null && !namespaceSymbol.IsGlobalNamespace ?
- namespaceSymbol.FullQualifiedName() :
+ namespaceSymbol.FullQualifiedNameOmitGlobal() :
string.Empty;
bool hasNamespace = classNs.Length != 0;
bool isInnerClass = symbol.ContainingType != null;
- string uniqueHint = symbol.FullQualifiedName().SanitizeQualifiedNameForUniqueHint()
- + "_ScriptPropertyDefVal_Generated";
+ string uniqueHint = symbol.FullQualifiedNameOmitGlobal().SanitizeQualifiedNameForUniqueHint()
+ + "_ScriptPropertyDefVal.generated";
var source = new StringBuilder();
@@ -163,14 +164,69 @@ namespace Godot.SourceGenerators
continue;
}
- // TODO: Detect default value from simple property getters (currently we only detect from initializers)
+ var propertyDeclarationSyntax = property.DeclaringSyntaxReferences
+ .Select(r => r.GetSyntax() as PropertyDeclarationSyntax).FirstOrDefault();
- EqualsValueClauseSyntax? initializer = property.DeclaringSyntaxReferences
- .Select(r => r.GetSyntax() as PropertyDeclarationSyntax)
- .Select(s => s?.Initializer ?? null)
- .FirstOrDefault();
-
- string? value = initializer?.Value.ToString();
+ // Fully qualify the value to avoid issues with namespaces.
+ string? value = null;
+ if (propertyDeclarationSyntax != null)
+ {
+ if (propertyDeclarationSyntax.Initializer != null)
+ {
+ var sm = context.Compilation.GetSemanticModel(propertyDeclarationSyntax.Initializer.SyntaxTree);
+ value = propertyDeclarationSyntax.Initializer.Value.FullQualifiedSyntax(sm);
+ }
+ else
+ {
+ var propertyGet = propertyDeclarationSyntax.AccessorList?.Accessors.Where(a => a.Keyword.IsKind(SyntaxKind.GetKeyword)).FirstOrDefault();
+ if (propertyGet != null)
+ {
+ if (propertyGet.ExpressionBody != null)
+ {
+ if (propertyGet.ExpressionBody.Expression is IdentifierNameSyntax identifierNameSyntax)
+ {
+ var sm = context.Compilation.GetSemanticModel(identifierNameSyntax.SyntaxTree);
+ var fieldSymbol = sm.GetSymbolInfo(identifierNameSyntax).Symbol as IFieldSymbol;
+ EqualsValueClauseSyntax? initializer = fieldSymbol?.DeclaringSyntaxReferences
+ .Select(r => r.GetSyntax())
+ .OfType<VariableDeclaratorSyntax>()
+ .Select(s => s.Initializer)
+ .FirstOrDefault(i => i != null);
+
+ if (initializer != null)
+ {
+ sm = context.Compilation.GetSemanticModel(initializer.SyntaxTree);
+ value = initializer.Value.FullQualifiedSyntax(sm);
+ }
+ }
+ }
+ else
+ {
+ var returns = propertyGet.DescendantNodes().OfType<ReturnStatementSyntax>();
+ if (returns.Count() == 1)
+ {// Generate only single return
+ var returnStatementSyntax = returns.Single();
+ if (returnStatementSyntax.Expression is IdentifierNameSyntax identifierNameSyntax)
+ {
+ var sm = context.Compilation.GetSemanticModel(identifierNameSyntax.SyntaxTree);
+ var fieldSymbol = sm.GetSymbolInfo(identifierNameSyntax).Symbol as IFieldSymbol;
+ EqualsValueClauseSyntax? initializer = fieldSymbol?.DeclaringSyntaxReferences
+ .Select(r => r.GetSyntax())
+ .OfType<VariableDeclaratorSyntax>()
+ .Select(s => s.Initializer)
+ .FirstOrDefault(i => i != null);
+
+ if (initializer != null)
+ {
+ sm = context.Compilation.GetSemanticModel(initializer.SyntaxTree);
+ value = initializer.Value.FullQualifiedSyntax(sm);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
exportedMembers.Add(new ExportedPropertyMetadata(
property.Name, marshalType.Value, propertyType, value));
@@ -207,7 +263,13 @@ namespace Godot.SourceGenerators
.Select(s => s.Initializer)
.FirstOrDefault(i => i != null);
- string? value = initializer?.Value.ToString();
+ // This needs to be fully qualified to avoid issues with namespaces.
+ string? value = null;
+ if (initializer != null)
+ {
+ var sm = context.Compilation.GetSemanticModel(initializer.SyntaxTree);
+ value = initializer.Value.FullQualifiedSyntax(sm);
+ }
exportedMembers.Add(new ExportedPropertyMetadata(
field.Name, marshalType.Value, fieldType, value));
@@ -237,7 +299,7 @@ namespace Godot.SourceGenerators
string defaultValueLocalName = string.Concat("__", exportedMember.Name, "_default_value");
source.Append(" ");
- source.Append(exportedMember.TypeSymbol.FullQualifiedName());
+ source.Append(exportedMember.TypeSymbol.FullQualifiedNameIncludeGlobal());
source.Append(" ");
source.Append(defaultValueLocalName);
source.Append(" = ");
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSerializationGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSerializationGenerator.cs
index a40220565f..ed877cbd17 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSerializationGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSerializationGenerator.cs
@@ -66,14 +66,14 @@ namespace Godot.SourceGenerators
{
INamespaceSymbol namespaceSymbol = symbol.ContainingNamespace;
string classNs = namespaceSymbol != null && !namespaceSymbol.IsGlobalNamespace ?
- namespaceSymbol.FullQualifiedName() :
+ namespaceSymbol.FullQualifiedNameOmitGlobal() :
string.Empty;
bool hasNamespace = classNs.Length != 0;
bool isInnerClass = symbol.ContainingType != null;
- string uniqueHint = symbol.FullQualifiedName().SanitizeQualifiedNameForUniqueHint()
- + "_ScriptSerialization_Generated";
+ string uniqueHint = symbol.FullQualifiedNameOmitGlobal().SanitizeQualifiedNameForUniqueHint()
+ + "_ScriptSerialization.generated";
var source = new StringBuilder();
@@ -241,7 +241,7 @@ namespace Godot.SourceGenerators
foreach (var signalDelegate in godotSignalDelegates)
{
string signalName = signalDelegate.Name;
- string signalDelegateQualifiedName = signalDelegate.DelegateSymbol.FullQualifiedName();
+ string signalDelegateQualifiedName = signalDelegate.DelegateSymbol.FullQualifiedNameIncludeGlobal();
source.Append(" if (info.TryGetSignalEventDelegate<")
.Append(signalDelegateQualifiedName)
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs
index 1df41a905b..119cc9d4f0 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs
@@ -7,7 +7,7 @@ using Microsoft.CodeAnalysis.Text;
// TODO:
// Determine a proper way to emit the signal.
-// 'Emit(nameof(TheEvent))' creates a StringName everytime and has the overhead of string marshaling.
+// 'Emit(nameof(TheEvent))' creates a StringName every time and has the overhead of string marshaling.
// I haven't decided on the best option yet. Some possibilities:
// - Expose the generated StringName fields to the user, for use with 'Emit(...)'.
// - Generate a 'EmitSignalName' method for each event signal.
@@ -75,14 +75,14 @@ namespace Godot.SourceGenerators
{
INamespaceSymbol namespaceSymbol = symbol.ContainingNamespace;
string classNs = namespaceSymbol != null && !namespaceSymbol.IsGlobalNamespace ?
- namespaceSymbol.FullQualifiedName() :
+ namespaceSymbol.FullQualifiedNameOmitGlobal() :
string.Empty;
bool hasNamespace = classNs.Length != 0;
bool isInnerClass = symbol.ContainingType != null;
- string uniqueHint = symbol.FullQualifiedName().SanitizeQualifiedNameForUniqueHint()
- + "_ScriptSignals_Generated";
+ string uniqueHint = symbol.FullQualifiedNameOmitGlobal().SanitizeQualifiedNameForUniqueHint()
+ + "_ScriptSignals.generated";
var source = new StringBuilder();
@@ -167,6 +167,7 @@ namespace Godot.SourceGenerators
Common.ReportSignalDelegateSignatureMustReturnVoid(context, signalDelegateSymbol);
}
}
+
continue;
}
@@ -175,14 +176,14 @@ namespace Godot.SourceGenerators
source.Append("#pragma warning disable CS0109 // Disable warning about redundant 'new' keyword\n");
- source.Append($" public new class SignalName : {symbol.BaseType.FullQualifiedName()}.SignalName {{\n");
+ source.Append($" public new class SignalName : {symbol.BaseType.FullQualifiedNameIncludeGlobal()}.SignalName {{\n");
// Generate cached StringNames for methods and properties, for fast lookup
foreach (var signalDelegate in godotSignalDelegates)
{
string signalName = signalDelegate.Name;
- source.Append(" public new static readonly StringName ");
+ source.Append(" public new static readonly global::Godot.StringName ");
source.Append(signalName);
source.Append(" = \"");
source.Append(signalName);
@@ -195,7 +196,7 @@ namespace Godot.SourceGenerators
if (godotSignalDelegates.Count > 0)
{
- const string listType = "System.Collections.Generic.List<global::Godot.Bridge.MethodInfo>";
+ const string listType = "global::System.Collections.Generic.List<global::Godot.Bridge.MethodInfo>";
source.Append(" internal new static ")
.Append(listType)
@@ -230,13 +231,15 @@ namespace Godot.SourceGenerators
// as it doesn't emit the signal, only the event delegates. This can confuse users.
// Maybe we should directly connect the delegates, as we do with native signals?
source.Append(" private ")
- .Append(signalDelegate.DelegateSymbol.FullQualifiedName())
+ .Append(signalDelegate.DelegateSymbol.FullQualifiedNameIncludeGlobal())
.Append(" backing_")
.Append(signalName)
.Append(";\n");
+ source.Append($" /// <inheritdoc cref=\"{signalDelegate.DelegateSymbol.FullQualifiedNameIncludeGlobal()}\"/>\n");
+
source.Append(" public event ")
- .Append(signalDelegate.DelegateSymbol.FullQualifiedName())
+ .Append(signalDelegate.DelegateSymbol.FullQualifiedNameIncludeGlobal())
.Append(" ")
.Append(signalName)
.Append(" {\n")
@@ -255,14 +258,14 @@ namespace Godot.SourceGenerators
{
source.Append(
" protected override void RaiseGodotClassSignalCallbacks(in godot_string_name signal, ");
- source.Append("NativeVariantPtrArgs args, int argCount)\n {\n");
+ source.Append("NativeVariantPtrArgs args)\n {\n");
foreach (var signal in godotSignalDelegates)
{
GenerateSignalEventInvoker(signal, source);
}
- source.Append(" base.RaiseGodotClassSignalCallbacks(signal, args, argCount);\n");
+ source.Append(" base.RaiseGodotClassSignalCallbacks(signal, args);\n");
source.Append(" }\n");
}
@@ -297,7 +300,7 @@ namespace Godot.SourceGenerators
AppendPropertyInfo(source, methodInfo.ReturnVal);
- source.Append(", flags: (Godot.MethodFlags)")
+ source.Append(", flags: (global::Godot.MethodFlags)")
.Append((int)methodInfo.Flags)
.Append(", arguments: ");
@@ -325,15 +328,15 @@ namespace Godot.SourceGenerators
private static void AppendPropertyInfo(StringBuilder source, PropertyInfo propertyInfo)
{
- source.Append("new(type: (Godot.Variant.Type)")
+ source.Append("new(type: (global::Godot.Variant.Type)")
.Append((int)propertyInfo.Type)
.Append(", name: \"")
.Append(propertyInfo.Name)
- .Append("\", hint: (Godot.PropertyHint)")
+ .Append("\", hint: (global::Godot.PropertyHint)")
.Append((int)propertyInfo.Hint)
.Append(", hintString: \"")
.Append(propertyInfo.HintString)
- .Append("\", usage: (Godot.PropertyUsageFlags)")
+ .Append("\", usage: (global::Godot.PropertyUsageFlags)")
.Append((int)propertyInfo.Usage)
.Append(", exported: ")
.Append(propertyInfo.Exported ? "true" : "false")
@@ -402,7 +405,7 @@ namespace Godot.SourceGenerators
source.Append(" if (signal == SignalName.");
source.Append(signalName);
- source.Append(" && argCount == ");
+ source.Append(" && args.Count == ");
source.Append(invokeMethodData.ParamTypes.Length);
source.Append(") {\n");
source.Append(" backing_");
diff --git a/modules/mono/editor/GodotTools/GodotTools.IdeMessaging/Utils/SemaphoreExtensions.cs b/modules/mono/editor/GodotTools/GodotTools.IdeMessaging/Utils/SemaphoreExtensions.cs
index 9d593fbf8a..ab21527344 100644
--- a/modules/mono/editor/GodotTools/GodotTools.IdeMessaging/Utils/SemaphoreExtensions.cs
+++ b/modules/mono/editor/GodotTools/GodotTools.IdeMessaging/Utils/SemaphoreExtensions.cs
@@ -13,7 +13,7 @@ namespace GodotTools.IdeMessaging.Utils
return waitAsyncTask.ContinueWith<IDisposable>(t => wrapper, cancellationToken).ConfigureAwait(false);
}
- private struct SemaphoreSlimWaitReleaseWrapper : IDisposable
+ private readonly struct SemaphoreSlimWaitReleaseWrapper : IDisposable
{
private readonly SemaphoreSlim semaphoreSlim;
diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs b/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs
index ad4fce8daa..4d40724a83 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs
@@ -69,51 +69,41 @@ namespace GodotTools.Build
private void LoadIssuesFromFile(string csvFile)
{
- using (var file = new Godot.File())
+ using var file = FileAccess.Open(csvFile, FileAccess.ModeFlags.Read);
+
+ if (file == null)
+ return;
+
+ while (!file.EofReached())
{
- try
- {
- Error openError = file.Open(csvFile, Godot.File.ModeFlags.Read);
+ string[] csvColumns = file.GetCsvLine();
- if (openError != Error.Ok)
- return;
+ if (csvColumns.Length == 1 && string.IsNullOrEmpty(csvColumns[0]))
+ return;
- while (!file.EofReached())
- {
- string[] csvColumns = file.GetCsvLine();
-
- if (csvColumns.Length == 1 && string.IsNullOrEmpty(csvColumns[0]))
- return;
-
- if (csvColumns.Length != 7)
- {
- GD.PushError($"Expected 7 columns, got {csvColumns.Length}");
- continue;
- }
-
- var issue = new BuildIssue
- {
- Warning = csvColumns[0] == "warning",
- File = csvColumns[1],
- Line = int.Parse(csvColumns[2]),
- Column = int.Parse(csvColumns[3]),
- Code = csvColumns[4],
- Message = csvColumns[5],
- ProjectFile = csvColumns[6]
- };
-
- if (issue.Warning)
- WarningCount += 1;
- else
- ErrorCount += 1;
-
- _issues.Add(issue);
- }
- }
- finally
+ if (csvColumns.Length != 7)
{
- file.Close(); // Disposing it is not enough. We need to call Close()
+ GD.PushError($"Expected 7 columns, got {csvColumns.Length}");
+ continue;
}
+
+ var issue = new BuildIssue
+ {
+ Warning = csvColumns[0] == "warning",
+ File = csvColumns[1],
+ Line = int.Parse(csvColumns[2]),
+ Column = int.Parse(csvColumns[3]),
+ Code = csvColumns[4],
+ Message = csvColumns[5],
+ ProjectFile = csvColumns[6]
+ };
+
+ if (issue.Warning)
+ WarningCount += 1;
+ else
+ ErrorCount += 1;
+
+ _issues.Add(issue);
}
}
diff --git a/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs b/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs
index 2184cae6d6..94efcba3f1 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs
@@ -22,7 +22,7 @@ namespace GodotTools.Export
public bool FullAot;
private bool _useInterpreter;
- public bool UseInterpreter { get => _useInterpreter && !LLVMOnly; set => _useInterpreter = value; }
+ public bool UseInterpreter { readonly get => _useInterpreter && !LLVMOnly; set => _useInterpreter = value; }
public string[] ExtraAotOptions;
public string[] ExtraOptimizerOptions;
diff --git a/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs b/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs
index 0d2bea2363..745a8b73f8 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs
@@ -17,6 +17,8 @@ namespace GodotTools.Export
{
public partial class ExportPlugin : EditorExportPlugin
{
+ private List<string> _tempFolders = new List<string>();
+
public void RegisterExportSettings()
{
// TODO: These would be better as export preset options, but that doesn't seem to be supported yet
@@ -111,62 +113,78 @@ namespace GodotTools.Export
string buildConfig = isDebug ? "ExportDebug" : "ExportRelease";
- // TODO: This works for now, as we only implemented support for x86 family desktop so far, but it needs to be fixed
- string arch = features.Contains("x86_64") ? "x86_64" : "x86";
-
- string ridOS = DetermineRuntimeIdentifierOS(platform);
- string ridArch = DetermineRuntimeIdentifierArch(arch);
- string runtimeIdentifier = $"{ridOS}-{ridArch}";
-
- // Create temporary publish output directory
-
- string publishOutputTempDir = Path.Combine(Path.GetTempPath(), "godot-publish-dotnet",
- $"{Process.GetCurrentProcess().Id}-{buildConfig}-{runtimeIdentifier}");
-
- if (!Directory.Exists(publishOutputTempDir))
- Directory.CreateDirectory(publishOutputTempDir);
-
- // Execute dotnet publish
-
- if (!BuildManager.PublishProjectBlocking(buildConfig, platform,
- runtimeIdentifier, publishOutputTempDir))
+ var archs = new List<string>();
+ if (features.Contains("x86_64"))
{
- throw new InvalidOperationException("Failed to build project.");
+ archs.Add("x86_64");
}
-
- string soExt = ridOS switch
+ else if (features.Contains("x86_32"))
{
- OS.DotNetOS.Win or OS.DotNetOS.Win10 => "dll",
- OS.DotNetOS.OSX or OS.DotNetOS.iOS => "dylib",
- _ => "so"
- };
-
- if (!File.Exists(Path.Combine(publishOutputTempDir, $"{GodotSharpDirs.ProjectAssemblyName}.dll"))
- // NativeAOT shared library output
- && !File.Exists(Path.Combine(publishOutputTempDir, $"{GodotSharpDirs.ProjectAssemblyName}.{soExt}")))
+ archs.Add("x86_32");
+ }
+ else if (features.Contains("arm64"))
{
- throw new NotSupportedException(
- "Publish succeeded but project assembly not found in the output directory");
+ archs.Add("arm64");
}
-
- // Copy all files from the dotnet publish output directory to
- // a data directory next to the Godot output executable.
-
- string outputDataDir = Path.Combine(outputDir, DetermineDataDirNameForProject());
-
- if (Directory.Exists(outputDataDir))
- Directory.Delete(outputDataDir, recursive: true); // Clean first
-
- Directory.CreateDirectory(outputDataDir);
-
- foreach (string dir in Directory.GetDirectories(publishOutputTempDir, "*", SearchOption.AllDirectories))
+ else if (features.Contains("universal"))
{
- Directory.CreateDirectory(Path.Combine(outputDataDir, dir.Substring(publishOutputTempDir.Length + 1)));
+ if (platform == OS.Platforms.MacOS)
+ {
+ archs.Add("x86_64");
+ archs.Add("arm64");
+ }
}
- foreach (string file in Directory.GetFiles(publishOutputTempDir, "*", SearchOption.AllDirectories))
+ foreach (var arch in archs)
{
- File.Copy(file, Path.Combine(outputDataDir, file.Substring(publishOutputTempDir.Length + 1)));
+ string ridOS = DetermineRuntimeIdentifierOS(platform);
+ string ridArch = DetermineRuntimeIdentifierArch(arch);
+ string runtimeIdentifier = $"{ridOS}-{ridArch}";
+ string projectDataDirName = $"{DetermineDataDirNameForProject()}_{arch}";
+ if (platform == OS.Platforms.MacOS)
+ {
+ projectDataDirName = Path.Combine("Contents", "Resources", projectDataDirName);
+ }
+
+ // Create temporary publish output directory
+
+ string publishOutputTempDir = Path.Combine(Path.GetTempPath(), "godot-publish-dotnet",
+ $"{Process.GetCurrentProcess().Id}-{buildConfig}-{runtimeIdentifier}");
+
+ _tempFolders.Add(publishOutputTempDir);
+
+ if (!Directory.Exists(publishOutputTempDir))
+ Directory.CreateDirectory(publishOutputTempDir);
+
+ // Execute dotnet publish
+
+ if (!BuildManager.PublishProjectBlocking(buildConfig, platform,
+ runtimeIdentifier, publishOutputTempDir))
+ {
+ throw new InvalidOperationException("Failed to build project.");
+ }
+
+ string soExt = ridOS switch
+ {
+ OS.DotNetOS.Win or OS.DotNetOS.Win10 => "dll",
+ OS.DotNetOS.OSX or OS.DotNetOS.iOS => "dylib",
+ _ => "so"
+ };
+
+ if (!File.Exists(Path.Combine(publishOutputTempDir, $"{GodotSharpDirs.ProjectAssemblyName}.dll"))
+ // NativeAOT shared library output
+ && !File.Exists(Path.Combine(publishOutputTempDir, $"{GodotSharpDirs.ProjectAssemblyName}.{soExt}")))
+ {
+ throw new NotSupportedException(
+ "Publish succeeded but project assembly not found in the output directory");
+ }
+
+ // Add to the exported project shared object list.
+
+ foreach (string file in Directory.GetFiles(publishOutputTempDir, "*", SearchOption.AllDirectories))
+ {
+ AddSharedObject(file, tags: null, projectDataDirName);
+ }
}
}
@@ -198,6 +216,12 @@ namespace GodotTools.Export
if (Directory.Exists(aotTempDir))
Directory.Delete(aotTempDir, recursive: true);
+ foreach (string folder in _tempFolders)
+ {
+ Directory.Delete(folder, recursive: true);
+ }
+ _tempFolders.Clear();
+
// TODO: The following is just a workaround until the export plugins can be made to abort with errors
// We check for empty as well, because it's set to empty after hot-reloading
diff --git a/modules/mono/editor/GodotTools/GodotTools/PlaySettings.cs b/modules/mono/editor/GodotTools/GodotTools/PlaySettings.cs
index 820d0c0b83..9a8fdcc7c5 100644
--- a/modules/mono/editor/GodotTools/GodotTools/PlaySettings.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/PlaySettings.cs
@@ -1,6 +1,6 @@
namespace GodotTools
{
- public struct PlaySettings
+ public readonly struct PlaySettings
{
public bool HasDebugger { get; }
public string DebuggerHost { get; }
diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp
index ce4ac9b796..9185506776 100644
--- a/modules/mono/editor/bindings_generator.cpp
+++ b/modules/mono/editor/bindings_generator.cpp
@@ -1614,7 +1614,7 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
output << MEMBER_BEGIN "protected internal " << (is_derived_type ? "override" : "virtual")
<< " bool " CS_METHOD_INVOKE_GODOT_CLASS_METHOD "(in godot_string_name method, "
- << "NativeVariantPtrArgs args, int argCount, out godot_variant ret)\n"
+ << "NativeVariantPtrArgs args, out godot_variant ret)\n"
<< INDENT1 "{\n";
for (const MethodInterface &imethod : itype.methods) {
@@ -1630,7 +1630,7 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
// We check both native names (snake_case) and proxy names (PascalCase)
output << INDENT2 "if ((method == " << CS_STATIC_FIELD_METHOD_PROXY_NAME_PREFIX << imethod.name
<< " || method == MethodName." << imethod.proxy_name
- << ") && argCount == " << itos(imethod.arguments.size())
+ << ") && args.Count == " << itos(imethod.arguments.size())
<< " && " << CS_METHOD_HAS_GODOT_CLASS_METHOD << "((godot_string_name)"
<< CS_STATIC_FIELD_METHOD_PROXY_NAME_PREFIX << imethod.name << ".NativeValue))\n"
<< INDENT2 "{\n";
@@ -1682,7 +1682,7 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
}
if (is_derived_type) {
- output << INDENT2 "return base." CS_METHOD_INVOKE_GODOT_CLASS_METHOD "(method, args, argCount, out ret);\n";
+ output << INDENT2 "return base." CS_METHOD_INVOKE_GODOT_CLASS_METHOD "(method, args, out ret);\n";
} else {
output << INDENT2 "ret = default;\n"
<< INDENT2 "return false;\n";
@@ -2200,6 +2200,11 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
Error BindingsGenerator::_generate_cs_signal(const BindingsGenerator::TypeInterface &p_itype, const BindingsGenerator::SignalInterface &p_isignal, StringBuilder &p_output) {
String arguments_sig;
+ String delegate_type_params;
+
+ if (!p_isignal.arguments.is_empty()) {
+ delegate_type_params += "<";
+ }
// Retrieve information from the arguments
const ArgumentInterface &first = p_isignal.arguments.front()->get();
@@ -2220,15 +2225,31 @@ Error BindingsGenerator::_generate_cs_signal(const BindingsGenerator::TypeInterf
if (&iarg != &first) {
arguments_sig += ", ";
+ delegate_type_params += ", ";
}
arguments_sig += arg_type->cs_type;
arguments_sig += " ";
arguments_sig += iarg.name;
+
+ delegate_type_params += arg_type->cs_type;
+ }
+
+ if (!p_isignal.arguments.is_empty()) {
+ delegate_type_params += ">";
}
// Generate signal
{
+ p_output.append(MEMBER_BEGIN "/// <summary>\n");
+ p_output.append(INDENT1 "/// ");
+ p_output.append("Represents the method that handles the ");
+ p_output.append("<see cref=\"" BINDINGS_NAMESPACE "." + p_itype.proxy_name + "." + p_isignal.proxy_name + "\"/>");
+ p_output.append(" event of a ");
+ p_output.append("<see cref=\"" BINDINGS_NAMESPACE "." + p_itype.proxy_name + "\"/>");
+ p_output.append(" class.\n");
+ p_output.append(INDENT1 "/// </summary>");
+
if (p_isignal.is_deprecated) {
if (p_isignal.deprecation_message.is_empty()) {
WARN_PRINT("An empty deprecation message is discouraged. Signal: '" + p_isignal.proxy_name + "'.");
@@ -2239,15 +2260,45 @@ Error BindingsGenerator::_generate_cs_signal(const BindingsGenerator::TypeInterf
p_output.append("\")]");
}
- String delegate_name = p_isignal.proxy_name;
- delegate_name += "EventHandler"; // Delegate name is [SignalName]EventHandler
+ bool is_parameterless = p_isignal.arguments.size() == 0;
- // Generate delegate
- p_output.append(MEMBER_BEGIN "public delegate void ");
- p_output.append(delegate_name);
- p_output.append("(");
- p_output.append(arguments_sig);
- p_output.append(");\n");
+ // Delegate name is [SignalName]EventHandler
+ String delegate_name = is_parameterless ? "Action" : p_isignal.proxy_name + "EventHandler";
+
+ if (!is_parameterless) {
+ // Generate delegate
+ p_output.append(MEMBER_BEGIN "public delegate void ");
+ p_output.append(delegate_name);
+ p_output.append("(");
+ p_output.append(arguments_sig);
+ p_output.append(");\n");
+
+ // Generate Callable trampoline for the delegate
+ p_output << MEMBER_BEGIN "private static void " << p_isignal.proxy_name << "Trampoline"
+ << "(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)\n"
+ << INDENT1 "{\n"
+ << INDENT2 "Callable.ThrowIfArgCountMismatch(args, " << itos(p_isignal.arguments.size()) << ");\n"
+ << INDENT2 "((" << delegate_name << ")delegateObj)(";
+
+ int idx = 0;
+ for (const ArgumentInterface &iarg : p_isignal.arguments) {
+ const TypeInterface *arg_type = _get_type_or_null(iarg.type);
+ ERR_FAIL_NULL_V(arg_type, ERR_BUG); // Argument type not found
+
+ if (idx != 0) {
+ p_output << ",";
+ }
+
+ p_output << sformat(arg_type->cs_variant_to_managed,
+ "args[" + itos(idx) + "]", arg_type->cs_type, arg_type->name);
+
+ idx++;
+ }
+
+ p_output << ");\n"
+ << INDENT2 "ret = default;\n"
+ << INDENT1 "}\n";
+ }
if (p_isignal.method_doc && p_isignal.method_doc->description.size()) {
String xml_summary = bbcode_to_xml(fix_doc_description(p_isignal.method_doc->description), &p_itype);
@@ -2283,6 +2334,11 @@ Error BindingsGenerator::_generate_cs_signal(const BindingsGenerator::TypeInterf
p_output.append("static ");
}
+ if (!is_parameterless) {
+ // `unsafe` is needed for taking the trampoline's function pointer
+ p_output << "unsafe ";
+ }
+
p_output.append("event ");
p_output.append(delegate_name);
p_output.append(" ");
@@ -2295,8 +2351,13 @@ Error BindingsGenerator::_generate_cs_signal(const BindingsGenerator::TypeInterf
p_output.append("add => Connect(SignalName.");
}
- p_output.append(p_isignal.proxy_name);
- p_output.append(", new Callable(value));\n");
+ if (is_parameterless) {
+ // Delegate type is Action. No need for custom trampoline.
+ p_output << p_isignal.proxy_name << ", Callable.From(value));\n";
+ } else {
+ p_output << p_isignal.proxy_name
+ << ", Callable.CreateWithUnsafeTrampoline(value, &" << p_isignal.proxy_name << "Trampoline));\n";
+ }
if (p_itype.is_singleton) {
p_output.append(INDENT2 "remove => " CS_PROPERTY_SINGLETON ".Disconnect(SignalName.");
@@ -2304,8 +2365,14 @@ Error BindingsGenerator::_generate_cs_signal(const BindingsGenerator::TypeInterf
p_output.append(INDENT2 "remove => Disconnect(SignalName.");
}
- p_output.append(p_isignal.proxy_name);
- p_output.append(", new Callable(value));\n");
+ if (is_parameterless) {
+ // Delegate type is Action. No need for custom trampoline.
+ p_output << p_isignal.proxy_name << ", Callable.From(value));\n";
+ } else {
+ p_output << p_isignal.proxy_name
+ << ", Callable.CreateWithUnsafeTrampoline(value, &" << p_isignal.proxy_name << "Trampoline));\n";
+ }
+
p_output.append(CLOSE_BLOCK_L1);
}
@@ -2475,15 +2542,13 @@ Error BindingsGenerator::_generate_cs_native_calls(const InternalCall &p_icall,
<< INDENT2 "int total_length = " << real_argc_str << " + vararg_length;\n";
r_output << INDENT2 "Span<godot_variant.movable> varargs_span = vararg_length <= VarArgsSpanThreshold ?\n"
- << INDENT3 "stackalloc godot_variant.movable[VarArgsSpanThreshold].Cleared() :\n"
+ << INDENT3 "stackalloc godot_variant.movable[VarArgsSpanThreshold] :\n"
<< INDENT3 "new godot_variant.movable[vararg_length];\n";
r_output << INDENT2 "Span<IntPtr> " C_LOCAL_PTRCALL_ARGS "_span = total_length <= VarArgsSpanThreshold ?\n"
<< INDENT3 "stackalloc IntPtr[VarArgsSpanThreshold] :\n"
<< INDENT3 "new IntPtr[total_length];\n";
- r_output << INDENT2 "using var variantSpanDisposer = new VariantSpanDisposer(varargs_span);\n";
-
r_output << INDENT2 "fixed (godot_variant.movable* varargs = &MemoryMarshal.GetReference(varargs_span))\n"
<< INDENT2 "fixed (IntPtr* " C_LOCAL_PTRCALL_ARGS " = "
"&MemoryMarshal.GetReference(" C_LOCAL_PTRCALL_ARGS "_span))\n"
@@ -3110,9 +3175,10 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
for (const KeyValue<StringName, ClassDB::ClassInfo::EnumInfo> &E : enum_map) {
StringName enum_proxy_cname = E.key;
String enum_proxy_name = enum_proxy_cname.operator String();
- if (itype.find_property_by_proxy_name(enum_proxy_cname)) {
- // We have several conflicts between enums and PascalCase properties,
- // so we append 'Enum' to the enum name in those cases.
+ if (itype.find_property_by_proxy_name(enum_proxy_name) || itype.find_method_by_proxy_name(enum_proxy_name) || itype.find_signal_by_proxy_name(enum_proxy_name)) {
+ // In case the enum name conflicts with other PascalCase members,
+ // we append 'Enum' to the enum name in those cases.
+ // We have several conflicts between enums and PascalCase properties.
enum_proxy_name += "Enum";
enum_proxy_cname = StringName(enum_proxy_name);
}
@@ -3161,7 +3227,15 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
int64_t *value = class_info->constant_map.getptr(StringName(constant_name));
ERR_FAIL_NULL_V(value, false);
- ConstantInterface iconstant(constant_name, snake_to_pascal_case(constant_name, true), *value);
+ String constant_proxy_name = snake_to_pascal_case(constant_name, true);
+
+ if (itype.find_property_by_proxy_name(constant_proxy_name) || itype.find_method_by_proxy_name(constant_proxy_name) || itype.find_signal_by_proxy_name(constant_proxy_name)) {
+ // In case the constant name conflicts with other PascalCase members,
+ // we append 'Constant' to the constant name in those cases.
+ constant_proxy_name += "Constant";
+ }
+
+ ConstantInterface iconstant(constant_name, constant_proxy_name, *value);
iconstant.const_doc = nullptr;
for (int i = 0; i < itype.class_doc->constants.size(); i++) {
@@ -3317,11 +3391,11 @@ bool BindingsGenerator::_arg_default_value_from_variant(const Variant &p_val, Ar
r_iarg.def_param_mode = ArgumentInterface::NULLABLE_VAL;
} break;
case Variant::PROJECTION: {
- Projection transform = p_val.operator Projection();
- if (transform == Projection()) {
+ Projection projection = p_val.operator Projection();
+ if (projection == Projection()) {
r_iarg.default_argument = "Projection.Identity";
} else {
- r_iarg.default_argument = "new Projection(new Vector4" + transform.matrix[0].operator String() + ", new Vector4" + transform.matrix[1].operator String() + ", new Vector4" + transform.matrix[2].operator String() + ", new Vector4" + transform.matrix[3].operator String() + ")";
+ r_iarg.default_argument = "new Projection(new Vector4" + projection.columns[0].operator String() + ", new Vector4" + projection.columns[1].operator String() + ", new Vector4" + projection.columns[2].operator String() + ", new Vector4" + projection.columns[3].operator String() + ")";
}
r_iarg.def_param_mode = ArgumentInterface::NULLABLE_VAL;
} break;
diff --git a/modules/mono/editor/code_completion.cpp b/modules/mono/editor/code_completion.cpp
index 40296eef10..dc69567261 100644
--- a/modules/mono/editor/code_completion.cpp
+++ b/modules/mono/editor/code_completion.cpp
@@ -140,7 +140,7 @@ PackedStringArray get_code_completion(CompletionKind p_kind, const String &p_scr
}
} break;
case CompletionKind::RESOURCE_PATHS: {
- if (bool(EditorSettings::get_singleton()->get("text_editor/completion/complete_file_paths"))) {
+ if (bool(EDITOR_GET("text_editor/completion/complete_file_paths"))) {
_get_directory_contents(EditorFileSystem::get_singleton()->get_filesystem(), suggestions);
}
} break;
diff --git a/modules/mono/editor/editor_internal_calls.cpp b/modules/mono/editor/editor_internal_calls.cpp
index 6f42ad6916..91392c8f79 100644
--- a/modules/mono/editor/editor_internal_calls.cpp
+++ b/modules/mono/editor/editor_internal_calls.cpp
@@ -152,7 +152,7 @@ bool godot_icall_Internal_ScriptEditorEdit(Resource *p_resource, int32_t p_line,
}
void godot_icall_Internal_EditorNodeShowScriptScreen() {
- EditorNode::get_singleton()->call("_editor_select", EditorNode::EDITOR_SCRIPT);
+ EditorNode::get_singleton()->editor_select(EditorNode::EDITOR_SCRIPT);
}
void godot_icall_Internal_EditorRunPlay() {