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"
}
}
}