Feat/bindnodesignal generator#152
Merged
Merged
Conversation
- 实现 BindNodeSignalGenerator 源生成器,用于自动生成 Godot 节点事件绑定与解绑逻辑 - 添加 BindNodeSignalAttribute 特性,标记需要生成绑定逻辑的事件处理方法 - 实现完整的诊断系统,包括嵌套类型、静态方法、字段类型等错误检查 - 添加生命周期方法调用检查,在 _Ready 和 _ExitTree 中验证生成方法的调用 - 支持方法签名与事件委托的兼容性验证 - 实现单元测试覆盖各种使用场景和错误情况
- 新增 AnalyzerReleases.Unshipped.md 文件记录代码分析规则 - 添加 GF_Godot_GetNode 系列规则定义(001-006) - 添加 GF_Godot_BindNodeSignal 系列规则定义(001-009) - 创建 README.md 文件详述源码生成器使用方法 - 文档化 GetNode 和 BindNodeSignal 特性用法示例 - 说明 Godot 场景相关的编译期生成能力
Reviewer's Guide引入了一个新的 [BindNodeSignal] 特性以及对应的 Roslyn 增量生成器,用于自动生成 Godot 节点信号订阅/取消订阅方法,并包含诊断信息、测试以及文档更新。 BindNodeSignal 增量生成与运行时使用的时序图sequenceDiagram
participant Dev as Developer
participant CSharpCompiler as CSharpCompiler
participant Roslyn as RoslynIncrementalPipeline
participant Gen as BindNodeSignalGenerator
participant Hud as TestAppHud
participant Button as GodotButton
Dev->>CSharpCompiler: Build project with [BindNodeSignal] methods
CSharpCompiler->>Roslyn: Provide syntax trees and symbols
Roslyn->>Gen: Initialize(context)
Roslyn->>Gen: Execute(compilation, candidates)
Gen->>Gen: Find methods with BindNodeSignalAttribute
Gen->>Gen: Validate node field, event, and handler signature
Gen-->>Roslyn: Generated partial Hud with __BindNodeSignals_Generated and __UnbindNodeSignals_Generated
Roslyn-->>CSharpCompiler: Add generated source to compilation
CSharpCompiler-->>Dev: Emit assembly
Dev->>Hud: Instantiate and add to scene
Hud->>Hud: _Ready()
Hud->>Hud: __BindNodeSignals_Generated()
Hud->>Button: subscribe Pressed += OnStartButtonPressed
Button-->>Hud: Pressed event
Hud->>Hud: OnStartButtonPressed()
Hud->>Hud: _ExitTree()
Hud->>Hud: __UnbindNodeSignals_Generated()
Hud->>Button: unsubscribe Pressed -= OnStartButtonPressed
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your Experience访问你的 dashboard 以:
Getting HelpOriginal review guide in EnglishReviewer's GuideIntroduces a new [BindNodeSignal] attribute and corresponding Roslyn incremental generator to auto-generate Godot node signal subscription/unsubscription methods, along with diagnostics, tests, and documentation updates. Sequence diagram for BindNodeSignal incremental generation and runtime usagesequenceDiagram
participant Dev as Developer
participant CSharpCompiler as CSharpCompiler
participant Roslyn as RoslynIncrementalPipeline
participant Gen as BindNodeSignalGenerator
participant Hud as TestAppHud
participant Button as GodotButton
Dev->>CSharpCompiler: Build project with [BindNodeSignal] methods
CSharpCompiler->>Roslyn: Provide syntax trees and symbols
Roslyn->>Gen: Initialize(context)
Roslyn->>Gen: Execute(compilation, candidates)
Gen->>Gen: Find methods with BindNodeSignalAttribute
Gen->>Gen: Validate node field, event, and handler signature
Gen-->>Roslyn: Generated partial Hud with __BindNodeSignals_Generated and __UnbindNodeSignals_Generated
Roslyn-->>CSharpCompiler: Add generated source to compilation
CSharpCompiler-->>Dev: Emit assembly
Dev->>Hud: Instantiate and add to scene
Hud->>Hud: _Ready()
Hud->>Hud: __BindNodeSignals_Generated()
Hud->>Button: subscribe Pressed += OnStartButtonPressed
Button-->>Hud: Pressed event
Hud->>Hud: OnStartButtonPressed()
Hud->>Hud: _ExitTree()
Hud->>Hud: __UnbindNodeSignals_Generated()
Hud->>Button: unsubscribe Pressed -= OnStartButtonPressed
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
|
|
Overall Grade |
Security Reliability Complexity Hygiene |
Code Review Summary
| Analyzer | Status | Updated (UTC) | Details |
|---|---|---|---|
| C# | Mar 31, 2026 4:11a.m. | Review ↗ | |
| Secrets | Mar 31, 2026 4:11a.m. | Review ↗ |
There was a problem hiding this comment.
Hey - 我发现了两个问题,并给出了一些总体反馈:
- 建议防范用户自定义名为
__BindNodeSignals_Generated或__UnbindNodeSignals_Generated的成员(例如,通过检查是否已存在这些名称的方法并报告诊断),以避免当使用方意外定义了相同签名时出现静默的编译冲突。 - 当前的
IsCandidate过滤器使用的是attribute.Name.ToString().Contains("BindNodeSignal", StringComparison.Ordinal),这可能会匹配到无关的特性,并带来字符串分配开销;你可以改为匹配IdentifierNameSyntax/QualifiedNameSyntax,并将简单名称精确地与BindNodeSignal比较,以同时提升正确性和性能。 - AnalyzerReleases.Unshipped.md 中声明的规则目前到
GF_Godot_BindNodeSignal_008,但BindNodeSignalDiagnostics还定义了GF_Godot_BindNodeSignal_009;建议将该规则加入表格,使分析器元数据与已实现的诊断保持同步。
面向 AI Agent 的提示词
Please address the comments from this code review:
## Overall Comments
- Consider guarding against user-defined members named `__BindNodeSignals_Generated` or `__UnbindNodeSignals_Generated` (e.g., by checking for existing methods with these names and reporting a diagnostic) to avoid silent compilation conflicts when a consumer accidentally defines the same signatures.
- The `IsCandidate` filter currently uses `attribute.Name.ToString().Contains("BindNodeSignal", StringComparison.Ordinal)`, which may match unrelated attributes and adds string-allocation overhead; you could instead match on `IdentifierNameSyntax`/`QualifiedNameSyntax` and compare the simple name exactly to `BindNodeSignal` for both correctness and performance.
- AnalyzerReleases.Unshipped.md declares rules up to `GF_Godot_BindNodeSignal_008`, but `BindNodeSignalDiagnostics` also defines `GF_Godot_BindNodeSignal_009`; consider adding this rule to the table so analyzer metadata stays in sync with the implemented diagnostics.
## Individual Comments
### Comment 1
<location path="GFramework.Godot.SourceGenerators/BindNodeSignalGenerator.cs" line_range="71-74" />
<code_context>
+ if (bindNodeSignalAttribute is null || godotNodeSymbol is null)
+ return;
+
+ var methodCandidates = candidates
+ .Where(static candidate => candidate is not null)
+ .Select(static candidate => candidate!)
+ .Where(candidate => ResolveAttributes(candidate.MethodSymbol, bindNodeSignalAttribute).Count > 0)
+ .ToList();
+
</code_context>
<issue_to_address>
**suggestion (performance):** ResolveAttributes 每个方法被调用两次,这是可以避免的开销。
在 `Execute` 中,`ResolveAttributes` 既在 LINQ 过滤器里计算,又在 `group.Methods` 循环内部再次调用。由于特性解析依赖语义分析且相对昂贵,建议针对每个 `MethodCandidate` 只解析一次特性(例如,在 `MethodCandidate` 上存一个 `IReadOnlyList<AttributeData>`,或者使用一个中间投影),然后复用该结果,以避免重复工作,这对大型项目会有帮助。
建议实现方式:
```csharp
if (bindNodeSignalAttribute is null || godotNodeSymbol is null)
return;
// Cache resolved attributes per method candidate to avoid repeated semantic work.
var methodAttributes = candidates
.Where(static candidate => candidate is not null)
.Select(static candidate => candidate!)
.ToDictionary(
static candidate => candidate,
candidate => ResolveAttributes(candidate.MethodSymbol, bindNodeSignalAttribute));
var methodCandidates = methodAttributes
.Where(static kvp => kvp.Value.Count > 0)
.Select(static kvp => kvp.Key)
.ToList();
```
为了在 `Execute` 中彻底避免对每个方法调用两次 `ResolveAttributes`,你还需要:
1. 找到后面 `Execute` 中 `group.Methods` 的循环,在那里又调用了 `ResolveAttributes`(大致类似 `ResolveAttributes(methodCandidate.MethodSymbol, bindNodeSignalAttribute)`)。
2. 将这些调用替换为对上面创建的 `methodAttributes` 字典的查找。例如:
- 如果当前有 `var attributes = ResolveAttributes(methodCandidate.MethodSymbol, bindNodeSignalAttribute);`,请改为 `var attributes = methodAttributes[methodCandidate];`。
3. 确保在定义 `group.Methods` 循环的作用域内可以访问 `methodAttributes` 字典。如果该循环在一个嵌套的本地函数或单独的辅助方法里,请将 `methodAttributes` 作为参数传入,而不是在那儿重新计算特性。
这些调整能确保每个方法的特性只解析一次,并在过滤和生成逻辑中复用。
</issue_to_address>
### Comment 2
<location path="GFramework.Godot.SourceGenerators/BindNodeSignalGenerator.cs" line_range="247-254" />
<code_context>
+ context.ReportDiagnostic(Diagnostic.Create(descriptor, location, messageArgs));
+ }
+
+ private static string ResolveCtorString(
+ AttributeData attribute,
+ int index)
+ {
+ if (attribute.ConstructorArguments.Length <= index)
+ return string.Empty;
+
+ return attribute.ConstructorArguments[index].Value as string ?? string.Empty;
+ }
+
</code_context>
<issue_to_address>
**suggestion:** 缺失的构造函数参数会退化为空字符串,这会导致诊断信息令人困惑。
由于 `ResolveCtorString` 在构造函数参数缺失或非字符串时会返回 `string.Empty`,这个空名称会继续流入 `FindField` / `FindEvent`,从而产生类似 “field '' not found” 这种不清晰的诊断。建议显式检测“缺失或类型错误”的情况并报告专门的诊断,或者至少在解析出的名称为空时尽早短路,让用户能得到关于错误特性用法的更清晰提示。
建议实现方式:
```csharp
private static bool TryResolveCtorString(
AttributeData attribute,
int index,
out string value)
{
value = string.Empty;
// Missing ctor argument at the requested index.
if (attribute.ConstructorArguments.Length <= index)
return false;
var ctorArgument = attribute.ConstructorArguments[index];
// We only support primitive string literals here; anything else is considered invalid.
if (ctorArgument.Kind != TypedConstantKind.Primitive || ctorArgument.Value is not string s)
return false;
// Treat empty/whitespace-only names as invalid to avoid confusing diagnostics like "field '' not found".
if (string.IsNullOrWhiteSpace(s))
return false;
value = s;
return true;
}
/// <summary>
/// Legacy helper kept for backward compatibility. Prefer <see cref="TryResolveCtorString"/>.
/// This method returns <see cref="string.Empty"/> when the constructor argument is missing or invalid.
/// </summary>
private static string ResolveCtorString(
AttributeData attribute,
int index)
{
return TryResolveCtorString(attribute, index, out var value)
? value
: string.Empty;
}
```
为了完整实现你在诊断行为上的改进建议,还需要在本文件其他位置做以下修改:
1. **更新所有调用点**,将目前类似以下形式:
- `var fieldName = ResolveCtorString(attribute, 0);`
- `var eventName = ResolveCtorString(attribute, 0);`
然后把这些值传入 `FindField`、`FindEvent` 或类似方法的调用,改为:
```csharp
if (!TryResolveCtorString(attribute, 0, out var fieldName))
{
// Report a dedicated "invalid attribute usage" diagnostic and return.
ReportDiagnostic(
context,
InvalidBindNodeSignalAttributeDescriptor, // define this descriptor if it doesn't exist yet
candidate,
attribute,
/* any message arguments you need, e.g. candidate.Method.Identifier.Text */
);
return;
}
var field = FindField(fieldName, ...);
```
2. **引入一个专门的诊断描述符**(如果你还没有的话),用于 `BindNodeSignalAttribute` 上无效/缺失的构造函数参数,例如:
```csharp
private static readonly DiagnosticDescriptor InvalidBindNodeSignalAttributeDescriptor =
new DiagnosticDescriptor(
"GODOTSG001",
"Invalid BindNodeSignal attribute usage",
"The {0} attribute requires a non-empty string literal for its '{1}' constructor argument.",
"Usage",
DiagnosticSeverity.Error,
isEnabledByDefault: true);
```
3. 当 `TryResolveCtorString` 返回 `false` 时,在提前返回的路径上使用这个新的描述符,这样用户能看到类似以下清晰的诊断信息:
- “The BindNodeSignal attribute requires a non-empty string literal for its 'signalName' constructor argument.”
而不是后续产生的诸如 “field '' not found” 之类的诊断。
这些更改可以确保缺失或类型不正确的构造函数参数不再悄然退化为空字符串,并让用户获得关于错误特性用法的明确诊断提示。
</issue_to_address>帮我变得更有用!请在每条评论上点 👍 或 👎,我会根据反馈改进后续的审查。
Original comment in English
Hey - I've found 2 issues, and left some high level feedback:
- Consider guarding against user-defined members named
__BindNodeSignals_Generatedor__UnbindNodeSignals_Generated(e.g., by checking for existing methods with these names and reporting a diagnostic) to avoid silent compilation conflicts when a consumer accidentally defines the same signatures. - The
IsCandidatefilter currently usesattribute.Name.ToString().Contains("BindNodeSignal", StringComparison.Ordinal), which may match unrelated attributes and adds string-allocation overhead; you could instead match onIdentifierNameSyntax/QualifiedNameSyntaxand compare the simple name exactly toBindNodeSignalfor both correctness and performance. - AnalyzerReleases.Unshipped.md declares rules up to
GF_Godot_BindNodeSignal_008, butBindNodeSignalDiagnosticsalso definesGF_Godot_BindNodeSignal_009; consider adding this rule to the table so analyzer metadata stays in sync with the implemented diagnostics.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- Consider guarding against user-defined members named `__BindNodeSignals_Generated` or `__UnbindNodeSignals_Generated` (e.g., by checking for existing methods with these names and reporting a diagnostic) to avoid silent compilation conflicts when a consumer accidentally defines the same signatures.
- The `IsCandidate` filter currently uses `attribute.Name.ToString().Contains("BindNodeSignal", StringComparison.Ordinal)`, which may match unrelated attributes and adds string-allocation overhead; you could instead match on `IdentifierNameSyntax`/`QualifiedNameSyntax` and compare the simple name exactly to `BindNodeSignal` for both correctness and performance.
- AnalyzerReleases.Unshipped.md declares rules up to `GF_Godot_BindNodeSignal_008`, but `BindNodeSignalDiagnostics` also defines `GF_Godot_BindNodeSignal_009`; consider adding this rule to the table so analyzer metadata stays in sync with the implemented diagnostics.
## Individual Comments
### Comment 1
<location path="GFramework.Godot.SourceGenerators/BindNodeSignalGenerator.cs" line_range="71-74" />
<code_context>
+ if (bindNodeSignalAttribute is null || godotNodeSymbol is null)
+ return;
+
+ var methodCandidates = candidates
+ .Where(static candidate => candidate is not null)
+ .Select(static candidate => candidate!)
+ .Where(candidate => ResolveAttributes(candidate.MethodSymbol, bindNodeSignalAttribute).Count > 0)
+ .ToList();
+
</code_context>
<issue_to_address>
**suggestion (performance):** ResolveAttributes is invoked twice per method, which is avoidable work.
In `Execute`, `ResolveAttributes` is evaluated in the LINQ filter and again inside the `group.Methods` loop. Since attribute resolution is semantic and relatively expensive, consider resolving attributes once per `MethodCandidate` (e.g., store an `IReadOnlyList<AttributeData>` on `MethodCandidate` or use an intermediate projection) and reuse that result to avoid duplicate work, which will help on large projects.
Suggested implementation:
```csharp
if (bindNodeSignalAttribute is null || godotNodeSymbol is null)
return;
// Cache resolved attributes per method candidate to avoid repeated semantic work.
var methodAttributes = candidates
.Where(static candidate => candidate is not null)
.Select(static candidate => candidate!)
.ToDictionary(
static candidate => candidate,
candidate => ResolveAttributes(candidate.MethodSymbol, bindNodeSignalAttribute));
var methodCandidates = methodAttributes
.Where(static kvp => kvp.Value.Count > 0)
.Select(static kvp => kvp.Key)
.ToList();
```
To fully avoid invoking `ResolveAttributes` twice per method in `Execute`, you should also:
1. Locate the `group.Methods` loop later in `Execute` where `ResolveAttributes` is called again (likely something like `ResolveAttributes(methodCandidate.MethodSymbol, bindNodeSignalAttribute)`).
2. Replace those calls with lookups into the `methodAttributes` dictionary introduced above. For example:
- If you have `var attributes = ResolveAttributes(methodCandidate.MethodSymbol, bindNodeSignalAttribute);`, change it to `var attributes = methodAttributes[methodCandidate];`.
3. Ensure the `methodAttributes` dictionary is in scope where the `group.Methods` loop is defined. If the loop is in a nested local function or separate helper, pass `methodAttributes` as a parameter to that function instead of recomputing attributes there.
These adjustments will make sure each method's attributes are resolved exactly once and reused across both the filtering and the generation logic.
</issue_to_address>
### Comment 2
<location path="GFramework.Godot.SourceGenerators/BindNodeSignalGenerator.cs" line_range="247-254" />
<code_context>
+ context.ReportDiagnostic(Diagnostic.Create(descriptor, location, messageArgs));
+ }
+
+ private static string ResolveCtorString(
+ AttributeData attribute,
+ int index)
+ {
+ if (attribute.ConstructorArguments.Length <= index)
+ return string.Empty;
+
+ return attribute.ConstructorArguments[index].Value as string ?? string.Empty;
+ }
+
</code_context>
<issue_to_address>
**suggestion:** Missing constructor arguments degrade into empty strings, which can lead to confusing diagnostics.
Because `ResolveCtorString` returns `string.Empty` for missing or non-string ctor args, that empty name flows into `FindField` / `FindEvent` and yields diagnostics like “field '' not found,” which are unclear. Consider detecting the "missing or wrong type" case explicitly and reporting a dedicated diagnostic, or at least short-circuiting when the resolved name is empty so the user gets a clearer message about incorrect attribute usage.
Suggested implementation:
```csharp
private static bool TryResolveCtorString(
AttributeData attribute,
int index,
out string value)
{
value = string.Empty;
// Missing ctor argument at the requested index.
if (attribute.ConstructorArguments.Length <= index)
return false;
var ctorArgument = attribute.ConstructorArguments[index];
// We only support primitive string literals here; anything else is considered invalid.
if (ctorArgument.Kind != TypedConstantKind.Primitive || ctorArgument.Value is not string s)
return false;
// Treat empty/whitespace-only names as invalid to avoid confusing diagnostics like "field '' not found".
if (string.IsNullOrWhiteSpace(s))
return false;
value = s;
return true;
}
/// <summary>
/// Legacy helper kept for backward compatibility. Prefer <see cref="TryResolveCtorString"/>.
/// This method returns <see cref="string.Empty"/> when the constructor argument is missing or invalid.
/// </summary>
private static string ResolveCtorString(
AttributeData attribute,
int index)
{
return TryResolveCtorString(attribute, index, out var value)
? value
: string.Empty;
}
```
To fully implement your diagnostic-behavior suggestion, the following additional changes are required elsewhere in this file:
1. **Update all call sites** that currently do something like:
- `var fieldName = ResolveCtorString(attribute, 0);`
- `var eventName = ResolveCtorString(attribute, 0);`
and then pass those values into `FindField`, `FindEvent`, or similar, to instead use:
```csharp
if (!TryResolveCtorString(attribute, 0, out var fieldName))
{
// Report a dedicated "invalid attribute usage" diagnostic and return.
ReportDiagnostic(
context,
InvalidBindNodeSignalAttributeDescriptor, // define this descriptor if it doesn't exist yet
candidate,
attribute,
/* any message arguments you need, e.g. candidate.Method.Identifier.Text */
);
return;
}
var field = FindField(fieldName, ...);
```
2. **Introduce a dedicated diagnostic descriptor** (if you don't already have one) for invalid/missing constructor arguments on `BindNodeSignalAttribute`, for example:
```csharp
private static readonly DiagnosticDescriptor InvalidBindNodeSignalAttributeDescriptor =
new DiagnosticDescriptor(
"GODOTSG001",
"Invalid BindNodeSignal attribute usage",
"The {0} attribute requires a non-empty string literal for its '{1}' constructor argument.",
"Usage",
DiagnosticSeverity.Error,
isEnabledByDefault: true);
```
3. Use this new descriptor in the early-return path when `TryResolveCtorString` returns `false`, so that users see a clear diagnostic like:
- “The BindNodeSignal attribute requires a non-empty string literal for its 'signalName' constructor argument.”
instead of downstream diagnostics like “field '' not found”.
These changes ensure that missing or incorrectly-typed constructor arguments no longer degrade into empty strings, and that users get a targeted, understandable diagnostic about incorrect attribute usage.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
- 实现 BindNodeSignalGenerator 源代码生成器,用于自动化节点信号绑定 - 添加完整的诊断系统,包含 11 种不同的错误和警告场景检测 - 生成对称的绑定和解绑方法,确保资源正确释放 - 支持一个处理方法通过多个特性绑定到多个节点事件 - 实现生命周期钩子调用检查,确保在 _Ready 和 _ExitTree 中正确调用生成的方法 - 提供详细的单元测试覆盖各种使用场景和边界条件 - 生成器与现有的 GetNode 声明完全兼容并可共存 - 包含命名冲突检测和构造参数验证等安全检查机制
- 实现 BindNodeSignalGenerator 用于生成节点信号绑定与解绑逻辑 - 实现 GetNodeGenerator 用于生成 Godot 节点获取注入逻辑 - 添加 BindNodeSignalDiagnostics 提供详细的诊断错误信息 - 集成到 AnalyzerReleases.Unshipped.md 追踪新的分析规则 - 支持 [BindNodeSignal] 属性的方法自动生成事件绑定代码 - 支持 [GetNode] 属性的字段自动生成节点获取代码 - 提供生命周期方法集成的智能提示和验证功能
- 在 BindNodeSignalDiagnostics.cs 中添加 Microsoft.CodeAnalysis 引用 - 在 BindNodeSignalGenerator.cs 中添加 Roslyn 相关命名空间引用 - 在 GetNodeGenerator.cs 中添加 Roslyn 相关命名空间引用 - 在 GlobalUsings.cs 中集中管理全局命名空间引用 - 在 ContextGetGenerator.cs 中添加字符串和扩展方法引用 - 在 CommonDiagnostics.cs 中添加诊断相关命名空间引用 - 在 Common 全局引用文件中统一管理 Microsoft.CodeAnalysis 引用
This was referenced May 10, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary by Sourcery
添加了一个新的 Roslyn 增量生成器,用于基于一个新的特性自动绑定和解绑 Godot 节点的 CLR 事件,并包含相应的诊断、测试和文档。
New Features:
BindNodeSignalAttribute,以声明式方式描述 Godot 节点字段与其 CLR 事件之间的绑定关系。BindNodeSignalAttribute标记的、作为 partial 的 Godot 节点类生成__BindNodeSignals_Generated和__UnbindNodeSignals_Generated辅助方法,用于集中管理事件订阅。Enhancements:
BindNodeSignal专用的诊断描述符和规则注册,用于验证其用法以及为生成的绑定配置生命周期钩子。Documentation:
BindNodeSignal的使用方式以及生成的辅助方法,并包含示例代码。Tests:
BindNodeSignalGenerator测试套件,覆盖代码生成、与GetNode的共存、无效的信号或处理程序配置,以及生命周期钩子相关警告诊断等场景。Original summary in English
Summary by Sourcery
Add a new Roslyn incremental generator to automatically bind and unbind Godot node CLR events based on a new attribute, including diagnostics, tests, and documentation.
New Features:
Enhancements:
Documentation:
Tests: