diff --git a/Directory.Build.targets b/Directory.Build.targets
index 4390bae9..b4c1f5b5 100644
--- a/Directory.Build.targets
+++ b/Directory.Build.targets
@@ -37,7 +37,7 @@
-
+
diff --git a/README.md b/README.md
index 3526ae9a..ce808223 100644
--- a/README.md
+++ b/README.md
@@ -194,6 +194,7 @@ Options:
generate-tests-xunit Basic tests validating size, blittability, and associated metadata should be generated for XUnit.
generate-aggressive-inlining [MethodImpl(MethodImplOptions.AggressiveInlining)] should be added to generated helper functions.
generate-cpp-attributes [CppAttributeList("")] should be generated to document the encountered C++ attributes.
+ generate-doc-includes <include> xml documentation tags should be generated for declarations.
generate-file-scoped-namespaces Namespaces should be scoped to the file to reduce nesting.
generate-helper-types Code files should be generated for various helper attributes and declared transparent structs.
generate-macro-bindings Bindings for macro-definitions should be generated. This currently only works with value like macros and not function-like ones.
diff --git a/sources/ClangSharp.PInvokeGenerator/Abstractions/FieldDesc.cs b/sources/ClangSharp.PInvokeGenerator/Abstractions/FieldDesc.cs
index 23e4a0da..ca13f2bc 100644
--- a/sources/ClangSharp.PInvokeGenerator/Abstractions/FieldDesc.cs
+++ b/sources/ClangSharp.PInvokeGenerator/Abstractions/FieldDesc.cs
@@ -10,6 +10,7 @@ internal struct FieldDesc
public AccessSpecifier AccessSpecifier { get; set; }
public string NativeTypeName { get; set; }
public string EscapedName { get; set; }
+ public string ParentName { get; set; }
public int? Offset { get; set; }
public bool NeedsNewKeyword { get; set; }
public bool HasBody { get; set; }
diff --git a/sources/ClangSharp.PInvokeGenerator/Abstractions/FunctionOrDelegateDesc.cs b/sources/ClangSharp.PInvokeGenerator/Abstractions/FunctionOrDelegateDesc.cs
index 79ec2b0d..4b8837ff 100644
--- a/sources/ClangSharp.PInvokeGenerator/Abstractions/FunctionOrDelegateDesc.cs
+++ b/sources/ClangSharp.PInvokeGenerator/Abstractions/FunctionOrDelegateDesc.cs
@@ -12,6 +12,7 @@ internal struct FunctionOrDelegateDesc
public string NativeTypeName { get; set; }
public string EscapedName { get; set; }
public string EntryPoint { get; set; }
+ public string ParentName { get; set; }
public string LibraryPath { get; set; }
public string ReturnType { get; set; }
public CallingConvention CallingConvention { get; set; }
@@ -19,6 +20,7 @@ internal struct FunctionOrDelegateDesc
public long? VtblIndex { get; set; }
public CXSourceLocation? Location { get; set; }
public bool HasBody { get; set; }
+ public bool IsInherited { get; set; }
public bool IsVirtual
{
diff --git a/sources/ClangSharp.PInvokeGenerator/Abstractions/ValueDesc.cs b/sources/ClangSharp.PInvokeGenerator/Abstractions/ValueDesc.cs
index a071d1c6..1c0aa1ae 100644
--- a/sources/ClangSharp.PInvokeGenerator/Abstractions/ValueDesc.cs
+++ b/sources/ClangSharp.PInvokeGenerator/Abstractions/ValueDesc.cs
@@ -11,6 +11,8 @@ internal struct ValueDesc
public string TypeName { get; set; }
public string EscapedName { get; set; }
public string NativeTypeName { get; set; }
+
+ public string ParentName { get; set; }
public ValueKind Kind { get; set; }
public ValueFlags Flags { get; set; }
public CXSourceLocation? Location { get; set; }
diff --git a/sources/ClangSharp.PInvokeGenerator/CSharp/CSharpOutputBuilder.VisitDecl.cs b/sources/ClangSharp.PInvokeGenerator/CSharp/CSharpOutputBuilder.VisitDecl.cs
index bc558938..84d51f3c 100644
--- a/sources/ClangSharp.PInvokeGenerator/CSharp/CSharpOutputBuilder.VisitDecl.cs
+++ b/sources/ClangSharp.PInvokeGenerator/CSharp/CSharpOutputBuilder.VisitDecl.cs
@@ -31,6 +31,17 @@ public void EndUnchecked()
public void BeginValue(in ValueDesc desc)
{
+ if (_config.GenerateDocIncludes && (desc.Kind == ValueKind.Enumerator))
+ {
+ WriteIndented("/// ");
+ }
+
if (desc.NativeTypeName is not null)
{
AddNativeTypeNameAttribute(desc.NativeTypeName);
@@ -174,6 +185,11 @@ public void EndValue(in ValueDesc desc)
case ValueKind.Enumerator:
{
WriteLine(',');
+
+ if (_config.GenerateDocIncludes)
+ {
+ NeedsNewline = true;
+ }
break;
}
@@ -204,6 +220,15 @@ public void EndValue(in ValueDesc desc)
public void BeginEnum(in EnumDesc desc)
{
+ if (_config.GenerateDocIncludes)
+ {
+ WriteIndented("/// ");
+ }
+
if (desc.NativeType is not null)
{
AddNativeTypeNameAttribute(desc.NativeType);
@@ -234,6 +259,17 @@ public void BeginEnum(in EnumDesc desc)
public void BeginField(in FieldDesc desc)
{
+ if (_config.GenerateDocIncludes && !string.IsNullOrWhiteSpace(desc.ParentName))
+ {
+ WriteIndented("/// ");
+ }
+
if (desc.Offset is not null)
{
WriteIndentedLine($"[FieldOffset({desc.Offset})]");
@@ -299,6 +335,28 @@ public void EndField(in FieldDesc desc)
public void BeginFunctionOrDelegate(in FunctionOrDelegateDesc desc, ref bool isMethodClassUnsafe)
{
+ if (_config.GenerateDocIncludes && !string.IsNullOrEmpty(desc.ParentName))
+ {
+ if (desc.IsInherited)
+ {
+ WriteIndented("/// ");
+ }
+ else
+ {
+ WriteIndented("/// ");
+ }
+ }
+
if (desc.IsVirtual)
{
Debug.Assert(!desc.HasFnPtrCodeGen);
@@ -599,6 +657,15 @@ public void EndFunctionOrDelegate(in FunctionOrDelegateDesc desc)
public void BeginStruct(in StructDesc desc)
{
+ if (_config.GenerateDocIncludes)
+ {
+ WriteIndented("/// ");
+ }
+
if (desc.LayoutAttribute is not null)
{
AddUsingDirective("System.Runtime.InteropServices");
@@ -687,7 +754,20 @@ public void BeginMarkerInterface(string[] baseTypeNames)
public void BeginExplicitVtbl()
{
- WriteIndentedLine("public partial struct Vtbl");
+ WriteIndented("public partial struct Vtbl");
+
+ if (_config.GenerateMarkerInterfaces && !_config.ExcludeFnptrCodegen)
+ {
+ WriteLine("");
+ IncreaseIndentation();
+ WriteIndentedLine("where TSelf : unmanaged, Interface");
+ DecreaseIndentation();
+ }
+ else
+ {
+ WriteNewline();
+ }
+
WriteBlockStart();
}
diff --git a/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.VisitDecl.cs b/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.VisitDecl.cs
index 0b434635..0e0ed742 100644
--- a/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.VisitDecl.cs
+++ b/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.VisitDecl.cs
@@ -263,11 +263,23 @@ private void VisitEnumConstantDecl(EnumConstantDecl enumConstantDecl)
var escapedName = EscapeName(name);
var typeName = GetTargetTypeName(enumConstantDecl, out _);
var isAnonymousEnum = false;
+ var parentName = "";
- if ((enumConstantDecl.DeclContext is EnumDecl enumDecl) && GetRemappedCursorName(enumDecl).StartsWith("__AnonymousEnum_"))
+ if (enumConstantDecl.DeclContext is EnumDecl enumDecl)
{
- isAnonymousEnum = true;
- accessSpecifier = GetAccessSpecifier(enumDecl);
+ parentName = GetRemappedCursorName(enumDecl);
+
+ if (parentName.StartsWith("__AnonymousEnum_"))
+ {
+ parentName = "";
+ isAnonymousEnum = true;
+ accessSpecifier = GetAccessSpecifier(enumDecl);
+ }
+ }
+
+ if (string.IsNullOrEmpty(parentName))
+ {
+ parentName = _outputBuilder.Name;
}
var kind = isAnonymousEnum ? ValueKind.Primitive : ValueKind.Enumerator;
@@ -283,17 +295,17 @@ private void VisitEnumConstantDecl(EnumConstantDecl enumConstantDecl)
TypeName = typeName,
EscapedName = escapedName,
NativeTypeName = null,
+ ParentName = parentName,
Kind = kind,
Flags = flags,
Location = enumConstantDecl.Location,
WriteCustomAttrs = static context => {
- (var name, var generator) = ((string, PInvokeGenerator))context;
- generator.WithAttributes(name);
+ (var enumConstantDecl, var generator) = ((EnumConstantDecl, PInvokeGenerator))context;
- generator.WithUsings("*");
- generator.WithUsings(name);
+ generator.WithAttributes(enumConstantDecl);
+ generator.WithUsings(enumConstantDecl);
},
- CustomAttrGeneratorData = (name, this),
+ CustomAttrGeneratorData = (enumConstantDecl, this),
};
_outputBuilder.BeginValue(in desc);
@@ -354,13 +366,12 @@ private void VisitEnumDecl(EnumDecl enumDecl)
Location = enumDecl.Location,
IsNested = enumDecl.DeclContext is TagDecl,
WriteCustomAttrs = static context => {
- (var name, var generator) = ((string, PInvokeGenerator))context;
- generator.WithAttributes(name);
+ (var enumDecl, var generator) = ((EnumDecl, PInvokeGenerator))context;
- generator.WithUsings("*");
- generator.WithUsings(name);
+ generator.WithAttributes(enumDecl);
+ generator.WithUsings(enumDecl);
},
- CustomAttrGeneratorData = (name, this),
+ CustomAttrGeneratorData = (enumDecl, this),
};
_outputBuilder.BeginEnum(in desc);
@@ -401,17 +412,17 @@ private void VisitFieldDecl(FieldDecl fieldDecl)
AccessSpecifier = accessSpecifier,
NativeTypeName = nativeTypeName,
EscapedName = escapedName,
+ ParentName = GetRemappedCursorName(fieldDecl.Parent),
Offset = offset,
NeedsNewKeyword = NeedsNewKeyword(name),
Location = fieldDecl.Location,
WriteCustomAttrs = static context => {
- (var name, var generator) = ((string, PInvokeGenerator))context;
- generator.WithAttributes(name);
+ (var fieldDecl, var generator) = ((FieldDecl, PInvokeGenerator))context;
- generator.WithUsings("*");
- generator.WithUsings(name);
+ generator.WithAttributes(fieldDecl);
+ generator.WithUsings(fieldDecl);
},
- CustomAttrGeneratorData = (name, this),
+ CustomAttrGeneratorData = (fieldDecl, this),
};
_outputBuilder.BeginField(in desc);
@@ -452,11 +463,13 @@ private void VisitFunctionDecl(FunctionDecl functionDecl)
var name = GetRemappedCursorName(functionDecl);
var className = name;
+ var parentName = "";
if (functionDecl.DeclContext is not CXXRecordDecl cxxRecordDecl)
{
cxxRecordDecl = null;
className = GetClass(name);
+ parentName = className;
StartUsingOutputBuilder(className);
}
else if ((Cursor)functionDecl.LexicalDeclContext != cxxRecordDecl)
@@ -500,13 +513,14 @@ private void VisitFunctionDecl(FunctionDecl functionDecl)
AccessSpecifier = accessSppecifier,
NativeTypeName = nativeTypeName,
EscapedName = escapedName,
+ ParentName = parentName,
EntryPoint = entryPoint,
CallingConvention = callingConventionName,
LibraryPath = isDllImport ? GetLibraryPath(name).Unquote() : null,
IsVirtual = isVirtual,
IsDllImport = isDllImport,
HasFnPtrCodeGen = !_config.ExcludeFnptrCodegen,
- SetLastError = GetSetLastError(name),
+ SetLastError = GetSetLastError(functionDecl),
IsCxx = cxxMethodDecl is not null,
IsStatic = isDllImport || (cxxMethodDecl?.IsStatic ?? true),
NeedsNewKeyword = NeedsNewKeyword(escapedName, functionDecl.Parameters),
@@ -519,13 +533,17 @@ private void VisitFunctionDecl(FunctionDecl functionDecl)
Location = functionDecl.Location,
HasBody = body is not null,
WriteCustomAttrs = static context => {
- (var name, var generator) = ((string, PInvokeGenerator))context;
- generator.WithAttributes(name);
+ (var functionDecl, var outputBuilder, var generator) = ((FunctionDecl, IOutputBuilder, PInvokeGenerator))context;
- generator.WithUsings("*");
- generator.WithUsings(name);
+ generator.WithAttributes(functionDecl);
+ generator.WithUsings(functionDecl);
+
+ if (generator.HasSuppressGCTransition(functionDecl))
+ {
+ outputBuilder.WriteCustomAttribute("SuppressGCTransition");
+ }
},
- CustomAttrGeneratorData = (name, this),
+ CustomAttrGeneratorData = (functionDecl, _outputBuilder, this),
};
_ = _isTopLevelClassUnsafe.TryGetValue(className, out var isUnsafe);
@@ -548,14 +566,6 @@ private void VisitFunctionDecl(FunctionDecl functionDecl)
var parameterDesc = new ParameterDesc {
Name = "pThis",
Type = $"{cxxRecordEscapedName}*",
- WriteCustomAttrs = static context => {
- (var name, var generator) = ((string, PInvokeGenerator))context;
- generator.WithAttributes(name);
-
- generator.WithUsings("*");
- generator.WithUsings(name);
- },
- CustomAttrGeneratorData = ("pThis", this),
};
_outputBuilder.BeginParameter(in parameterDesc);
@@ -748,18 +758,18 @@ private void VisitIndirectFieldDecl(IndirectFieldDecl indirectFieldDecl)
AccessSpecifier = accessSpecifier,
NativeTypeName = null,
EscapedName = escapedName,
+ ParentName = GetRemappedCursorName(fieldDecl.Parent),
Offset = null,
NeedsNewKeyword = false,
Location = fieldDecl.Location,
HasBody = true,
WriteCustomAttrs = static context => {
- (var name, var generator) = ((string, PInvokeGenerator))context;
- generator.WithAttributes(name);
+ (var fieldDecl, var generator) = ((FieldDecl, PInvokeGenerator))context;
- generator.WithUsings("*");
- generator.WithUsings(name);
+ generator.WithAttributes(fieldDecl);
+ generator.WithUsings(fieldDecl);
},
- CustomAttrGeneratorData = (name, this),
+ CustomAttrGeneratorData = (fieldDecl, this),
};
_outputBuilder.WriteDivider(true);
@@ -1002,11 +1012,10 @@ void ForFunctionDecl(ParmVarDecl parmVarDecl, FunctionDecl functionDecl)
: null,
Location = parmVarDecl.Location,
WriteCustomAttrs = static context => {
- (var name, var generator, var csharpOutputBuilder, var defaultArg) = ((string, PInvokeGenerator, CSharp.CSharpOutputBuilder, Expr))context;
- generator.WithAttributes(name);
+ (var parmVarDecl, var generator, var csharpOutputBuilder, var defaultArg) = ((ParmVarDecl, PInvokeGenerator, CSharp.CSharpOutputBuilder, Expr))context;
- generator.WithUsings("*");
- generator.WithUsings(name);
+ generator.WithAttributes(parmVarDecl);
+ generator.WithUsings(parmVarDecl);
if (defaultArg is not null)
{
@@ -1020,7 +1029,7 @@ void ForFunctionDecl(ParmVarDecl parmVarDecl, FunctionDecl functionDecl)
csharpOutputBuilder.WriteCustomAttribute("Optional", null);
}
},
- CustomAttrGeneratorData = (name, this, null as CSharp.CSharpOutputBuilder, null as Expr),
+ CustomAttrGeneratorData = (parmVarDecl, this, null as CSharp.CSharpOutputBuilder, null as Expr),
};
var handledDefaultArg = false;
@@ -1036,7 +1045,7 @@ void ForFunctionDecl(ParmVarDecl parmVarDecl, FunctionDecl functionDecl)
return _config.WithTransparentStructs.ContainsKey(typeName);
})))
{
- desc.CustomAttrGeneratorData = (name, this, csharpOutputBuilder, isExprDefaultValue ? null : parmVarDecl.DefaultArg);
+ desc.CustomAttrGeneratorData = (parmVarDecl, this, csharpOutputBuilder, isExprDefaultValue ? null : parmVarDecl.DefaultArg);
handledDefaultArg = true;
}
}
@@ -1103,13 +1112,12 @@ void ForTypedefDecl(ParmVarDecl parmVarDecl, TypedefDecl typedefDecl)
: null,
Location = parmVarDecl.Location,
WriteCustomAttrs = static context => {
- (var name, var generator) = ((string, PInvokeGenerator))context;
- generator.WithAttributes(name);
+ (var parmVarDecl, var generator) = ((ParmVarDecl, PInvokeGenerator))context;
- generator.WithUsings("*");
- generator.WithUsings(name);
+ generator.WithAttributes(parmVarDecl);
+ generator.WithUsings(parmVarDecl);
},
- CustomAttrGeneratorData = (name, this),
+ CustomAttrGeneratorData = (parmVarDecl, this),
};
_outputBuilder.BeginParameter(in desc);
@@ -1171,8 +1179,7 @@ private void VisitRecordDecl(RecordDecl recordDecl)
_testOutputBuilder.Write(escapedName);
_testOutputBuilder.WriteLine("\" /> struct.");
- WithAttributes("*", onlySupportedOSPlatform: true, isTestOutput: true);
- WithAttributes(name, onlySupportedOSPlatform: true, isTestOutput: true);
+ WithAttributes(recordDecl, onlySupportedOSPlatform: true, isTestOutput: true);
_testOutputBuilder.WriteIndented("public static unsafe partial class ");
_testOutputBuilder.Write(escapedName);
@@ -1298,13 +1305,12 @@ private void VisitRecordDecl(RecordDecl recordDecl)
Location = recordDecl.Location,
IsNested = recordDecl.DeclContext is TagDecl,
WriteCustomAttrs = static context => {
- (var name, var generator) = ((string, PInvokeGenerator))context;
- generator.WithAttributes(name);
+ (var recordDecl, var generator) = ((RecordDecl, PInvokeGenerator))context;
- generator.WithUsings("*");
- generator.WithUsings(name);
+ generator.WithAttributes(recordDecl);
+ generator.WithUsings(recordDecl);
},
- CustomAttrGeneratorData = (name, this),
+ CustomAttrGeneratorData = (recordDecl, this),
};
if (!isTopLevelStruct)
@@ -1378,14 +1384,6 @@ private void VisitRecordDecl(RecordDecl recordDecl)
EscapedName = "lpVtbl",
Offset = null,
NeedsNewKeyword = false,
- WriteCustomAttrs = static context => {
- (var name, var generator) = ((string, PInvokeGenerator))context;
- generator.WithAttributes(name);
-
- generator.WithUsings("*");
- generator.WithUsings(name);
- },
- CustomAttrGeneratorData = ("lpVtbl", this),
};
_outputBuilder.BeginField(in fieldDesc);
@@ -1422,14 +1420,6 @@ private void VisitRecordDecl(RecordDecl recordDecl)
NeedsNewKeyword = false,
InheritedFrom = parent,
Location = cxxBaseSpecifier.Location,
- WriteCustomAttrs = static context => {
- (var name, var generator) = ((string, PInvokeGenerator))context;
- generator.WithAttributes(name);
-
- generator.WithUsings("*");
- generator.WithUsings(name);
- },
- CustomAttrGeneratorData = (baseFieldName, this),
};
_outputBuilder.BeginField(in fieldDesc);
@@ -1789,13 +1779,12 @@ void OutputMarkerInterface(CXXRecordDecl cxxRecordDecl, CXXMethodDecl cxxMethodD
VtblIndex = _config.GenerateVtblIndexAttribute ? cxxMethodDecl.VtblIndex : -1,
Location = cxxMethodDecl.Location,
WriteCustomAttrs = static context => {
- (var name, var generator) = ((string, PInvokeGenerator))context;
- generator.WithAttributes(name);
+ (var cxxMethodDecl, var generator) = ((CXXMethodDecl, PInvokeGenerator))context;
- generator.WithUsings("*");
- generator.WithUsings(name);
+ generator.WithAttributes(cxxMethodDecl);
+ generator.WithUsings(cxxMethodDecl);
},
- CustomAttrGeneratorData = (name, this),
+ CustomAttrGeneratorData = (cxxMethodDecl, this),
};
var isUnsafe = true;
@@ -1859,6 +1848,12 @@ void OutputVtblEntry(CXXRecordDecl cxxRecordDecl, CXXMethodDecl cxxMethodDecl)
var cxxMethodDeclTypeName = GetRemappedTypeName(cxxMethodDecl, cxxRecordDecl, cxxMethodDecl.Type, out var nativeTypeName, skipUsing: false, ignoreTransparentStructsWhereRequired: true);
+ if (_config.GenerateMarkerInterfaces && !_config.ExcludeFnptrCodegen)
+ {
+ var cxxRecordDeclName = GetRemappedCursorName(cxxRecordDecl);
+ cxxMethodDeclTypeName = cxxMethodDeclTypeName.Replace($"<{cxxRecordDeclName}*,", " {
- (var name, var generator) = ((string, PInvokeGenerator))context;
- generator.WithAttributes(name);
+ (var cxxMethodDecl, var generator) = ((CXXMethodDecl, PInvokeGenerator))context;
- generator.WithUsings("*");
- generator.WithUsings(name);
+ generator.WithAttributes(cxxMethodDecl);
+ generator.WithUsings(cxxMethodDecl);
},
- CustomAttrGeneratorData = (remappedName, this),
+ CustomAttrGeneratorData = (cxxMethodDecl, this),
};
_outputBuilder.BeginField(in desc);
@@ -1908,6 +1902,15 @@ void OutputVtblHelperMethod(CXXRecordDecl cxxRecordDecl, CXXMethodDecl cxxMethod
var name = GetRemappedCursorName(cxxMethodDecl);
var needsReturnFixup = false;
var needsCastToTransparentStruct = false;
+ var cxxRecordDeclName = GetRemappedCursorName(cxxRecordDecl);
+ var parentName = cxxRecordDeclName;
+ var isInherited = false;
+
+ if (cxxMethodDecl.Parent != cxxRecordDecl)
+ {
+ parentName = GetRemappedCursorName(cxxMethodDecl.Parent);
+ isInherited = true;
+ }
if (returnType.Kind != CXTypeKind.CXType_Void)
{
@@ -1919,7 +1922,9 @@ void OutputVtblHelperMethod(CXXRecordDecl cxxRecordDecl, CXXMethodDecl cxxMethod
AccessSpecifier = AccessSpecifier.Public,
IsAggressivelyInlined = _config.GenerateAggressiveInlining,
EscapedName = EscapeAndStripName(name),
+ ParentName = parentName,
IsMemberFunction = true,
+ IsInherited = isInherited,
NativeTypeName = nativeTypeName,
NeedsNewKeyword = NeedsNewKeyword(name, cxxMethodDecl.Parameters),
HasFnPtrCodeGen = !_config.ExcludeFnptrCodegen,
@@ -1932,13 +1937,12 @@ void OutputVtblHelperMethod(CXXRecordDecl cxxRecordDecl, CXXMethodDecl cxxMethod
Location = cxxMethodDecl.Location,
HasBody = true,
WriteCustomAttrs = static context => {
- (var name, var generator) = ((string, PInvokeGenerator))context;
- generator.WithAttributes(name);
+ (var cxxMethodDecl, var generator) = ((CXXMethodDecl, PInvokeGenerator))context;
- generator.WithUsings("*");
- generator.WithUsings(name);
+ generator.WithAttributes(cxxMethodDecl);
+ generator.WithUsings(cxxMethodDecl);
},
- CustomAttrGeneratorData = (name, this),
+ CustomAttrGeneratorData = (cxxMethodDecl, this),
};
var isUnsafe = true;
@@ -1951,7 +1955,6 @@ void OutputVtblHelperMethod(CXXRecordDecl cxxRecordDecl, CXXMethodDecl cxxMethod
_outputBuilder.EndFunctionInnerPrototype();
_outputBuilder.BeginBody();
- var cxxRecordDeclName = GetRemappedCursorName(cxxRecordDecl);
var escapedCXXRecordDeclName = EscapeName(cxxRecordDeclName);
_outputBuilder.BeginInnerFunctionBody();
@@ -2171,14 +2174,6 @@ void VisitBitfieldDecl(FieldDecl fieldDecl, Type[] types, RecordDecl recordDecl,
Offset = fieldDecl.Parent.IsUnion ? 0 : null,
NeedsNewKeyword = false,
Location = fieldDecl.Location,
- WriteCustomAttrs = static context => {
- (var name, var generator) = ((string, PInvokeGenerator))context;
- generator.WithAttributes(name);
-
- generator.WithUsings("*");
- generator.WithUsings(name);
- },
- CustomAttrGeneratorData = (bitfieldName, this),
};
_outputBuilder.BeginField(in fieldDesc);
_outputBuilder.WriteRegularField(typeNameBacking, bitfieldName);
@@ -2363,18 +2358,18 @@ void VisitBitfieldDecl(FieldDecl fieldDecl, Type[] types, RecordDecl recordDecl,
AccessSpecifier = accessSpecifier,
NativeTypeName = nativeTypeName,
EscapedName = escapedName,
+ ParentName = GetRemappedCursorName(fieldDecl.Parent),
Offset = null,
NeedsNewKeyword = false,
Location = fieldDecl.Location,
HasBody = true,
WriteCustomAttrs = static context => {
- (var name, var generator) = ((string, PInvokeGenerator))context;
- generator.WithAttributes(name);
+ (var fieldDecl, var generator) = ((FieldDecl, PInvokeGenerator))context;
- generator.WithUsings("*");
- generator.WithUsings(name);
+ generator.WithAttributes(fieldDecl);
+ generator.WithUsings(fieldDecl);
},
- CustomAttrGeneratorData = (name, this),
+ CustomAttrGeneratorData = (fieldDecl, this),
};
_outputBuilder.WriteDivider();
@@ -2621,13 +2616,12 @@ void VisitConstantArrayFieldDecl(RecordDecl recordDecl, FieldDecl constantArray)
Location = constantArray.Location,
IsNested = true,
WriteCustomAttrs = static context => {
- (var name, var generator) = ((string, PInvokeGenerator))context;
- generator.WithAttributes(name);
+ (var fieldDecl, var generator) = ((FieldDecl, PInvokeGenerator))context;
- generator.WithUsings("*");
- generator.WithUsings(name);
+ generator.WithAttributes(fieldDecl);
+ generator.WithUsings(fieldDecl);
},
- CustomAttrGeneratorData = (name, this),
+ CustomAttrGeneratorData = (constantArray, this),
};
_outputBuilder.BeginStruct(in desc);
@@ -2673,14 +2667,6 @@ void VisitConstantArrayFieldDecl(RecordDecl recordDecl, FieldDecl constantArray)
Offset = null,
NeedsNewKeyword = false,
Location = constantArray.Location,
- WriteCustomAttrs = static context => {
- (var name, var generator) = ((string, PInvokeGenerator))context;
- generator.WithAttributes(name);
-
- generator.WithUsings("*");
- generator.WithUsings(name);
- },
- CustomAttrGeneratorData = (fieldName, this),
};
_outputBuilder.BeginField(in fieldDesc);
@@ -2702,14 +2688,6 @@ void VisitConstantArrayFieldDecl(RecordDecl recordDecl, FieldDecl constantArray)
var param = new ParameterDesc {
Name = "index",
Type = "int",
- WriteCustomAttrs = static context => {
- (var name, var generator) = ((string, PInvokeGenerator))context;
- generator.WithAttributes(name);
-
- generator.WithUsings("*");
- generator.WithUsings(name);
- },
- CustomAttrGeneratorData = ("index", this),
};
_outputBuilder.BeginParameter(in param);
_outputBuilder.EndParameter(in param);
@@ -2743,14 +2721,6 @@ void VisitConstantArrayFieldDecl(RecordDecl recordDecl, FieldDecl constantArray)
var param = new ParameterDesc {
Name = "index",
Type = "int",
- WriteCustomAttrs = static context => {
- (var name, var generator) = ((string, PInvokeGenerator))context;
- generator.WithAttributes(name);
-
- generator.WithUsings("*");
- generator.WithUsings(name);
- },
- CustomAttrGeneratorData = ("index", this),
};
_outputBuilder.BeginParameter(in param);
_outputBuilder.EndParameter(in param);
@@ -2787,14 +2757,6 @@ void VisitConstantArrayFieldDecl(RecordDecl recordDecl, FieldDecl constantArray)
ReturnType = $"Span<{typeName}>",
Location = constantArray.Location,
HasBody = true,
- WriteCustomAttrs = static context => {
- (var name, var generator) = ((string, PInvokeGenerator))context;
- generator.WithAttributes(name);
-
- generator.WithUsings("*");
- generator.WithUsings(name);
- },
- CustomAttrGeneratorData = ("AsSpan", this),
};
var isUnsafe = false;
@@ -2807,14 +2769,6 @@ void VisitConstantArrayFieldDecl(RecordDecl recordDecl, FieldDecl constantArray)
param = new ParameterDesc {
Name = "length",
Type = "int",
- WriteCustomAttrs = static context => {
- (var name, var generator) = ((string, PInvokeGenerator))context;
- generator.WithAttributes(name);
-
- generator.WithUsings("*");
- generator.WithUsings(name);
- },
- CustomAttrGeneratorData = ("length", this),
};
_outputBuilder.BeginParameter(in param);
@@ -2892,13 +2846,12 @@ void ForFunctionProtoType(TypedefDecl typedefDecl, FunctionProtoType functionPro
Location = typedefDecl.Location,
HasBody = true,
WriteCustomAttrs = static context => {
- (var name, var generator) = ((string, PInvokeGenerator))context;
- generator.WithAttributes(name);
+ (var typedefDecl, var generator) = ((TypedefDecl, PInvokeGenerator))context;
- generator.WithUsings("*");
- generator.WithUsings(name);
+ generator.WithAttributes(typedefDecl);
+ generator.WithUsings(typedefDecl);
},
- CustomAttrGeneratorData = (name, this),
+ CustomAttrGeneratorData = (typedefDecl, this),
};
var isUnsafe = desc.IsUnsafe;
@@ -3211,13 +3164,12 @@ private void VisitVarDecl(VarDecl varDecl)
Flags = flags,
Location = varDecl.Location,
WriteCustomAttrs = static context => {
- (var name, var generator) = ((string, PInvokeGenerator))context;
- generator.WithAttributes(name);
+ (var varDecl, var generator) = ((VarDecl, PInvokeGenerator))context;
- generator.WithUsings("*");
- generator.WithUsings(name);
+ generator.WithAttributes(varDecl);
+ generator.WithUsings(varDecl);
},
- CustomAttrGeneratorData = (name, this),
+ CustomAttrGeneratorData = (varDecl, this),
};
if (openedOutputBuilder)
diff --git a/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.cs b/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.cs
index 066e32d1..d6b3db5f 100644
--- a/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.cs
+++ b/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.cs
@@ -1914,9 +1914,7 @@ private CallingConvention GetCallingConvention(Cursor cursor, Cursor context, Ty
{
if (cursor is NamedDecl namedDecl)
{
- var remappedName = GetRemappedCursorName(namedDecl);
-
- if (_config.WithCallConvs.TryGetValue(remappedName, out var callConv) || _config.WithCallConvs.TryGetValue("*", out callConv))
+ if (TryGetRemappedValue(namedDecl, _config.WithCallConvs, out var callConv, matchStar: true))
{
if (Enum.TryParse(callConv, true, out var remappedCallingConvention))
{
@@ -2579,8 +2577,7 @@ private string GetRemappedTypeName(Cursor cursor, Cursor context, Type type, out
remappedName = "uint";
}
- WithType("*", ref remappedName, ref nativeTypeName);
- WithType(enumDeclName, ref remappedName, ref nativeTypeName);
+ WithType(enumDecl, ref remappedName, ref nativeTypeName);
}
}
@@ -3072,13 +3069,23 @@ private string GetTypeNameForPointeeType(Cursor cursor, Cursor context, Type roo
if (!isMacroDefinitionRecord)
{
_ = nameBuilder.Append(" unmanaged");
+ var hasSuppressGCTransition = HasSuppressGCTransition(cursor);
if (callConv != CallingConvention.Winapi)
{
_ = nameBuilder.Append('[');
_ = nameBuilder.Append(callConv.AsString(true));
+
+ if (hasSuppressGCTransition)
+ {
+ _ = nameBuilder.Append(", SuppressGCTransition");
+ }
_ = nameBuilder.Append(']');
}
+ else if (hasSuppressGCTransition)
+ {
+ _ = nameBuilder.Append("[SuppressGCTransition]");
+ }
}
_ = nameBuilder.Append('<');
@@ -3668,6 +3675,15 @@ private void GetTypeSize(Cursor cursor, Type type, ref long alignment32, ref lon
}
}
+ private bool HasSuppressGCTransition(Cursor cursor)
+ {
+ if (cursor is not NamedDecl namedDecl)
+ {
+ return false;
+ }
+ return HasRemapping(namedDecl, _config.WithSuppressGCTransitions);
+ }
+
private bool HasVtbl(CXXRecordDecl cxxRecordDecl)
{
var hasDirectVtbl = cxxRecordDecl.Methods.Any((method) => method.IsVirtual);
@@ -3779,7 +3795,7 @@ bool IsExcludedByFile(Cursor cursor)
declLocation.GetExpansionLocation(out var expansionFile, out var expansionLine, out var expansionColumn, out _);
- if ((expansionFile == file) && (expansionLine == line) && (expansionColumn == column) && (_config.TraversalNames.Length != 0))
+ if ((expansionFile == file) && (expansionLine == line) && (expansionColumn == column) && _config.TraversalNames.Any())
{
// clang_getLocation is a very expensive call, so exit early if the expansion file is the same
// However, if we are not explicitly specifying traversal names, its possible the expansion location
@@ -3920,7 +3936,7 @@ bool IsExcludedByName(Cursor cursor, ref uint isExcludedValue)
return true;
}
- if ((_config.IncludedNames.Length != 0) && !_config.IncludedNames.Contains(qualifiedName) && !_config.IncludedNames.Contains(dottedQualifiedName) && !_config.IncludedNames.Contains(name))
+ if (_config.IncludedNames.Any() && !_config.IncludedNames.Contains(qualifiedName) && !_config.IncludedNames.Contains(dottedQualifiedName) && !_config.IncludedNames.Contains(name))
{
if (_config.LogExclusions)
{
@@ -3958,7 +3974,7 @@ bool IsIncludedFileOrLocation(Cursor cursor, CXFile file, CXSourceLocation locat
{
return true;
}
- else if ((_config.TraversalNames.Length == 0) && location.IsFromMainFile)
+ else if (!_config.TraversalNames.Any() && location.IsFromMainFile)
{
return true;
}
@@ -5162,7 +5178,7 @@ private void StartUsingOutputBuilder(string name, bool includeTestOutput = false
{
if (!_outputBuilderFactory.TryGetOutputBuilder(nameTests, out var testOutputBuilder))
{
- CreateTestOutputBuilder(nameTests);
+ CreateTestOutputBuilder(name, nameTests);
}
else
{
@@ -5182,7 +5198,7 @@ private void StartUsingOutputBuilder(string name, bool includeTestOutput = false
if (includeTestOutput && !string.IsNullOrWhiteSpace(_config.TestOutputLocation))
{
- CreateTestOutputBuilder(nameTests);
+ CreateTestOutputBuilder(name, nameTests);
}
}
else
@@ -5193,7 +5209,7 @@ private void StartUsingOutputBuilder(string name, bool includeTestOutput = false
{
if (!_outputBuilderFactory.TryGetOutputBuilder(nameTests, out var testOutputBuilder))
{
- CreateTestOutputBuilder(nameTests);
+ CreateTestOutputBuilder(name, nameTests);
}
else
{
@@ -5206,9 +5222,9 @@ private void StartUsingOutputBuilder(string name, bool includeTestOutput = false
}
_outputBuilderUsers++;
- void CreateTestOutputBuilder(string name)
+ void CreateTestOutputBuilder(string name, string nameTests)
{
- _testOutputBuilder = _outputBuilderFactory.CreateTests(name);
+ _testOutputBuilder = _outputBuilderFactory.CreateTests(nameTests);
var isTopLevelStruct = _config.WithTypes.TryGetValue(name, out var withType) && (withType == "struct");
@@ -5525,11 +5541,11 @@ private void Visit(IEnumerable cursors)
private void Visit(IEnumerable cursors, IEnumerable excludedCursors) => Visit(cursors.Except(excludedCursors));
- private void WithAttributes(string remappedName, bool onlySupportedOSPlatform = false, bool isTestOutput = false)
+ private void WithAttributes(NamedDecl namedDecl, bool onlySupportedOSPlatform = false, bool isTestOutput = false)
{
var outputBuilder = isTestOutput ? _testOutputBuilder : _outputBuilder;
- if (_config.WithAttributes.TryGetValue(remappedName, out var attributes))
+ if (TryGetRemappedValue(namedDecl, _config.WithAttributes, out var attributes))
{
foreach (var attribute in attributes.Where((a) => !onlySupportedOSPlatform || a.StartsWith("SupportedOSPlatform(")))
{
@@ -5625,13 +5641,77 @@ private bool TryGetNamespace(string remappedName, out string namespaceName)
return _config.WithNamespaces.TryGetValue(remappedName, out namespaceName);
}
- private bool GetSetLastError(string remappedName) => _config.WithSetLastErrors.Contains("*") ||
- _config.WithSetLastErrors.Contains(remappedName);
+ private bool GetSetLastError(NamedDecl namedDecl) => HasRemapping(namedDecl, _config.WithSetLastErrors, matchStar: true);
+
+ private bool HasRemapping(NamedDecl namedDecl, IReadOnlyCollection entries, bool matchStar = false)
+ {
+ var name = GetCursorQualifiedName(namedDecl);
+
+ if (name.StartsWith("ClangSharpMacro_"))
+ {
+ name = name["ClangSharpMacro_".Length..];
+ }
+
+ if (entries.Contains(name))
+ {
+ return true;
+ }
+
+ name = name.Replace("::", ".");
+
+ if (entries.Contains(name))
+ {
+ return true;
+ }
+
+ name = GetCursorQualifiedName(namedDecl, truncateFunctionParameters: true);
+
+ if (name.StartsWith("ClangSharpMacro_"))
+ {
+ name = name["ClangSharpMacro_".Length..];
+ }
+
+ if (entries.Contains(name))
+ {
+ return true;
+ }
+
+ name = name.Replace("::", ".");
+
+ if (entries.Contains(name))
+ {
+ return true;
+ }
+
+ name = GetRemappedCursorName(namedDecl);
+
+ if (name.StartsWith("ClangSharpMacro_"))
+ {
+ name = name["ClangSharpMacro_".Length..];
+ }
+
+ if (entries.Contains(name))
+ {
+ return true;
+ }
+
+ if (matchStar && entries.Contains("*"))
+ {
+ return true;
+ }
+
+ return false;
+ }
- private bool TryGetRemappedValue(NamedDecl namedDecl, IReadOnlyDictionary remappings, out T value)
+ private bool TryGetRemappedValue(NamedDecl namedDecl, IReadOnlyDictionary remappings, out T value, bool matchStar = false)
{
var name = GetCursorQualifiedName(namedDecl);
+ if (name.StartsWith("ClangSharpMacro_"))
+ {
+ name = name["ClangSharpMacro_".Length..];
+ }
+
if (remappings.TryGetValue(name, out value))
{
return true;
@@ -5646,6 +5726,11 @@ private bool TryGetRemappedValue(NamedDecl namedDecl, IReadOnlyDictionary(NamedDecl namedDecl, IReadOnlyDictionary _forceRemappedNames;
- private readonly Dictionary _remappedNames;
- private readonly Dictionary _withAccessSpecifiers;
- private readonly Dictionary> _withAttributes;
- private readonly Dictionary _withCallConvs;
- private readonly Dictionary _withClasses;
- private readonly Dictionary _withLibraryPaths;
- private readonly Dictionary _withNamespaces;
- private readonly Dictionary _withTransparentStructs;
- private readonly Dictionary _withTypes;
- private readonly Dictionary> _withUsings;
+ private readonly SortedSet _excludedNames;
+ private readonly SortedSet _forceRemappedNames;
+ private readonly SortedSet _includedNames;
+ private readonly SortedSet _traversalNames;
+ private readonly SortedSet _withSetLastErrors;
+ private readonly SortedSet _withSuppressGCTransitions;
+
+ private readonly SortedDictionary _remappedNames;
+ private readonly SortedDictionary _withAccessSpecifiers;
+ private readonly SortedDictionary> _withAttributes;
+ private readonly SortedDictionary _withCallConvs;
+ private readonly SortedDictionary _withClasses;
+ private readonly SortedDictionary _withLibraryPaths;
+ private readonly SortedDictionary _withNamespaces;
+ private readonly SortedDictionary _withTransparentStructs;
+ private readonly SortedDictionary _withTypes;
+ private readonly SortedDictionary> _withUsings;
private PInvokeGeneratorConfigurationOptions _options;
- public PInvokeGeneratorConfiguration(string libraryPath, string namespaceName, string outputLocation, string testOutputLocation, PInvokeGeneratorOutputMode outputMode = PInvokeGeneratorOutputMode.CSharp, PInvokeGeneratorConfigurationOptions options = PInvokeGeneratorConfigurationOptions.None, string[] excludedNames = null, string[] includedNames = null, string headerFile = null, string methodClassName = null, string methodPrefixToStrip = null, IReadOnlyDictionary remappedNames = null, string[] traversalNames = null, IReadOnlyDictionary withAccessSpecifiers = null, IReadOnlyDictionary> withAttributes = null, IReadOnlyDictionary withCallConvs = null, IReadOnlyDictionary withClasses = null, IReadOnlyDictionary withLibraryPaths = null, IReadOnlyDictionary withNamespaces = null, string[] withSetLastErrors = null, IReadOnlyDictionary withTransparentStructs = null, IReadOnlyDictionary withTypes = null, IReadOnlyDictionary> withUsings = null)
+ public PInvokeGeneratorConfiguration(string libraryPath, string namespaceName, string outputLocation, string testOutputLocation, PInvokeGeneratorOutputMode outputMode = PInvokeGeneratorOutputMode.CSharp, PInvokeGeneratorConfigurationOptions options = PInvokeGeneratorConfigurationOptions.None, IReadOnlyCollection excludedNames = null, IReadOnlyCollection includedNames = null, string headerFile = null, string methodClassName = null, string methodPrefixToStrip = null, IReadOnlyDictionary remappedNames = null, IReadOnlyCollection traversalNames = null, IReadOnlyDictionary withAccessSpecifiers = null, IReadOnlyDictionary> withAttributes = null, IReadOnlyDictionary withCallConvs = null, IReadOnlyDictionary withClasses = null, IReadOnlyDictionary withLibraryPaths = null, IReadOnlyDictionary withNamespaces = null, IReadOnlyCollection withSetLastErrors = null, IReadOnlyCollection withSuppressGCTransitions = null, IReadOnlyDictionary withTransparentStructs = null, IReadOnlyDictionary withTypes = null, IReadOnlyDictionary> withUsings = null)
{
- if (excludedNames is null)
- {
- excludedNames = Array.Empty();
- }
-
- if (includedNames is null)
- {
- includedNames = Array.Empty();
- }
-
if (string.IsNullOrWhiteSpace(libraryPath))
{
libraryPath = string.Empty;
@@ -83,32 +79,27 @@ public PInvokeGeneratorConfiguration(string libraryPath, string namespaceName, s
throw new ArgumentNullException(nameof(outputLocation));
}
- if (traversalNames is null)
- {
- traversalNames = Array.Empty();
- }
+ _options = options;
- if (withSetLastErrors is null)
- {
- withSetLastErrors = Array.Empty();
- }
+ _excludedNames = new SortedSet();
+ _forceRemappedNames = new SortedSet();
+ _includedNames = new SortedSet();
+ _traversalNames = new SortedSet();
+ _withSetLastErrors = new SortedSet();
+ _withSuppressGCTransitions = new SortedSet();
+
+ _remappedNames = new SortedDictionary();
+ _withAccessSpecifiers = new SortedDictionary();
+ _withAttributes = new SortedDictionary>();
+ _withCallConvs = new SortedDictionary();
+ _withClasses = new SortedDictionary();
+ _withLibraryPaths = new SortedDictionary();
+ _withNamespaces = new SortedDictionary();
+ _withTransparentStructs = new SortedDictionary();
+ _withTypes = new SortedDictionary();
+ _withUsings = new SortedDictionary>();
- _options = options;
- _forceRemappedNames = new HashSet();
- _remappedNames = new Dictionary();
- _withAccessSpecifiers = new Dictionary();
- _withAttributes = new Dictionary>();
- _withCallConvs = new Dictionary();
- _withClasses = new Dictionary();
- _withLibraryPaths = new Dictionary();
- _withNamespaces = new Dictionary();
- _withTransparentStructs = new Dictionary();
- _withTypes = new Dictionary();
- _withUsings = new Dictionary>();
-
- ExcludedNames = excludedNames;
HeaderText = string.IsNullOrWhiteSpace(headerFile) ? string.Empty : File.ReadAllText(headerFile);
- IncludedNames = includedNames;
LibraryPath = $@"""{libraryPath}""";
DefaultClass = methodClassName;
MethodPrefixToStrip = methodPrefixToStrip;
@@ -117,10 +108,6 @@ public PInvokeGeneratorConfiguration(string libraryPath, string namespaceName, s
OutputLocation = Path.GetFullPath(outputLocation);
TestOutputLocation = !string.IsNullOrWhiteSpace(testOutputLocation) ? Path.GetFullPath(testOutputLocation) : string.Empty;
- // Normalize the traversal names to use \ rather than / so path comparisons are simpler
- TraversalNames = traversalNames.Select(traversalName => traversalName.Replace('\\', '/')).ToArray();
- WithSetLastErrors = withSetLastErrors;
-
if (!_options.HasFlag(PInvokeGeneratorConfigurationOptions.NoDefaultRemappings))
{
if (!ExcludeNIntCodegen)
@@ -139,7 +126,13 @@ public PInvokeGeneratorConfiguration(string libraryPath, string namespaceName, s
}
}
+ AddRange(_excludedNames, excludedNames);
AddRange(_forceRemappedNames, remappedNames, ValueStartsWithAt);
+ AddRange(_includedNames, includedNames);
+ AddRange(_traversalNames, traversalNames, NormalizePathSeparators);
+ AddRange(_withSetLastErrors, withSetLastErrors);
+ AddRange(_withSuppressGCTransitions, withSuppressGCTransitions);
+
AddRange(_remappedNames, remappedNames, RemoveAtPrefix);
AddRange(_withAccessSpecifiers, withAccessSpecifiers, ConvertStringToAccessSpecifier);
AddRange(_withAttributes, withAttributes);
@@ -160,14 +153,16 @@ public PInvokeGeneratorConfiguration(string libraryPath, string namespaceName, s
public bool ExcludeEnumOperators => _options.HasFlag(PInvokeGeneratorConfigurationOptions.ExcludeEnumOperators);
- public string[] ExcludedNames { get; }
+ public IReadOnlyCollection ExcludedNames => _excludedNames;
- public string[] IncludedNames { get; }
+ public IReadOnlyCollection IncludedNames => _includedNames;
public bool GenerateAggressiveInlining => _options.HasFlag(PInvokeGeneratorConfigurationOptions.GenerateAggressiveInlining);
public bool GenerateCompatibleCode => _options.HasFlag(PInvokeGeneratorConfigurationOptions.GenerateCompatibleCode);
+ public bool GenerateDocIncludes => _options.HasFlag(PInvokeGeneratorConfigurationOptions.GenerateDocIncludes);
+
public bool GenerateExplicitVtbls => _options.HasFlag(PInvokeGeneratorConfigurationOptions.GenerateExplicitVtbls);
public bool GenerateFileScopedNamespaces => _options.HasFlag(PInvokeGeneratorConfigurationOptions.GenerateFileScopedNamespaces);
@@ -254,7 +249,7 @@ public bool ExcludeFnptrCodegen
public string TestOutputLocation { get; }
- public string[] TraversalNames { get; }
+ public IReadOnlyCollection TraversalNames => _traversalNames;
public IReadOnlyDictionary WithAccessSpcifier => _withAccessSpecifiers;
@@ -268,7 +263,9 @@ public bool ExcludeFnptrCodegen
public IReadOnlyDictionary WithNamespaces => _withNamespaces;
- public string[] WithSetLastErrors { get; }
+ public IReadOnlyCollection WithSetLastErrors => _withSetLastErrors;
+
+ public IReadOnlyCollection WithSuppressGCTransitions => _withSuppressGCTransitions;
public IReadOnlyDictionary WithTransparentStructs => _withTransparentStructs;
@@ -276,7 +273,7 @@ public bool ExcludeFnptrCodegen
public IReadOnlyDictionary> WithUsings => _withUsings;
- private static void AddRange(Dictionary dictionary, IEnumerable> keyValuePairs)
+ private static void AddRange(SortedDictionary dictionary, IEnumerable> keyValuePairs)
{
if (keyValuePairs != null)
{
@@ -289,29 +286,51 @@ private static void AddRange(Dictionary dictionary, IEnu
}
}
- private static void AddRange(HashSet hashSet, IEnumerable> keyValuePairs, Func shouldAdd)
+ private static void AddRange(SortedDictionary dictionary, IEnumerable> keyValuePairs, Func convert)
{
if (keyValuePairs != null)
{
foreach (var keyValuePair in keyValuePairs)
{
- if (shouldAdd(keyValuePair.Value))
- {
- _ = hashSet.Add(keyValuePair.Key);
- }
+ // Use the indexer, rather than Add, so that any
+ // default mappings can be overwritten if desired.
+ dictionary[keyValuePair.Key] = convert(keyValuePair.Value);
}
}
}
- private static void AddRange(Dictionary dictionary, IEnumerable> keyValuePairs, Func convert)
+ private static void AddRange(SortedSet hashSet, IEnumerable keys)
+ {
+ if (keys != null)
+ {
+ foreach (var key in keys)
+ {
+ _ = hashSet.Add(key);
+ }
+ }
+ }
+
+ private static void AddRange(SortedSet hashSet, IEnumerable keys, Func convert)
+ {
+ if (keys != null)
+ {
+ foreach (var key in keys)
+ {
+ _ = hashSet.Add(convert(key));
+ }
+ }
+ }
+
+ private static void AddRange(SortedSet hashSet, IEnumerable> keyValuePairs, Func shouldAdd)
{
if (keyValuePairs != null)
{
foreach (var keyValuePair in keyValuePairs)
{
- // Use the indexer, rather than Add, so that any
- // default mappings can be overwritten if desired.
- dictionary[keyValuePair.Key] = convert(keyValuePair.Value);
+ if (shouldAdd(keyValuePair.Value))
+ {
+ _ = hashSet.Add(keyValuePair.Key);
+ }
}
}
}
@@ -348,6 +367,8 @@ private static AccessSpecifier ConvertStringToAccessSpecifier(string input)
}
}
+ private static string NormalizePathSeparators(string value) => value.Replace('\\', '/');
+
private static string RemoveAtPrefix(string value) => ValueStartsWithAt(value) ? value[1..] : value;
private static (string, PInvokeGeneratorTransparentStructKind) RemoveAtPrefix((string Name, PInvokeGeneratorTransparentStructKind Kind) value) => (ValueStartsWithAt(value.Name) ? value.Name[1..] : value.Name, value.Kind);
diff --git a/sources/ClangSharp.PInvokeGenerator/PInvokeGeneratorConfigurationOptions.cs b/sources/ClangSharp.PInvokeGenerator/PInvokeGeneratorConfigurationOptions.cs
index 8e682f15..60605f91 100644
--- a/sources/ClangSharp.PInvokeGenerator/PInvokeGeneratorConfigurationOptions.cs
+++ b/sources/ClangSharp.PInvokeGenerator/PInvokeGeneratorConfigurationOptions.cs
@@ -72,5 +72,7 @@ public enum PInvokeGeneratorConfigurationOptions : ulong
GenerateFileScopedNamespaces = 1UL << 30,
GenerateSetsLastSystemErrorAttribute = 1UL << 31,
+
+ GenerateDocIncludes = 1UL << 32,
}
}
diff --git a/sources/ClangSharpPInvokeGenerator/Program.cs b/sources/ClangSharpPInvokeGenerator/Program.cs
index a53a96df..d970068d 100644
--- a/sources/ClangSharpPInvokeGenerator/Program.cs
+++ b/sources/ClangSharpPInvokeGenerator/Program.cs
@@ -5,7 +5,6 @@
using System.CommandLine;
using System.CommandLine.Help;
using System.CommandLine.Invocation;
-using System.CommandLine.IO;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
@@ -66,6 +65,7 @@ public class Program
new HelpItem("generate-aggressive-inlining", "[MethodImpl(MethodImplOptions.AggressiveInlining)] should be added to generated helper functions."),
new HelpItem("generate-cpp-attributes", "[CppAttributeList(\"\")] should be generated to document the encountered C++ attributes."),
+ new HelpItem("generate-doc-includes", " xml documentation tags should be generated for declarations."),
new HelpItem("generate-file-scoped-namespaces", "Namespaces should be scoped to the file to reduce nesting."),
new HelpItem("generate-helper-types", "Code files should be generated for various helper attributes and declared transparent structs."),
new HelpItem("generate-macro-bindings", "Bindings for macro-definitions should be generated. This currently only works with value like macros and not function-like ones."),
@@ -119,6 +119,7 @@ public static async Task Main(params string[] args)
AddWithLibraryPathOption(s_rootCommand);
AddWithNamespaceOption(s_rootCommand);
AddWithSetLastErrorOption(s_rootCommand);
+ AddWithSuppressGCTransitionOption(s_rootCommand);
AddWithTransparentStructOption(s_rootCommand);
AddWithTypeOption(s_rootCommand);
AddWithUsingOption(s_rootCommand);
@@ -156,6 +157,7 @@ public static int Run(InvocationContext context)
var withLibraryPathNameValuePairs = context.ParseResult.ValueForOption("--with-librarypath");
var withNamespaceNameValuePairs = context.ParseResult.ValueForOption("--with-namespace");
var withSetLastErrors = context.ParseResult.ValueForOption("--with-setlasterror");
+ var withSuppressGCTransitions = context.ParseResult.ValueForOption("--with-suppressgctransition");
var withTransparentStructNameValuePairs = context.ParseResult.ValueForOption("--with-transparent-struct");
var withTypeNameValuePairs = context.ParseResult.ValueForOption("--with-type");
var withUsingNameValuePairs = context.ParseResult.ValueForOption("--with-using");
@@ -399,6 +401,12 @@ public static int Run(InvocationContext context)
break;
}
+ case "generate-doc-includes":
+ {
+ configOptions |= PInvokeGeneratorConfigurationOptions.GenerateDocIncludes;
+ break;
+ }
+
case "generate-file-scoped-namespaces":
{
configOptions |= PInvokeGeneratorConfigurationOptions.GenerateFileScopedNamespaces;
@@ -548,7 +556,7 @@ public static int Run(InvocationContext context)
translationFlags |= CXTranslationUnit_Flags.CXTranslationUnit_IncludeAttributedTypes; // Include attributed types in CXType
translationFlags |= CXTranslationUnit_Flags.CXTranslationUnit_VisitImplicitAttributes; // Implicit attributes should be visited
- var config = new PInvokeGeneratorConfiguration(libraryPath, namespaceName, outputLocation, testOutputLocation, outputMode, configOptions, excludedNames, includedNames, headerFile, methodClassName, methodPrefixToStrip, remappedNames, traversalNames, withAccessSpecifiers, withAttributes, withCallConvs, withClasses, withLibraryPath, withNamespaces, withSetLastErrors, withTransparentStructs, withTypes, withUsings);
+ var config = new PInvokeGeneratorConfiguration(libraryPath, namespaceName, outputLocation, testOutputLocation, outputMode, configOptions, excludedNames, includedNames, headerFile, methodClassName, methodPrefixToStrip, remappedNames, traversalNames, withAccessSpecifiers, withAttributes, withCallConvs, withClasses, withLibraryPath, withNamespaces, withSetLastErrors, withSuppressGCTransitions, withTransparentStructs, withTypes, withUsings);
if (config.GenerateMacroBindings)
{
@@ -1092,7 +1100,20 @@ private static void AddWithSetLastErrorOption(RootCommand rootCommand)
{
var option = new Option(
aliases: new string[] { "--with-setlasterror", "-wsle" },
- description: "Add the SetLastError=true modifier to a given DllImport or UnmanagedFunctionPointer.",
+ description: "Add the SetLastError=true modifier or SetsSystemLastError attribute to a given DllImport or UnmanagedFunctionPointer.",
+ argumentType: typeof(string),
+ getDefaultValue: Array.Empty,
+ arity: ArgumentArity.OneOrMore
+ );
+
+ rootCommand.AddOption(option);
+ }
+
+ private static void AddWithSuppressGCTransitionOption(RootCommand rootCommand)
+ {
+ var option = new Option(
+ aliases: new string[] { "--with-suppressgctransition", "-wsgct" },
+ description: "Add the SuppressGCTransition calling convention to a given DllImport or UnmanagedFunctionPointer.",
argumentType: typeof(string),
getDefaultValue: Array.Empty,
arity: ArgumentArity.OneOrMore
diff --git a/tests/ClangSharp.PInvokeGenerator.UnitTests/PInvokeGeneratorTest.cs b/tests/ClangSharp.PInvokeGenerator.UnitTests/PInvokeGeneratorTest.cs
index 642f9bf6..c7e4e279 100644
--- a/tests/ClangSharp.PInvokeGenerator.UnitTests/PInvokeGeneratorTest.cs
+++ b/tests/ClangSharp.PInvokeGenerator.UnitTests/PInvokeGeneratorTest.cs
@@ -64,7 +64,7 @@ private static async Task ValidateGeneratedBindingsAsync(string inputContents, s
using var unsavedFile = CXUnsavedFile.Create(DefaultInputFileName, inputContents);
var unsavedFiles = new CXUnsavedFile[] { unsavedFile };
- var config = new PInvokeGeneratorConfiguration(libraryPath, DefaultNamespaceName, Path.GetRandomFileName(), testOutputLocation: null, outputMode, configOptions, excludedNames, includedNames: null, headerFile: null, methodClassName: null, methodPrefixToStrip: null, remappedNames, traversalNames: null, withAccessSpecifiers, withAttributes, withCallConvs, withClasses, withLibraryPaths, withNamespaces, withSetLastErrors, withTransparentStructs, withTypes, withUsings);
+ var config = new PInvokeGeneratorConfiguration(libraryPath, DefaultNamespaceName, Path.GetRandomFileName(), testOutputLocation: null, outputMode, configOptions, excludedNames, includedNames: null, headerFile: null, methodClassName: null, methodPrefixToStrip: null, remappedNames, traversalNames: null, withAccessSpecifiers, withAttributes, withCallConvs, withClasses, withLibraryPaths, withNamespaces, withSetLastErrors, withSuppressGCTransitions: null, withTransparentStructs, withTypes, withUsings);
using (var pinvokeGenerator = new PInvokeGenerator(config, (path) => outputStream))
{