diff --git a/README.md b/README.md index 8d8df0c9..3a36108e 100644 --- a/README.md +++ b/README.md @@ -256,6 +256,10 @@ Options: generate-unmanaged-constants Unmanaged constants should be generated using static ref readonly properties. This is currently experimental. generate-vtbl-index-attribute [VtblIndex(#)] attribute should be generated to document the underlying VTBL index for a helper method. + # Stripping Options + + strip-enum-member-type-name Strips the enum type name from the beginning of its member names. + # Logging Options log-exclusions A list of excluded declaration types should be generated. This will also log if the exclusion was due to an exact or partial match. diff --git a/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.VisitDecl.cs b/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.VisitDecl.cs index 10a6b486..974b98da 100644 --- a/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.VisitDecl.cs +++ b/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.VisitDecl.cs @@ -7,6 +7,7 @@ using System.Linq; using System.Runtime.InteropServices; using System.Text; +using System.Text.RegularExpressions; using ClangSharp.Abstractions; using ClangSharp.CSharp; using static ClangSharp.Interop.CX_CastKind; @@ -294,6 +295,11 @@ private void VisitEnumConstantDecl(EnumConstantDecl enumConstantDecl) parentName = _outputBuilder.Name; } + if (Config.StripEnumMemberTypeName) + { + escapedName = PrefixAndStrip(escapedName, parentName, trimChar: '_'); + } + var kind = isAnonymousEnum ? ValueKind.Primitive : ValueKind.Enumerator; var flags = ValueFlags.Constant; @@ -535,12 +541,12 @@ private void VisitFunctionDecl(FunctionDecl functionDecl) if ((cxxMethodDecl is not null) && cxxMethodDecl.IsVirtual) { isVirtual = true; - escapedName = PrefixAndStripName(name, GetOverloadIndex(cxxMethodDecl)); + escapedName = PrefixAndStripMethodName(name, GetOverloadIndex(cxxMethodDecl)); } else { isVirtual = false; - escapedName = EscapeAndStripName(name); + escapedName = EscapeAndStripMethodName(name); } var returnType = functionDecl.ReturnType; @@ -2024,7 +2030,7 @@ void OutputMarkerInterface(CXXRecordDecl cxxRecordDecl, CXXMethodDecl cxxMethodD var desc = new FunctionOrDelegateDesc { AccessSpecifier = AccessSpecifier.Public, - EscapedName = EscapeAndStripName(name), + EscapedName = EscapeAndStripMethodName(name), IsMemberFunction = true, NativeTypeName = nativeTypeName, HasFnPtrCodeGen = !_config.ExcludeFnptrCodegen, @@ -2112,7 +2118,7 @@ void OutputVtblEntry(CXXRecordDecl cxxRecordDecl, CXXMethodDecl cxxMethodDecl) } var remappedName = FixupNameForMultipleHits(cxxMethodDecl); - var escapedName = EscapeAndStripName(remappedName); + var escapedName = EscapeAndStripMethodName(remappedName); var desc = new FieldDesc { @@ -2181,7 +2187,7 @@ void OutputVtblHelperMethod(CXXRecordDecl cxxRecordDecl, CXXMethodDecl cxxMethod var desc = new FunctionOrDelegateDesc { AccessSpecifier = AccessSpecifier.Public, IsAggressivelyInlined = _config.GenerateAggressiveInlining, - EscapedName = EscapeAndStripName(name), + EscapedName = EscapeAndStripMethodName(name), ParentName = parentName, IsMemberFunction = true, IsInherited = isInherited, @@ -2261,7 +2267,7 @@ void OutputVtblHelperMethod(CXXRecordDecl cxxRecordDecl, CXXMethodDecl cxxMethod { body.Write("Marshal.GetDelegateForFunctionPointer<"); body.BeginMarker("delegate"); - body.Write(PrefixAndStripName(name, GetOverloadIndex(cxxMethodDecl))); + body.Write(PrefixAndStripMethodName(name, GetOverloadIndex(cxxMethodDecl))); body.EndMarker("delegate"); body.Write(">("); } @@ -2270,7 +2276,7 @@ void OutputVtblHelperMethod(CXXRecordDecl cxxRecordDecl, CXXMethodDecl cxxMethod { body.Write("lpVtbl->"); body.BeginMarker("vtbl", new KeyValuePair("explicit", true)); - body.Write(EscapeAndStripName(remappedName)); + body.Write(EscapeAndStripMethodName(remappedName)); body.EndMarker("vtbl"); } else diff --git a/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.VisitStmt.cs b/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.VisitStmt.cs index e216d889..3fd39a09 100644 --- a/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.VisitStmt.cs +++ b/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.VisitStmt.cs @@ -970,7 +970,7 @@ private void VisitDeclRefExpr(DeclRefExpr declRefExpr) if (declRefExpr.Decl is FunctionDecl) { - escapedName = EscapeAndStripName(name); + escapedName = EscapeAndStripMethodName(name); } } diff --git a/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.cs b/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.cs index 6edb8098..c6cbcc7c 100644 --- a/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.cs +++ b/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.cs @@ -1454,18 +1454,18 @@ static void GenerateTransparentStructs(PInvokeGenerator generator, Stream? strea return type.Contains('*', StringComparison.Ordinal) ? (8, 4, +1) : type switch { - "sbyte" => (1, 1, -1), - "byte" => (1, 1, +1), - "short" => (2, 2, -1), - "ushort" => (2, 2, +1), - "int" => (4, 4, -1), - "uint" => (4, 4, +1), - "nint" => (8, 4, -1), - "nuint" => (8, 4, +1), - "long" => (8, 8, -1), - "ulong" => (8, 8, +1), - _ => (0, 0, 0), - }; + "sbyte" => (1, 1, -1), + "byte" => (1, 1, +1), + "short" => (2, 2, -1), + "ushort" => (2, 2, +1), + "int" => (4, 4, -1), + "uint" => (4, 4, +1), + "nint" => (8, 4, -1), + "nuint" => (8, 4, +1), + "long" => (8, 8, -1), + "ulong" => (8, 8, +1), + _ => (0, 0, 0), + }; } static void OutputConversions(StreamWriter sw, string indentString, string name, string type, PInvokeGeneratorTransparentStructKind kind, string target) @@ -2326,13 +2326,9 @@ private static string EscapeName(string name) } } - private string EscapeAndStripName(string name) + private string EscapeAndStripMethodName(string name) { - if (name.StartsWith(_config.MethodPrefixToStrip, StringComparison.Ordinal)) - { - name = name[_config.MethodPrefixToStrip.Length..]; - } - + name = PrefixAndStrip(name, _config.MethodPrefixToStrip); return EscapeName(name); } @@ -5407,7 +5403,7 @@ private static bool IsTransparentStructBoolean(PInvokeGeneratorTransparentStruct => kind is PInvokeGeneratorTransparentStructKind.Boolean; private static bool IsTransparentStructHandle(PInvokeGeneratorTransparentStructKind kind) - => kind is PInvokeGeneratorTransparentStructKind.Handle + => kind is PInvokeGeneratorTransparentStructKind.Handle or PInvokeGeneratorTransparentStructKind.HandleWin32; private static bool IsTransparentStructHexBased(PInvokeGeneratorTransparentStructKind kind) @@ -6153,7 +6149,7 @@ private bool NeedsReturnFixup(CXXMethodDecl cxxMethodDecl) private static bool NeedsNewKeyword(string name) { - return name.Equals("Equals",StringComparison.Ordinal) + return name.Equals("Equals", StringComparison.Ordinal) || name.Equals("GetHashCode", StringComparison.Ordinal) || name.Equals("GetType", StringComparison.Ordinal) || name.Equals("MemberwiseClone", StringComparison.Ordinal) @@ -6198,13 +6194,32 @@ private void ParenthesizeStmt(Stmt stmt) } } - private string PrefixAndStripName(string name, uint overloadIndex) + /// + /// Checks whether the specified name starts with a prefix, optionally trims a separator character following the prefix and returns the remainder. + /// + /// The name to strip. + /// The prefix to strip from . + /// Additional separator that may follow which should also be trimmed away. + /// + /// if it does not start with ; + /// otherwise, + /// the remainder of after stripping and all immediate following occurences of from it beginning. + /// + private static string PrefixAndStrip(string name, string prefix, char trimChar = '\0') { - if (name.StartsWith(_config.MethodPrefixToStrip, StringComparison.Ordinal)) + var nameSpan = name.AsSpan(); + if (nameSpan.StartsWith(prefix, StringComparison.Ordinal)) { - name = name[_config.MethodPrefixToStrip.Length..]; + nameSpan = nameSpan[prefix.Length..]; + nameSpan = nameSpan.TrimStart(trimChar); + return nameSpan.ToString(); } + return name; + } + private string PrefixAndStripMethodName(string name, uint overloadIndex) + { + name = PrefixAndStrip(name, _config.MethodPrefixToStrip); return $"_{name}{((overloadIndex != 0) ? overloadIndex.ToString(CultureInfo.InvariantCulture) : "")}"; } diff --git a/sources/ClangSharp.PInvokeGenerator/PInvokeGeneratorConfiguration.cs b/sources/ClangSharp.PInvokeGenerator/PInvokeGeneratorConfiguration.cs index 3dfb786b..e36133e0 100644 --- a/sources/ClangSharp.PInvokeGenerator/PInvokeGeneratorConfiguration.cs +++ b/sources/ClangSharp.PInvokeGenerator/PInvokeGeneratorConfiguration.cs @@ -265,6 +265,8 @@ public IReadOnlyCollection ExcludedNames public bool GenerateVtblIndexAttribute => _options.HasFlag(PInvokeGeneratorConfigurationOptions.GenerateVtblIndexAttribute); + public bool StripEnumMemberTypeName => _options.HasFlag(PInvokeGeneratorConfigurationOptions.StripEnumMemberTypeName); + public string HeaderText => _headerText; [AllowNull] diff --git a/sources/ClangSharp.PInvokeGenerator/PInvokeGeneratorConfigurationOptions.cs b/sources/ClangSharp.PInvokeGenerator/PInvokeGeneratorConfigurationOptions.cs index db91ccd4..c2a34293 100644 --- a/sources/ClangSharp.PInvokeGenerator/PInvokeGeneratorConfigurationOptions.cs +++ b/sources/ClangSharp.PInvokeGenerator/PInvokeGeneratorConfigurationOptions.cs @@ -86,4 +86,6 @@ public enum PInvokeGeneratorConfigurationOptions : long GenerateCallConvMemberFunction = 1L << 37, GenerateGenericPointerWrapper = 1L << 38, + + StripEnumMemberTypeName = 1L << 39, } diff --git a/sources/ClangSharpPInvokeGenerator/Program.cs b/sources/ClangSharpPInvokeGenerator/Program.cs index 6dd06fee..69eb17ee 100644 --- a/sources/ClangSharpPInvokeGenerator/Program.cs +++ b/sources/ClangSharpPInvokeGenerator/Program.cs @@ -177,6 +177,12 @@ public static class Program new TwoColumnHelpRow("generate-unmanaged-constants", "Unmanaged constants should be generated using static ref readonly properties. This is currently experimental."), new TwoColumnHelpRow("generate-vtbl-index-attribute", "[VtblIndex(#)] attribute should be generated to document the underlying VTBL index for a helper method."), + new TwoColumnHelpRow("", ""), + new TwoColumnHelpRow("# Stripping Options", ""), + new TwoColumnHelpRow("", ""), + + new TwoColumnHelpRow("strip-enum-member-type-name", "Strips the enum type name from the beginning of its member names."), + new TwoColumnHelpRow("", ""), new TwoColumnHelpRow("# Logging Options", ""), new TwoColumnHelpRow("", ""), @@ -617,6 +623,14 @@ public static void Run(InvocationContext context) break; } + // Strip Options + + case "strip-enum-member-type-name": + { + configOptions |= PInvokeGeneratorConfigurationOptions.StripEnumMemberTypeName; + break; + } + // Legacy Options case "default-remappings":