diff --git a/Directory.Build.props b/Directory.Build.props index 66a4d5e4..af219597 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -47,7 +47,7 @@ 17.0.0 ClangSharp ClangSharp - 20.1.2.2 + 20.1.2.3 rc1 pr diff --git a/sources/ClangSharp.PInvokeGenerator/CSharp/CSharpOutputBuilder.cs b/sources/ClangSharp.PInvokeGenerator/CSharp/CSharpOutputBuilder.cs index 7c6c232d..f6d52daa 100644 --- a/sources/ClangSharp.PInvokeGenerator/CSharp/CSharpOutputBuilder.cs +++ b/sources/ClangSharp.PInvokeGenerator/CSharp/CSharpOutputBuilder.cs @@ -104,6 +104,31 @@ public void WriteIndentedLine(T value) WriteLine(value); } + public void WriteLabel(string name) + { + if (_currentLine.Length >= _indentationString.Length) + { + var match = true; + + for (var i = 0; i < _indentationString.Length; i++) + { + if (_currentLine[_currentLine.Length - i - 1] != _indentationString[_indentationString.Length - 1 - i]) + { + match = false; + break; + } + } + + if (match) + { + _ = _currentLine.Remove(_currentLine.Length - _indentationString.Length, _indentationString.Length); + } + } + + Write(name); + WriteLine(':'); + } + public void WriteLine(T value) { Write(value); diff --git a/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.VisitDecl.cs b/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.VisitDecl.cs index 271e6583..fcfa5c6f 100644 --- a/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.VisitDecl.cs +++ b/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.VisitDecl.cs @@ -7,11 +7,9 @@ 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; -using static ClangSharp.Interop.CX_CharacterKind; using static ClangSharp.Interop.CX_DeclKind; using static ClangSharp.Interop.CX_StmtClass; using static ClangSharp.Interop.CX_StorageClass; @@ -607,7 +605,7 @@ private void VisitFunctionDecl(FunctionDecl functionDecl) IsCxx = cxxMethodDecl is not null, IsStatic = isDllImport || (cxxMethodDecl is null) || cxxMethodDecl.IsStatic, NeedsNewKeyword = NeedsNewKeyword(escapedName, functionDecl.Parameters), - IsReadOnly = (cxxMethodDecl is not null) && cxxMethodDecl.IsConst, + IsReadOnly = IsReadonly(cxxMethodDecl), IsUnsafe = IsUnsafe(functionDecl), IsCtxCxxRecord = cxxRecordDecl is not null, IsCxxRecordCtxUnsafe = cxxRecordDecl is not null && IsUnsafe(cxxRecordDecl), @@ -2228,7 +2226,7 @@ void OutputVtblHelperMethod(CXXRecordDecl cxxRecordDecl, CXXMethodDecl cxxMethod HasFnPtrCodeGen = !_config.ExcludeFnptrCodegen, IsCtxCxxRecord = true, IsCxxRecordCtxUnsafe = IsUnsafe(cxxRecordDecl), - IsReadOnly = cxxMethodDecl.IsConst, + IsReadOnly = IsReadonly(cxxMethodDecl), IsUnsafe = true, NeedsReturnFixup = needsReturnFixup, ReturnType = returnTypeName, @@ -2353,7 +2351,7 @@ void OutputVtblHelperMethod(CXXRecordDecl cxxRecordDecl, CXXMethodDecl cxxMethod body.Write(escapedCXXRecordDeclName); body.Write("*)Unsafe.AsPointer("); - if (cxxMethodDecl.IsConst) + if (IsReadonly(cxxMethodDecl)) { if (!_config.GenerateLatestCode) { diff --git a/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.VisitStmt.cs b/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.VisitStmt.cs index 25ed853c..5eaf6372 100644 --- a/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.VisitStmt.cs +++ b/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.VisitStmt.cs @@ -2070,9 +2070,7 @@ private void VisitIntegerLiteral(IntegerLiteral integerLiteral) private void VisitLabelStmt(LabelStmt labelStmt) { var outputBuilder = StartCSharpCode(); - - outputBuilder.Write(labelStmt.Decl.Name); - outputBuilder.WriteLine(':'); + outputBuilder.WriteLabel(labelStmt.Decl.Name); outputBuilder.WriteIndentation(); Visit(labelStmt.SubStmt); diff --git a/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.cs b/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.cs index 147788d7..01eb5810 100644 --- a/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.cs +++ b/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.cs @@ -1412,7 +1412,7 @@ static void GenerateTransparentStructs(PInvokeGenerator generator, Stream? strea sw.Write(indentString); sw.WriteLine(" {"); sw.Write(indentString); - sw.Write(" if (obj is "); + sw.Write(" if (obj is "); sw.Write(name); sw.WriteLine(" other)"); sw.Write(indentString); @@ -3258,29 +3258,22 @@ private static int GetAnonymousRecordIndex(RecordDecl recordDecl, RecordDecl par index++; } - if (parentRecordDecl.Parent is RecordDecl grandParentRecordDecl) + if (parentRecordDecl.Parent is RecordDecl grandparentRecordDecl) { - var parentIndex = GetAnonymousRecordIndex(parentRecordDecl, grandParentRecordDecl); + var parentIndex = GetAnonymousRecordIndex(parentRecordDecl, grandparentRecordDecl); // We can't have the nested anonymous record have the same name as the parent // so skip that index and just go one higher instead. This could still conflict // with another anonymous record at a different level, but that is less likely // and will still be unambiguous in total. - if (parentIndex == index) + if ((parentIndex == index) || ((parentIndex > 0) && (index > parentIndex))) { if (recordDecl.IsUnion == parentRecordDecl.IsUnion) { index++; } } - else if ((parentIndex > 0) && (index > parentIndex)) - { - if (recordDecl.IsUnion == parentRecordDecl.AnonymousRecords[parentIndex].IsUnion) - { - index++; - } - } } } } @@ -5402,6 +5395,15 @@ private bool IsPrevContextStmt([MaybeNullWhen(false)] out T cursor, out objec } } + private bool IsReadonly(CXXMethodDecl? cxxMethodDecl) + { + if (cxxMethodDecl is not null) + { + return cxxMethodDecl.IsConst || HasRemapping(cxxMethodDecl, _config._withReadonlys, matchStar: true); + } + return false; + } + private static bool IsStmtAsWritten(Cursor cursor, [MaybeNullWhen(false)] out T value, bool removeParens = false) where T : Stmt { diff --git a/sources/ClangSharp.PInvokeGenerator/PInvokeGeneratorConfiguration.cs b/sources/ClangSharp.PInvokeGenerator/PInvokeGeneratorConfiguration.cs index be02ba35..426f85a2 100644 --- a/sources/ClangSharp.PInvokeGenerator/PInvokeGeneratorConfiguration.cs +++ b/sources/ClangSharp.PInvokeGenerator/PInvokeGeneratorConfiguration.cs @@ -33,6 +33,7 @@ public sealed class PInvokeGeneratorConfiguration private readonly HashSet _nativeTypeNamesToStrip; private readonly HashSet _withManualImports; private readonly HashSet _traversalNames; + internal readonly HashSet _withReadonlys; internal readonly HashSet _withSetLastErrors; internal readonly HashSet _withSuppressGCTransitions; @@ -87,6 +88,7 @@ public PInvokeGeneratorConfiguration(string language, string languageStandard, s _nativeTypeNamesToStrip = new HashSet(StringComparer.Ordinal); _withManualImports = new HashSet(StringComparer.Ordinal); _traversalNames = new HashSet(StringComparer.Ordinal); + _withReadonlys = new HashSet(QualifiedNameComparer.Default); _withSetLastErrors = new HashSet(QualifiedNameComparer.Default); _withSuppressGCTransitions = new HashSet(QualifiedNameComparer.Default); @@ -516,6 +518,20 @@ public IReadOnlyDictionary WithNamespaces } } + [AllowNull] + public IReadOnlyCollection WithReadonlys + { + get + { + return _withReadonlys; + } + + init + { + AddRange(_withReadonlys, value); + } + } + [AllowNull] public IReadOnlyCollection WithSetLastErrors { diff --git a/sources/ClangSharpPInvokeGenerator/Program.cs b/sources/ClangSharpPInvokeGenerator/Program.cs index 04af033e..742c0290 100644 --- a/sources/ClangSharpPInvokeGenerator/Program.cs +++ b/sources/ClangSharpPInvokeGenerator/Program.cs @@ -54,6 +54,7 @@ internal static class Program private static readonly string[] s_withManualImportOptionAliases = ["--with-manual-import", "-wmi"]; private static readonly string[] s_withNamespaceOptionAliases = ["--with-namespace", "-wn"]; private static readonly string[] s_withPackingOptionAliases = ["--with-packing", "-wp"]; + private static readonly string[] s_withReadonlyOptionAliases = ["--with-readonly", "-wro"]; private static readonly string[] s_withSetLastErrorOptionAliases = ["--with-setlasterror", "-wsle"]; private static readonly string[] s_withSuppressGCTransitionOptionAliases = ["--with-suppressgctransition", "-wsgct"]; private static readonly string[] s_withTransparentStructOptionAliases = ["--with-transparent-struct", "-wts"]; @@ -92,6 +93,7 @@ internal static class Program private static readonly Option s_withManualImports = GetWithManualImportOption(); private static readonly Option s_withNamespaceNameValuePairs = GetWithNamespaceOption(); private static readonly Option s_withPackingNameValuePairs = GetWithPackingOption(); + private static readonly Option s_withReadonlys = GetWithReadonlyOption(); private static readonly Option s_withSetLastErrors = GetWithSetLastErrorOption(); private static readonly Option s_withSuppressGCTransitions = GetWithSuppressGCTransitionOption(); private static readonly Option s_withTransparentStructNameValuePairs = GetWithTransparentStructOption(); @@ -255,6 +257,7 @@ public static void Run(InvocationContext context) var withLibraryPathNameValuePairs = context.ParseResult.GetValueForOption(s_withLibraryPathNameValuePairs) ?? []; var withManualImports = context.ParseResult.GetValueForOption(s_withManualImports) ?? []; var withNamespaceNameValuePairs = context.ParseResult.GetValueForOption(s_withNamespaceNameValuePairs) ?? []; + var withReadonlys = context.ParseResult.GetValueForOption(s_withReadonlys) ?? []; var withSetLastErrors = context.ParseResult.GetValueForOption(s_withSetLastErrors) ?? []; var withSuppressGCTransitions = context.ParseResult.GetValueForOption(s_withSuppressGCTransitions) ?? []; var withTransparentStructNameValuePairs = context.ParseResult.GetValueForOption(s_withTransparentStructNameValuePairs) ?? []; @@ -729,6 +732,7 @@ public static void Run(InvocationContext context) WithLibraryPaths = withLibraryPaths, WithManualImports = withManualImports, WithNamespaces = withNamespaces, + WithReadonlys = withReadonlys, WithSetLastErrors = withSetLastErrors, WithSuppressGCTransitions = withSuppressGCTransitions, WithTransparentStructs = withTransparentStructs, @@ -1202,6 +1206,7 @@ private static RootCommand GetRootCommand() s_withManualImports, s_withNamespaceNameValuePairs, s_withPackingNameValuePairs, + s_withReadonlys, s_withSetLastErrors, s_withSuppressGCTransitions, s_withTransparentStructNameValuePairs, @@ -1350,6 +1355,17 @@ private static Option GetWithNamespaceOption() }; } + private static Option GetWithReadonlyOption() + { + return new Option( + aliases: s_withReadonlyOptionAliases, + description: "Add the readonly modifier to a given instance method. Supports wildcards.", + getDefaultValue: Array.Empty + ) { + AllowMultipleArgumentsPerToken = true + }; + } + private static Option GetWithSetLastErrorOption() { return new Option( diff --git a/sources/ClangSharpPInvokeGenerator/Properties/launchSettings.json b/sources/ClangSharpPInvokeGenerator/Properties/launchSettings.json index cef15055..b961eec5 100644 --- a/sources/ClangSharpPInvokeGenerator/Properties/launchSettings.json +++ b/sources/ClangSharpPInvokeGenerator/Properties/launchSettings.json @@ -12,7 +12,7 @@ "GenerateLocal": { "commandName": "Project", "commandLineArgs": "@generate.rsp", - "workingDirectory": "D:\\repos\\terrafx.interop.windows\\generation\\DirectX\\um\\dcommon" + "workingDirectory": "D:\\repos\\terrafx.interop.windows\\generation\\windows\\um\\winioctl" } } }