Generation Update

A few changes to start adding more generation methods.
This commit is contained in:
JacobTech 2023-12-22 11:20:45 -05:00
parent dd05aca370
commit 0cf7404b85
6 changed files with 171 additions and 2 deletions

View File

@ -0,0 +1,12 @@
namespace ServerDatabase.SourceGenerator;
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
public sealed class JsonIgnoreIndexAttribute : Attribute
{
public JsonIgnoreIndexAttribute(int index = 0)
{
this.Index = index;
}
public int Index { get; private set; } = 0;
}

View File

@ -0,0 +1,14 @@
namespace ServerDatabase.SourceGenerator;
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
public sealed class JsonSubObjectAttribute : Attribute
{
public JsonSubObjectAttribute(Type type, int index = 0)
{
this.Type = type;
this.Index = index;
}
public int Index { get; private set; } = 0;
public Type Type { get; private set; }
}

View File

@ -0,0 +1,14 @@
namespace ServerDatabase.SourceGenerator;
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
public sealed class JsonTableRowAttribute : Attribute
{
public JsonTableRowAttribute(Type type, int index = 0)
{
this.Type = type;
this.Index = index;
}
public int Index { get; private set; } = 0;
public Type Type { get; private set; }
}

View File

@ -0,0 +1,130 @@
using System.Diagnostics;
using System.Reflection;
using System.Text;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
using TypeInfo = Microsoft.CodeAnalysis.TypeInfo;
namespace ServerDatabase.SourceGenerator;
[Generator]
public class JsonTableRowGenerator : ISourceGenerator
{
public void Initialize(GeneratorInitializationContext context)
{
#if DEBUG
if (!Debugger.IsAttached) Debugger.Launch();
#endif
}
public void Execute(GeneratorExecutionContext context)
{
try
{
INamedTypeSymbol? attributeSymbol = context.Compilation.GetTypeByMetadataName(typeof(JsonTableRowAttribute).FullName);
IEnumerable<SyntaxTree> classWithAttributes = context.Compilation.SyntaxTrees.Where(st => st.GetRoot().DescendantNodes().OfType<ClassDeclarationSyntax>()
.Any(p => p.DescendantNodes().OfType<AttributeSyntax>().Any()));
foreach (SyntaxTree? tree in classWithAttributes)
{
if (tree is null) continue;
SemanticModel semanticModel = context.Compilation.GetSemanticModel(tree);
foreach (ClassDeclarationSyntax? declaredClass in tree.GetRoot().DescendantNodes().OfType<ClassDeclarationSyntax>().Where(cd => cd.DescendantNodes().OfType<AttributeSyntax>().Any()))
{
if (declaredClass is null) continue;
List<SyntaxToken>? nodes = declaredClass
.DescendantNodes()
.OfType<AttributeSyntax>()
.FirstOrDefault(a => a.DescendantTokens().Any(dt => dt.IsKind(SyntaxKind.IdentifierToken) && dt.Parent is not null && semanticModel.GetTypeInfo(dt.Parent).Type is not null && semanticModel.GetTypeInfo(dt.Parent).Type.Name == attributeSymbol.Name))
?.DescendantTokens()
?.Where(dt => dt.IsKind(SyntaxKind.IdentifierToken))
?.ToList();
if(nodes == null)
{
continue;
}
TypeInfo relatedClass = semanticModel.GetTypeInfo(nodes.Last().Parent);
StringBuilder generatedClass = this.GenerateClass(tree.GetRoot().DescendantNodes().OfType<FileScopedNamespaceDeclarationSyntax>().First().Name.ToString(), declaredClass);
foreach(IPropertySymbol? classProperty in relatedClass.Type.GetMembers().OfType<IPropertySymbol>())
{
this.GenerateProperty(classProperty, ref generatedClass);
}
this.CloseClass(generatedClass);
context.AddSource($"{declaredClass.Identifier}_{relatedClass.Type.Name}.g.cs", SourceText.From(generatedClass.ToString(), Encoding.UTF8));
}
}
}
catch (Exception e)
{
context.AddSource("teste.g.cs", SourceText.From(@$"// <auto-generated/>
using System;
namespace ServerDatabase.SourceGenerator.Generated
{{
public class bobe
{{
public string e = @""{e}"";
}}
}}", Encoding.UTF8));
}
return;
}
private void GenerateProperty(IPropertySymbol prop, ref StringBuilder builder)
{
prop.GetAttributes().SelectMany(s => s.NamedArguments);
string bad = prop.Type.ToString();
Console.WriteLine(prop);
bad = bad.Replace("ServerDatabase.TableColumn<", "");
bad = bad.Remove(bad.LastIndexOf('>'));
if (bad.ToLower() == "byte[]") bad = "string";
EqualsValueClauseSyntax? equalsSyntax = prop.DeclaringSyntaxReferences[0].GetSyntax() switch
{
PropertyDeclarationSyntax property => property.Initializer,
VariableDeclaratorSyntax variable => variable.Initializer,
_ => throw new Exception("Unknown declaration syntax")
};
// If the property/field has an initializer
if (equalsSyntax is not null)
{
string valueAsStr = equalsSyntax.Value.ToString().Split('"')[1];
builder.AppendLine($" [JsonInclude]");
builder.AppendLine($" [JsonPropertyName(\"{valueAsStr}\")]");
builder.AppendLine($" public {bad} {prop.Name} {{ get; set; }}");
}
}
private StringBuilder GenerateClass(string n, ClassDeclarationSyntax og)
{
StringBuilder sb = new StringBuilder();
sb.Append(@$"// <auto-generated/>
using System;
namespace {n}
{{
public partial class " + og.Identifier);
sb.Append(@"
{
");
return sb;
}
private void CloseClass(StringBuilder generatedClass)
{
generatedClass.Append(
@" }
}");
}
}

View File

@ -6,7 +6,7 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<TargetFramework>netstandard2.0</TargetFramework> <TargetFramework>netstandard2.0</TargetFramework>
<IncludeBuildOutput>true</IncludeBuildOutput> <IncludeBuildOutput>true</IncludeBuildOutput>
<Version>1.0.1</Version> <Version>1.0.2-alpha10</Version>
<Title>Server Database Source Generator</Title> <Title>Server Database Source Generator</Title>
<Authors>JacobTech</Authors> <Authors>JacobTech</Authors>
</PropertyGroup> </PropertyGroup>

View File

@ -59,7 +59,6 @@ public class TableRowGenerator : ISourceGenerator
this.CloseClass(generatedClass); this.CloseClass(generatedClass);
context.AddSource($"{declaredClass.Identifier}_{relatedClass.Type.Name}.g.cs", SourceText.From(generatedClass.ToString(), Encoding.UTF8)); context.AddSource($"{declaredClass.Identifier}_{relatedClass.Type.Name}.g.cs", SourceText.From(generatedClass.ToString(), Encoding.UTF8));
//context.AddSource($"{declaredClass.Identifier}_{relatedClass.Type.Name}_goooddddd.g.cs", SourceText.From(generatedClass.ToString().Replace("partial ", "").Replace(declaredClass.Identifier.ToString(), declaredClass.Identifier.ToString() + "GODDD"), Encoding.UTF8));
} }
} }
} }