From 6386a9ec165b60493750da2b9c3bf4a801fea680 Mon Sep 17 00:00:00 2001 From: Timothy Schenk Date: Sat, 18 Jan 2025 17:48:33 +0100 Subject: [PATCH] rough outline --- .../Examples.cs | 1 - .../PacketMediator.Generator.Tests.csproj | 2 +- ...SourceGeneratorWithAdditionalFilesTests.cs | 3 +- .../SourceGeneratorWithAttributesTests.cs | 1 + .../PacketMediator.Generator.csproj | 25 --- .../PacketMediatorGenerator.cs | 164 ------------------ .../Properties/launchSettings.json | 9 - .../PacketMediator.Generator/Readme.md | 29 ---- PacketMediator.Samples/Program.cs | 5 - PacketMediator.slnx | 1 - 10 files changed, 3 insertions(+), 237 deletions(-) delete mode 100644 PacketMediator.Generator/PacketMediator.Generator/PacketMediator.Generator.csproj delete mode 100644 PacketMediator.Generator/PacketMediator.Generator/PacketMediatorGenerator.cs delete mode 100644 PacketMediator.Generator/PacketMediator.Generator/Properties/launchSettings.json delete mode 100644 PacketMediator.Generator/PacketMediator.Generator/Readme.md diff --git a/PacketMediator.Generator/PacketMediator.Generator.Sample/Examples.cs b/PacketMediator.Generator/PacketMediator.Generator.Sample/Examples.cs index 1e2f118..226bf9e 100644 --- a/PacketMediator.Generator/PacketMediator.Generator.Sample/Examples.cs +++ b/PacketMediator.Generator/PacketMediator.Generator.Sample/Examples.cs @@ -1,5 +1,4 @@ using System; -using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using RaiNote.PacketMediator; diff --git a/PacketMediator.Generator/PacketMediator.Generator.Tests/PacketMediator.Generator.Tests.csproj b/PacketMediator.Generator/PacketMediator.Generator.Tests/PacketMediator.Generator.Tests.csproj index 183ac8b..7b66ad0 100644 --- a/PacketMediator.Generator/PacketMediator.Generator.Tests/PacketMediator.Generator.Tests.csproj +++ b/PacketMediator.Generator/PacketMediator.Generator.Tests/PacketMediator.Generator.Tests.csproj @@ -21,7 +21,7 @@ - + diff --git a/PacketMediator.Generator/PacketMediator.Generator.Tests/SourceGeneratorWithAdditionalFilesTests.cs b/PacketMediator.Generator/PacketMediator.Generator.Tests/SourceGeneratorWithAdditionalFilesTests.cs index bc86d5c..d27fc80 100644 --- a/PacketMediator.Generator/PacketMediator.Generator.Tests/SourceGeneratorWithAdditionalFilesTests.cs +++ b/PacketMediator.Generator/PacketMediator.Generator.Tests/SourceGeneratorWithAdditionalFilesTests.cs @@ -1,9 +1,8 @@ -using System.Collections.Immutable; using System.IO; using System.Linq; using Microsoft.CodeAnalysis; -using PacketMediator.Generator.Tests.Utils; using Microsoft.CodeAnalysis.CSharp; +using RaiNote.PacketMediator; using Xunit; namespace PacketMediator.Generator.Tests; diff --git a/PacketMediator.Generator/PacketMediator.Generator.Tests/SourceGeneratorWithAttributesTests.cs b/PacketMediator.Generator/PacketMediator.Generator.Tests/SourceGeneratorWithAttributesTests.cs index a222404..5da808d 100644 --- a/PacketMediator.Generator/PacketMediator.Generator.Tests/SourceGeneratorWithAttributesTests.cs +++ b/PacketMediator.Generator/PacketMediator.Generator.Tests/SourceGeneratorWithAttributesTests.cs @@ -1,6 +1,7 @@ using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; +using RaiNote.PacketMediator; using Xunit; namespace PacketMediator.Generator.Tests; diff --git a/PacketMediator.Generator/PacketMediator.Generator/PacketMediator.Generator.csproj b/PacketMediator.Generator/PacketMediator.Generator/PacketMediator.Generator.csproj deleted file mode 100644 index 3d0d4f6..0000000 --- a/PacketMediator.Generator/PacketMediator.Generator/PacketMediator.Generator.csproj +++ /dev/null @@ -1,25 +0,0 @@ - - - - netstandard2.0 - false - enable - latest - - true - true - - PacketMediator.Generator - PacketMediator.Generator - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - diff --git a/PacketMediator.Generator/PacketMediator.Generator/PacketMediatorGenerator.cs b/PacketMediator.Generator/PacketMediator.Generator/PacketMediatorGenerator.cs deleted file mode 100644 index 5e917ed..0000000 --- a/PacketMediator.Generator/PacketMediator.Generator/PacketMediatorGenerator.cs +++ /dev/null @@ -1,164 +0,0 @@ -// Licensed to Timothy Schenk under the Apache 2.0 License. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Text; - -namespace PacketMediator.Generator; - -[Generator] -public class PacketMediatorGenerator : IIncrementalGenerator { - public void Initialize(IncrementalGeneratorInitializationContext context) { - context.RegisterPostInitializationOutput(ctx => { - ctx.AddSource("PacketMediatorStatic.g.cs", SourceText.From(@" -using System; -using System.Diagnostics; - -namespace RaiNote.PacketMediator; -[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, Inherited = false)] -public abstract class PacketIdAttribute : Attribute where TPacketIdEnum : Enum -{ - protected PacketIdAttribute(TPacketIdEnum code) - { - Code = code; - } - - public TPacketIdEnum Code { get; } -} -public interface IPacket; -public interface IIncomingPacket : IPacket -{ - public void Deserialize(byte[] data); -} -public interface IOutgoingPacket : IPacket -{ - public byte[] Serialize(); -} - -public interface IBidirectionalPacket : IOutgoingPacket, IIncomingPacket; - -public interface IPacketHandler : IPacketHandler - where TIncomingPacket : IIncomingPacket -{ - async Task IPacketHandler.TryHandleAsync(IIncomingPacket packet, TSession session, - CancellationToken cancellationToken) - { - if (packet is not TIncomingPacket tPacket) - { - return false; - } - - using var activity = new ActivitySource(nameof(PacketMediator)).StartActivity(nameof(HandleAsync)); - activity?.AddTag(""Handler"", ToString()); - activity?.AddTag(""Packet"", packet.ToString()); - await HandleAsync(tPacket, session, cancellationToken); - - return true; - } - - [UsedImplicitly(ImplicitUseTargetFlags.WithInheritors)] - public Task HandleAsync(TIncomingPacket packet, TSession session, CancellationToken cancellationToken); -} - -public interface IPacketHandler -{ - Task TryHandleAsync(IIncomingPacket packet, TSession session, CancellationToken cancellationToken); -} - -", Encoding.UTF8)); - }); - // Find all struct declarations - var structsWithAttributes = context.SyntaxProvider - .CreateSyntaxProvider( - predicate: (node, _) => node is StructDeclarationSyntax structSyntax && - structSyntax.AttributeLists.Count > 0, - transform: (syntaxContext, _) => { - var structDeclaration = (StructDeclarationSyntax)syntaxContext.Node; - var model = syntaxContext.SemanticModel; - var symbol = model.GetDeclaredSymbol(structDeclaration) as INamedTypeSymbol; - var requiredInterfaces = new[] { "IPacket", "IIncomingPacket", "IOutgoingPacket", "IBidirectionalPacket" }; - var implementsInterface = symbol != null && symbol.AllInterfaces - .Any(i => requiredInterfaces.Contains(i.Name)); - // Check for the marker attribute - var attribute = symbol?.GetAttributes() - .FirstOrDefault(attr => - { - var attrClass = attr.AttributeClass; - while (attrClass != null) - { - if (attrClass.Name == "PacketIdAttribute" && attrClass.ContainingNamespace.ToDisplayString() == "PacketMediator.Generator") - { - return true; - } - attrClass = attrClass.BaseType; - } - return false; - }); - if (attribute == null) { - return default; - } - - var attributeConstructorArgument = attribute.ConstructorArguments[0]; - var enumType = attributeConstructorArgument.Type; - var enumValue = attributeConstructorArgument.Value; - var enumMember = enumType?.GetMembers() - .OfType() - .FirstOrDefault(f => f.ConstantValue?.Equals(enumValue) == true); - var enumMaxValue = enumType?.GetMembers() - .OfType().Max(x => x.ConstantValue); - return (symbol, structDeclaration.Identifier.Text, value: enumValue,enumType,enumMember,enumMaxValue, implementsInterface); - - }) - .Where(result => result != default); - - // Collect and generate the dictionary - context.RegisterSourceOutput(structsWithAttributes.Collect(), (ctx, result) => { - var usedValues = new List(); - var highestValue = long.Parse(result.FirstOrDefault().enumMaxValue?.ToString() ?? throw new InvalidOperationException()); - - var sb = new StringBuilder(); - sb.AppendLine("using System.Collections.Generic;"); - sb.AppendLine(); - sb.AppendLine("public static class StructDictionary"); - sb.AppendLine("{"); - var enumTypeString = result.FirstOrDefault().enumType?.ToDisplayString(); - sb.AppendLine($" public static readonly Dictionary Values = new()"); - sb.AppendLine(" {"); - - foreach (var (symbol, structName, value, _,enumMember,_, implementsInterface) in result) { - if (!implementsInterface) { - var diagnostic = Diagnostic.Create( - new DiagnosticDescriptor( - id: "MYGEN001", - title: "Struct does not implement required interface", - messageFormat: $"The struct '{{0}}' must implement at least one of: \"IPacket\", \"IIncomingPacket\", \"IOutgoingPacket\", \"IBidirectionalPacket\" ", - category: "SourceGenerator", - DiagnosticSeverity.Error, - isEnabledByDefault: true), - symbol?.Locations.FirstOrDefault(), structName); - - ctx.ReportDiagnostic(diagnostic); - continue; - } - var tempVal = long.Parse(value?.ToString() ?? throw new InvalidOperationException()); - usedValues.Add(tempVal); - sb.AppendLine($" {{ \"{structName}{highestValue}\", {enumMember} }},"); - } - - - for (long i = 0; i <= highestValue; i++) { - if(!usedValues.Contains(i)) - sb.AppendLine($" {{ \"Dead\", (({enumTypeString}){i}) }},"); - } - - sb.AppendLine(" };"); - sb.AppendLine("}"); - - ctx.AddSource("StructDictionary.g.cs", SourceText.From(sb.ToString(), Encoding.UTF8)); - }); - } -} diff --git a/PacketMediator.Generator/PacketMediator.Generator/Properties/launchSettings.json b/PacketMediator.Generator/PacketMediator.Generator/Properties/launchSettings.json deleted file mode 100644 index b38aac5..0000000 --- a/PacketMediator.Generator/PacketMediator.Generator/Properties/launchSettings.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "$schema": "https://json.schemastore.org/launchsettings.json", - "profiles": { - "DebugRoslynSourceGenerator": { - "commandName": "DebugRoslynComponent", - "targetProject": "../PacketMediator.Generator.Sample/PacketMediator.Generator.Sample.csproj" - } - } -} diff --git a/PacketMediator.Generator/PacketMediator.Generator/Readme.md b/PacketMediator.Generator/PacketMediator.Generator/Readme.md deleted file mode 100644 index a0d1ef8..0000000 --- a/PacketMediator.Generator/PacketMediator.Generator/Readme.md +++ /dev/null @@ -1,29 +0,0 @@ -# Roslyn Source Generators Sample - -A set of three projects that illustrates Roslyn source generators. Enjoy this template to learn from and modify source generators for your own needs. - -## Content -### PacketMediator.Generator -A .NET Standard project with implementations of sample source generators. -**You must build this project to see the result (generated code) in the IDE.** - -- [SampleSourceGenerator.cs](SampleSourceGenerator.cs): A source generator that creates C# classes based on a text file (in this case, Domain Driven Design ubiquitous language registry). -- [SampleIncrementalSourceGenerator.cs](SampleIncrementalSourceGenerator.cs): A source generator that creates a custom report based on class properties. The target class should be annotated with the `Generators.ReportAttribute` attribute. - -### PacketMediator.Generator.Sample -A project that references source generators. Note the parameters of `ProjectReference` in [PacketMediator.Generator.Sample.csproj](../PacketMediator.Generator.Sample/PacketMediator.Generator.Sample.csproj), they make sure that the project is referenced as a set of source generators. - -### PacketMediator.Generator.Tests -Unit tests for source generators. The easiest way to develop language-related features is to start with unit tests. - -## How To? -### How to debug? -- Use the [launchSettings.json](Properties/launchSettings.json) profile. -- Debug tests. - -### How can I determine which syntax nodes I should expect? -Consider installing the Roslyn syntax tree viewer plugin [Rossynt](https://plugins.jetbrains.com/plugin/16902-rossynt/). - -### How to learn more about wiring source generators? -Watch the walkthrough video: [Let’s Build an Incremental Source Generator With Roslyn, by Stefan Pölz](https://youtu.be/azJm_Y2nbAI) -The complete set of information is available in [Source Generators Cookbook](https://github.com/dotnet/roslyn/blob/main/docs/features/source-generators.cookbook.md). \ No newline at end of file diff --git a/PacketMediator.Samples/Program.cs b/PacketMediator.Samples/Program.cs index 2f1a43f..cf121b5 100644 --- a/PacketMediator.Samples/Program.cs +++ b/PacketMediator.Samples/Program.cs @@ -1,8 +1,3 @@ // Licensed to Timothy Schenk under the Apache 2.0 License. -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Text; - Console.WriteLine("Hello, World!"); - -Workspace workspace = Workspace. diff --git a/PacketMediator.slnx b/PacketMediator.slnx index f8c4ba9..85099de 100644 --- a/PacketMediator.slnx +++ b/PacketMediator.slnx @@ -1,7 +1,6 @@  -