From da34b2fa2abd777022db59174abbdbbab915680f Mon Sep 17 00:00:00 2001
From: GeWuYou <95328647+GeWuYou@users.noreply.github.com>
Date: Mon, 30 Mar 2026 09:13:45 +0800
Subject: [PATCH] =?UTF-8?q?feat(generator):=20=E6=B7=BB=E5=8A=A0=E5=AF=B9?=
=?UTF-8?q?=20const=20=E5=AD=97=E6=AE=B5=E7=9A=84=E6=98=BE=E5=BC=8F?=
=?UTF-8?q?=E8=B7=B3=E8=BF=87=E6=94=AF=E6=8C=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 在 ContextGetGenerator 中添加对 const 字段的显式检查和跳过逻辑
- 更新文档说明 const、static 和 readonly 字段的处理方式
- 重构测试代码使用 MarkupTestSource 解析器进行更精确的诊断测试
- 添加新的 MarkupTestSource 类用于源码标记解析和诊断定位
---
.../Core/MarkupTestSource.cs | 120 ++++
.../Rule/ContextGetGeneratorTests.cs | 556 +++++++++---------
GFramework.SourceGenerators/README.md | 2 +-
.../Rule/ContextGetGenerator.cs | 7 +-
4 files changed, 407 insertions(+), 278 deletions(-)
create mode 100644 GFramework.SourceGenerators.Tests/Core/MarkupTestSource.cs
diff --git a/GFramework.SourceGenerators.Tests/Core/MarkupTestSource.cs b/GFramework.SourceGenerators.Tests/Core/MarkupTestSource.cs
new file mode 100644
index 0000000..8e97991
--- /dev/null
+++ b/GFramework.SourceGenerators.Tests/Core/MarkupTestSource.cs
@@ -0,0 +1,120 @@
+using System.Text;
+
+namespace GFramework.SourceGenerators.Tests.Core;
+
+///
+/// 为源生成器测试提供轻量的源码标记解析能力。
+///
+public sealed class MarkupTestSource
+{
+ private readonly SourceText _sourceText;
+ private readonly IReadOnlyDictionary _spans;
+
+ private MarkupTestSource(
+ string source,
+ SourceText sourceText,
+ IReadOnlyDictionary spans)
+ {
+ Source = source;
+ _sourceText = sourceText;
+ _spans = spans;
+ }
+
+ ///
+ /// 获取移除标记后的源码文本。
+ ///
+ public string Source { get; }
+
+ ///
+ /// 解析形如 {|#0:identifier|} 的单层标记,并保留去标记后的源码。
+ ///
+ /// 包含测试标记的源码。
+ /// 可用于测试输入和诊断定位的解析结果。
+ /// 标记格式不合法,或存在重复标记编号时抛出。
+ public static MarkupTestSource Parse(string markupSource)
+ {
+ var builder = new StringBuilder(markupSource.Length);
+ var spans = new Dictionary(StringComparer.Ordinal);
+
+ for (var index = 0; index < markupSource.Length; index++)
+ {
+ if (!StartsWithMarker(markupSource, index))
+ {
+ builder.Append(markupSource[index]);
+ continue;
+ }
+
+ index += 3;
+ var markerIdStart = index;
+ while (index < markupSource.Length && markupSource[index] != ':')
+ index++;
+
+ if (index >= markupSource.Length)
+ throw new InvalidOperationException("Unterminated markup marker identifier.");
+
+ var markerId = markupSource.Substring(markerIdStart, index - markerIdStart);
+ if (markerId.Length == 0)
+ throw new InvalidOperationException("Markup marker identifier cannot be empty.");
+
+ var spanStart = builder.Length;
+ index++;
+
+ while (index < markupSource.Length && !EndsWithMarker(markupSource, index))
+ {
+ builder.Append(markupSource[index]);
+ index++;
+ }
+
+ if (index >= markupSource.Length)
+ throw new InvalidOperationException($"Unterminated markup marker '{markerId}'.");
+
+ if (!spans.TryAdd(markerId, TextSpan.FromBounds(spanStart, builder.Length)))
+ throw new InvalidOperationException($"Duplicate markup marker '{markerId}'.");
+
+ index++;
+ }
+
+ var source = builder.ToString();
+ return new MarkupTestSource(source, SourceText.From(source), spans);
+ }
+
+ ///
+ /// 将标记位置应用到诊断断言,避免测试依赖硬编码行列号。
+ ///
+ /// 要补全定位信息的诊断断言。
+ /// 标记编号。
+ /// 包含定位信息的诊断断言。
+ /// 指定标记不存在时抛出。
+ public DiagnosticResult WithSpan(
+ DiagnosticResult diagnosticResult,
+ string markerId)
+ {
+ var span = _spans[markerId];
+ var lineSpan = _sourceText.Lines.GetLinePositionSpan(span);
+
+ return diagnosticResult.WithSpan(
+ lineSpan.Start.Line + 1,
+ lineSpan.Start.Character + 1,
+ lineSpan.End.Line + 1,
+ lineSpan.End.Character + 1);
+ }
+
+ private static bool StartsWithMarker(
+ string text,
+ int index)
+ {
+ return index + 3 < text.Length &&
+ text[index] == '{' &&
+ text[index + 1] == '|' &&
+ text[index + 2] == '#';
+ }
+
+ private static bool EndsWithMarker(
+ string text,
+ int index)
+ {
+ return index + 1 < text.Length &&
+ text[index] == '|' &&
+ text[index + 1] == '}';
+ }
+}
\ No newline at end of file
diff --git a/GFramework.SourceGenerators.Tests/Rule/ContextGetGeneratorTests.cs b/GFramework.SourceGenerators.Tests/Rule/ContextGetGeneratorTests.cs
index 30d165a..1bea458 100644
--- a/GFramework.SourceGenerators.Tests/Rule/ContextGetGeneratorTests.cs
+++ b/GFramework.SourceGenerators.Tests/Rule/ContextGetGeneratorTests.cs
@@ -463,63 +463,63 @@ public class ContextGetGeneratorTests
[Test]
public async Task Warns_And_Skips_Readonly_Inferred_Field_For_GetAll_Class()
{
- var source = """
- using System;
- using GFramework.SourceGenerators.Abstractions.Rule;
+ var source = MarkupTestSource.Parse("""
+ using System;
+ using GFramework.SourceGenerators.Abstractions.Rule;
- namespace GFramework.SourceGenerators.Abstractions.Rule
- {
- [AttributeUsage(AttributeTargets.Class, Inherited = false)]
- public sealed class GetAllAttribute : Attribute { }
- }
+ namespace GFramework.SourceGenerators.Abstractions.Rule
+ {
+ [AttributeUsage(AttributeTargets.Class, Inherited = false)]
+ public sealed class GetAllAttribute : Attribute { }
+ }
- namespace GFramework.Core.Abstractions.Rule
- {
- public interface IContextAware { }
- }
+ namespace GFramework.Core.Abstractions.Rule
+ {
+ public interface IContextAware { }
+ }
- namespace GFramework.Core.Rule
- {
- public abstract class ContextAwareBase : GFramework.Core.Abstractions.Rule.IContextAware { }
- }
+ namespace GFramework.Core.Rule
+ {
+ public abstract class ContextAwareBase : GFramework.Core.Abstractions.Rule.IContextAware { }
+ }
- namespace GFramework.Core.Abstractions.Model
- {
- public interface IModel { }
- }
+ namespace GFramework.Core.Abstractions.Model
+ {
+ public interface IModel { }
+ }
- namespace GFramework.Core.Abstractions.Systems
- {
- public interface ISystem { }
- }
+ namespace GFramework.Core.Abstractions.Systems
+ {
+ public interface ISystem { }
+ }
- namespace GFramework.Core.Abstractions.Utility
- {
- public interface IUtility { }
- }
+ namespace GFramework.Core.Abstractions.Utility
+ {
+ public interface IUtility { }
+ }
- namespace GFramework.Core.Extensions
- {
- public static class ContextAwareServiceExtensions
- {
- public static T GetModel(this object contextAware) => default!;
- public static T GetSystem(this object contextAware) => default!;
- }
- }
+ namespace GFramework.Core.Extensions
+ {
+ public static class ContextAwareServiceExtensions
+ {
+ public static T GetModel(this object contextAware) => default!;
+ public static T GetSystem(this object contextAware) => default!;
+ }
+ }
- namespace TestApp
- {
- public interface IInventoryModel : GFramework.Core.Abstractions.Model.IModel { }
- public interface ICombatSystem : GFramework.Core.Abstractions.Systems.ISystem { }
+ namespace TestApp
+ {
+ public interface IInventoryModel : GFramework.Core.Abstractions.Model.IModel { }
+ public interface ICombatSystem : GFramework.Core.Abstractions.Systems.ISystem { }
- [GetAll]
- public partial class BattlePanel : GFramework.Core.Rule.ContextAwareBase
- {
- private readonly IInventoryModel _model = null!;
- private ICombatSystem _system = null!;
- }
- }
- """;
+ [GetAll]
+ public partial class BattlePanel : GFramework.Core.Rule.ContextAwareBase
+ {
+ private readonly IInventoryModel {|#0:_model|} = null!;
+ private ICombatSystem _system = null!;
+ }
+ }
+ """);
const string expected = """
//
@@ -543,7 +543,7 @@ public class ContextGetGeneratorTests
{
TestState =
{
- Sources = { source },
+ Sources = { source.Source },
GeneratedSources =
{
(typeof(ContextGetGenerator), "TestApp_BattlePanel.ContextGet.g.cs", expected)
@@ -552,8 +552,9 @@ public class ContextGetGeneratorTests
DisabledDiagnostics = { "GF_Common_Trace_001" }
};
- test.ExpectedDiagnostics.Add(new DiagnosticResult("GF_ContextGet_008", DiagnosticSeverity.Warning)
- .WithSpan(52, 42, 52, 48)
+ test.ExpectedDiagnostics.Add(source.WithSpan(
+ new DiagnosticResult("GF_ContextGet_008", DiagnosticSeverity.Warning),
+ "0")
.WithArguments("_model"));
await test.RunAsync();
@@ -563,63 +564,63 @@ public class ContextGetGeneratorTests
[Test]
public async Task Warns_And_Skips_Static_Inferred_Field_For_GetAll_Class()
{
- var source = """
- using System;
- using GFramework.SourceGenerators.Abstractions.Rule;
+ var source = MarkupTestSource.Parse("""
+ using System;
+ using GFramework.SourceGenerators.Abstractions.Rule;
- namespace GFramework.SourceGenerators.Abstractions.Rule
- {
- [AttributeUsage(AttributeTargets.Class, Inherited = false)]
- public sealed class GetAllAttribute : Attribute { }
- }
+ namespace GFramework.SourceGenerators.Abstractions.Rule
+ {
+ [AttributeUsage(AttributeTargets.Class, Inherited = false)]
+ public sealed class GetAllAttribute : Attribute { }
+ }
- namespace GFramework.Core.Abstractions.Rule
- {
- public interface IContextAware { }
- }
+ namespace GFramework.Core.Abstractions.Rule
+ {
+ public interface IContextAware { }
+ }
- namespace GFramework.Core.Rule
- {
- public abstract class ContextAwareBase : GFramework.Core.Abstractions.Rule.IContextAware { }
- }
+ namespace GFramework.Core.Rule
+ {
+ public abstract class ContextAwareBase : GFramework.Core.Abstractions.Rule.IContextAware { }
+ }
- namespace GFramework.Core.Abstractions.Model
- {
- public interface IModel { }
- }
+ namespace GFramework.Core.Abstractions.Model
+ {
+ public interface IModel { }
+ }
- namespace GFramework.Core.Abstractions.Systems
- {
- public interface ISystem { }
- }
+ namespace GFramework.Core.Abstractions.Systems
+ {
+ public interface ISystem { }
+ }
- namespace GFramework.Core.Abstractions.Utility
- {
- public interface IUtility { }
- }
+ namespace GFramework.Core.Abstractions.Utility
+ {
+ public interface IUtility { }
+ }
- namespace GFramework.Core.Extensions
- {
- public static class ContextAwareServiceExtensions
- {
- public static T GetModel(this object contextAware) => default!;
- public static T GetSystem(this object contextAware) => default!;
- }
- }
+ namespace GFramework.Core.Extensions
+ {
+ public static class ContextAwareServiceExtensions
+ {
+ public static T GetModel(this object contextAware) => default!;
+ public static T GetSystem(this object contextAware) => default!;
+ }
+ }
- namespace TestApp
- {
- public interface IInventoryModel : GFramework.Core.Abstractions.Model.IModel { }
- public interface ICombatSystem : GFramework.Core.Abstractions.Systems.ISystem { }
+ namespace TestApp
+ {
+ public interface IInventoryModel : GFramework.Core.Abstractions.Model.IModel { }
+ public interface ICombatSystem : GFramework.Core.Abstractions.Systems.ISystem { }
- [GetAll]
- public partial class BattlePanel : GFramework.Core.Rule.ContextAwareBase
- {
- private static IInventoryModel _model = null!;
- private ICombatSystem _system = null!;
- }
- }
- """;
+ [GetAll]
+ public partial class BattlePanel : GFramework.Core.Rule.ContextAwareBase
+ {
+ private static IInventoryModel {|#0:_model|} = null!;
+ private ICombatSystem _system = null!;
+ }
+ }
+ """);
const string expected = """
//
@@ -643,7 +644,7 @@ public class ContextGetGeneratorTests
{
TestState =
{
- Sources = { source },
+ Sources = { source.Source },
GeneratedSources =
{
(typeof(ContextGetGenerator), "TestApp_BattlePanel.ContextGet.g.cs", expected)
@@ -652,8 +653,9 @@ public class ContextGetGeneratorTests
DisabledDiagnostics = { "GF_Common_Trace_001" }
};
- test.ExpectedDiagnostics.Add(new DiagnosticResult("GF_ContextGet_007", DiagnosticSeverity.Warning)
- .WithSpan(52, 40, 52, 46)
+ test.ExpectedDiagnostics.Add(source.WithSpan(
+ new DiagnosticResult("GF_ContextGet_007", DiagnosticSeverity.Warning),
+ "0")
.WithArguments("_model"));
await test.RunAsync();
@@ -832,62 +834,63 @@ public class ContextGetGeneratorTests
[Test]
public async Task Reports_Diagnostic_When_Class_Is_Not_ContextAware()
{
- var source = """
- using System;
- using GFramework.SourceGenerators.Abstractions.Rule;
+ var source = MarkupTestSource.Parse("""
+ using System;
+ using GFramework.SourceGenerators.Abstractions.Rule;
- namespace GFramework.SourceGenerators.Abstractions.Rule
- {
- [AttributeUsage(AttributeTargets.Field, Inherited = false)]
- public sealed class GetModelAttribute : Attribute { }
- }
+ namespace GFramework.SourceGenerators.Abstractions.Rule
+ {
+ [AttributeUsage(AttributeTargets.Field, Inherited = false)]
+ public sealed class GetModelAttribute : Attribute { }
+ }
- namespace GFramework.Core.Abstractions.Model
- {
- public interface IModel { }
- }
+ namespace GFramework.Core.Abstractions.Model
+ {
+ public interface IModel { }
+ }
- namespace GFramework.Core.Abstractions.Systems
- {
- public interface ISystem { }
- }
+ namespace GFramework.Core.Abstractions.Systems
+ {
+ public interface ISystem { }
+ }
- namespace GFramework.Core.Abstractions.Utility
- {
- public interface IUtility { }
- }
+ namespace GFramework.Core.Abstractions.Utility
+ {
+ public interface IUtility { }
+ }
- namespace GFramework.Core.Extensions
- {
- public static class ContextAwareServiceExtensions
- {
- public static T GetModel(this object contextAware) => default!;
- }
- }
+ namespace GFramework.Core.Extensions
+ {
+ public static class ContextAwareServiceExtensions
+ {
+ public static T GetModel(this object contextAware) => default!;
+ }
+ }
- namespace TestApp
- {
- public interface IInventoryModel : GFramework.Core.Abstractions.Model.IModel { }
+ namespace TestApp
+ {
+ public interface IInventoryModel : GFramework.Core.Abstractions.Model.IModel { }
- public partial class InventoryPanel
- {
- [GetModel]
- private IInventoryModel _model = null!;
- }
- }
- """;
+ public partial class InventoryPanel
+ {
+ [GetModel]
+ private IInventoryModel {|#0:_model|} = null!;
+ }
+ }
+ """);
var test = new CSharpSourceGeneratorTest
{
TestState =
{
- Sources = { source }
+ Sources = { source.Source }
},
DisabledDiagnostics = { "GF_Common_Trace_001" }
};
- test.ExpectedDiagnostics.Add(new DiagnosticResult("GF_ContextGet_005", DiagnosticSeverity.Error)
- .WithSpan(40, 33, 40, 39)
+ test.ExpectedDiagnostics.Add(source.WithSpan(
+ new DiagnosticResult("GF_ContextGet_005", DiagnosticSeverity.Error),
+ "0")
.WithArguments("InventoryPanel"));
await test.RunAsync();
@@ -897,68 +900,69 @@ public class ContextGetGeneratorTests
[Test]
public async Task Reports_Diagnostic_When_GetModels_Field_Is_Not_IReadOnlyList()
{
- var source = """
- using System;
- using System.Collections.Generic;
- using GFramework.SourceGenerators.Abstractions.Rule;
+ var source = MarkupTestSource.Parse("""
+ using System;
+ using System.Collections.Generic;
+ using GFramework.SourceGenerators.Abstractions.Rule;
- namespace GFramework.SourceGenerators.Abstractions.Rule
- {
- [AttributeUsage(AttributeTargets.Field, Inherited = false)]
- public sealed class GetModelsAttribute : Attribute { }
- }
+ namespace GFramework.SourceGenerators.Abstractions.Rule
+ {
+ [AttributeUsage(AttributeTargets.Field, Inherited = false)]
+ public sealed class GetModelsAttribute : Attribute { }
+ }
- namespace GFramework.Core.Abstractions.Rule
- {
- public interface IContextAware { }
- }
+ namespace GFramework.Core.Abstractions.Rule
+ {
+ public interface IContextAware { }
+ }
- namespace GFramework.Core.Abstractions.Model
- {
- public interface IModel { }
- }
+ namespace GFramework.Core.Abstractions.Model
+ {
+ public interface IModel { }
+ }
- namespace GFramework.Core.Abstractions.Systems
- {
- public interface ISystem { }
- }
+ namespace GFramework.Core.Abstractions.Systems
+ {
+ public interface ISystem { }
+ }
- namespace GFramework.Core.Abstractions.Utility
- {
- public interface IUtility { }
- }
+ namespace GFramework.Core.Abstractions.Utility
+ {
+ public interface IUtility { }
+ }
- namespace GFramework.Core.Extensions
- {
- public static class ContextAwareServiceExtensions
- {
- public static IReadOnlyList GetModels(this object contextAware) => default!;
- }
- }
+ namespace GFramework.Core.Extensions
+ {
+ public static class ContextAwareServiceExtensions
+ {
+ public static IReadOnlyList GetModels(this object contextAware) => default!;
+ }
+ }
- namespace TestApp
- {
- public interface IInventoryModel : GFramework.Core.Abstractions.Model.IModel { }
+ namespace TestApp
+ {
+ public interface IInventoryModel : GFramework.Core.Abstractions.Model.IModel { }
- public partial class InventoryPanel : GFramework.Core.Abstractions.Rule.IContextAware
- {
- [GetModels]
- private List _models = new();
- }
- }
- """;
+ public partial class InventoryPanel : GFramework.Core.Abstractions.Rule.IContextAware
+ {
+ [GetModels]
+ private List {|#0:_models|} = new();
+ }
+ }
+ """);
var test = new CSharpSourceGeneratorTest
{
TestState =
{
- Sources = { source }
+ Sources = { source.Source }
},
DisabledDiagnostics = { "GF_Common_Trace_001" }
};
- test.ExpectedDiagnostics.Add(new DiagnosticResult("GF_ContextGet_004", DiagnosticSeverity.Error)
- .WithSpan(46, 39, 46, 46)
+ test.ExpectedDiagnostics.Add(source.WithSpan(
+ new DiagnosticResult("GF_ContextGet_004", DiagnosticSeverity.Error),
+ "0")
.WithArguments("_models", "System.Collections.Generic.List", "GetModels"));
await test.RunAsync();
@@ -968,67 +972,68 @@ public class ContextGetGeneratorTests
[Test]
public async Task Reports_Diagnostic_For_Readonly_Explicit_GetModel_Field()
{
- var source = """
- using System;
- using GFramework.SourceGenerators.Abstractions.Rule;
+ var source = MarkupTestSource.Parse("""
+ using System;
+ using GFramework.SourceGenerators.Abstractions.Rule;
- namespace GFramework.SourceGenerators.Abstractions.Rule
- {
- [AttributeUsage(AttributeTargets.Field, Inherited = false)]
- public sealed class GetModelAttribute : Attribute { }
- }
+ namespace GFramework.SourceGenerators.Abstractions.Rule
+ {
+ [AttributeUsage(AttributeTargets.Field, Inherited = false)]
+ public sealed class GetModelAttribute : Attribute { }
+ }
- namespace GFramework.Core.Abstractions.Rule
- {
- public interface IContextAware { }
- }
+ namespace GFramework.Core.Abstractions.Rule
+ {
+ public interface IContextAware { }
+ }
- namespace GFramework.Core.Abstractions.Model
- {
- public interface IModel { }
- }
+ namespace GFramework.Core.Abstractions.Model
+ {
+ public interface IModel { }
+ }
- namespace GFramework.Core.Abstractions.Systems
- {
- public interface ISystem { }
- }
+ namespace GFramework.Core.Abstractions.Systems
+ {
+ public interface ISystem { }
+ }
- namespace GFramework.Core.Abstractions.Utility
- {
- public interface IUtility { }
- }
+ namespace GFramework.Core.Abstractions.Utility
+ {
+ public interface IUtility { }
+ }
- namespace GFramework.Core.Extensions
- {
- public static class ContextAwareServiceExtensions
- {
- public static T GetModel(this object contextAware) => default!;
- }
- }
+ namespace GFramework.Core.Extensions
+ {
+ public static class ContextAwareServiceExtensions
+ {
+ public static T GetModel(this object contextAware) => default!;
+ }
+ }
- namespace TestApp
- {
- public interface IInventoryModel : GFramework.Core.Abstractions.Model.IModel { }
+ namespace TestApp
+ {
+ public interface IInventoryModel : GFramework.Core.Abstractions.Model.IModel { }
- public partial class InventoryPanel : GFramework.Core.Abstractions.Rule.IContextAware
- {
- [GetModel]
- private readonly IInventoryModel _model = null!;
- }
- }
- """;
+ public partial class InventoryPanel : GFramework.Core.Abstractions.Rule.IContextAware
+ {
+ [GetModel]
+ private readonly IInventoryModel {|#0:_model|} = null!;
+ }
+ }
+ """);
var test = new CSharpSourceGeneratorTest
{
TestState =
{
- Sources = { source }
+ Sources = { source.Source }
},
DisabledDiagnostics = { "GF_Common_Trace_001" }
};
- test.ExpectedDiagnostics.Add(new DiagnosticResult("GF_ContextGet_003", DiagnosticSeverity.Error)
- .WithSpan(45, 42, 45, 48)
+ test.ExpectedDiagnostics.Add(source.WithSpan(
+ new DiagnosticResult("GF_ContextGet_003", DiagnosticSeverity.Error),
+ "0")
.WithArguments("_model"));
await test.RunAsync();
@@ -1038,67 +1043,68 @@ public class ContextGetGeneratorTests
[Test]
public async Task Reports_Diagnostic_For_Static_Explicit_GetModel_Field()
{
- var source = """
- using System;
- using GFramework.SourceGenerators.Abstractions.Rule;
+ var source = MarkupTestSource.Parse("""
+ using System;
+ using GFramework.SourceGenerators.Abstractions.Rule;
- namespace GFramework.SourceGenerators.Abstractions.Rule
- {
- [AttributeUsage(AttributeTargets.Field, Inherited = false)]
- public sealed class GetModelAttribute : Attribute { }
- }
+ namespace GFramework.SourceGenerators.Abstractions.Rule
+ {
+ [AttributeUsage(AttributeTargets.Field, Inherited = false)]
+ public sealed class GetModelAttribute : Attribute { }
+ }
- namespace GFramework.Core.Abstractions.Rule
- {
- public interface IContextAware { }
- }
+ namespace GFramework.Core.Abstractions.Rule
+ {
+ public interface IContextAware { }
+ }
- namespace GFramework.Core.Abstractions.Model
- {
- public interface IModel { }
- }
+ namespace GFramework.Core.Abstractions.Model
+ {
+ public interface IModel { }
+ }
- namespace GFramework.Core.Abstractions.Systems
- {
- public interface ISystem { }
- }
+ namespace GFramework.Core.Abstractions.Systems
+ {
+ public interface ISystem { }
+ }
- namespace GFramework.Core.Abstractions.Utility
- {
- public interface IUtility { }
- }
+ namespace GFramework.Core.Abstractions.Utility
+ {
+ public interface IUtility { }
+ }
- namespace GFramework.Core.Extensions
- {
- public static class ContextAwareServiceExtensions
- {
- public static T GetModel(this object contextAware) => default!;
- }
- }
+ namespace GFramework.Core.Extensions
+ {
+ public static class ContextAwareServiceExtensions
+ {
+ public static T GetModel(this object contextAware) => default!;
+ }
+ }
- namespace TestApp
- {
- public interface IInventoryModel : GFramework.Core.Abstractions.Model.IModel { }
+ namespace TestApp
+ {
+ public interface IInventoryModel : GFramework.Core.Abstractions.Model.IModel { }
- public partial class InventoryPanel : GFramework.Core.Abstractions.Rule.IContextAware
- {
- [GetModel]
- private static IInventoryModel _model = null!;
- }
- }
- """;
+ public partial class InventoryPanel : GFramework.Core.Abstractions.Rule.IContextAware
+ {
+ [GetModel]
+ private static IInventoryModel {|#0:_model|} = null!;
+ }
+ }
+ """);
var test = new CSharpSourceGeneratorTest
{
TestState =
{
- Sources = { source }
+ Sources = { source.Source }
},
DisabledDiagnostics = { "GF_Common_Trace_001" }
};
- test.ExpectedDiagnostics.Add(new DiagnosticResult("GF_ContextGet_002", DiagnosticSeverity.Error)
- .WithSpan(45, 40, 45, 46)
+ test.ExpectedDiagnostics.Add(source.WithSpan(
+ new DiagnosticResult("GF_ContextGet_002", DiagnosticSeverity.Error),
+ "0")
.WithArguments("_model"));
await test.RunAsync();
diff --git a/GFramework.SourceGenerators/README.md b/GFramework.SourceGenerators/README.md
index 6578ddb..7ed6db8 100644
--- a/GFramework.SourceGenerators/README.md
+++ b/GFramework.SourceGenerators/README.md
@@ -49,4 +49,4 @@ public partial class InventoryPanel
`[GetServices]`,避免将非上下文服务字段误判为服务依赖。
`[GetAll]` 会跳过 `const`、`static` 和 `readonly` 字段。若某个字段本来会被 `[GetAll]` 推断为
-`Model`、`System` 或 `Utility` 绑定,但因为字段不可赋值而被跳过,生成器会发出警告提示该字段不会参与生成。
+`Model`、`System` 或 `Utility` 绑定,但因为是不可赋值的 `static` 或 `readonly` 字段而被跳过,生成器会发出警告提示该字段不会参与生成。
diff --git a/GFramework.SourceGenerators/Rule/ContextGetGenerator.cs b/GFramework.SourceGenerators/Rule/ContextGetGenerator.cs
index 6d47253..83aaf0e 100644
--- a/GFramework.SourceGenerators/Rule/ContextGetGenerator.cs
+++ b/GFramework.SourceGenerators/Rule/ContextGetGenerator.cs
@@ -1,7 +1,5 @@
-using System.Text;
using GFramework.SourceGenerators.Common.Constants;
using GFramework.SourceGenerators.Common.Diagnostics;
-using GFramework.SourceGenerators.Common.Extensions;
using GFramework.SourceGenerators.Common.Info;
using GFramework.SourceGenerators.Diagnostics;
@@ -298,6 +296,11 @@ public sealed class ContextGetGenerator : IIncrementalGenerator
if (explicitFields.Contains(field))
continue;
+ // Const fields are compile-time constants, so [GetAll] should skip them explicitly instead of relying on
+ // type inference to fall through implicitly.
+ if (field.IsConst)
+ continue;
+
// Infer the target first so [GetAll] only warns for fields it would otherwise bind.
if (!TryCreateInferredBinding(field, symbols, out var binding))
continue;