База для нового бэкэнда
This commit is contained in:
@@ -17,74 +17,57 @@ namespace mROA.Codegen
|
||||
[Generator]
|
||||
public class mROASourceGenerator : ISourceGenerator
|
||||
{
|
||||
private const string Namespace = "mROA.Implementation";
|
||||
private const string AttributeName = "SharedObjectInterafceAttribute";
|
||||
|
||||
private const string AttributeSourceCode = $@"// <auto-generated/>
|
||||
|
||||
namespace {Namespace}
|
||||
{{
|
||||
[System.AttributeUsage(System.AttributeTargets.Class)]
|
||||
public class {AttributeName} : System.Attribute
|
||||
{{
|
||||
}}
|
||||
}}";
|
||||
|
||||
/// <summary>
|
||||
/// Generate code action.
|
||||
/// It will be executed on specific nodes (ClassDeclarationSyntax annotated with the [Report] attribute) changed by the user.
|
||||
/// </summary>
|
||||
/// <param name="context">Source generation context used to add source files.</param>
|
||||
/// <param name="compilation">Compilation used to provide access to the Semantic Model.</param>
|
||||
/// <param name="classes">Nodes annotated with the [Report] attribute that trigger the generate action.</param>
|
||||
private void GenerateCode(GeneratorExecutionContext context, Compilation compilation,
|
||||
ImmutableArray<InterfaceDeclarationSyntax> classes)
|
||||
{
|
||||
var methods = new List<(string, IMethodSymbol)>();
|
||||
var frontendContextRepo = new List<string>();
|
||||
// Go through all filtered class declarations.
|
||||
|
||||
var declarations = classes.ToList().OrderBy(i => i.Identifier.Text).ToList();
|
||||
foreach (var classDeclarationSyntax in declarations)
|
||||
{
|
||||
// We need to get semantic model of the class to retrieve metadata.
|
||||
{
|
||||
var semanticModel = compilation.GetSemanticModel(classDeclarationSyntax.SyntaxTree);
|
||||
|
||||
|
||||
// Symbols allow us to get the compile-time information.
|
||||
if (semanticModel.GetDeclaredSymbol(classDeclarationSyntax) is not INamedTypeSymbol classSymbol)
|
||||
continue;
|
||||
|
||||
|
||||
|
||||
var namespaceName = classSymbol.ContainingNamespace.ToDisplayString();
|
||||
|
||||
|
||||
|
||||
// 'Identifier' means the token of the node. Get class name from the syntax node.
|
||||
var className = classDeclarationSyntax.Identifier.Text;
|
||||
|
||||
// Go through all class members with a particular type (property) to generate method lines.
|
||||
var methodBody = classSymbol.GetMembers()
|
||||
.OfType<IMethodSymbol>().OrderBy(i => i.Name);
|
||||
|
||||
var methodBody = CollectMethods(classSymbol);
|
||||
|
||||
var originalName = className;
|
||||
// Build up the source code
|
||||
|
||||
className = className.TrimStart('I') + "RemoteEndpoint";
|
||||
|
||||
|
||||
var methodsText = new List<string>();
|
||||
|
||||
|
||||
foreach (var method in methodBody)
|
||||
{
|
||||
var index = methods.Count;
|
||||
methods.Add((namespaceName + "." + originalName, method));
|
||||
var sb = new StringBuilder();
|
||||
|
||||
bool isParametrized;
|
||||
|
||||
bool isAsync = method.ReturnType.Name == "Task";
|
||||
bool isVoid = method.ReturnType.Name == "Void" ||
|
||||
method.ReturnType.ToString() == "System.Threading.Tasks.Task";
|
||||
bool isParametrized = method.Parameters.Length == 1 && !isAsync ||
|
||||
method.Parameters.Length == 2 && isAsync;
|
||||
bool isAsync;
|
||||
bool isVoid;
|
||||
|
||||
switch (method.ReturnType)
|
||||
{
|
||||
case INamedTypeSymbol namedType:
|
||||
isAsync = namedType.Name == "Task";
|
||||
isVoid = isAsync && namedType.TypeParameters.Length == 0 || namedType.Name == "Void";
|
||||
isParametrized = method.Parameters.Length == 1 && !isAsync ||
|
||||
method.Parameters.Length == 2 && isAsync;
|
||||
break;
|
||||
case IArrayTypeSymbol:
|
||||
isAsync = false;
|
||||
isVoid = false;
|
||||
isParametrized = method.Parameters.Length != 0;
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
||||
//Creating signature
|
||||
sb.AppendLine("public" + (isAsync
|
||||
@@ -140,7 +123,7 @@ namespace {namespaceName}
|
||||
|
||||
|
||||
// Add the source code to the compilation.
|
||||
context.AddSource($"{className}.g.cs", SourceText.From(code, Encoding.UTF8));
|
||||
// context.AddSource($"{className}.g.cs", SourceText.From(code, Encoding.UTF8));
|
||||
|
||||
frontendContextRepo.Add(
|
||||
$"{{ typeof({classSymbol.ToDisplayString()}), typeof({namespaceName}.{className}) }}");
|
||||
@@ -148,31 +131,27 @@ namespace {namespaceName}
|
||||
|
||||
if (methods.Count != 0)
|
||||
{
|
||||
// var methodsStringed = methods.Select(i =>
|
||||
// $"typeof({i.Item1}).GetMethod(\"{i.Item2.Name}\", new Type[] {{{string.Join(", ", i.Item2.Parameters.Select(p => $"typeof({p.Type.ToDisplayString()})"))}}})")
|
||||
// .ToList();
|
||||
var methodsStringed = methods.Select(i =>
|
||||
$"typeof({i.Item1}).GetMethod(\"{i.Item2.Name}\")")
|
||||
.ToList();
|
||||
var methodsStringed = Array.Empty<string>();
|
||||
|
||||
var coCodegenRepoCode = @$"// <auto-generated/>
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using mROA.Abstract;
|
||||
using mROA.Implementation;
|
||||
using System;
|
||||
|
||||
namespace mROA.Codegen
|
||||
{{
|
||||
public class CoCodegenMethodRepository : IMethodRepository
|
||||
{{
|
||||
private readonly List<MethodInfo> _methods = new () {{
|
||||
private readonly List<IMethodInvoker> _methods = new () {{
|
||||
{string.Join(",\r\n\t\t\t", methodsStringed)}
|
||||
}};
|
||||
|
||||
public MethodInfo GetMethod(int id)
|
||||
public IMethodInvoker GetMethod(int id)
|
||||
{{
|
||||
if (id == -1)
|
||||
return typeof(IDisposable).GetMethod(""Dispose"");
|
||||
return mROA.Implementation.MethodInvoker.Dispose;
|
||||
|
||||
if (_methods.Count <= id)
|
||||
return null;
|
||||
@@ -186,7 +165,7 @@ namespace mROA.Codegen
|
||||
}}
|
||||
}}
|
||||
";
|
||||
context.AddSource($"CoCodegenMethodRepository.g.cs", SourceText.From(coCodegenRepoCode, Encoding.UTF8));
|
||||
context.AddSource("CoCodegenMethodRepository.g.cs", SourceText.From(coCodegenRepoCode, Encoding.UTF8));
|
||||
}
|
||||
|
||||
if (frontendContextRepo.Count != 0)
|
||||
@@ -209,7 +188,7 @@ namespace mROA.Codegen
|
||||
}}
|
||||
}}
|
||||
";
|
||||
context.AddSource("RemoteTypeBinder.g.cs", SourceText.From(fronendRepoCode, Encoding.UTF8));
|
||||
// context.AddSource("RemoteTypeBinder.g.cs", SourceText.From(fronendRepoCode, Encoding.UTF8));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,9 +204,7 @@ namespace mROA.Codegen
|
||||
|
||||
private string ExtractTaskType(ITypeSymbol taskType)
|
||||
{
|
||||
var type = taskType.ToString();
|
||||
type = type.Substring(type.IndexOf('<') + 1);
|
||||
return type.Substring(0, type.Length - 1);
|
||||
return (taskType as INamedTypeSymbol).TypeParameters[0].ToDisplayString();
|
||||
}
|
||||
|
||||
public void Initialize(GeneratorInitializationContext context)
|
||||
@@ -266,8 +243,7 @@ namespace mROA.Codegen
|
||||
private bool ContainsSOIAttribute(SyntaxList<AttributeListSyntax> attributes, GeneratorExecutionContext context,
|
||||
InterfaceDeclarationSyntax interfaceDeclarationSyntax)
|
||||
{
|
||||
foreach (AttributeListSyntax attributeListSyntax in attributes)
|
||||
foreach (AttributeSyntax attributeSyntax in attributeListSyntax.Attributes)
|
||||
foreach (var attributeSyntax in attributes.SelectMany(attributeListSyntax => attributeListSyntax.Attributes))
|
||||
{
|
||||
if (context.Compilation.GetSemanticModel(interfaceDeclarationSyntax.SyntaxTree)
|
||||
.GetSymbolInfo(attributeSyntax).Symbol is not IMethodSymbol attributeSymbol)
|
||||
@@ -282,5 +258,16 @@ namespace mROA.Codegen
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private List<IMethodSymbol> CollectMethods(INamedTypeSymbol type)
|
||||
{
|
||||
var methods = type.GetMembers().OfType<IMethodSymbol>().ToList();
|
||||
foreach (var inner in type.AllInterfaces)
|
||||
{
|
||||
methods.AddRange(inner.GetMembers().OfType<IMethodSymbol>());
|
||||
}
|
||||
|
||||
return methods.OrderBy(i => i.Name).ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user