Procházet zdrojové kódy

添加ETGetComponentGenerator 用于生成Get组件方法代码

wenchao před 2 roky
rodič
revize
017d60e8e2

+ 23 - 0
Share/Analyzer/Extension/AnalyzerHelper.cs

@@ -375,5 +375,28 @@ namespace ET.Analyzer
 
             return false;
         }
+
+        public static string? GetNameSpace(this INamedTypeSymbol namedTypeSymbol)
+        {
+            INamespaceSymbol? namespaceSymbol = namedTypeSymbol.ContainingNamespace;
+            string? namespaceName = namespaceSymbol?.Name;
+            while (namespaceSymbol?.ContainingNamespace != null)
+            {
+                namespaceSymbol = namespaceSymbol.ContainingNamespace;
+                if (string.IsNullOrEmpty(namespaceSymbol.Name))
+                {
+                    break;
+                }
+
+                namespaceName = $"{namespaceSymbol.Name}.{namespaceName}";
+            }
+
+            if (string.IsNullOrEmpty(namespaceName))
+            {
+                return null;
+            }
+
+            return namespaceName;
+        }
     }
 }

+ 136 - 0
Share/Share.SourceGenerator/Generator/ETGetComponentGenerator.cs

@@ -0,0 +1,136 @@
+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 ETGetComponentGenerator : ISourceGenerator
+{
+    
+    public void Initialize(GeneratorInitializationContext context)
+    {
+        context.RegisterForSyntaxNotifications(SyntaxContextReceiver.Create);
+    }
+
+    public void Execute(GeneratorExecutionContext context)
+    {
+        if (context.SyntaxContextReceiver is not SyntaxContextReceiver receiver || receiver.ComponentOfDatas.Count==0 )
+        {
+            return;
+        }
+
+        foreach (var kv in receiver.ComponentOfDatas)
+        {
+            GenerateCSFiles(context, kv.Key,kv.Value);
+        }
+
+    }
+    
+    private void GenerateCSFiles(GeneratorExecutionContext context,string nameSpace, List<ComponentOfData> componentOfDatas)
+    {
+        StringBuilder contenSb = new StringBuilder();
+
+        foreach (var componentOfData in componentOfDatas)
+        {
+            GenerateGetComponentCode(context, componentOfData, contenSb);
+        }
+
+        string? assemblyName = context.Compilation.AssemblyName?.Replace(".", "_");
+        string code = $$"""
+namespace {{nameSpace}}
+{
+    public static class {{assemblyName}}ETGetComponentExtension
+    {
+        {{contenSb}}
+    }
+}
+""";
+        context.AddSource($"ETGetComponentGenerator.{nameSpace}.g.cs", code);
+    }
+
+    private void GenerateGetComponentCode(GeneratorExecutionContext context,ComponentOfData componentOfData,StringBuilder contenSb)
+    {
+        string getComponentName = componentOfData.ComponentName;
+        string parentEntityName = componentOfData.ParentEntityName;
+        contenSb.AppendLine($$"""
+
+        public static {{getComponentName}} Get{{getComponentName}} (this {{parentEntityName}} self)
+        {
+            return self.GetComponent<{{getComponentName}}>();
+        }
+
+""");
+    }
+
+    struct ComponentOfData
+    {
+        public string ComponentName;
+
+        public string ParentEntityName;
+    }
+
+    class SyntaxContextReceiver: ISyntaxContextReceiver
+    {
+        internal static ISyntaxContextReceiver Create()
+        {
+            return new SyntaxContextReceiver();
+        }
+        
+        public Dictionary<string, List<ComponentOfData>> ComponentOfDatas = new();
+
+        public void OnVisitSyntaxNode(GeneratorSyntaxContext context)
+        {
+            SyntaxNode node = context.Node;
+            if (node is not ClassDeclarationSyntax classDeclarationSyntax)
+            {
+                return;
+            }
+
+            if (classDeclarationSyntax.AttributeLists.Count==0)
+            {
+                return;
+            }
+            
+            var classTypeSymbol = context.SemanticModel.GetDeclaredSymbol(classDeclarationSyntax) as INamedTypeSymbol;
+            if (classTypeSymbol==null)
+            {
+                return;
+            }
+            // 筛选出含有 ComponentOf标签的
+            var componentOfAttrData = classTypeSymbol.GetFirstAttribute(Definition.ComponentOfAttribute);
+            if (componentOfAttrData==null)
+            {
+                return;
+            }
+
+            // 忽略无Type参数的
+            if (componentOfAttrData.ConstructorArguments[0].Value is not INamedTypeSymbol parentEntityTypeSymbol)
+            {
+                return;
+            }
+            
+            
+            string? nameSpace = classTypeSymbol.GetNameSpace();
+            if (nameSpace==null)
+            {
+                return;
+            }
+
+            if (!ComponentOfDatas.ContainsKey(nameSpace))
+            {
+                ComponentOfDatas.Add(nameSpace,new());
+            }
+
+            this.ComponentOfDatas[nameSpace].Add(new ComponentOfData()
+            {
+                ComponentName = classTypeSymbol.Name,
+                ParentEntityName = parentEntityTypeSymbol.Name,
+            });
+        }
+    }
+}
+

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

@@ -17,6 +17,7 @@
         <Compile Include="../Analyzer/Extension/*.cs">
             <Link>Extension\%(RecursiveDir)%(FileName)%(Extension)</Link>
         </Compile>
+        <Compile Include="../Analyzer/Config/Definition.cs" />
     </ItemGroup>
 
     <ItemGroup>