rough outline

Signed-off-by: Timothy Schenk <admin@rainote.dev>
This commit is contained in:
Timothy Schenk 2025-01-20 00:47:51 +01:00
parent b6cf60e909
commit da32bd5957
Signed by: rainote
SSH key fingerprint: SHA256:pnkNSDwpAnaip00xaZlVFHKKsS7T8UtOomMzvs0yITE
6 changed files with 110 additions and 93 deletions

View file

@ -0,0 +1,5 @@
namespace RaiNote.PacketMediator;
internal record IntermediateHandlerAndStructTuple(
IntermediatePacketHandlerData HandlerData,
IntermediatePacketStructData StructData);

View file

@ -1,7 +1,5 @@
// Licensed to Timothy Schenk under the Apache 2.0 License.
using Microsoft.CodeAnalysis;
namespace RaiNote.PacketMediator;
internal class IntermediatePacketHandlerData {
@ -14,16 +12,3 @@ internal class IntermediatePacketHandlerData {
public string PacketHandlerIdentifier { get; set; }
public IntermediatePacketStructHandlerData? PacketStructHandlerData { get; set; }
}
internal record IntermediatePacketStructData(
Location SymbolLocation,
string PacketStructFullIdentifier,
string EnumValue,
string EnumTypeFullIdentifier,
string EnumMemberIdentifier,
string EnumMaxValue,
bool ImplementsInterface);
internal record IntermediateHandlerAndStructTuple(
IntermediatePacketHandlerData HandlerData,
IntermediatePacketStructData StructData);

View file

@ -0,0 +1,12 @@
using Microsoft.CodeAnalysis;
namespace RaiNote.PacketMediator;
internal record IntermediatePacketStructData(
Location SymbolLocation,
string PacketStructFullIdentifier,
string? EnumValue,
string EnumTypeFullIdentifier,
string EnumMemberIdentifier,
string? EnumMaxValue,
bool ImplementsInterface);

View file

@ -88,69 +88,7 @@ public class PacketMediatorGenerator : IIncrementalGenerator {
var structsWithAttributes = context.SyntaxProvider
.CreateSyntaxProvider(
predicate: (node, _) => node is StructDeclarationSyntax { AttributeLists.Count: > 0 },
transform: (syntaxContext, cancellationToken) => {
var structDeclaration = (StructDeclarationSyntax)syntaxContext.Node;
var model = syntaxContext.SemanticModel;
var symbol =
ModelExtensions.GetDeclaredSymbol(model, structDeclaration,
cancellationToken: cancellationToken) as
INamedTypeSymbol;
var requiredInterfaces = new[] {
"IPacket", "IIncomingPacket", "IOutgoingPacket", "IBidirectionalPacket"
};
var implementsInterface = symbol != null && symbol.AllInterfaces
.Any(i => requiredInterfaces.Contains(i.Name, StringComparer.Ordinal));
if (!implementsInterface) {
// TODO: https://github.com/dotnet/roslyn/blob/main/docs/features/incremental-generators.cookbook.md#issue-diagnostics
// or Analyzer
var diagnostic = Diagnostic.Create(_rpmGen001Diagnostic, symbol?.Locations.First(),
symbol?.ToDisplayString());
}
// Check for the marker attribute
var attribute = symbol?.GetAttributes()
.FirstOrDefault(attr => {
var attrClass = attr.AttributeClass;
while (attrClass != null) {
if (string.Equals(attrClass.Name, "PacketIdAttribute", StringComparison.Ordinal) &&
string.Equals(attrClass.ContainingNamespace.ToDisplayString(),
"RaiNote.PacketMediator", StringComparison.Ordinal)) {
return true;
}
attrClass = attrClass.BaseType;
}
return false;
});
if (attribute == null) {
return null;
}
var attributeConstructorArgument = attribute.ConstructorArguments[0];
var enumType = attributeConstructorArgument.Type;
var enumValue = attributeConstructorArgument.Value;
var enumMember = enumType?.GetMembers()
.OfType<IFieldSymbol>()
.FirstOrDefault(f => f.ConstantValue?.Equals(enumValue) == true);
var enumMaxValue = enumType?.GetMembers()
.OfType<IFieldSymbol>().Max(x => x.ConstantValue);
if (symbol == null || enumMember == null || enumMaxValue == null || enumType == null ||
enumValue == null)
return null;
var intermediatePacketStructData = new IntermediatePacketStructData(symbol.Locations.First(),
symbol.ToDisplayString(),
enumValue.ToString(),
enumType.ToDisplayString(),
enumMember.ToDisplayString(),
enumMaxValue.ToString(), implementsInterface);
return intermediatePacketStructData;
})
transform: TransformPacketStructs)
.Where(result => result != null);
var packetHandlerValues = context.SyntaxProvider.CreateSyntaxProvider(
@ -170,9 +108,11 @@ public class PacketMediatorGenerator : IIncrementalGenerator {
if (handlerData == null)
return null;
var structs = structDatas.Where(sData => {
if (handlerData.PacketStructHandlerData == null)
return false;
var equals =
sData != null && sData.PacketStructFullIdentifier.Equals(handlerData.PacketStructHandlerData
?.PacketStructFullIdentifier);
.PacketStructFullIdentifier, StringComparison.Ordinal);
return equals;
}).FirstOrDefault();
@ -188,7 +128,8 @@ public class PacketMediatorGenerator : IIncrementalGenerator {
// Collect and generate the dictionary
context.RegisterSourceOutput(combinedResults, (ctx, result) => {
var combinedInfo = result.ToList();
var combinedInfo = result.Where(x => x != null).Select(IntermediateHandlerAndStructTuple (x) => x!)
.ToList();
if (combinedInfo.Count <= 0)
return;
@ -198,7 +139,8 @@ public class PacketMediatorGenerator : IIncrementalGenerator {
var intermediatePacketStructData = combinedInfo.First()?.StructData;
if (intermediatePacketStructData?.EnumMaxValue == null)
return;
var highestValue = long.Parse(intermediatePacketStructData.EnumMaxValue);
var highestValue = long.Parse(intermediatePacketStructData.EnumMaxValue, NumberStyles.Integer,
new NumberFormatInfo());
var ms = new MemoryStream();
var sw = new StreamWriter(ms, Encoding.UTF8);
sw.AutoFlush = true;
@ -216,11 +158,13 @@ public class PacketMediatorGenerator : IIncrementalGenerator {
{
""");
var valueTuples = combinedInfo.Select((value, i) => (value, i));
foreach (var ((handlerData, packetStructData), i) in valueTuples) {
var tempVal = long.Parse(packetStructData.EnumValue,
new NumberFormatInfo());
usedValues.Add(tempVal);
foreach (var (handlerData, packetStructData) in combinedInfo) {
if (packetStructData.EnumValue != null) {
var tempVal = long.Parse(packetStructData.EnumValue,
new NumberFormatInfo());
usedValues.Add(tempVal);
}
sw.WriteLine($"""
case {packetStructData.EnumMemberIdentifier}:
var packet = new {handlerData.PacketHandlerIdentifier}();
@ -279,6 +223,67 @@ public class PacketMediatorGenerator : IIncrementalGenerator {
});
}
private IntermediatePacketStructData? TransformPacketStructs(GeneratorSyntaxContext syntaxContext,
CancellationToken cancellationToken) {
var structDeclaration = (StructDeclarationSyntax)syntaxContext.Node;
var model = syntaxContext.SemanticModel;
var symbol =
ModelExtensions.GetDeclaredSymbol(model, structDeclaration, cancellationToken: cancellationToken) as
INamedTypeSymbol;
var requiredInterfaces = new[] { "IPacket", "IIncomingPacket", "IOutgoingPacket", "IBidirectionalPacket" };
var implementsInterface = symbol != null &&
symbol.AllInterfaces.Any(i =>
requiredInterfaces.Contains(i.Name, StringComparer.Ordinal));
if (!implementsInterface) {
// TODO: https://github.com/dotnet/roslyn/blob/main/docs/features/incremental-generators.cookbook.md#issue-diagnostics
// or Analyzer
/*var diagnostic = Diagnostic.Create(_rpmGen001Diagnostic, symbol?.Locations.First(),
symbol?.ToDisplayString());*/
}
// Check for the marker attribute
var attribute = symbol?.GetAttributes()
.FirstOrDefault(attr => {
var attrClass = attr.AttributeClass;
while (attrClass != null) {
if (string.Equals(attrClass.Name, "PacketIdAttribute", StringComparison.Ordinal) &&
attrClass.ContainingNamespace != null &&
string.Equals(attrClass.ContainingNamespace.ToDisplayString(), "RaiNote.PacketMediator",
StringComparison.Ordinal)) {
return true;
}
attrClass = attrClass.BaseType;
}
return false;
});
if (attribute == null) {
return null;
}
var attributeConstructorArgument = attribute.ConstructorArguments[0];
var enumType = attributeConstructorArgument.Type;
var enumValue = attributeConstructorArgument.Value;
var enumMember = enumType?.GetMembers()
.OfType<IFieldSymbol>()
.FirstOrDefault(f => f.ConstantValue?.Equals(enumValue) == true);
var enumMaxValue = enumType?.GetMembers()
.OfType<IFieldSymbol>()
.Max(x => x.ConstantValue);
if (symbol == null || enumMember == null || enumMaxValue == null || enumType == null ||
enumValue == null) return null;
var intermediatePacketStructData = new IntermediatePacketStructData(symbol.Locations.First(),
symbol.ToDisplayString(), enumValue.ToString(), enumType.ToDisplayString(), enumMember.ToDisplayString(),
enumMaxValue.ToString(), implementsInterface);
return intermediatePacketStructData;
}
private static IntermediatePacketHandlerData? TransformPacketHandlers(GeneratorSyntaxContext syntaxContext,
CancellationToken cancellationToken) {
var classDeclaration = (ClassDeclarationSyntax)syntaxContext.Node;
@ -286,8 +291,8 @@ public class PacketMediatorGenerator : IIncrementalGenerator {
var symbol =
ModelExtensions.GetDeclaredSymbol(model, classDeclaration, cancellationToken: cancellationToken) as
INamedTypeSymbol;
var packetStruct = (symbol.Interfaces.Select(interfaceSyntax => {
if (!interfaceSyntax.Name.Equals("IPacketHandler")) {
var packetStruct = (symbol?.Interfaces.Select(interfaceSyntax => {
if (!interfaceSyntax.Name.Equals("IPacketHandler", StringComparison.Ordinal)) {
return null;
}
@ -313,10 +318,10 @@ public class PacketMediatorGenerator : IIncrementalGenerator {
Expression: MemberAccessExpressionSyntax { Name: { } nameSyntax }
} invocation &&
context.SemanticModel.GetOperation(context.Node,
cancellationToken) is IInvocationOperation targetOperation &&
targetOperation.TargetMethod is
{ Name: "AddPacketHandlerServices", ContainingNamespace: { Name: "RaiNote.PacketMediator" } }
) {
cancellationToken) is IInvocationOperation {
TargetMethod:
{ Name: "AddPacketHandlerServices", ContainingNamespace.Name: "RaiNote.PacketMediator" }
}) {
#pragma warning disable RSEXPERIMENTAL002 // / Experimental interceptable location API
if (context.SemanticModel.GetInterceptableLocation(invocation, cancellationToken: cancellationToken) is
{ } location) {
@ -338,6 +343,6 @@ public class PacketMediatorGenerator : IIncrementalGenerator {
}
#pragma warning disable RSEXPERIMENTAL002 // / Experimental interceptable location API
public record CandidateInvocation(InterceptableLocation Location);
private record CandidateInvocation(InterceptableLocation Location);
#pragma warning restore RSEXPERIMENTAL002
}

View file

@ -48,6 +48,14 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Roslynator.CodeAnalysis.Analyzers" Version="4.12.10">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Roslynator.Formatting.Analyzers" Version="4.12.10">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
</Project>

View file

@ -0,0 +1,2 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeInspection/Daemon/ConfigureAwaitAnalysisMode/@EntryValue">Library</s:String></wpf:ResourceDictionary>