GFramework/GFramework.SourceGenerators/rule/ContextAwareGenerator.cs
GwWuYou 02e2e31e95 feat(core): 添加上下文感知扩展方法并完善架构上下文接口
- 新增 ContextAwareExtensions 扩展类,提供便捷的上下文访问方法
- 为 IContextAware 接口添加 GetContext 方法以获取架构上下文
- 更新 ContextAwareBase 基类实现 GetContext 方法
- 改进源代码生成器的 Generate 方法参数结构
- 重构 ContextAwareGenerator 生成器实现接口方法自动实现
- 更新单元测试以验证新生成的上下文感知代码正确性
2025-12-29 20:06:25 +08:00

187 lines
5.9 KiB
C#

using System.Linq;
using System.Text;
using GFramework.SourceGenerators.Common.constants;
using GFramework.SourceGenerators.Common.generator;
using GFramework.SourceGenerators.diagnostics;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
namespace GFramework.SourceGenerators.rule;
[Generator]
public sealed class ContextAwareGenerator : MetadataAttributeClassGeneratorBase
{
protected override string AttributeMetadataName =>
$"{PathContests.SourceGeneratorsAbstractionsPath}.rule.ContextAwareAttribute";
protected override string AttributeShortNameWithoutSuffix => "ContextAware";
protected override bool ValidateSymbol(
SourceProductionContext context,
Compilation compilation,
ClassDeclarationSyntax syntax,
INamedTypeSymbol symbol,
AttributeData attr)
{
var iContextAware = compilation.GetTypeByMetadataName(
$"{PathContests.CoreAbstractionsNamespace}.rule.IContextAware");
if (iContextAware is null)
{
context.ReportDiagnostic(Diagnostic.Create(
ContextAwareDiagnostic.ClassMustImplementIContextAware,
syntax.Identifier.GetLocation(),
symbol.Name));
return false;
}
if (!symbol.AllInterfaces.Any(i =>
SymbolEqualityComparer.Default.Equals(i, iContextAware)))
{
context.ReportDiagnostic(Diagnostic.Create(
ContextAwareDiagnostic.ClassMustImplementIContextAware,
syntax.Identifier.GetLocation(),
symbol.Name));
return false;
}
return true;
}
/// <summary>
/// 生成源代码
/// </summary>
/// <param name="context">源生产上下文</param>
/// <param name="compilation">编译对象</param>
/// <param name="symbol">命名类型符号</param>
/// <param name="attr">属性数据</param>
/// <returns>生成的源代码字符串</returns>
protected override string Generate(
SourceProductionContext context,
Compilation compilation,
INamedTypeSymbol symbol,
AttributeData attr)
{
var ns = symbol.ContainingNamespace.IsGlobalNamespace
? null
: symbol.ContainingNamespace.ToDisplayString();
var iContextAware = compilation.GetTypeByMetadataName(
$"{PathContests.CoreAbstractionsNamespace}.rule.IContextAware");
var sb = new StringBuilder();
sb.AppendLine("// <auto-generated/>");
sb.AppendLine("#nullable enable");
sb.AppendLine();
if (ns is not null)
{
sb.AppendLine($"namespace {ns};");
sb.AppendLine();
}
sb.AppendLine($"partial class {symbol.Name}");
sb.AppendLine("{");
GenerateContextProperty(sb);
GenerateInterfaceImplementations(sb, iContextAware!);
sb.AppendLine("}");
return sb.ToString().TrimEnd();
}
protected override string GetHintName(INamedTypeSymbol symbol)
=> $"{symbol.Name}.ContextAware.g.cs";
// =========================
// 生成 Context 属性
// =========================
private static void GenerateContextProperty(StringBuilder sb)
{
sb.AppendLine(" /// <summary>");
sb.AppendLine(" /// 自动注入的架构上下文");
sb.AppendLine(" /// </summary>");
sb.AppendLine(
$" protected {PathContests.CoreAbstractionsNamespace}.architecture.IArchitectureContext Context {{ get; private set; }} = null!;");
sb.AppendLine();
}
// =========================
// 自动实现接口方法
// =========================
private static void GenerateInterfaceImplementations(
StringBuilder sb,
INamedTypeSymbol interfaceSymbol)
{
var interfaceFullName = interfaceSymbol.ToDisplayString(
SymbolDisplayFormat.FullyQualifiedFormat);
foreach (var member in interfaceSymbol.GetMembers().OfType<IMethodSymbol>())
{
if (member.MethodKind != MethodKind.Ordinary)
continue;
GenerateMethod(sb, interfaceFullName, member);
sb.AppendLine();
}
}
private static void GenerateMethod(
StringBuilder sb,
string interfaceFullName,
IMethodSymbol method)
{
var returnType = method.ReturnType.ToDisplayString(
SymbolDisplayFormat.FullyQualifiedFormat);
var parameters = string.Join(", ",
method.Parameters.Select(p =>
$"{p.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)} {p.Name}"));
sb.AppendLine(
$" {returnType} {interfaceFullName}.{method.Name}({parameters})");
sb.AppendLine(" {");
GenerateMethodBody(sb, method);
sb.AppendLine(" }");
}
// =========================
// 方法语义策略
// =========================
private static void GenerateMethodBody(
StringBuilder sb,
IMethodSymbol method)
{
switch (method.Name)
{
case "SetContext":
sb.AppendLine(" Context = context;");
break;
case "GetContext":
sb.AppendLine(" return Context;");
break;
default:
GenerateFallbackBody(sb, method);
break;
}
}
private static void GenerateFallbackBody(
StringBuilder sb,
IMethodSymbol method)
{
if (method.ReturnsVoid)
{
sb.AppendLine(" // no-op");
}
else
{
sb.AppendLine(
$" throw new System.NotImplementedException(");
sb.AppendLine(
$" \"Method '{method.Name}' is not supported by ContextAwareGenerator.\");");
}
}
}