GeWuYou fb14d7122c docs(style): 更新文档中的命名空间导入格式
- 将所有小写的命名空间导入更正为首字母大写格式
- 统一 GFramework 框架的命名空间引用规范
- 修复 core、ecs、godot 等模块的命名空间导入错误
- 标准化文档示例代码中的 using 语句格式
- 确保所有文档中的命名空间引用保持一致性
- 更新 global using 语句以匹配正确的命名空间格式
2026-03-10 07:18:49 +08:00

153 lines
5.0 KiB
C#

using System.Text;
using GFramework.SourceGenerators.Common.Constants;
using GFramework.SourceGenerators.Common.Generator;
using GFramework.SourceGenerators.Diagnostics;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
namespace GFramework.SourceGenerators.Bases;
/// <summary>
/// Priority 特性生成器,为标记了 [Priority] 的类自动生成 IPrioritized 接口实现
/// </summary>
[Generator]
public sealed class PriorityGenerator : MetadataAttributeClassGeneratorBase
{
/// <summary>
/// 获取特性的元数据名称
/// </summary>
protected override string AttributeMetadataName =>
$"{PathContests.SourceGeneratorsAbstractionsPath}.Bases.PriorityAttribute";
/// <summary>
/// 获取特性的短名称(不包含后缀)
/// </summary>
protected override string AttributeShortNameWithoutSuffix => "Priority";
/// <summary>
/// 验证符号是否符合生成条件
/// </summary>
protected override bool ValidateSymbol(
SourceProductionContext context,
Compilation compilation,
ClassDeclarationSyntax syntax,
INamedTypeSymbol symbol,
AttributeData attr)
{
// 1. 必须是 class
if (symbol.TypeKind != TypeKind.Class)
{
context.ReportDiagnostic(Diagnostic.Create(
PriorityDiagnostic.OnlyApplyToClass,
syntax.Identifier.GetLocation(),
symbol.ToDisplayString()));
return false;
}
// 2. 不支持嵌套类
if (symbol.ContainingType != null)
{
context.ReportDiagnostic(Diagnostic.Create(
PriorityDiagnostic.NestedClassNotSupported,
syntax.Identifier.GetLocation(),
symbol.Name));
return false;
}
// 3. 必须是 partial
if (syntax.Modifiers.All(m => m.Kind() != SyntaxKind.PartialKeyword))
{
context.ReportDiagnostic(Diagnostic.Create(
PriorityDiagnostic.MustBePartial,
syntax.Identifier.GetLocation(),
symbol.Name));
return false;
}
// 4. 检查是否已手动实现 IPrioritized
var iPrioritized = compilation.GetTypeByMetadataName(
$"{PathContests.CoreAbstractionsNamespace}.Bases.IPrioritized");
if (iPrioritized != null && symbol.AllInterfaces.Contains(iPrioritized, SymbolEqualityComparer.Default))
{
context.ReportDiagnostic(Diagnostic.Create(
PriorityDiagnostic.AlreadyImplemented,
syntax.Identifier.GetLocation(),
symbol.Name));
return false;
}
// 5. 验证特性参数
if (attr.ConstructorArguments.Length == 0 ||
attr.ConstructorArguments[0].Value is not int)
{
context.ReportDiagnostic(Diagnostic.Create(
PriorityDiagnostic.InvalidValue,
syntax.Identifier.GetLocation()));
return false;
}
return true;
}
/// <summary>
/// 生成源代码
/// </summary>
protected override string Generate(
SourceProductionContext context,
Compilation compilation,
INamedTypeSymbol symbol,
AttributeData attr)
{
var ns = symbol.ContainingNamespace.IsGlobalNamespace
? null
: symbol.ContainingNamespace.ToDisplayString();
var priorityValue = (int)attr.ConstructorArguments[0].Value!;
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();
}
// 生成泛型参数(如果有)
var typeParameters = symbol.TypeParameters.Length > 0
? $"<{string.Join(", ", symbol.TypeParameters.Select(tp => tp.Name))}>"
: string.Empty;
sb.AppendLine(
$"partial class {symbol.Name}{typeParameters} : global::GFramework.Core.Abstractions.Bases.IPrioritized");
sb.AppendLine("{");
sb.AppendLine(" /// <summary>");
sb.AppendLine($" /// 获取优先级值: {priorityValue}");
sb.AppendLine(" /// </summary>");
sb.AppendLine($" public int Priority => {priorityValue};");
sb.AppendLine("}");
return sb.ToString().TrimEnd();
}
/// <summary>
/// 获取生成文件的提示名称
/// </summary>
protected override string GetHintName(INamedTypeSymbol symbol)
{
// 使用完整的元数据名称以避免冲突
var metadataName = symbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)
.Replace("global::", "")
.Replace("<", "_")
.Replace(">", "_")
.Replace(",", "_")
.Replace(" ", "")
.Replace(".", "_");
return $"{metadataName}.Priority.g.cs";
}
}