add: Patchable items and frames
This commit is contained in:
@@ -86,6 +86,33 @@ public abstract class AssetProcessGenerator : ISourceGenerator
|
||||
}
|
||||
|
||||
|
||||
protected IEnumerable<InterfaceInfo> GetInterfacesWithAttribute(GeneratorExecutionContext context,
|
||||
INamedTypeSymbol? attribute)
|
||||
{
|
||||
if(context.SyntaxReceiver is not ClassSyntaxReceiver receiver)
|
||||
yield break;
|
||||
Compilation compilation = context.Compilation;
|
||||
foreach (InterfaceDeclarationSyntax ifc in receiver.Interfaces)
|
||||
{
|
||||
SemanticModel model = compilation.GetSemanticModel(ifc.SyntaxTree);
|
||||
INamedTypeSymbol? interfaceSymbol = model.GetDeclaredSymbol(ifc) as INamedTypeSymbol;
|
||||
string filePath = ifc.SyntaxTree.FilePath;
|
||||
string interfaceName = Path.GetFileNameWithoutExtension(filePath);
|
||||
if(interfaceSymbol is null)
|
||||
continue;
|
||||
if (HasAttribute(interfaceSymbol, attribute))
|
||||
yield return new InterfaceInfo
|
||||
{
|
||||
DeclarationSyntax = ifc,
|
||||
InterfaceName = interfaceName,
|
||||
InterfaceFillName = interfaceSymbol.ToDisplayString(),
|
||||
Path = filePath,
|
||||
Symbol = interfaceSymbol,
|
||||
Namespace = interfaceSymbol.ContainingNamespace.ToDisplayString()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
protected IEnumerable<ClassInfo> GetClassesWithAttribute(GeneratorExecutionContext context,
|
||||
INamedTypeSymbol? attribute)
|
||||
{
|
||||
|
||||
@@ -6,13 +6,14 @@ namespace Polonium.Generators;
|
||||
|
||||
public class ClassSyntaxReceiver : ISyntaxReceiver
|
||||
{
|
||||
public List<ClassDeclarationSyntax> Classes { get; set; } = new ();
|
||||
public List<ClassDeclarationSyntax> Classes { get; } = new ();
|
||||
public List<InterfaceDeclarationSyntax> Interfaces { get; } = new ();
|
||||
|
||||
public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
|
||||
{
|
||||
if (syntaxNode is ClassDeclarationSyntax classDeclaration)
|
||||
{
|
||||
Classes.Add(classDeclaration);
|
||||
}
|
||||
if(syntaxNode is InterfaceDeclarationSyntax interfaceDeclaration)
|
||||
Interfaces.Add(interfaceDeclaration);
|
||||
}
|
||||
}
|
||||
131
src/Generators/FramePatchGenerator.cs
Normal file
131
src/Generators/FramePatchGenerator.cs
Normal file
@@ -0,0 +1,131 @@
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
|
||||
namespace Polonium.Generators.Generators;
|
||||
[Generator]
|
||||
public class FramePatchGenerator : AssetProcessGenerator
|
||||
{
|
||||
public override void Execute(GeneratorExecutionContext context)
|
||||
{
|
||||
if(context.SyntaxReceiver is not ClassSyntaxReceiver receiver)
|
||||
return;
|
||||
Compilation compilation = context.Compilation;
|
||||
INamedTypeSymbol? autoPatch = compilation.GetTypeByMetadataName("Polonium.Attributes.AutoPatch");
|
||||
INamedTypeSymbol? patchableProperty = compilation.GetTypeByMetadataName("Polonium.Attributes.PatchableProperty");
|
||||
foreach (InterfaceInfo inf in GetInterfacesWithAttribute(context, autoPatch))
|
||||
{
|
||||
|
||||
PropertyDeclarationSyntax? underlying = inf.DeclarationSyntax.Members
|
||||
.OfType<PropertyDeclarationSyntax>()
|
||||
.FirstOrDefault(m => m.AttributeLists
|
||||
.SelectMany(a => a.Attributes)
|
||||
.Any(a =>
|
||||
{
|
||||
SemanticModel model = compilation.GetSemanticModel(a.SyntaxTree);
|
||||
INamedTypeSymbol? attributeSymbol = model.GetSymbolInfo(a).Symbol?.ContainingType;
|
||||
return SymbolEqualityComparer.Default.Equals(attributeSymbol, patchableProperty);
|
||||
}));
|
||||
if (underlying is null)
|
||||
continue;
|
||||
SemanticModel model = compilation.GetSemanticModel(underlying.SyntaxTree);
|
||||
ITypeSymbol? underlyingType = model.GetTypeInfo(underlying.Type).Type;
|
||||
ITypeSymbol? hashSet = compilation
|
||||
.GetTypeByMetadataName("Polonium.DataStructures.PatchableItems.PatchableHashSet`1");
|
||||
ITypeSymbol? dictionary = compilation
|
||||
.GetTypeByMetadataName("Polonium.DataStructures.PatchableItems.PatchableDictionary`2");
|
||||
string typeString = "";
|
||||
StringBuilder sb = new();
|
||||
sb
|
||||
.AppendLine("using System;")
|
||||
.AppendLine("using System.Collections.Generic;")
|
||||
.AppendLine("using System.Linq;")
|
||||
.AppendLine("using Polonium.Interfaces;")
|
||||
.AppendLine("using Polonium.DataStructures.PatchableItems;")
|
||||
.AppendLine("using Polonium.Resources.FramePatches;")
|
||||
.AppendLine("using Polonium.Resources.FramePatches.Generic;")
|
||||
.AppendLine($"namespace {inf.Namespace};");
|
||||
|
||||
string lName = inf.InterfaceName[0] == 'I' ? inf.InterfaceName.Substring(1) : inf.InterfaceName;
|
||||
if (SymbolEqualityComparer.Default.Equals(underlyingType?.OriginalDefinition, hashSet))
|
||||
{
|
||||
ITypeSymbol? x1 = (underlyingType as INamedTypeSymbol)?.TypeArguments[0];
|
||||
sb
|
||||
.AppendLine($"public partial class {lName}Patch : HashSetFramePatch<{x1?.ToDisplayString()}>")
|
||||
.AppendLine("{")
|
||||
.AppendLine($" public override void Patch(IPatchableFrame frame)")
|
||||
.AppendLine(" {")
|
||||
.AppendLine($" if(frame is not {inf.InterfaceFillName} sFrame)")
|
||||
.AppendLine(" return;")
|
||||
.AppendLine($" switch (sFrame.{underlying.Identifier.ToString()}.UpdateMethod )")
|
||||
.AppendLine(" {")
|
||||
.AppendLine(" case UpdateMethods.None:")
|
||||
.AppendLine(" return;")
|
||||
.AppendLine(" case UpdateMethods.Update:")
|
||||
.AppendLine($" foreach({x1?.ToDisplayString()} x in Updates)")
|
||||
.AppendLine($" sFrame.{underlying.Identifier.ToString()}.Add(x);")
|
||||
.AppendLine(" return;")
|
||||
.AppendLine(" case UpdateMethods.Replace:")
|
||||
.AppendLine($" sFrame.{underlying.Identifier.ToString()}.Data = Updates;")
|
||||
.AppendLine(" return;")
|
||||
.AppendLine(" case UpdateMethods.Custom:")
|
||||
.AppendLine($" sFrame.{underlying.Identifier.ToString()}.CustomUpdate(Updates);")
|
||||
.AppendLine(" return;")
|
||||
.AppendLine(" default:")
|
||||
.AppendLine(" return;")
|
||||
.AppendLine(" }")
|
||||
.AppendLine(" }")
|
||||
.AppendLine("}");
|
||||
}
|
||||
else if (SymbolEqualityComparer.Default.Equals(underlyingType?.OriginalDefinition, dictionary))
|
||||
{
|
||||
ITypeSymbol? x1 = (underlyingType as INamedTypeSymbol)?.TypeArguments[0];
|
||||
ITypeSymbol? x2 = (underlyingType as INamedTypeSymbol)?.TypeArguments[1];
|
||||
sb
|
||||
.AppendLine($"public partial class {lName}Patch : DictionaryFramePatch<{x1?.ToDisplayString()}, {x2?.ToDisplayString()}>")
|
||||
.AppendLine("{")
|
||||
.AppendLine(" public override void Patch(IPatchableFrame frame)")
|
||||
.AppendLine(" {")
|
||||
.AppendLine($" if(frame is not {inf.InterfaceFillName} sFrame)")
|
||||
.AppendLine(" return;")
|
||||
.AppendLine($" switch (sFrame.{underlying.Identifier.ToString()}.UpdateMethod )")
|
||||
.AppendLine(" {")
|
||||
.AppendLine(" case UpdateMethods.None:")
|
||||
.AppendLine(" return;")
|
||||
.AppendLine(" case UpdateMethods.Update:")
|
||||
.AppendLine($" foreach({x1?.ToDisplayString()} x in Updates.Keys)")
|
||||
.AppendLine($" sFrame.{underlying.Identifier.ToString()}[x] = Updates[x];")
|
||||
.AppendLine(" return;")
|
||||
.AppendLine(" case UpdateMethods.Replace:")
|
||||
.AppendLine($" sFrame.{underlying.Identifier.ToString()}.Data = Updates;")
|
||||
.AppendLine(" return;")
|
||||
.AppendLine(" case UpdateMethods.Custom:")
|
||||
.AppendLine($" sFrame.{underlying.Identifier.ToString()}.CustomUpdate(Updates);")
|
||||
.AppendLine(" return;")
|
||||
.AppendLine(" default:")
|
||||
.AppendLine(" return;")
|
||||
.AppendLine(" }")
|
||||
.AppendLine(" }")
|
||||
.AppendLine("}");
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
sb
|
||||
|
||||
.AppendLine($"public partial class {lName}Patch : FramePatch<{underlyingType?.ToDisplayString()}>")
|
||||
.AppendLine("{")
|
||||
.AppendLine(" public override void Patch(IPatchableFrame frame)")
|
||||
.AppendLine(" {")
|
||||
.AppendLine($" if(frame is not {inf.InterfaceFillName} sFrame)")
|
||||
.AppendLine(" return;")
|
||||
.AppendLine($" sFrame.{underlying.Identifier.ToString()} = Updates;")
|
||||
.AppendLine(" }")
|
||||
.AppendLine("}");
|
||||
}
|
||||
context.AddSource($"{lName}Patch.g.cs", sb.ToString());
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
14
src/InterfaceInfo.cs
Normal file
14
src/InterfaceInfo.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
|
||||
namespace Polonium.Generators;
|
||||
|
||||
public class InterfaceInfo
|
||||
{
|
||||
public INamedTypeSymbol Symbol { get; set; }
|
||||
public InterfaceDeclarationSyntax DeclarationSyntax { get; set; }
|
||||
public string InterfaceName { get; set; }
|
||||
public string InterfaceFillName { get; set; }
|
||||
public string Namespace { get; set; }
|
||||
public string Path { get; set; }
|
||||
}
|
||||
Reference in New Issue
Block a user