Files
Polonium.Tasks/src/GenerateProxyNodesTask.cs
2025-02-15 08:25:01 +00:00

116 lines
4.9 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
namespace Polonium.Tasks;
public class GenerateProxyNodesTask : Task
{
[Required]
public string SourceDirectory { get; set; }
[Required]
public string TemplateDirectory { get; set; }
[Required]
public string AttributeName { get; set; }
public override bool Execute()
{
try
{
string[] csFiles = Directory.GetFiles(SourceDirectory, "*.cs", SearchOption.AllDirectories);
foreach (string csFile in csFiles)
{
string code = File.ReadAllText(csFile);
SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(code);
CompilationUnitSyntax root = syntaxTree.GetCompilationUnitRoot();
IEnumerable<ClassDeclarationSyntax> classes = root.DescendantNodes().OfType<ClassDeclarationSyntax>()
.Where(cls => cls.AttributeLists
.SelectMany(attrList => attrList.Attributes)
.Any(attr => attr.Name.ToString().Contains(AttributeName)));
foreach (ClassDeclarationSyntax cls in classes)
{
string className = cls.Identifier.Text;
StringBuilder sbx = new StringBuilder();
sbx
.AppendLine("// meta-default: true")
.AppendLine("using _BINDINGS_NAMESPACE_;")
.AppendLine("using System;")
.AppendLine($"public partial class _CLASS_ : {GetDisplayName(cls)}")
.AppendLine("{");
IEnumerable<MethodDeclarationSyntax> methods = cls.Members
.OfType<MethodDeclarationSyntax>()
.Where(m => m.AttributeLists
.SelectMany(a => a.Attributes)
.Any(attr => attr.Name.ToString().Contains("ProxyMethod"))
);
IEnumerable<PropertyDeclarationSyntax> properties = cls.Members
.OfType<PropertyDeclarationSyntax>()
.Where(m => m.AttributeLists
.SelectMany(a => a.Attributes)
.Any(attr => attr.Name.ToString().Contains("ProxyProperty"))
);
foreach (PropertyDeclarationSyntax prop in properties)
{
sbx.AppendLine($" public override {prop.Type.ToString()} {prop.Identifier.ToString()} => base.{prop.Identifier.ToString()};");
}
foreach (MethodDeclarationSyntax proxyMethod in methods)
{
string methodReturnType = proxyMethod.ReturnType.ToString();
string methodName = proxyMethod.Identifier.Text;
string methodArgs = string.Join(", ", proxyMethod.ParameterList.Parameters.Select(p => p.ToString()));
string paramNames = string.Join(", ", proxyMethod.ParameterList.Parameters.Select(p => p.Identifier.Text));
sbx
.AppendLine($" public override {methodReturnType} {methodName}({methodArgs})")
.AppendLine(" {");
if(methodReturnType=="void")
sbx.AppendLine($" base.{methodName}({paramNames});");
else
sbx.AppendLine($" return base.{methodName}({paramNames});");
sbx.AppendLine(" }");
}
sbx
.AppendLine("}");
if(!Directory.Exists($"{TemplateDirectory}/{className}"))
Directory.CreateDirectory($"{TemplateDirectory}/{className}");
string templateFile = $"{TemplateDirectory}/{className}/Polonium_{className}.cs";
File.WriteAllText(templateFile, sbx.ToString());
}
}
return true;
}
catch (Exception ex)
{
Log.LogErrorFromException(ex);
return false;
}
}
private string GetDisplayName(ClassDeclarationSyntax cls)
{
string name = cls.Identifier.Text;
SyntaxNode node = cls.Parent;
while (node is not null)
{
if(node is NamespaceDeclarationSyntax ns)
name = ns.Name.ToString() + "." + name;
else if (node is FileScopedNamespaceDeclarationSyntax fs)
name = fs.Name.ToString() + "." + name;
node = node.Parent;
}
return name;
}
}