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 classes = root.DescendantNodes().OfType() .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 methods = cls.Members .OfType() .Where(m => m.AttributeLists .SelectMany(a => a.Attributes) .Any(attr => attr.Name.ToString().Contains("ProxyMethod")) ); IEnumerable properties = cls.Members .OfType() .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; } }