框架更新

This commit is contained in:
Bob.Song
2025-10-29 17:59:43 +08:00
parent fc18c8626a
commit a2cb248512
429 changed files with 7173 additions and 38748 deletions

View File

@@ -0,0 +1,101 @@
using System.Linq;
using Microsoft.CodeAnalysis;
namespace Fantasy.SourceGenerator.Common
{
/// <summary>
/// 编译环境检测帮助类
/// 提供检测 Fantasy 框架、Unity 环境等公共方法
/// </summary>
public static class CompilationHelper
{
/// <summary>
/// 检查是否定义了 Fantasy 框架的预编译符号
/// 只有定义了 FANTASY_NET的项目才会生成代码
/// </summary>
public static bool HasFantasyNETDefine(Compilation compilation)
{
// 遍历所有语法树的预处理符号
foreach (var tree in compilation.SyntaxTrees)
{
var defines = tree.Options.PreprocessorSymbolNames;
if (defines.Contains("FANTASY_NET"))
{
return true;
}
}
return false;
}
/// <summary>
/// 检查是否定义了 Fantasy 框架的预编译符号
/// 只有定义了 FANTASY_UNITY的项目才会生成代码
/// </summary>
public static bool HasFantasyUNITYDefine(Compilation compilation)
{
// 遍历所有语法树的预处理符号
foreach (var tree in compilation.SyntaxTrees)
{
var defines = tree.Options.PreprocessorSymbolNames;
if (defines.Contains("FANTASY_UNITY"))
{
return true;
}
}
return false;
}
/// <summary>
/// 检查是否定义了 Fantasy 框架的预编译符号
/// 只有定义了 FANTASY_NET 或 FANTASY_UNITY 的项目才会生成代码
/// </summary>
public static bool HasFantasyDefine(Compilation compilation)
{
// 遍历所有语法树的预处理符号
foreach (var tree in compilation.SyntaxTrees)
{
var defines = tree.Options.PreprocessorSymbolNames;
if (defines.Contains("FANTASY_NET") || defines.Contains("FANTASY_UNITY"))
{
return true;
}
}
return false;
}
/// <summary>
/// 检测是否是 Unity 编译环境
/// 优先检查是否引用了 UnityEngine 核心程序集或类型,这是最可靠的方式
/// </summary>
public static bool IsUnityCompilation(Compilation compilation)
{
// 方法1: 检查是否引用了 UnityEngine.CoreModule 或 UnityEngine 程序集(最可靠)
foreach (var reference in compilation.References)
{
if (reference is PortableExecutableReference peRef)
{
var display = peRef.Display ?? "";
// Unity 2017+ 使用模块化程序集
if (display.Contains("UnityEngine.CoreModule.dll") ||
display.Contains("UnityEngine.dll"))
{
return true;
}
}
}
// 方法2: 检查是否能够找到 UnityEngine 命名空间的核心类型
var unityMonoBehaviour = compilation.GetTypeByMetadataName("UnityEngine.MonoBehaviour");
var unityGameObject = compilation.GetTypeByMetadataName("UnityEngine.GameObject");
if (unityMonoBehaviour != null || unityGameObject != null)
{
return true;
}
return false;
}
}
}

View File

@@ -0,0 +1,43 @@
namespace Fantasy.SourceGenerator.Common
{
/// <summary>
/// Source Generator 使用的常量定义
/// </summary>
internal static class GeneratorConstants
{
/// <summary>
/// 生成文件的命名空间
/// </summary>
public const string GeneratedNamespace = "Fantasy.Generated";
/// <summary>
/// 诊断 ID 前缀
/// </summary>
public const string DiagnosticIdPrefix = "FANTASY";
/// <summary>
/// 生成的代码文件注释头
/// </summary>
public const string AutoGeneratedHeader = @"//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by Fantasy.SourceGenerator.
// Runtime Version: 1.0.0
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
#nullable enable
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
// ReSharper disable MergeIntoPattern
// ReSharper disable SuspiciousTypeConversion.Global
// ReSharper disable NullCoalescingConditionIsAlwaysNotNullAccordingToAPIContract
// ReSharper disable CheckNamespace
#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type.
#pragma warning disable CS8603 // Possible null reference return.
#pragma warning disable CS8602 // Dereference of a possibly null reference.
#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type.
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
";
}
}

View File

@@ -0,0 +1,45 @@
using System;
namespace Fantasy.SourceGenerator.Common
{
/// <summary>
/// HashCode 算法帮助类 (Source Generator 版本)
/// 用于在编译时计算类型哈希值
/// 注意:此实现必须与 Fantasy.Helper.HashCodeHelper.ComputeHash64 保持完全一致
/// </summary>
internal static class HashCodeHelper
{
/// <summary>
/// 使用 MurmurHash3 算法生成一个 long 的值
/// </summary>
/// <param name="str">输入字符串</param>
/// <returns>64位哈希值</returns>
public static long ComputeHash64(string str)
{
const ulong seed = 0xc58f1a7bc58f1a7bUL; // 64-bit seed
var hash = seed;
var c1 = 0x87c37b91114253d5UL;
var c2 = 0x4cf5ad432745937fUL;
for (var i = 0; i < str.Length; i++)
{
var k1 = (ulong)str[i];
k1 *= c1;
k1 = (k1 << 31) | (k1 >> (64 - 31));
k1 *= c2;
hash ^= k1;
hash = (hash << 27) | (hash >> (64 - 27));
hash = hash * 5 + 0x52dce729;
}
hash ^= (ulong)str.Length;
hash ^= hash >> 33;
hash *= 0xff51afd7ed558ccdUL;
hash ^= hash >> 33;
hash *= 0xc4ceb9fe1a85ec53UL;
hash ^= hash >> 33;
return (long)hash;
}
}
}

View File

@@ -0,0 +1,33 @@
// ReSharper disable CheckNamespace
//------------------------------------------------------------------------------
// 这个 IsExternalInit 类是一个 polyfill兼容性填充
// 用于在 .NET Standard 2.0 或较低版本的框架中启用 C# 9.0 的 init 访问器和 record 类型功能。
// 为什么需要它?
// C# 9.0 引入了 init 访问器(只在初始化时可设置的属性)
// 编译器在编译 init 属性时,会查找 IsExternalInit 类型
// 示例:
// public class Person
// {
// public string Name { get; init; } // 需要 IsExternalInit
// public int Age { get; init; }
// }
// 使用
// var person = new Person { Name = "Alice", Age = 30 };
// person.Name = "Bob"; // ❌ 编译错误init 属性只能在对象初始化时设置
// 不定义会怎样?
// 如果目标框架是 netstandard2.0 但没定义 IsExternalInit编译器会报错
// error CS0518: Predefined type 'System.Runtime.CompilerServices.IsExternalInit'
// is not defined or imported
// 实际应用场景
// 在 IncrementalGenerator 中,你可能会生成或使用带 init 的代码
//------------------------------------------------------------------------------
#if NETSTANDARD2_0 || NETFRAMEWORK
namespace System.Runtime.CompilerServices
{
/// <summary>
/// Polyfill for C# 9.0 record types in netstandard2.0
/// </summary>
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
internal static class IsExternalInit { }
}
#endif

View File

@@ -0,0 +1,134 @@
using Microsoft.CodeAnalysis;
using System.Collections.Generic;
using System.Linq;
namespace Fantasy.SourceGenerator.Common
{
/// <summary>
/// Roslyn 相关的扩展方法
/// </summary>
internal static class RoslynExtensions
{
/// <summary>
/// 检查类型是否实现了指定的接口(通过完全限定名)
/// </summary>
public static bool ImplementsInterface(this INamedTypeSymbol typeSymbol, string interfaceFullName)
{
return typeSymbol.AllInterfaces.Any(i => i.ToDisplayString() == interfaceFullName);
}
/// <summary>
/// 检查类型是否继承自指定的基类(通过完全限定名)
/// </summary>
public static bool InheritsFrom(this INamedTypeSymbol typeSymbol, string baseTypeFullName)
{
var current = typeSymbol.BaseType;
while (current != null)
{
if (current.ToDisplayString() == baseTypeFullName)
{
return true;
}
current = current.BaseType;
}
return false;
}
/// <summary>
/// 获取类型的完全限定名(包括命名空间)
/// </summary>
public static string GetFullName(this ITypeSymbol typeSymbol, bool includeGlobal = true)
{
var displayString = typeSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
return includeGlobal ? displayString : displayString.Replace("global::", "");
}
/// <summary>
/// 检查类型是否可以被实例化(非抽象、非接口、非泛型定义)
/// </summary>
public static bool IsInstantiable(this INamedTypeSymbol typeSymbol)
{
// 允许:具体的类(非抽象、非静态)
// 排除:抽象类、静态类、接口、开放泛型类型(如 MyClass<T> where T 未指定)
return typeSymbol is { IsAbstract: false, IsStatic: false, TypeKind: TypeKind.Class };
}
/// <summary>
/// 获取所有实现指定接口的类型
/// </summary>
public static IEnumerable<INamedTypeSymbol> GetTypesImplementingInterface(
this Compilation compilation,
string interfaceFullName)
{
var visitor = new InterfaceImplementationVisitor(interfaceFullName);
visitor.Visit(compilation.GlobalNamespace);
return visitor.ImplementingTypes;
}
/// <summary>
/// 转换为驼峰命名
/// </summary>
public static string ToCamelCase(this string name)
{
if (string.IsNullOrEmpty(name) || char.IsLower(name[0]))
{
return name;
}
return char.ToLowerInvariant(name[0]) + name.Substring(1);
}
/// <summary>
/// 访问器:查找实现特定接口的所有类型
/// </summary>
private class InterfaceImplementationVisitor : SymbolVisitor
{
private readonly string _interfaceFullName;
private readonly List<INamedTypeSymbol> _implementingTypes = new List<INamedTypeSymbol>();
public IReadOnlyList<INamedTypeSymbol> ImplementingTypes => _implementingTypes;
public InterfaceImplementationVisitor(string interfaceFullName)
{
_interfaceFullName = interfaceFullName;
}
public override void VisitNamespace(INamespaceSymbol symbol)
{
foreach (var member in symbol.GetMembers())
{
member.Accept(this);
}
}
public override void VisitNamedType(INamedTypeSymbol symbol)
{
if (symbol.IsInstantiable() && symbol.ImplementsInterface(_interfaceFullName))
{
_implementingTypes.Add(symbol);
}
// 递归访问嵌套类型
foreach (var nestedType in symbol.GetTypeMembers())
{
nestedType.Accept(this);
}
}
}
/// <summary>
/// 尝试获取泛型接口的类型参数
/// 例如IAwakeSystem&lt;PlayerEntity&gt; 返回 PlayerEntity
/// </summary>
public static ITypeSymbol? GetGenericInterfaceTypeArgument(
this INamedTypeSymbol typeSymbol,
string genericInterfaceName)
{
var matchingInterface = typeSymbol.AllInterfaces.FirstOrDefault(i =>
i.IsGenericType &&
i.ConstructedFrom.ToDisplayString() == genericInterfaceName);
return matchingInterface?.TypeArguments.FirstOrDefault();
}
}
}

View File

@@ -0,0 +1,211 @@
using System.Text;
namespace Fantasy.SourceGenerator.Common
{
/// <summary>
/// 辅助构建生成代码的工具类
/// </summary>
internal sealed class SourceCodeBuilder
{
private readonly StringBuilder _builder;
private int _indentLevel;
private const string IndentString = " "; // 4 空格缩进
public SourceCodeBuilder(int indentLevel = 0)
{
_builder = new StringBuilder();
_indentLevel = indentLevel;
}
/// <summary>
/// 增加缩进级别
/// </summary>
public SourceCodeBuilder Indent(int indentLevel = 1)
{
_indentLevel += indentLevel;
return this;
}
/// <summary>
/// 减少缩进级别
/// </summary>
public SourceCodeBuilder Unindent()
{
if (_indentLevel > 0)
{
_indentLevel--;
}
return this;
}
public void Append(string code = "")
{
_builder.Append(code);
}
/// <summary>
/// 添加一行代码(自动处理缩进)
/// </summary>
public SourceCodeBuilder AppendLine(string code = "", bool indent = true)
{
if (string.IsNullOrEmpty(code))
{
_builder.AppendLine();
}
else
{
if (indent)
{
for (int i = 0; i < _indentLevel; i++)
{
_builder.Append(IndentString);
}
}
_builder.AppendLine(code);
}
return this;
}
/// <summary>
/// 添加代码块开始 {
/// </summary>
public SourceCodeBuilder OpenBrace()
{
AppendLine("{");
Indent();
return this;
}
/// <summary>
/// 添加代码块结束 }
/// </summary>
public SourceCodeBuilder CloseBrace(bool semicolon = false)
{
Unindent();
AppendLine(semicolon ? "};" : "}");
return this;
}
/// <summary>
/// 添加 using 语句
/// </summary>
public SourceCodeBuilder AddUsing(string @namespace)
{
AppendLine($"using {@namespace};");
return this;
}
/// <summary>
/// 添加多个 using 语句
/// </summary>
public SourceCodeBuilder AddUsings(params string[] namespaces)
{
foreach (var ns in namespaces)
{
AddUsing(ns);
}
return this;
}
/// <summary>
/// 开始命名空间
/// </summary>
public SourceCodeBuilder BeginNamespace(string @namespace)
{
AppendLine($"namespace {@namespace}");
OpenBrace();
return this;
}
/// <summary>
/// 结束命名空间
/// </summary>
public SourceCodeBuilder EndNamespace()
{
CloseBrace();
return this;
}
/// <summary>
/// 开始类定义
/// </summary>
public SourceCodeBuilder BeginClass(string className, string? modifiers = "internal static", string? baseTypes = null)
{
var classDeclaration = $"{modifiers} class {className}";
if (!string.IsNullOrEmpty(baseTypes))
{
classDeclaration += $" : {baseTypes}";
}
AppendLine(classDeclaration);
OpenBrace();
return this;
}
/// <summary>
/// 结束类定义
/// </summary>
public SourceCodeBuilder EndClass()
{
CloseBrace();
return this;
}
/// <summary>
/// 开始方法定义
/// </summary>
public SourceCodeBuilder BeginMethod(string signature)
{
AppendLine(signature);
OpenBrace();
return this;
}
/// <summary>
/// 结束方法定义
/// </summary>
public SourceCodeBuilder EndMethod()
{
CloseBrace();
return this;
}
/// <summary>
/// 添加注释
/// </summary>
public SourceCodeBuilder AddComment(string comment)
{
AppendLine($"// {comment}");
return this;
}
/// <summary>
/// 添加 XML 文档注释
/// </summary>
public SourceCodeBuilder AddXmlComment(string summary)
{
AppendLine("/// <summary>");
AppendLine($"/// {summary}");
AppendLine("/// </summary>");
return this;
}
/// <summary>
/// 构建最终代码
/// </summary>
public override string ToString()
{
return _builder.ToString();
}
/// <summary>
/// 清空构建器
/// </summary>
public void Clear()
{
_builder.Clear();
_indentLevel = 0;
}
}
}