Просмотр исходного кода

添加ETSystem SourceGenerator

wuwenchao 2 лет назад
Родитель
Сommit
4213016604

+ 2 - 1
DotNet/Core/DotNet.Core.csproj

@@ -35,7 +35,8 @@
     </ItemGroup>
     
     <ItemGroup>
-      <ProjectReference Include="..\..\Share\Analyzer\Share.Analyzer.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
+      <ProjectReference Include="..\..\Share\Analyzer\Share.Analyzer.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" /> 
+      <ProjectReference Include="..\..\Share\Share.SourceGenerator\Share.SourceGenerator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false"/>
       <ProjectReference Include="..\ThirdParty\DotNet.ThirdParty.csproj" />
     </ItemGroup>
 

+ 1 - 0
DotNet/Hotfix/DotNet.Hotfix.csproj

@@ -37,6 +37,7 @@
     </ItemGroup>
     <ItemGroup>
         <ProjectReference Include="..\..\Share\Analyzer\Share.Analyzer.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
+        <ProjectReference Include="..\..\Share\Share.SourceGenerator\Share.SourceGenerator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false"/>
         <ProjectReference Include="..\Loader\DotNet.Loader.csproj" />
         <ProjectReference Include="..\Model\DotNet.Model.csproj" />
     </ItemGroup>

+ 1 - 0
DotNet/Loader/DotNet.Loader.csproj

@@ -28,6 +28,7 @@
     </ItemGroup> 
     <ItemGroup> 
         <ProjectReference Include="..\..\Share\Analyzer\Share.Analyzer.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
+        <ProjectReference Include="..\..\Share\Share.SourceGenerator\Share.SourceGenerator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false"/>
         <ProjectReference Include="..\Core\DotNet.Core.csproj" />
         <ProjectReference Include="..\ThirdParty\DotNet.ThirdParty.csproj" />
     </ItemGroup>

+ 1 - 0
DotNet/Model/DotNet.Model.csproj

@@ -44,6 +44,7 @@
     </ItemGroup> 
     <ItemGroup> 
         <ProjectReference Include="..\..\Share\Analyzer\Share.Analyzer.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
+        <ProjectReference Include="..\..\Share\Share.SourceGenerator\Share.SourceGenerator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false"/>
         <ProjectReference Include="..\Core\DotNet.Core.csproj" />
         <ProjectReference Include="..\Loader\DotNet.Loader.csproj" />
         <ProjectReference Include="..\ThirdParty\DotNet.ThirdParty.csproj" />

+ 15 - 0
ET.sln

@@ -43,6 +43,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotNet.Loader", "DotNet\Loa
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Unity.Codes", "Unity\Unity.Codes.csproj", "{C8CDB918-7F4F-0E46-C7AA-900F18D8C944}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Share.SourceGenerator", "Share\Share.SourceGenerator\Share.SourceGenerator.csproj", "{B29C9195-BEE7-4291-B57C-990425CDEF81}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -257,6 +259,18 @@ Global
 		{C8CDB918-7F4F-0E46-C7AA-900F18D8C944}.Release|x64.Build.0 = Debug|Any CPU
 		{C8CDB918-7F4F-0E46-C7AA-900F18D8C944}.Release|x86.ActiveCfg = Debug|Any CPU
 		{C8CDB918-7F4F-0E46-C7AA-900F18D8C944}.Release|x86.Build.0 = Debug|Any CPU
+		{B29C9195-BEE7-4291-B57C-990425CDEF81}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{B29C9195-BEE7-4291-B57C-990425CDEF81}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{B29C9195-BEE7-4291-B57C-990425CDEF81}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{B29C9195-BEE7-4291-B57C-990425CDEF81}.Debug|x64.Build.0 = Debug|Any CPU
+		{B29C9195-BEE7-4291-B57C-990425CDEF81}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{B29C9195-BEE7-4291-B57C-990425CDEF81}.Debug|x86.Build.0 = Debug|Any CPU
+		{B29C9195-BEE7-4291-B57C-990425CDEF81}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{B29C9195-BEE7-4291-B57C-990425CDEF81}.Release|Any CPU.Build.0 = Release|Any CPU
+		{B29C9195-BEE7-4291-B57C-990425CDEF81}.Release|x64.ActiveCfg = Release|Any CPU
+		{B29C9195-BEE7-4291-B57C-990425CDEF81}.Release|x64.Build.0 = Release|Any CPU
+		{B29C9195-BEE7-4291-B57C-990425CDEF81}.Release|x86.ActiveCfg = Release|Any CPU
+		{B29C9195-BEE7-4291-B57C-990425CDEF81}.Release|x86.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
@@ -279,6 +293,7 @@ Global
 		{9498BFB4-D9F5-C441-13E3-3F26F7700E29} = {914C77C9-212A-4DD0-8D9A-074620E77FAA}
 		{C109842F-01DA-64D4-DBF2-00C6449E459E} = {914C77C9-212A-4DD0-8D9A-074620E77FAA}
 		{C8CDB918-7F4F-0E46-C7AA-900F18D8C944} = {914C77C9-212A-4DD0-8D9A-074620E77FAA}
+		{B29C9195-BEE7-4291-B57C-990425CDEF81} = {1272AF7B-A962-4BA4-8A9C-FFA7E131A0AC}
 	EndGlobalSection
 	GlobalSection(ExtensibilityGlobals) = postSolution
 		SolutionGuid = {EABC01E3-3EB5-47EF-B46E-AAD8BB3585F1}

+ 167 - 0
Share/Share.SourceGenerator/Generator/ETSystemGenerator/ETSystemGenerator.cs

@@ -0,0 +1,167 @@
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using ET.Analyzer;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+namespace ET.Generator;
+
+[Generator(LanguageNames.CSharp)]
+public class ETSystemGenerator : ISourceGenerator
+{
+    public void Initialize(GeneratorInitializationContext context)
+    {
+        context.RegisterForSyntaxNotifications(SyntaxContextReceiver.Create);
+    }
+
+    public void Execute(GeneratorExecutionContext context)
+    {
+        if (context.SyntaxContextReceiver is not SyntaxContextReceiver receiver || receiver.MethodDeclarations.Count==0)
+        {
+            return;
+        }
+
+        foreach (var kv in receiver.MethodDeclarations)
+        {
+            this.GenerateCSFiles(kv.Key,kv.Value,context);
+        }
+    }
+
+    /// <summary>
+    /// 每个静态类生成一个cs文件
+    /// </summary>
+    private void GenerateCSFiles(ClassDeclarationSyntax classDeclarationSyntax, HashSet<MethodDeclarationSyntax>methodDeclarationSyntaxes,GeneratorExecutionContext context)
+    {
+        var className = classDeclarationSyntax.Identifier.Text;
+        var semanticModel = context.Compilation.GetSemanticModel(classDeclarationSyntax.SyntaxTree);
+        var classTypeSymbol = semanticModel.GetDeclaredSymbol(classDeclarationSyntax) as INamedTypeSymbol;
+        if (classTypeSymbol==null)
+        {
+            context.AddSource($"{className}.g.cs", "classTypeSymbol==null");
+            return;
+        }
+        var namespaceSymbol = classTypeSymbol?.ContainingNamespace;
+        var namespaceName = namespaceSymbol?.Name;
+        while (namespaceSymbol?.ContainingNamespace != null)
+        {
+            namespaceSymbol = namespaceSymbol.ContainingNamespace;
+            if (string.IsNullOrEmpty(namespaceSymbol.Name))
+            {
+                break;
+            }
+            namespaceName = $"{namespaceSymbol.Name}.{namespaceName}";
+        }
+        
+        var inClassSb = new StringBuilder();
+
+        this.GenerateSystemCodeByTemplate(inClassSb, classDeclarationSyntax, methodDeclarationSyntaxes, context,semanticModel);
+
+        string code = $$"""
+namespace {{namespaceName}}{
+    public static partial class {{className}}
+    {
+{{inClassSb}}
+    }
+}
+""";
+        context.AddSource($"{className}.g.cs",code);
+    }
+
+    /// <summary>
+    /// 根据模板生成System代码
+    /// </summary>
+    private void GenerateSystemCodeByTemplate(StringBuilder inClassSb,ClassDeclarationSyntax classDeclarationSyntax, HashSet<MethodDeclarationSyntax>methodDeclarationSyntaxes,GeneratorExecutionContext context, SemanticModel semanticModel)
+    {
+        foreach (var methodDeclarationSyntax in methodDeclarationSyntaxes)
+        {
+            var componentParam = methodDeclarationSyntax.ParameterList.Parameters.FirstOrDefault();
+            if (componentParam==null)
+            {
+                continue;
+            }
+            var methodSymbol = semanticModel.GetDeclaredSymbol(methodDeclarationSyntax) as IMethodSymbol;
+            if (methodSymbol==null)
+            {
+                continue;
+            }
+            var methodName = methodDeclarationSyntax.Identifier.Text;
+            var componentName = componentParam.Type?.ToString();
+            
+            var argsTypes = new StringBuilder();
+            for (int i = 0; i < methodSymbol.Parameters.Length; i++)
+            {
+                argsTypes.Append(i == 0? $"{methodSymbol.Parameters[i].Type}" : $",{methodSymbol.Parameters[i].Type}");
+            }
+
+            var argsTypeVars = new StringBuilder();
+            for (int i = 0; i < methodSymbol.Parameters.Length; i++)
+            {
+                argsTypeVars.Append(i == 0? $"{methodSymbol.Parameters[i].Type} self" : $",{methodSymbol.Parameters[i].Type} args{i}");
+            }
+
+            var argsVars = new StringBuilder();
+            if (methodSymbol.Parameters.Length>1)
+            {
+                for (int i = 1; i < methodSymbol.Parameters.Length; i++)
+                {
+                    argsVars.Append(i == 1? $"args1" : $",args{i}");
+                }
+            }
+            
+            inClassSb.AppendLine($$"""
+        public class {{componentName}}{{methodName}}System: {{methodName}}System<{{argsTypes}}>
+        {   
+            protected override void {{methodName}}({{argsTypeVars}})
+            {
+                self.{{methodName}}({{argsVars}});
+            }
+        }
+""");
+        }
+    }
+    
+    class SyntaxContextReceiver : ISyntaxContextReceiver
+    {
+        internal static ISyntaxContextReceiver Create()
+        {
+            return new SyntaxContextReceiver();
+        }
+
+        public Dictionary<ClassDeclarationSyntax, HashSet<MethodDeclarationSyntax>> MethodDeclarations { get; } = new ();
+        
+
+        public void OnVisitSyntaxNode(GeneratorSyntaxContext context)
+        {
+            var node = context.Node;
+            if (node is not MethodDeclarationSyntax methodDeclarationSyntax)
+            {
+                return;
+            }
+            if (methodDeclarationSyntax.AttributeLists.Count == 0)
+            {
+                return;
+            }
+            
+            var attr = methodDeclarationSyntax.AttributeLists.SelectMany(x => x.Attributes)
+                    .FirstOrDefault(x=>x.Name.ToString()=="EntitySystem");
+            if (attr == null)
+            {
+                return;
+            }
+
+            var parentClass = methodDeclarationSyntax.GetParentClassDeclaration();
+            if (parentClass==null)
+            {
+                
+                return;
+            }
+
+            if (!MethodDeclarations.ContainsKey(parentClass))
+            {
+                MethodDeclarations[parentClass] = new HashSet<MethodDeclarationSyntax>();
+            }
+            
+            MethodDeclarations[parentClass].Add(methodDeclarationSyntax);
+        }
+    }
+}

+ 22 - 0
Share/Share.SourceGenerator/Share.SourceGenerator.csproj

@@ -0,0 +1,22 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+    <PropertyGroup>
+        <TargetFramework>netstandard2.0</TargetFramework>
+        <IncludeBuildOutput>false</IncludeBuildOutput>
+        <Nullable>enable</Nullable>
+        <LangVersion>11</LangVersion>
+    </PropertyGroup>
+
+    <ItemGroup>
+        <Compile Include="../Analyzer/Extension/*.cs" />
+    </ItemGroup>
+
+    <ItemGroup>
+        <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.9.0" PrivateAssets="all" />
+        <PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.3">
+            <PrivateAssets>all</PrivateAssets>
+            <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
+        </PackageReference>
+    </ItemGroup>
+
+</Project>

BIN
Unity/Assets/Plugins/Share.SourceGenerator.dll


+ 71 - 0
Unity/Assets/Plugins/Share.SourceGenerator.dll.meta

@@ -0,0 +1,71 @@
+fileFormatVersion: 2
+guid: dbed22035f711974b8caf049edbfe8f8
+labels:
+- RoslynAnalyzer
+PluginImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  iconMap: {}
+  executionOrder: {}
+  defineConstraints: []
+  isPreloaded: 0
+  isOverridable: 0
+  isExplicitlyReferenced: 0
+  validateReferences: 1
+  platformData:
+  - first:
+      : Any
+    second:
+      enabled: 0
+      settings:
+        Exclude Editor: 1
+        Exclude Linux64: 1
+        Exclude OSXUniversal: 1
+        Exclude Win: 1
+        Exclude Win64: 1
+  - first:
+      Any: 
+    second:
+      enabled: 0
+      settings: {}
+  - first:
+      Editor: Editor
+    second:
+      enabled: 0
+      settings:
+        CPU: AnyCPU
+        DefaultValueInitialized: true
+        OS: AnyOS
+  - first:
+      Standalone: Linux64
+    second:
+      enabled: 0
+      settings:
+        CPU: None
+  - first:
+      Standalone: OSXUniversal
+    second:
+      enabled: 0
+      settings:
+        CPU: None
+  - first:
+      Standalone: Win
+    second:
+      enabled: 0
+      settings:
+        CPU: None
+  - first:
+      Standalone: Win64
+    second:
+      enabled: 0
+      settings:
+        CPU: None
+  - first:
+      Windows Store Apps: WindowsStoreApps
+    second:
+      enabled: 0
+      settings:
+        CPU: AnyCPU
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: