summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/classes/Signal.xml45
-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/MoreExportedFields.cs19
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs45
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs16
5 files changed, 115 insertions, 15 deletions
diff --git a/doc/classes/Signal.xml b/doc/classes/Signal.xml
index 3c98a0a0e1..ce2d443ba7 100644
--- a/doc/classes/Signal.xml
+++ b/doc/classes/Signal.xml
@@ -1,11 +1,29 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="Signal" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
- Class representing a signal defined in an object.
+ Built-in type representing a signal defined in an object.
</brief_description>
<description>
- Signals can be connected to [Callable]s and emitted. When a signal is emitted, all connected callables are called.
- Usually signals are accessed as properties of objects, but it's also possible to assign them to variables and pass them around, allowing for more dynamic connections.
+ [Signal] is a built-in [Variant] type that represents a signal of an [Object] instance. Like all [Variant] types, it can be stored in variables and passed to functions. Signals allow all connected [Callable]s (and by extension their respective objects) to listen and react to events, without directly referencing one another. This keeps the code flexible and easier to manage.
+ In GDScript, signals can be declared with the [code]signal[/code] keyword. In C#, you may use the [code][Signal][/code] attribute on a delegate.
+ [codeblock]
+ [gdscript]
+ signal attacked
+
+ # Additional arguments may be declared.
+ # These arguments must be passed when the signal is emitted.
+ signal item_dropped(item_name, amount)
+ [/gdscript]
+ [csharp]
+ [Signal]
+ delegate void Attacked();
+
+ // Additional arguments may be declared.
+ // These arguments must be passed when the signal is emitted.
+ [Signal]
+ delegate void ItemDropped(itemName: string, amount: int);
+ [/csharp]
+ [/codeblock]
</description>
<tutorials>
<link title="Using Signals">$DOCS_URL/getting_started/step_by_step/signals.html</link>
@@ -15,7 +33,7 @@
<constructor name="Signal">
<return type="Signal" />
<description>
- Constructs a null [Signal] with no object nor signal name bound.
+ Constructs an empty [Signal] with no object nor signal name bound.
</description>
</constructor>
<constructor name="Signal">
@@ -30,7 +48,7 @@
<param index="0" name="object" type="Object" />
<param index="1" name="signal" type="StringName" />
<description>
- Creates a new [Signal] with the name [param signal] in the specified [param object].
+ Creates a new [Signal] named [param signal] in the specified [param object].
</description>
</constructor>
</constructors>
@@ -40,12 +58,13 @@
<param index="0" name="callable" type="Callable" />
<param index="1" name="flags" type="int" default="0" />
<description>
- Connects this signal to the specified [Callable], optionally providing connection flags. You can provide additional arguments to the connected method call by using [method Callable.bind].
+ Connects this signal to the specified [param callable]. Optional [param flags] can be also added to configure the connection's behavior (see [enum Object.ConnectFlags] constants). You can provide additional arguments to the connected [param callable] by using [method Callable.bind].
+ A signal can only be connected once to the same [Callable]. If the signal is already connected, returns [constant ERR_INVALID_PARAMETER] and pushes an error message, unless the signal is connected with [constant Object.CONNECT_REFERENCE_COUNTED]. To prevent this, use [method is_connected] first to check for existing connections.
[codeblock]
for button in $Buttons.get_children():
- button.pressed.connect(on_pressed.bind(button))
+ button.pressed.connect(_on_pressed.bind(button))
- func on_pressed(button):
+ func _on_pressed(button):
print(button.name, " was pressed")
[/codeblock]
</description>
@@ -54,13 +73,13 @@
<return type="void" />
<param index="0" name="callable" type="Callable" />
<description>
- Disconnects this signal from the specified [Callable].
+ Disconnects this signal from the specified [Callable]. If the connection does not exist, generates an error. Use [method is_connected] to make sure that the connection exists.
</description>
</method>
<method name="emit" qualifiers="vararg const">
<return type="void" />
<description>
- Emits this signal to all connected objects.
+ Emits this signal. All [Callable]s connected to this signal will be triggered. This method supports a variable number of arguments, so parameters can be passed as a comma separated list.
</description>
</method>
<method name="get_connections" qualifiers="const">
@@ -97,7 +116,7 @@
<method name="is_null" qualifiers="const">
<return type="bool" />
<description>
- Returns [code]true[/code] if either object or signal name are not valid.
+ Returns [code]true[/code] if the signal's name does not exist in its object, or the object is not valid.
</description>
</method>
</methods>
@@ -106,14 +125,14 @@
<return type="bool" />
<param index="0" name="right" type="Signal" />
<description>
- Returns [code]true[/code] if two signals are not equal.
+ Returns [code]true[/code] if the signals do not share the same object and name.
</description>
</operator>
<operator name="operator ==">
<return type="bool" />
<param index="0" name="right" type="Signal" />
<description>
- Returns [code]true[/code] if two signals are equal, i.e. their object and name are the same.
+ Returns [code]true[/code] if both signals share the same object and name.
</description>
</operator>
</operators>
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/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/ExtensionMethods.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs
index 8de12de23b..9e3add4262 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;
@@ -165,6 +166,50 @@ namespace Godot.SourceGenerators
public static string FullQualifiedName(this INamespaceSymbol namespaceSymbol)
=> namespaceSymbol.ToDisplayString(FullyQualifiedFormatOmitGlobal);
+ public static string FullQualifiedName(this ISymbol symbol)
+ => symbol.ToDisplayString(FullyQualifiedFormatOmitGlobal);
+
+ public static string FullQualifiedSyntax(this SyntaxNode node, SemanticModel sm)
+ {
+ StringBuilder sb = new();
+ FullQualifiedSyntax_(node, sm, sb, true);
+ return sb.ToString();
+ }
+
+ 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?.FullQualifiedName() ?? 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
// AddSource() doesn't support angle brackets
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 98b9745c16..9a18ba3ab2 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs
@@ -170,7 +170,13 @@ namespace Godot.SourceGenerators
.Select(s => s?.Initializer ?? null)
.FirstOrDefault();
- string? value = initializer?.Value.ToString();
+ // Fully qualify the value 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(
property.Name, marshalType.Value, propertyType, value));
@@ -207,7 +213,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));