From 4e45397e08708c8ddf7748c51d4f3cdf6e92e6a2 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Tue, 7 Jun 2022 17:22:58 -0700 Subject: [PATCH 1/4] Fixing UTF-8 string literals to no longer include an explicit null --- .../ClangSharp.PInvokeGenerator/PInvokeGenerator.VisitStmt.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.VisitStmt.cs b/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.VisitStmt.cs index 5ba4c90c..a0278d93 100644 --- a/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.VisitStmt.cs +++ b/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.VisitStmt.cs @@ -2296,7 +2296,8 @@ private void VisitStringLiteral(StringLiteral stringLiteral) { outputBuilder.Write('"'); outputBuilder.Write(EscapeString(stringLiteral.String)); - outputBuilder.Write("\\0\"u8"); + outputBuilder.Write('"'); + outputBuilder.Write("u8"); } else { From 648d30a1659a1b24d64f82e43a69f8b2fea132b0 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Wed, 15 Jun 2022 16:17:49 -0700 Subject: [PATCH 2/4] Adding better support for specifying type GUIDs --- .../Abstractions/ValueKind.cs | 1 + .../CSharp/CSharpOutputBuilder.VisitDecl.cs | 31 ++++++++-- .../PInvokeGenerator.VisitDecl.cs | 57 +++++++++++++++---- .../PInvokeGenerator.VisitStmt.cs | 2 +- .../PInvokeGenerator.cs | 26 +++++++-- .../PInvokeGeneratorConfiguration.cs | 23 +++++++- .../PInvokeGeneratorConfigurationOptions.cs | 2 + sources/ClangSharpPInvokeGenerator/Program.cs | 56 ++++++++++++++++++ 8 files changed, 175 insertions(+), 23 deletions(-) diff --git a/sources/ClangSharp.PInvokeGenerator/Abstractions/ValueKind.cs b/sources/ClangSharp.PInvokeGenerator/Abstractions/ValueKind.cs index c1d64462..548d7cfe 100644 --- a/sources/ClangSharp.PInvokeGenerator/Abstractions/ValueKind.cs +++ b/sources/ClangSharp.PInvokeGenerator/Abstractions/ValueKind.cs @@ -9,5 +9,6 @@ internal enum ValueKind Enumerator, Unmanaged, String, + GuidMember, } } diff --git a/sources/ClangSharp.PInvokeGenerator/CSharp/CSharpOutputBuilder.VisitDecl.cs b/sources/ClangSharp.PInvokeGenerator/CSharp/CSharpOutputBuilder.VisitDecl.cs index 2bc06e95..f6027818 100644 --- a/sources/ClangSharp.PInvokeGenerator/CSharp/CSharpOutputBuilder.VisitDecl.cs +++ b/sources/ClangSharp.PInvokeGenerator/CSharp/CSharpOutputBuilder.VisitDecl.cs @@ -147,6 +147,13 @@ public void BeginValue(in ValueDesc desc) Write(desc.TypeName); Write(' '); } + else if (desc.Kind == ValueKind.GuidMember) + { + Write("static "); + Write(desc.TypeName); + Write(' '); + isExpressionBody = true; + } Write(desc.EscapedName); @@ -215,6 +222,13 @@ public void EndValue(in ValueDesc desc) WriteLine(';'); break; } + + case ValueKind.GuidMember: + { + WriteLine(';'); + NeedsNewline = true; + break; + } } } @@ -755,11 +769,20 @@ public void BeginStruct(in StructDesc desc) Write("partial struct "); Write(desc.EscapedName); - if (desc.HasVtbl && _config.GenerateMarkerInterfaces) + if (_config.GenerateMarkerInterfaces) { - Write(" : "); - Write(desc.EscapedName); - Write(".Interface"); + if (desc.HasVtbl) + { + Write(" : "); + Write(desc.EscapedName); + Write(".Interface"); + } + + if ((desc.Uuid is not null) && _config.GenerateGuidMember && _config.GeneratePreviewCode) + { + Write(desc.HasVtbl ? ", " : " : "); + Write("INativeGuid"); + } } WriteNewline(); diff --git a/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.VisitDecl.cs b/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.VisitDecl.cs index 0dfe68fb..d9cd6a84 100644 --- a/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.VisitDecl.cs +++ b/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.VisitDecl.cs @@ -567,9 +567,9 @@ private void VisitFunctionDecl(FunctionDecl functionDecl) CustomAttrGeneratorData = (functionDecl, _outputBuilder, this), }; - _ = _isTopLevelClassUnsafe.TryGetValue(className, out var isUnsafe); + _ = _topLevelClassIsUnsafe.TryGetValue(className, out var isUnsafe); _outputBuilder.BeginFunctionOrDelegate(in desc, ref isUnsafe); - _isTopLevelClassUnsafe[className] = isUnsafe; + _topLevelClassIsUnsafe[className] = isUnsafe; _outputBuilder.BeginFunctionInnerPrototype(in desc); @@ -1255,17 +1255,19 @@ private void VisitRecordDecl(RecordDecl recordDecl) _testOutputBuilder.WriteBlockStart(); } - Guid? nullableUuid = null; + var nullableUuid = (Guid?)null; + var uuidName = ""; + if (TryGetUuid(recordDecl, out var uuid)) { nullableUuid = uuid; - var iidName = GetRemappedName($"IID_{nativeName}", recordDecl, tryRemapOperatorName: false, out var wasRemapped, skipUsing: true); + uuidName = GetRemappedName($"IID_{nativeName}", recordDecl, tryRemapOperatorName: false, out var wasRemapped, skipUsing: true); - _uuidsToGenerate.Add(iidName, uuid); + _uuidsToGenerate.Add(uuidName, uuid); if (_testOutputBuilder != null) { - var className = GetClass(iidName); + var className = GetClass(uuidName); _testOutputBuilder.AddUsingDirective("System"); _testOutputBuilder.AddUsingDirective($"static {GetNamespace(className)}.{className}"); @@ -1297,7 +1299,7 @@ private void VisitRecordDecl(RecordDecl recordDecl) _testOutputBuilder.Write("Is.EqualTo("); } - _testOutputBuilder.Write(iidName); + _testOutputBuilder.Write(uuidName); if (_config.GenerateTestsNUnit) { @@ -1312,6 +1314,8 @@ private void VisitRecordDecl(RecordDecl recordDecl) } } + var hasGuidMember = _config.GenerateGuidMember && !string.IsNullOrWhiteSpace(uuidName); + var layoutKind = recordDecl.IsUnion ? LayoutKind.Explicit : LayoutKind.Sequential; @@ -1355,7 +1359,7 @@ private void VisitRecordDecl(RecordDecl recordDecl) var desc = new StructDesc { AccessSpecifier = GetAccessSpecifier(recordDecl), EscapedName = escapedName, - IsUnsafe = IsUnsafe(recordDecl), + IsUnsafe = IsUnsafe(recordDecl) || hasGuidMember, HasVtbl = hasVtbl || hasBaseVtbl, IsUnion = recordDecl.IsUnion, Layout = new() { @@ -1440,10 +1444,43 @@ private void VisitRecordDecl(RecordDecl recordDecl) if (desc.IsUnsafe) { - _isTopLevelClassUnsafe[name] = true; + _topLevelClassIsUnsafe[name] = true; + } + + if (hasGuidMember) + { + _topLevelClassHasGuidMember[name] = true; } } + if (hasGuidMember) + { + var valueDesc = new ValueDesc { + AccessSpecifier = AccessSpecifier.None, + TypeName = "Guid*", + EscapedName = "INativeGuid.NativeGuid", + ParentName = name, + Kind = ValueKind.GuidMember, + Flags = ValueFlags.Initializer, + }; + + var uuidClassName = GetClass(uuidName); + + _outputBuilder.EmitUsingDirective("System"); + _outputBuilder.EmitUsingDirective("System.Runtime.CompilerServices"); + + _outputBuilder.EmitUsingDirective($"static {GetNamespace(uuidClassName)}.{uuidClassName}"); + _outputBuilder.BeginValue(in valueDesc); + + var code = _outputBuilder.BeginCSharpCode(); + code.Write("(Guid*)Unsafe.AsPointer(ref Unsafe.AsRef(in "); + code.Write(uuidName); + code.Write("))"); + _outputBuilder.EndCSharpCode(code); + + _outputBuilder.EndValue(in valueDesc); + } + if (hasVtbl || (hasBaseVtbl && !HasBaseField(cxxRecordDecl))) { var fieldDesc = new FieldDesc { @@ -3091,7 +3128,7 @@ private void VisitVarDecl(VarDecl varDecl) if (IsUnsafe(varDecl, type) && (!varDecl.HasInit || !IsStmtAsWritten(varDecl.Init, out _, removeParens: true))) { - _isTopLevelClassUnsafe[className] = true; + _topLevelClassIsUnsafe[className] = true; } } diff --git a/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.VisitStmt.cs b/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.VisitStmt.cs index a0278d93..66b46710 100644 --- a/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.VisitStmt.cs +++ b/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.VisitStmt.cs @@ -2381,7 +2381,7 @@ private void VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr unaryExprOrT { if (_topLevelClassNames.Contains(_outputBuilder.Name)) { - _isTopLevelClassUnsafe[_outputBuilder.Name] = true; + _topLevelClassIsUnsafe[_outputBuilder.Name] = true; } var parentType = null as Type; diff --git a/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.cs b/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.cs index 841fb96f..56368862 100644 --- a/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.cs +++ b/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.cs @@ -41,7 +41,8 @@ public sealed partial class PInvokeGenerator : IDisposable private readonly Dictionary> _traversedValidNameRemappings; private readonly Dictionary _overloadIndices; private readonly Dictionary _isExcluded; - private readonly Dictionary _isTopLevelClassUnsafe; + private readonly Dictionary _topLevelClassHasGuidMember; + private readonly Dictionary _topLevelClassIsUnsafe; private readonly Dictionary> _topLevelClassUsings; private readonly Dictionary> _topLevelClassAttributes; private readonly HashSet _topLevelClassNames; @@ -111,7 +112,8 @@ public PInvokeGenerator(PInvokeGeneratorConfiguration config, Func>(); _overloadIndices = new Dictionary(); _isExcluded = new Dictionary(); - _isTopLevelClassUnsafe = new Dictionary(); + _topLevelClassHasGuidMember = new Dictionary(); + _topLevelClassIsUnsafe = new Dictionary(); _topLevelClassNames = new HashSet(); _topLevelClassAttributes = new Dictionary>(); _topLevelClassUsings = new Dictionary>(); @@ -280,6 +282,9 @@ public void Close() { foreach (var entry in methodClassOutputBuilders) { + var hasGuidMember = _config.GenerateGuidMember && _config.GeneratePreviewCode; + hasGuidMember &= _uuidsToGenerate.ContainsKey(entry.Value.Name) || _generatedUuids.Contains(entry.Value.Name); + CloseOutputBuilder(stream, entry.Value, isMethodClass: true, leaveStreamOpen, emitNamespaceDeclaration); } @@ -631,7 +636,7 @@ static void GenerateTransparentStructs(PInvokeGenerator generator) sw.WriteLine(); - sw.Write("namespace ");sw.WriteLine(); + sw.Write("namespace "); sw.Write(targetNamespace); if (generator.Config.GenerateFileScopedNamespaces) @@ -1556,7 +1561,7 @@ void ForCSharp(CSharpOutputBuilder csharpOutputBuilder) sw.Write("static "); } - if ((_isTopLevelClassUnsafe.TryGetValue(nonTestName, out var isUnsafe) && isUnsafe) || (outputBuilder.IsTestOutput && isTopLevelStruct)) + if ((_topLevelClassIsUnsafe.TryGetValue(nonTestName, out var isUnsafe) && isUnsafe) || (outputBuilder.IsTestOutput && isTopLevelStruct)) { sw.Write("unsafe "); } @@ -1574,6 +1579,11 @@ void ForCSharp(CSharpOutputBuilder csharpOutputBuilder) sw.Write(outputBuilder.Name); + if (_topLevelClassHasGuidMember.TryGetValue(outputBuilder.Name, out var hasGuidMember) && hasGuidMember) + { + sw.Write(" : INativeGuid"); + } + sw.WriteLine(); sw.Write(indentationString); sw.Write('{'); @@ -1635,7 +1645,7 @@ void ForXml(XmlOutputBuilder xmlOutputBuilder) sw.Write(xmlOutputBuilder.Name); sw.Write("\" access=\"public\" static=\"true\""); - if (_isTopLevelClassUnsafe.TryGetValue(xmlOutputBuilder.Name, out var isUnsafe) && isUnsafe) + if (_topLevelClassIsUnsafe.TryGetValue(xmlOutputBuilder.Name, out var isUnsafe) && isUnsafe) { sw.Write(" unsafe=\"true\""); } @@ -5388,6 +5398,12 @@ private void StopUsingOutputBuilder() private bool TryGetUuid(RecordDecl recordDecl, out Guid uuid) { + if (TryGetRemappedValue(recordDecl, _config.WithGuids, out var guid)) + { + uuid = guid; + return true; + } + var uuidAttrs = recordDecl.Attrs.Where((attr) => attr.Kind == CX_AttrKind.CX_AttrKind_Uuid); if (!uuidAttrs.Any()) diff --git a/sources/ClangSharp.PInvokeGenerator/PInvokeGeneratorConfiguration.cs b/sources/ClangSharp.PInvokeGenerator/PInvokeGeneratorConfiguration.cs index 08df9c7b..dc0630e6 100644 --- a/sources/ClangSharp.PInvokeGenerator/PInvokeGeneratorConfiguration.cs +++ b/sources/ClangSharp.PInvokeGenerator/PInvokeGeneratorConfiguration.cs @@ -37,6 +37,7 @@ public sealed class PInvokeGeneratorConfiguration private readonly SortedDictionary> _withAttributes; private readonly SortedDictionary _withCallConvs; private readonly SortedDictionary _withClasses; + private readonly SortedDictionary _withGuids; private readonly SortedDictionary _withLibraryPaths; private readonly SortedDictionary _withNamespaces; private readonly SortedDictionary _withTransparentStructs; @@ -84,6 +85,7 @@ public PInvokeGeneratorConfiguration(string defaultNamespace, string outputLocat _withAttributes = new SortedDictionary>(); _withCallConvs = new SortedDictionary(); _withClasses = new SortedDictionary(); + _withGuids = new SortedDictionary(); _withLibraryPaths = new SortedDictionary(); _withNamespaces = new SortedDictionary(); _withTransparentStructs = new SortedDictionary(); @@ -192,6 +194,8 @@ public IReadOnlyCollection ExcludedNames public bool GenerateFileScopedNamespaces => _options.HasFlag(PInvokeGeneratorConfigurationOptions.GenerateFileScopedNamespaces); + public bool GenerateGuidMember => _options.HasFlag(PInvokeGeneratorConfigurationOptions.GenerateGuidMember); + public bool GenerateHelperTypes => _options.HasFlag(PInvokeGeneratorConfigurationOptions.GenerateHelperTypes); public bool GenerateMacroBindings => _options.HasFlag(PInvokeGeneratorConfigurationOptions.GenerateMacroBindings); @@ -369,16 +373,16 @@ public IReadOnlyDictionary WithClasses } } - public IReadOnlyCollection WithManualImports + public IReadOnlyDictionary WithGuids { get { - return _withManualImports; + return _withGuids; } init { - AddRange(_withManualImports, value); + AddRange(_withGuids, value); } } @@ -395,6 +399,19 @@ public IReadOnlyDictionary WithLibraryPaths } } + public IReadOnlyCollection WithManualImports + { + get + { + return _withManualImports; + } + + init + { + AddRange(_withManualImports, value); + } + } + public IReadOnlyDictionary WithNamespaces { get diff --git a/sources/ClangSharp.PInvokeGenerator/PInvokeGeneratorConfigurationOptions.cs b/sources/ClangSharp.PInvokeGenerator/PInvokeGeneratorConfigurationOptions.cs index 60605f91..9f435e70 100644 --- a/sources/ClangSharp.PInvokeGenerator/PInvokeGeneratorConfigurationOptions.cs +++ b/sources/ClangSharp.PInvokeGenerator/PInvokeGeneratorConfigurationOptions.cs @@ -74,5 +74,7 @@ public enum PInvokeGeneratorConfigurationOptions : ulong GenerateSetsLastSystemErrorAttribute = 1UL << 31, GenerateDocIncludes = 1UL << 32, + + GenerateGuidMember = 1UL << 33, } } diff --git a/sources/ClangSharpPInvokeGenerator/Program.cs b/sources/ClangSharpPInvokeGenerator/Program.cs index 18d61955..fea5dcc5 100644 --- a/sources/ClangSharpPInvokeGenerator/Program.cs +++ b/sources/ClangSharpPInvokeGenerator/Program.cs @@ -45,6 +45,7 @@ public class Program private static Option s_withAttributeNameValuePairs; private static Option s_withCallConvNameValuePairs; private static Option s_withClassNameValuePairs; + private static Option s_withGuidNameValuePairs; private static Option s_withLibraryPathNameValuePairs; private static Option s_withManualImports; private static Option s_withNamespaceNameValuePairs; @@ -103,6 +104,7 @@ public class Program new TwoColumnHelpRow("generate-cpp-attributes", "[CppAttributeList(\"\")] should be generated to document the encountered C++ attributes."), new TwoColumnHelpRow("generate-doc-includes", " xml documentation tags should be generated for declarations."), new TwoColumnHelpRow("generate-file-scoped-namespaces", "Namespaces should be scoped to the file to reduce nesting."), + new TwoColumnHelpRow("generate-guid-member", "Types with an associated GUID should have a corresponding member generated."), new TwoColumnHelpRow("generate-helper-types", "Code files should be generated for various helper attributes and declared transparent structs."), new TwoColumnHelpRow("generate-macro-bindings", "Bindings for macro-definitions should be generated. This currently only works with value like macros and not function-like ones."), new TwoColumnHelpRow("generate-marker-interfaces", "Bindings for marker interfaces representing native inheritance hierarchies should be generated."), @@ -147,6 +149,7 @@ public static async Task Main(params string[] args) s_withAttributeNameValuePairs = GetWithAttributeOption(); s_withCallConvNameValuePairs = GetWithCallConvOption(); s_withClassNameValuePairs = GetWithClassOption(); + s_withGuidNameValuePairs = GetWithGuidOption(); s_withLibraryPathNameValuePairs = GetWithLibraryPathOption(); s_withManualImports = GetWithManualImportOption(); s_withNamespaceNameValuePairs = GetWithNamespaceOption(); @@ -182,6 +185,7 @@ public static async Task Main(params string[] args) s_withAttributeNameValuePairs, s_withCallConvNameValuePairs, s_withClassNameValuePairs, + s_withGuidNameValuePairs, s_withLibraryPathNameValuePairs, s_withManualImports, s_withNamespaceNameValuePairs, @@ -234,6 +238,7 @@ public static void Run(InvocationContext context) var withAttributeNameValuePairs = context.ParseResult.GetValueForOption(s_withAttributeNameValuePairs); var withCallConvNameValuePairs = context.ParseResult.GetValueForOption(s_withCallConvNameValuePairs); var withClassNameValuePairs = context.ParseResult.GetValueForOption(s_withClassNameValuePairs); + var withGuidNameValuePairs = context.ParseResult.GetValueForOption(s_withGuidNameValuePairs); var withLibraryPathNameValuePairs = context.ParseResult.GetValueForOption(s_withLibraryPathNameValuePairs); var withManualImports = context.ParseResult.GetValueForOption(s_withManualImports); var withNamespaceNameValuePairs = context.ParseResult.GetValueForOption(s_withNamespaceNameValuePairs); @@ -276,6 +281,7 @@ public static void Run(InvocationContext context) ParseKeyValuePairs(withAttributeNameValuePairs, errorList, out Dictionary> withAttributes); ParseKeyValuePairs(withCallConvNameValuePairs, errorList, out Dictionary withCallConvs); ParseKeyValuePairs(withClassNameValuePairs, errorList, out Dictionary withClasses); + ParseKeyValuePairs(withGuidNameValuePairs, errorList, out Dictionary withGuids); ParseKeyValuePairs(withLibraryPathNameValuePairs, errorList, out Dictionary withLibraryPaths); ParseKeyValuePairs(withNamespaceNameValuePairs, errorList, out Dictionary withNamespaces); ParseKeyValuePairs(withTransparentStructNameValuePairs, errorList, out Dictionary withTransparentStructs); @@ -492,6 +498,12 @@ public static void Run(InvocationContext context) break; } + case "generate-guid-member": + { + configOptions |= PInvokeGeneratorConfigurationOptions.GenerateGuidMember; + break; + } + case "generate-helper-types": { configOptions |= PInvokeGeneratorConfigurationOptions.GenerateHelperTypes; @@ -651,6 +663,7 @@ public static void Run(InvocationContext context) WithAttributes = withAttributes, WithCallConvs = withCallConvs, WithClasses = withClasses, + WithGuids = withGuids, WithLibraryPaths = withLibraryPaths, WithManualImports = withManualImports, WithNamespaces = withNamespaces, @@ -806,6 +819,38 @@ private static void ParseKeyValuePairs(IEnumerable keyValuePairs, List keyValuePairs, List errorList, out Dictionary result) + { + result = new Dictionary(); + + foreach (var keyValuePair in keyValuePairs) + { + var parts = keyValuePair.Split('='); + + if (parts.Length != 2) + { + errorList.Add($"Error: Invalid key/value pair argument: {keyValuePair}. Expected 'name=value'"); + continue; + } + + var key = parts[0].TrimEnd(); + + if (result.ContainsKey(key)) + { + errorList.Add($"Error: A key with the given name already exists: {key}. Existing: {result[key]}"); + continue; + } + + if (!Guid.TryParse(parts[1].TrimStart(), out var guid)) + { + errorList.Add($"Error: Failed to parse guid: {parts[1]}"); + continue; + } + + result.Add(key, guid); + } + } + private static void ParseKeyValuePairs(IEnumerable keyValuePairs, List errorList, out Dictionary result) { result = new Dictionary(); @@ -1124,6 +1169,17 @@ private static Option GetWithClassOption() }; } + private static Option GetWithGuidOption() + { + return new Option( + aliases: new string[] { "--with-guid", "-wg" }, + description: "A GUID to be used for the given declaration during binding generation.", + getDefaultValue: Array.Empty + ) { + AllowMultipleArgumentsPerToken = true + }; + } + private static Option GetWithLibraryPathOption() { return new Option( From a1461ab5d2da602fc14f81f1bec820a0b8da6f18 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Fri, 17 Jun 2022 00:54:48 -0700 Subject: [PATCH 3/4] Ensure that attributes get basic handling --- .../ClangSharp.Interop/Extensions/CXCursor.cs | 8 +-- .../PInvokeGenerator.cs | 53 +++++++++++++++++++ 2 files changed, 57 insertions(+), 4 deletions(-) diff --git a/sources/ClangSharp.Interop/Extensions/CXCursor.cs b/sources/ClangSharp.Interop/Extensions/CXCursor.cs index 5bfcdef8..e58251e2 100644 --- a/sources/ClangSharp.Interop/Extensions/CXCursor.cs +++ b/sources/ClangSharp.Interop/Extensions/CXCursor.cs @@ -27,16 +27,16 @@ public string AttrKindSpelling { Debug.Assert(CX_AttrKind.CX_AttrKind_FirstDeclOrTypeAttr == CX_AttrKind.CX_AttrKind_AArch64VectorPcs); Debug.Assert(CX_AttrKind.CX_AttrKind_LastDeclOrTypeAttr == CX_AttrKind.CX_AttrKind_VectorCall); - Debug.Assert(CX_AttrKind.CX_AttrKind_FirstInheritableParamAttr == CX_AttrKind.CX_AttrKind_SwiftContext); + Debug.Assert(CX_AttrKind.CX_AttrKind_FirstInheritableParamAttr == CX_AttrKind.CX_AttrKind_SwiftAsyncContext); Debug.Assert(CX_AttrKind.CX_AttrKind_LastInheritableParamAttr == CX_AttrKind.CX_AttrKind_UseHandle); - Debug.Assert(CX_AttrKind.CX_AttrKind_FirstParameterABIAttr == CX_AttrKind.CX_AttrKind_SwiftContext); + Debug.Assert(CX_AttrKind.CX_AttrKind_FirstParameterABIAttr == CX_AttrKind.CX_AttrKind_SwiftAsyncContext); Debug.Assert(CX_AttrKind.CX_AttrKind_LastParameterABIAttr == CX_AttrKind.CX_AttrKind_SwiftIndirectResult); Debug.Assert(CX_AttrKind.CX_AttrKind_LastAttr == CX_AttrKind.CX_AttrKind_Thread); Debug.Assert(CX_AttrKind.CX_AttrKind_FirstTypeAttr == CX_AttrKind.CX_AttrKind_AddressSpace); Debug.Assert(CX_AttrKind.CX_AttrKind_LastTypeAttr == CX_AttrKind.CX_AttrKind_UPtr); Debug.Assert(CX_AttrKind.CX_AttrKind_FirstStmtAttr == CX_AttrKind.CX_AttrKind_FallThrough); - Debug.Assert(CX_AttrKind.CX_AttrKind_LastStmtAttr == CX_AttrKind.CX_AttrKind_Suppress); - Debug.Assert(CX_AttrKind.CX_AttrKind_FirstInheritableAttr == CX_AttrKind.CX_AttrKind_AArch64VectorPcs); + Debug.Assert(CX_AttrKind.CX_AttrKind_LastStmtAttr == CX_AttrKind.CX_AttrKind_Unlikely); + Debug.Assert(CX_AttrKind.CX_AttrKind_FirstInheritableAttr == CX_AttrKind.CX_AttrKind_NoMerge); Debug.Assert(CX_AttrKind.CX_AttrKind_LastInheritableAttr == CX_AttrKind.CX_AttrKind_XRayLogArgs); return AttrKind switch diff --git a/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.cs b/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.cs index 56368862..6b5aac9c 100644 --- a/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.cs +++ b/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.cs @@ -5698,6 +5698,59 @@ private void WithAttributes(NamedDecl namedDecl, bool onlySupportedOSPlatform = outputBuilder.WriteCustomAttribute(attribute); } } + + if (!isTestOutput && namedDecl.HasAttrs) + { + foreach (var attr in namedDecl.Attrs) + { + switch (attr.Kind) + { + case CX_AttrKind.CX_AttrKind_Aligned: + case CX_AttrKind.CX_AttrKind_AlwaysInline: + case CX_AttrKind.CX_AttrKind_DLLExport: + case CX_AttrKind.CX_AttrKind_DLLImport: + { + // Nothing to handle + break; + } + + case CX_AttrKind.CX_AttrKind_Deprecated: + { + var attrText = GetSourceRangeContents(namedDecl.TranslationUnit.Handle, attr.Extent); + + var textStart = attrText.IndexOf('"'); + var textLength = attrText.LastIndexOf('"') - textStart; + + if (textLength > 2) + { + var text = attrText.AsSpan(textStart + 1, textLength - 2); + outputBuilder.WriteCustomAttribute($"Obsolete(\"{text}\")"); + } + else + { + outputBuilder.WriteCustomAttribute($"Obsolete"); + } + break; + } + + case CX_AttrKind.CX_AttrKind_MSNoVTable: + case CX_AttrKind.CX_AttrKind_MSAllocator: + case CX_AttrKind.CX_AttrKind_MaxFieldAlignment: + case CX_AttrKind.CX_AttrKind_SelectAny: + case CX_AttrKind.CX_AttrKind_Uuid: + { + // Nothing to handle + break; + } + + default: + { + AddDiagnostic(DiagnosticLevel.Warning, $"Unsupported attribute: '{attr.KindSpelling}'. Generated bindings may be incomplete.", namedDecl); + break; + } + } + } + } } private string GetLibraryPath(string remappedName) From bccf6af4a3000d42cacbfcfeae11a771799e643e Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Fri, 17 Jun 2022 00:55:52 -0700 Subject: [PATCH 4/4] Ensure that generated transparent structs are readonly --- sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.cs b/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.cs index 6b5aac9c..61d26ab6 100644 --- a/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.cs +++ b/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.cs @@ -652,7 +652,7 @@ static void GenerateTransparentStructs(PInvokeGenerator generator) } sw.Write(indentString); - sw.Write("public "); + sw.Write("public readonly "); if (isTypePointer || IsTransparentStructHexBased(kind)) {