Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#nullable enable
namespace GFramework.Godot.SourceGenerators.Abstractions;

/// <summary>
/// 标记 Godot 节点事件处理方法,Source Generator 会为其生成事件绑定与解绑逻辑。
/// </summary>
/// <remarks>
/// 该特性通过节点字段名与事件名建立声明式订阅关系,适用于将
/// <c>_Ready()</c> / <c>_ExitTree()</c> 中重复的 <c>+=</c> 与 <c>-=</c> 样板代码
/// 收敛到生成器中统一维护。
/// </remarks>
[AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = true)]
public sealed class BindNodeSignalAttribute : Attribute
{
/// <summary>
/// 初始化 <see cref="BindNodeSignalAttribute" /> 的新实例。
/// </summary>
/// <param name="nodeFieldName">目标节点字段名。</param>
/// <param name="signalName">目标节点上的 CLR 事件名。</param>
/// <exception cref="ArgumentNullException">
/// <paramref name="nodeFieldName" /> 或 <paramref name="signalName" /> 为 <see langword="null" />。
/// </exception>
public BindNodeSignalAttribute(
string nodeFieldName,
string signalName)
{
NodeFieldName = nodeFieldName ?? throw new ArgumentNullException(nameof(nodeFieldName));
SignalName = signalName ?? throw new ArgumentNullException(nameof(signalName));
}

/// <summary>
/// 获取目标节点字段名。
/// </summary>
public string NodeFieldName { get; }

/// <summary>
/// 获取目标节点上的 CLR 事件名。
/// </summary>
public string SignalName { get; }
}

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
using GFramework.Godot.SourceGenerators.Tests.Core;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Testing;
using Microsoft.CodeAnalysis.Testing;
using NUnit.Framework;

namespace GFramework.Godot.SourceGenerators.Tests.GetNode;

Expand Down Expand Up @@ -240,4 +236,71 @@ public partial class TopBar : Node

await test.RunAsync();
}

[Test]
public async Task Reports_Diagnostic_When_Generated_Injection_Method_Name_Already_Exists()
{
const string source = """
using System;
using GFramework.Godot.SourceGenerators.Abstractions;
using Godot;

namespace GFramework.Godot.SourceGenerators.Abstractions
{
[AttributeUsage(AttributeTargets.Field, Inherited = false, AllowMultiple = false)]
public sealed class GetNodeAttribute : Attribute
{
public GetNodeAttribute() {}
}

public enum NodeLookupMode
{
Auto = 0
}
}

namespace Godot
{
public class Node
{
public virtual void _Ready() {}
public T GetNode<T>(string path) where T : Node => throw new InvalidOperationException(path);
public T? GetNodeOrNull<T>(string path) where T : Node => default;
}

public class HBoxContainer : Node
{
}
}

namespace TestApp
{
public partial class TopBar : HBoxContainer
{
[GetNode]
private HBoxContainer _leftContainer = null!;

private void {|#0:__InjectGetNodes_Generated|}()
{
}
}
}
""";

var test = new CSharpSourceGeneratorTest<GetNodeGenerator, DefaultVerifier>
{
TestState =
{
Sources = { source }
},
DisabledDiagnostics = { "GF_Common_Trace_001" },
TestBehaviors = TestBehaviors.SkipGeneratedSourcesCheck
};

test.ExpectedDiagnostics.Add(new DiagnosticResult("GF_Common_Class_002", DiagnosticSeverity.Error)
.WithLocation(0)
.WithArguments("TopBar", "__InjectGetNodes_Generated"));

await test.RunAsync();
}
}
26 changes: 18 additions & 8 deletions GFramework.Godot.SourceGenerators/AnalyzerReleases.Unshipped.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,21 @@

### New Rules

Rule ID | Category | Severity | Notes
----------------------|------------------|----------|--------------------
GF_Godot_GetNode_001 | GFramework.Godot | Error | GetNodeDiagnostics
GF_Godot_GetNode_002 | GFramework.Godot | Error | GetNodeDiagnostics
GF_Godot_GetNode_003 | GFramework.Godot | Error | GetNodeDiagnostics
GF_Godot_GetNode_004 | GFramework.Godot | Error | GetNodeDiagnostics
GF_Godot_GetNode_005 | GFramework.Godot | Error | GetNodeDiagnostics
GF_Godot_GetNode_006 | GFramework.Godot | Warning | GetNodeDiagnostics
Rule ID | Category | Severity | Notes
-----------------------------|------------------|----------|---------------------------
GF_Godot_GetNode_001 | GFramework.Godot | Error | GetNodeDiagnostics
GF_Godot_GetNode_002 | GFramework.Godot | Error | GetNodeDiagnostics
GF_Godot_GetNode_003 | GFramework.Godot | Error | GetNodeDiagnostics
GF_Godot_GetNode_004 | GFramework.Godot | Error | GetNodeDiagnostics
GF_Godot_GetNode_005 | GFramework.Godot | Error | GetNodeDiagnostics
GF_Godot_GetNode_006 | GFramework.Godot | Warning | GetNodeDiagnostics
GF_Godot_BindNodeSignal_001 | GFramework.Godot | Error | BindNodeSignalDiagnostics
GF_Godot_BindNodeSignal_002 | GFramework.Godot | Error | BindNodeSignalDiagnostics
GF_Godot_BindNodeSignal_003 | GFramework.Godot | Error | BindNodeSignalDiagnostics
GF_Godot_BindNodeSignal_004 | GFramework.Godot | Error | BindNodeSignalDiagnostics
GF_Godot_BindNodeSignal_005 | GFramework.Godot | Error | BindNodeSignalDiagnostics
GF_Godot_BindNodeSignal_006 | GFramework.Godot | Error | BindNodeSignalDiagnostics
GF_Godot_BindNodeSignal_007 | GFramework.Godot | Error | BindNodeSignalDiagnostics
GF_Godot_BindNodeSignal_008 | GFramework.Godot | Warning | BindNodeSignalDiagnostics
GF_Godot_BindNodeSignal_009 | GFramework.Godot | Warning | BindNodeSignalDiagnostics
GF_Godot_BindNodeSignal_010 | GFramework.Godot | Error | BindNodeSignalDiagnostics
Loading
Loading