From 168936d9ffe8f1d525e049b875facbd5b72d74f6 Mon Sep 17 00:00:00 2001 From: neuecc Date: Sat, 15 Apr 2023 18:45:52 +0900 Subject: [PATCH] complete GroupedNativeMethodsGenerator --- GroupedNativeMethodsGenerator/Class1.cs | 71 -------- .../GroupedNativeMethodsGenerator.cs | 168 ++++++++++++++++++ csbindgen/src/emitter.rs | 1 + dotnet-sandbox/BindingGroupExtensions.cs | 66 ++++--- dotnet-sandbox/CsbindgenDotnetConsoleApp.sln | 25 --- dotnet-sandbox/NativeMethods.cs | 1 + dotnet-sandbox/libphysx_csbindgen.cs | 1 + dotnet-sandbox/libpng16_csbindgen.cs | 1 + dotnet-sandbox/lz4_bindgen.cs | 1 + 9 files changed, 203 insertions(+), 132 deletions(-) delete mode 100644 GroupedNativeMethodsGenerator/Class1.cs create mode 100644 GroupedNativeMethodsGenerator/GroupedNativeMethodsGenerator.cs delete mode 100644 dotnet-sandbox/CsbindgenDotnetConsoleApp.sln diff --git a/GroupedNativeMethodsGenerator/Class1.cs b/GroupedNativeMethodsGenerator/Class1.cs deleted file mode 100644 index 3e15bb0..0000000 --- a/GroupedNativeMethodsGenerator/Class1.cs +++ /dev/null @@ -1,71 +0,0 @@ -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp.Syntax; - -namespace GroupedNativeMethodsGenerator; - -[Generator(LanguageNames.CSharp)] -public partial class GroupedNativeMethodsGenerator : IIncrementalGenerator -{ - public void Initialize(IncrementalGeneratorInitializationContext context) - { - context.RegisterPostInitializationOutput(ctx => - { - ctx.AddSource("GroupedNativeMethodsGenerator.Attribute.cs", """ -namespace GroupedNativeMethodsGenerator -{ - [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] - internal sealed class GroupedNativeMethodsAttribute : Attribute - { - public string RemovePrefix { get; set; } = ""; - public bool RemoveUntilTypeName { get; set; } = true; - - /// Fix method name as C# Style, e.g.: foo_bar_baz() -> FooBarBaz() - public bool FixMethodName { get; set; } = true; - } -} -"""); - }); - - var source = context.SyntaxProvider.ForAttributeWithMetadataName("GroupedNativeMethodsGenerator.GroupedNativeMethodsAttribute", - (node, token) => node is ClassDeclarationSyntax, - (ctx, token) => ctx); - - context.RegisterSourceOutput(source, Emit); - } - - static void Emit(SourceProductionContext context, GeneratorAttributeSyntaxContext source) - { - var typeSymbol = (INamedTypeSymbol)source.TargetSymbol; - var typeNode = (TypeDeclarationSyntax)source.TargetNode; - - var ns = typeSymbol.ContainingNamespace.IsGlobalNamespace - ? "" - : $"namespace {typeSymbol.ContainingNamespace};"; - - var fullType = typeSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat) - .Replace("global::", "") - .Replace("<", "_") - .Replace(">", "_"); - - var methods = typeSymbol.GetMembers() - .OfType(); - - - - // context.AddSource($"{fullType}.SampleGenerator.g.cs", code); - } -} - -// TODO:... -public static class DiagnosticDescriptors -{ - const string Category = "SampleGenerator"; - - public static readonly DiagnosticDescriptor ExistsOverrideToString = new( - id: "SAMPLE001", - title: "ToString override", - messageFormat: "The GenerateToString class '{0}' has ToString override but it is not allowed.", - category: Category, - defaultSeverity: DiagnosticSeverity.Error, - isEnabledByDefault: true); -} \ No newline at end of file diff --git a/GroupedNativeMethodsGenerator/GroupedNativeMethodsGenerator.cs b/GroupedNativeMethodsGenerator/GroupedNativeMethodsGenerator.cs new file mode 100644 index 0000000..b2b2bd4 --- /dev/null +++ b/GroupedNativeMethodsGenerator/GroupedNativeMethodsGenerator.cs @@ -0,0 +1,168 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using System.Text; +using System.Text.RegularExpressions; + +namespace GroupedNativeMethodsGenerator; + +[Generator(LanguageNames.CSharp)] +public partial class GroupedNativeMethodsGenerator : IIncrementalGenerator +{ + public void Initialize(IncrementalGeneratorInitializationContext context) + { + context.RegisterPostInitializationOutput(ctx => + { + ctx.AddSource("GroupedNativeMethodsGenerator.Attribute.cs", """ +namespace GroupedNativeMethodsGenerator +{ + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] + internal sealed class GroupedNativeMethodsAttribute : Attribute + { + public string RemovePrefix { get; } + public string RemoveSuffix { get; } + public bool RemoveUntilTypeName { get; } + public bool FixMethodName { get; } + + public GroupedNativeMethodsAttribute(string removePrefix = "", string removeSuffix = "", bool removeUntilTypeName = true, bool fixMethodName = true) + { + this.RemovePrefix = removePrefix; + this.RemoveSuffix = removeSuffix; + this.RemoveUntilTypeName = removeUntilTypeName; + this.FixMethodName = fixMethodName; + } + } +} +"""); + }); + + var source = context.SyntaxProvider.ForAttributeWithMetadataName("GroupedNativeMethodsGenerator.GroupedNativeMethodsAttribute", + (node, token) => node is ClassDeclarationSyntax, + (ctx, token) => ctx); + + context.RegisterSourceOutput(source, Emit); + } + + static void Emit(SourceProductionContext context, GeneratorAttributeSyntaxContext source) + { + var typeSymbol = (INamedTypeSymbol)source.TargetSymbol; + var typeNode = (TypeDeclarationSyntax)source.TargetNode; + + var ns = typeSymbol.ContainingNamespace.IsGlobalNamespace + ? "" + : $"namespace {typeSymbol.ContainingNamespace}\n{{"; + + var accessibility = typeSymbol.DeclaredAccessibility == Accessibility.Public ? "public" : "internal"; + + var fullType = typeSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat) + .Replace("global::", "") + .Replace("<", "_") + .Replace(">", "_"); + + var grouped = typeSymbol.GetMembers().OfType() + .Where(x => x.Parameters.Length != 0) + .Where(x => x.Parameters[0].Type is IPointerTypeSymbol t && (t.PointedAtType.SpecialType is SpecialType.None) && t.PointedAtType.TypeKind != TypeKind.Pointer) + .ToLookup(x => + { + return ((IPointerTypeSymbol)x.Parameters[0].Type).PointedAtType.ToDisplayString(); + }); + + var libTypeName = typeSymbol.Name; + var removePrefix = (string)source.Attributes[0].ConstructorArguments[0].Value!; + var removeSuffix = (string)source.Attributes[0].ConstructorArguments[1].Value!; + var removeUntilTypeName = (bool)source.Attributes[0].ConstructorArguments[2].Value!; + var fixMethodName = (bool)source.Attributes[0].ConstructorArguments[3].Value!; + + var code = new StringBuilder(); + + code.AppendLine($$""" +// +#nullable enable +#pragma warning disable CS8600 +#pragma warning disable CS8601 +#pragma warning disable CS8602 +#pragma warning disable CS8603 +#pragma warning disable CS8604 + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +{{ns}} + + {{accessibility}} static unsafe class {{typeSymbol.Name}}GroupingExtensions + { +"""); + foreach (var g in grouped) + { + code.AppendLine($"#region {g.Key}({g.Count()})"); + code.AppendLine(); + foreach (var item in g) + { + var firstArgument = item.Parameters[0]; + var ret = item.ReturnType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat); + var requireRet = ret == "void" ? "" : "return "; + + var convertedMethodName = ConvertMethodName(((IPointerTypeSymbol)firstArgument.Type).PointedAtType.Name, item.Name, removePrefix, removeSuffix, removeUntilTypeName, fixMethodName); + var pointedType = ((IPointerTypeSymbol)firstArgument.Type).PointedAtType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat); + var parameterPairs = string.Join("", item.Parameters.Skip(1).Select(x => $", {x.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)} @{x.Name}")); + var parameterNames = string.Join("", item.Parameters.Skip(1).Select(x => $", @{x.Name}")); + + code.AppendLine($" public static {ret} {convertedMethodName}(this ref {pointedType} @{firstArgument.Name}{parameterPairs})"); + code.AppendLine(" {"); + code.AppendLine($" {requireRet}{libTypeName}.{item.Name}(({pointedType}*)Unsafe.AsPointer(ref @{firstArgument.Name}){parameterNames});"); + code.AppendLine(" }"); + code.AppendLine(""); + } + code.AppendLine($"#endregion"); + code.AppendLine(); + } + + code.AppendLine(" }"); + if (ns != "") + { + code.AppendLine("}"); + } + + context.AddSource($"{fullType}.GroupedNativeMethods.g.cs", code.ToString()); + } + + static string ConvertMethodName(string typeName, string methodName, string removePrefix, string removeSuffix, bool removeUntilTypeName, bool fixMethodName) + { + if (removeUntilTypeName) + { + var match = methodName.IndexOf(typeName); + if (match != -1) + { + methodName = methodName.Substring(match + typeName.Length); + goto FINAL; + } + } + + if (!string.IsNullOrEmpty(removePrefix)) + { + methodName = Regex.Replace(methodName, $"^{Regex.Escape(removePrefix)}", ""); + } + + FINAL: + + if (!string.IsNullOrEmpty(removeSuffix)) + { + methodName = Regex.Replace(methodName, $"{Regex.Escape(removeSuffix)}$", ""); + } + + methodName = methodName.Trim('_'); + + if (fixMethodName) + { + var split = methodName.Split('_'); + methodName = string.Concat(split.Select(x => + { + if (x.Length == 0) return x; + if (x.Length == 1) return char.ToUpper(x[0]).ToString(); + return char.ToUpper(x[0]) + x.Substring(1); + })); + } + + return methodName; + } +} \ No newline at end of file diff --git a/csbindgen/src/emitter.rs b/csbindgen/src/emitter.rs index 0a82213..9f68467 100644 --- a/csbindgen/src/emitter.rs +++ b/csbindgen/src/emitter.rs @@ -292,6 +292,7 @@ pub fn emit_csharp( // This code is generated by csbindgen. // DON'T CHANGE THIS DIRECTLY. // +#pragma warning disable CS8500 #pragma warning disable CS8981 using System; using System.Runtime.InteropServices; diff --git a/dotnet-sandbox/BindingGroupExtensions.cs b/dotnet-sandbox/BindingGroupExtensions.cs index 1aeb8f3..09c500c 100644 --- a/dotnet-sandbox/BindingGroupExtensions.cs +++ b/dotnet-sandbox/BindingGroupExtensions.cs @@ -1,50 +1,44 @@ -using CsBindgen; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Text; -using System.Threading.Tasks; + -namespace CsbindgenDotnetConsoleApp +namespace Physx { - // Concept for grouping extension - - internal static unsafe class BindingGroupExtensions + [GroupedNativeMethodsGenerator.GroupedNativeMethods(removePrefix: "Px")] + internal static unsafe partial class LibPhysxd { - // public static extern bool quiche_conn_set_keylog_path(quiche_conn* conn, byte* path); - // public static extern nuint quiche_conn_max_send_udp_payload_size(quiche_conn* conn); - // public static extern int quiche_conn_close(quiche_conn* conn, [MarshalAs(UnmanagedType.U1)] bool app, ulong err, byte* reason, nuint reason_len); + } +} - public static bool SetKeylogPath(this ref quiche_conn conn, byte* path) - { - return LibQuiche.quiche_conn_set_keylog_path((quiche_conn*)Unsafe.AsPointer(ref conn), path); - } +namespace CsBindgen +{ + [GroupedNativeMethodsGenerator.GroupedNativeMethods(removePrefix: "b3")] + internal static unsafe partial class LibBullet3 + { + } - public static nuint MaxSendUdpPayloadSize(this ref quiche_conn conn) - { - return LibQuiche.quiche_conn_max_send_udp_payload_size((quiche_conn*)Unsafe.AsPointer(ref conn)); - } - - public static int MaxSendUdpPayloadSize(this ref quiche_conn conn, bool app, ulong err, byte* reason, nuint reason_len) - { - return LibQuiche.quiche_conn_close((quiche_conn*)Unsafe.AsPointer(ref conn), app, err, reason, reason_len); - } - - public static bool Hoge(quiche_conn* conn, byte* path) - { - return conn->SetKeylogPath(path); - } + [GroupedNativeMethodsGenerator.GroupedNativeMethods(removePrefix: "quiche_")] + internal static unsafe partial class LibQuiche + { + } + [GroupedNativeMethodsGenerator.GroupedNativeMethods(removePrefix: "sqlite3_")] + public static unsafe partial class LibSqlite3 + { } } -namespace Physx +namespace PixivApi.ImageFile { - [GroupedNativeMethodsGenerator.GroupedNativeMethods] - internal static unsafe partial class LibPhysxd + [GroupedNativeMethodsGenerator.GroupedNativeMethods(removePrefix: "png_")] + internal static unsafe partial class LibPng16 + { + } +} + +namespace Jolt +{ + [GroupedNativeMethodsGenerator.GroupedNativeMethods(removePrefix: "JPH_")] + internal static unsafe partial class NativeMethods { } } \ No newline at end of file diff --git a/dotnet-sandbox/CsbindgenDotnetConsoleApp.sln b/dotnet-sandbox/CsbindgenDotnetConsoleApp.sln deleted file mode 100644 index e01f71d..0000000 --- a/dotnet-sandbox/CsbindgenDotnetConsoleApp.sln +++ /dev/null @@ -1,25 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.5.33414.496 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CsbindgenDotnetConsoleApp", "CsbindgenDotnetConsoleApp.csproj", "{3ED7C644-A880-426C-9BF1-24675D7A6299}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {3ED7C644-A880-426C-9BF1-24675D7A6299}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3ED7C644-A880-426C-9BF1-24675D7A6299}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3ED7C644-A880-426C-9BF1-24675D7A6299}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3ED7C644-A880-426C-9BF1-24675D7A6299}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {DD647440-C307-4A09-9D97-DEA74660F797} - EndGlobalSection -EndGlobal diff --git a/dotnet-sandbox/NativeMethods.cs b/dotnet-sandbox/NativeMethods.cs index 3be320d..c6362c5 100644 --- a/dotnet-sandbox/NativeMethods.cs +++ b/dotnet-sandbox/NativeMethods.cs @@ -2,6 +2,7 @@ // This code is generated by csbindgen. // DON'T CHANGE THIS DIRECTLY. // +#pragma warning disable CS8500 #pragma warning disable CS8981 using System; using System.Runtime.InteropServices; diff --git a/dotnet-sandbox/libphysx_csbindgen.cs b/dotnet-sandbox/libphysx_csbindgen.cs index bd4fb67..5a1c68e 100644 --- a/dotnet-sandbox/libphysx_csbindgen.cs +++ b/dotnet-sandbox/libphysx_csbindgen.cs @@ -2,6 +2,7 @@ // This code is generated by csbindgen. // DON'T CHANGE THIS DIRECTLY. // +#pragma warning disable CS8500 #pragma warning disable CS8981 using System; using System.Runtime.InteropServices; diff --git a/dotnet-sandbox/libpng16_csbindgen.cs b/dotnet-sandbox/libpng16_csbindgen.cs index 3beb0d7..2858808 100644 --- a/dotnet-sandbox/libpng16_csbindgen.cs +++ b/dotnet-sandbox/libpng16_csbindgen.cs @@ -2,6 +2,7 @@ // This code is generated by csbindgen. // DON'T CHANGE THIS DIRECTLY. // +#pragma warning disable CS8500 #pragma warning disable CS8981 using System; using System.Runtime.InteropServices; diff --git a/dotnet-sandbox/lz4_bindgen.cs b/dotnet-sandbox/lz4_bindgen.cs index a44812e..3954733 100644 --- a/dotnet-sandbox/lz4_bindgen.cs +++ b/dotnet-sandbox/lz4_bindgen.cs @@ -2,6 +2,7 @@ // This code is generated by csbindgen. // DON'T CHANGE THIS DIRECTLY. // +#pragma warning disable CS8500 #pragma warning disable CS8981 using System; using System.Runtime.InteropServices;