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