diff --git a/sources/ClangSharp.PInvokeGenerator/Abstractions/IOutputBuilder.Visit.cs b/sources/ClangSharp.PInvokeGenerator/Abstractions/IOutputBuilder.Visit.cs index 0c736f28..89db1a8f 100644 --- a/sources/ClangSharp.PInvokeGenerator/Abstractions/IOutputBuilder.Visit.cs +++ b/sources/ClangSharp.PInvokeGenerator/Abstractions/IOutputBuilder.Visit.cs @@ -9,7 +9,7 @@ internal partial interface IOutputBuilder void WriteDivider(bool force = false); void SuppressDivider(); - void WriteCustomAttribute(string attribute); + void WriteCustomAttribute(string attribute, Action callback = null); void WriteIid(string name, Guid value); void EmitUsingDirective(string directive); } diff --git a/sources/ClangSharp.PInvokeGenerator/CSharp/CSharpOutputBuilder.Visit.cs b/sources/ClangSharp.PInvokeGenerator/CSharp/CSharpOutputBuilder.Visit.cs index 245cecbd..5580af3c 100644 --- a/sources/ClangSharp.PInvokeGenerator/CSharp/CSharpOutputBuilder.Visit.cs +++ b/sources/ClangSharp.PInvokeGenerator/CSharp/CSharpOutputBuilder.Visit.cs @@ -8,7 +8,7 @@ namespace ClangSharp.CSharp internal partial class CSharpOutputBuilder { private bool _customAttrIsForParameter = false; - public void WriteCustomAttribute(string attribute) + public void WriteCustomAttribute(string attribute, Action callback = null) { if (attribute.Equals("Flags") || attribute.Equals("Obsolete")) { @@ -18,22 +18,27 @@ public void WriteCustomAttribute(string attribute) { AddUsingDirective("System.ComponentModel"); } - else if (attribute.StartsWith("Guid(")) + else if (attribute.StartsWith("Guid(") || attribute.StartsWith("Optional, DefaultParameterValue(")) { AddUsingDirective("System.Runtime.InteropServices"); } if (!_customAttrIsForParameter) { - WriteIndented('['); - Write(attribute); - WriteLine(']'); + WriteIndentation(); + } + + Write('['); + Write(attribute); + callback?.Invoke(); + Write(']'); + + if (!_customAttrIsForParameter) + { + WriteNewline(); } else { - Write('['); - Write(attribute); - Write(']'); Write(' '); } } diff --git a/sources/ClangSharp.PInvokeGenerator/CSharp/CSharpOutputBuilder.VisitDecl.cs b/sources/ClangSharp.PInvokeGenerator/CSharp/CSharpOutputBuilder.VisitDecl.cs index e850753b..4a16d146 100644 --- a/sources/ClangSharp.PInvokeGenerator/CSharp/CSharpOutputBuilder.VisitDecl.cs +++ b/sources/ClangSharp.PInvokeGenerator/CSharp/CSharpOutputBuilder.VisitDecl.cs @@ -293,7 +293,7 @@ public void EndField(bool isBodyless = true) public void BeginFunctionOrDelegate(in FunctionOrDelegateDesc desc, ref bool isMethodClassUnsafe) { - desc.WriteCustomAttrs(desc.CustomAttrGeneratorData); + desc.WriteCustomAttrs?.Invoke(desc.CustomAttrGeneratorData); if (desc.IsVirtual) { @@ -478,7 +478,7 @@ public void BeginParameter(in ParameterDesc parameterDesc = new() { Name = "pThis", - Type = $"{cxxRecordEscapedName}*", - WriteCustomAttrs = static x => { }, - CustomAttrGeneratorData = default + Type = $"{cxxRecordEscapedName}*" }; _outputBuilder.BeginParameter(in parameterDesc); @@ -527,9 +524,7 @@ private void VisitFunctionDecl(FunctionDecl functionDecl) parameterDesc = new() { Name = "_result", - Type = $"{returnTypeName}*", - WriteCustomAttrs = static x => { }, - CustomAttrGeneratorData = default + Type = $"{returnTypeName}*" }; _outputBuilder.BeginParameter(in parameterDesc); _outputBuilder.EndParameter(); @@ -612,7 +607,7 @@ void VisitCtorInitializers(CXXConstructorDecl cxxConstructorDecl, int firstCtorI _outputBuilder.BeginConstructorInitializer(memberRefName, memberInitName); - var memberRefTypeName = GetRemappedTypeName(memberRef, context: null, memberRef.Type, out var memberRefNativeTypeName, skipUsing: false); + var memberRefTypeName = GetRemappedTypeName(memberRef, context: null, memberRef.Type, out var memberRefNativeTypeName); UncheckStmt(memberRefTypeName, memberInit); @@ -669,7 +664,7 @@ private void VisitIndirectFieldDecl(IndirectFieldDecl indirectFieldDecl) contextNameParts.Push(EscapeName(contextNamePart)); - contextTypeParts.Push(GetRemappedTypeName(rootRecordDecl, context: null, rootRecordDecl.TypeForDecl, out _, skipUsing: false)); + contextTypeParts.Push(GetRemappedTypeName(rootRecordDecl, context: null, rootRecordDecl.TypeForDecl, out _)); rootRecordDecl = parentRecordDecl; } @@ -693,10 +688,17 @@ private void VisitIndirectFieldDecl(IndirectFieldDecl indirectFieldDecl) var accessSpecifier = GetAccessSpecifier(anonymousRecordDecl); - var typeName = GetRemappedTypeName(fieldDecl, context: null, type, out _, skipUsing: false); + var typeName = GetRemappedTypeName(fieldDecl, context: null, type, out _); var name = GetRemappedCursorName(fieldDecl); var escapedName = EscapeName(name); + var rootRecordDeclName = GetRemappedCursorName(rootRecordDecl); + + if (_config.ExcludedNames.Contains($"{rootRecordDeclName}.{name}") || _config.ExcludedNames.Contains($"{rootRecordDeclName}::{name}")) + { + return; + } + var desc = new FieldDesc { AccessSpecifier = accessSpecifier, NativeTypeName = null, @@ -923,7 +925,7 @@ void ForFunctionDecl(ParmVarDecl parmVarDecl, FunctionDecl functionDecl) escapedName += index; } - var desc = new ParameterDesc<(string Name, PInvokeGenerator This)> + var desc = new ParameterDesc<(PInvokeGenerator This, CSharp.CSharpOutputBuilder CSharpOutputBuilder, Expr DefaultArg)> { Name = escapedName, Type = typeName, @@ -931,14 +933,43 @@ void ForFunctionDecl(ParmVarDecl parmVarDecl, FunctionDecl functionDecl) CppAttributes = _config.GenerateCppAttributes ? parmVarDecl.Attrs.Select(x => EscapeString(x.Spelling)) : null, - CustomAttrGeneratorData = (name, this), - WriteCustomAttrs = static _ => { }, Location = parmVarDecl.Location }; - _outputBuilder.BeginParameter(in desc); + var handledDefaultArg = false; + var isExprDefaultValue = false; if (parmVarDecl.HasDefaultArg) + { + isExprDefaultValue = IsDefaultValue(parmVarDecl.DefaultArg); + + if ((_outputBuilder is CSharp.CSharpOutputBuilder csharpOutputBuilder) && (_config.WithTransparentStructs.ContainsKey(typeName) || parameters.Skip(index).Any((parmVarDecl) => { + var type = parmVarDecl.Type; + var typeName = GetTargetTypeName(parmVarDecl, out var nativeTypeName); + return _config.WithTransparentStructs.ContainsKey(typeName); + }))) + { + desc.CustomAttrGeneratorData = (this, csharpOutputBuilder, isExprDefaultValue ? null : parmVarDecl.DefaultArg); + desc.WriteCustomAttrs = static x => { + if (x.DefaultArg is not null) + { + x.CSharpOutputBuilder.WriteCustomAttribute("Optional, DefaultParameterValue(", () => { + x.This.Visit(x.DefaultArg); + x.CSharpOutputBuilder.Write(')'); + }); + } + else + { + x.CSharpOutputBuilder.WriteCustomAttribute("Optional", null); + } + }; + handledDefaultArg = true; + } + } + + _outputBuilder.BeginParameter(in desc); + + if (parmVarDecl.HasDefaultArg && !handledDefaultArg) { _outputBuilder.BeginParameterDefault(); @@ -946,9 +977,7 @@ void ForFunctionDecl(ParmVarDecl parmVarDecl, FunctionDecl functionDecl) if (parmVarDecl.Type.CanonicalType.IsPointerType && (defaultArg.Handle.Evaluate.Kind == CXEvalResultKind.CXEval_UnExposed)) { - if (!IsStmtAsWritten(defaultArg, out _, removeParens: true) && - (!IsStmtAsWritten(defaultArg, out var castExpr, removeParens: true) || (castExpr.CastKind != CX_CastKind.CX_CK_NullToPointer)) && - (!IsStmtAsWritten(defaultArg, out var integerLiteral, removeParens: true) || (integerLiteral.Value != 0))) + if (!isExprDefaultValue) { AddDiagnostic(DiagnosticLevel.Info, $"Unsupported default parameter: '{name}'. Generated bindings may be incomplete.", defaultArg); } @@ -998,8 +1027,6 @@ void ForTypedefDecl(ParmVarDecl parmVarDecl, TypedefDecl typedefDecl) CppAttributes = _config.GenerateCppAttributes ? parmVarDecl.Attrs.Select(x => EscapeString(x.Spelling)) : null, - CustomAttrGeneratorData = (name, this), - WriteCustomAttrs = static _ => { }, Location = parmVarDecl.Location }; @@ -1019,6 +1046,13 @@ void ForTypedefDecl(ParmVarDecl parmVarDecl, TypedefDecl typedefDecl) _outputBuilder.WriteParameterSeparator(); } } + + bool IsDefaultValue(Expr defaultArg) + { + return IsStmtAsWritten(defaultArg, out _, removeParens: true) || + (IsStmtAsWritten(defaultArg, out var castExpr, removeParens: true) && (castExpr.CastKind == CX_CastKind.CX_CK_NullToPointer)) || + (IsStmtAsWritten(defaultArg, out var integerLiteral, removeParens: true) && (integerLiteral.Value == 0)); + } } private void VisitRecordDecl(RecordDecl recordDecl) @@ -1163,8 +1197,6 @@ private void VisitRecordDecl(RecordDecl recordDecl) Kind = layoutKind }, Uuid = nullableUuid, - CustomAttrGeneratorData = (name, this), - WriteCustomAttrs = static _ => { }, NativeType = nativeNameWithExtras, NativeInheritance = _config.GenerateNativeInheritanceAttribute ? nativeInheritance : null, Location = recordDecl.Location, @@ -1514,7 +1546,7 @@ void OutputVtblEntry(CXXRecordDecl cxxRecordDecl, CXXMethodDecl cxxMethodDecl) return; } - var cxxMethodDeclTypeName = GetRemappedTypeName(cxxMethodDecl, cxxRecordDecl, cxxMethodDecl.Type, out var nativeTypeName, skipUsing: false); + var cxxMethodDeclTypeName = GetRemappedTypeName(cxxMethodDecl, cxxRecordDecl, cxxMethodDecl.Type, out var nativeTypeName, skipUsing: false, ignoreTransparentStructsWhereRequired: true); var accessSpecifier = GetAccessSpecifier(cxxMethodDecl); var remappedName = FixupNameForMultipleHits(cxxMethodDecl); @@ -1552,7 +1584,7 @@ void OutputVtblHelperMethod(CXXRecordDecl cxxRecordDecl, CXXMethodDecl cxxMethod var currentContext = _context.AddLast((cxxMethodDecl, null)); var accessSpecifier = GetAccessSpecifier(cxxMethodDecl); var returnType = cxxMethodDecl.ReturnType; - var returnTypeName = GetRemappedTypeName(cxxMethodDecl, cxxRecordDecl, returnType, out var nativeTypeName, skipUsing: false); + var returnTypeName = GetRemappedTypeName(cxxMethodDecl, cxxRecordDecl, returnType, out var nativeTypeName); var remappedName = FixupNameForMultipleHits(cxxMethodDecl); var name = GetRemappedCursorName(cxxMethodDecl); @@ -1566,10 +1598,8 @@ void OutputVtblHelperMethod(CXXRecordDecl cxxRecordDecl, CXXMethodDecl cxxMethod var desc = new FunctionOrDelegateDesc<(string Name, PInvokeGenerator This)> { AccessSpecifier = accessSpecifier, - CustomAttrGeneratorData = (name, this), IsAggressivelyInlined = _config.GenerateAggressiveInlining, EscapedName = EscapeAndStripName(name), - WriteCustomAttrs = static _ => {}, IsMemberFunction = true, NativeTypeName = nativeTypeName, NeedsNewKeyword = NeedsNewKeyword(name, cxxMethodDecl.Parameters), @@ -1645,7 +1675,7 @@ void OutputVtblHelperMethod(CXXRecordDecl cxxRecordDecl, CXXMethodDecl cxxMethod } else { - var cxxMethodDeclTypeName = GetRemappedTypeName(cxxMethodDecl, cxxRecordDecl, cxxMethodDecl.Type, out _, skipUsing: false); + var cxxMethodDeclTypeName = GetRemappedTypeName(cxxMethodDecl, cxxRecordDecl, cxxMethodDecl.Type, out _, skipUsing: false, ignoreTransparentStructsWhereRequired: true); if (!_config.ExcludeFnptrCodegen) { @@ -1758,7 +1788,7 @@ void VisitBitfieldDecl(FieldDecl fieldDecl, Type[] types, RecordDecl recordDecl, Debug.Assert(fieldDecl.IsBitField); var type = fieldDecl.Type; - var typeName = GetRemappedTypeName(fieldDecl, context: null, type, out var nativeTypeName, skipUsing: false); + var typeName = GetRemappedTypeName(fieldDecl, context: null, type, out var nativeTypeName); if (string.IsNullOrWhiteSpace(nativeTypeName)) { @@ -1787,7 +1817,7 @@ void VisitBitfieldDecl(FieldDecl fieldDecl, Type[] types, RecordDecl recordDecl, previousSize = 0; typeBacking = (index > 0) ? types[index - 1] : types[0]; - typeNameBacking = GetRemappedTypeName(fieldDecl, context: null, typeBacking, out _, skipUsing: false); + typeNameBacking = GetRemappedTypeName(fieldDecl, context: null, typeBacking, out _); if (fieldDecl.Parent == recordDecl) { @@ -1820,7 +1850,7 @@ void VisitBitfieldDecl(FieldDecl fieldDecl, Type[] types, RecordDecl recordDecl, } typeBacking = (index > 0) ? types[index - 1] : types[0]; - typeNameBacking = GetRemappedTypeName(fieldDecl, context: null, typeBacking, out _, skipUsing: false); + typeNameBacking = GetRemappedTypeName(fieldDecl, context: null, typeBacking, out _); } var bitfieldOffset = (currentSize * 8) - remainingBits; @@ -2173,7 +2203,7 @@ void VisitConstantArrayFieldDecl(RecordDecl recordDecl, FieldDecl constantArray) var outputBuilder = _outputBuilder; var type = (ConstantArrayType)constantArray.Type.CanonicalType; - var typeName = GetRemappedTypeName(constantArray, context: null, constantArray.Type, out _, skipUsing: false); + var typeName = GetRemappedTypeName(constantArray, context: null, constantArray.Type, out _); if (IsSupportedFixedSizedBufferType(typeName)) { @@ -2218,7 +2248,6 @@ void VisitConstantArrayFieldDecl(RecordDecl recordDecl, FieldDecl constantArray) var desc = new StructDesc<(string Name, PInvokeGenerator This)> { AccessSpecifier = accessSpecifier, - CustomAttrGeneratorData = (name, this), EscapedName = escapedName, IsUnsafe = isUnsafeElementType, Layout = new() { @@ -2230,7 +2259,6 @@ void VisitConstantArrayFieldDecl(RecordDecl recordDecl, FieldDecl constantArray) MaxFieldAlignment = maxAlignm, Kind = LayoutKind.Sequential }, - WriteCustomAttrs = static _ => { }, Location = constantArray.Location, IsNested = true, }; @@ -2301,8 +2329,6 @@ void VisitConstantArrayFieldDecl(RecordDecl recordDecl, FieldDecl constantArray) { Name = "index", Type = "int", - CustomAttrGeneratorData = (name, this), - WriteCustomAttrs = static _ => {} }; _outputBuilder.BeginParameter(in param); _outputBuilder.EndParameter(); @@ -2337,8 +2363,6 @@ void VisitConstantArrayFieldDecl(RecordDecl recordDecl, FieldDecl constantArray) { Name = "index", Type = "int", - CustomAttrGeneratorData = (name, this), - WriteCustomAttrs = static _ => {} }; _outputBuilder.BeginParameter(in param); _outputBuilder.EndParameter(); @@ -2371,8 +2395,6 @@ void VisitConstantArrayFieldDecl(RecordDecl recordDecl, FieldDecl constantArray) AccessSpecifier = AccessSpecifier.Public, EscapedName = "AsSpan", IsAggressivelyInlined = _config.GenerateAggressiveInlining, - CustomAttrGeneratorData = (name, this), - WriteCustomAttrs = static _ => {}, IsStatic = false, IsMemberFunction = true, ReturnType = $"Span<{typeName}>", @@ -2388,8 +2410,6 @@ void VisitConstantArrayFieldDecl(RecordDecl recordDecl, FieldDecl constantArray) { Name = "length", Type = "int", - CustomAttrGeneratorData = (name, this), - WriteCustomAttrs = static _ => {} }; _outputBuilder.BeginParameter(in param); @@ -2452,7 +2472,7 @@ void ForFunctionProtoType(TypedefDecl typedefDecl, FunctionProtoType functionPro var callingConventionName = GetCallingConvention(typedefDecl, context: null, typedefDecl.TypeForDecl); var returnType = functionProtoType.ReturnType; - var returnTypeName = GetRemappedTypeName(typedefDecl, context: null, returnType, out var nativeTypeName, skipUsing: false); + var returnTypeName = GetRemappedTypeName(typedefDecl, context: null, returnType, out var nativeTypeName); StartUsingOutputBuilder(name); { @@ -2460,12 +2480,10 @@ void ForFunctionProtoType(TypedefDecl typedefDecl, FunctionProtoType functionPro { AccessSpecifier = GetAccessSpecifier(typedefDecl), CallingConvention = callingConventionName, - CustomAttrGeneratorData = (name, this), EscapedName = escapedName, IsVirtual = true, // such that it outputs as a delegate IsUnsafe = IsUnsafe(typedefDecl, functionProtoType), NativeTypeName = nativeTypeName, - WriteCustomAttrs = static _ => {}, ReturnType = returnTypeName, Location = typedefDecl.Location }; @@ -2617,7 +2635,7 @@ private void VisitVarDecl(VarDecl varDecl) var isMacroDefinitionRecord = false; var nativeName = GetCursorName(varDecl); - if (nativeName.StartsWith("ClangSharpMacro_")) + if (nativeName.StartsWith("ClangSharpMacro_" + "")) { type = varDecl.Init.Type; nativeName = nativeName["ClangSharpMacro_".Length..]; @@ -2725,6 +2743,10 @@ private void VisitVarDecl(VarDecl varDecl) { flags |= ValueFlags.Copy; } + else if (_config.WithTransparentStructs.TryGetValue(typeName, out var transparentValueTypeName)) + { + typeName = transparentValueTypeName; + } } else if ((varDecl.StorageClass == CX_StorageClass.CX_SC_Static) || openedOutputBuilder) { @@ -2842,7 +2864,7 @@ void ForDeclStmt(VarDecl varDecl, DeclStmt declStmt) if (varDecl == declStmt.Decls.First()) { var type = varDecl.Type; - var typeName = GetRemappedTypeName(varDecl, context: null, type, out _, skipUsing: false); + var typeName = GetRemappedTypeName(varDecl, context: null, type, out _); outputBuilder.Write(typeName); diff --git a/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.VisitStmt.cs b/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.VisitStmt.cs index 213bbbfa..7e614b97 100644 --- a/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.VisitStmt.cs +++ b/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.VisitStmt.cs @@ -423,7 +423,7 @@ private void VisitCXXNewExpr(CXXNewExpr cxxNewExpr) outputBuilder.Write("cxx_new<"); - var allocatedTypeName = GetRemappedTypeName(cxxNewExpr, null, cxxNewExpr.AllocatedType, out _, skipUsing: false); + var allocatedTypeName = GetRemappedTypeName(cxxNewExpr, null, cxxNewExpr.AllocatedType, out _); outputBuilder.Write(allocatedTypeName); outputBuilder.Write(">(sizeof("); @@ -544,7 +544,7 @@ private void VisitCXXUnresolvedConstructExpr(CXXUnresolvedConstructExpr cxxUnres var outputBuilder = StartCSharpCode(); outputBuilder.Write("new "); - var constructorName = GetRemappedTypeName(cxxUnresolvedConstructExpr, null, cxxUnresolvedConstructExpr.TypeAsWritten, out _, skipUsing: false); + var constructorName = GetRemappedTypeName(cxxUnresolvedConstructExpr, null, cxxUnresolvedConstructExpr.TypeAsWritten, out _); outputBuilder.Write(constructorName); outputBuilder.Write('('); @@ -571,7 +571,7 @@ private void VisitCXXUuidofExpr(CXXUuidofExpr cxxUuidofExpr) outputBuilder.Write("typeof("); var type = cxxUuidofExpr.IsTypeOperand ? cxxUuidofExpr.TypeOperand : cxxUuidofExpr.ExprOperand.Type; - var typeName = GetRemappedTypeName(cxxUuidofExpr, context: null, type, out _, skipUsing: false); + var typeName = GetRemappedTypeName(cxxUuidofExpr, context: null, type, out _); outputBuilder.Write(typeName); outputBuilder.Write(").GUID"); @@ -588,7 +588,17 @@ private void VisitDeclRefExpr(DeclRefExpr declRefExpr) if (!_config.DontUseUsingStaticsForEnums) { - outputBuilder.AddUsingDirective($"static {_config.Namespace}.{enumName}"); + if (enumName.StartsWith("__AnonymousEnum_")) + { + if (outputBuilder.Name != _config.MethodClassName) + { + outputBuilder.AddUsingDirective($"static {_config.Namespace}.{_config.MethodClassName}"); + } + } + else + { + outputBuilder.AddUsingDirective($"static {_config.Namespace}.{enumName}"); + } } else { @@ -680,13 +690,23 @@ private void VisitExplicitCastExpr(ExplicitCastExpr explicitCastExpr) if (IsPrevContextDecl(out _, out _) && explicitCastExpr.Type is EnumType enumType) { outputBuilder.Write('('); - var enumUnderlyingTypeName = GetRemappedTypeName(explicitCastExpr, context: null, enumType.Decl.IntegerType, out _, skipUsing: false); + var enumUnderlyingTypeName = GetRemappedTypeName(explicitCastExpr, context: null, enumType.Decl.IntegerType, out _); outputBuilder.Write(enumUnderlyingTypeName); outputBuilder.Write(')'); } var type = explicitCastExpr.Type; - var typeName = GetRemappedTypeName(explicitCastExpr, context: null, type, out _, skipUsing: false); + var typeName = GetRemappedTypeName(explicitCastExpr, context: null, type, out _); + + if (IsPrevContextDecl(out var varDecl, out _)) + { + var cursorName = GetCursorName(varDecl); + + if (cursorName.StartsWith("ClangSharpMacro_") && _config.WithTransparentStructs.TryGetValue(typeName, out var transparentValueTypeName)) + { + typeName = transparentValueTypeName; + } + } if (typeName == "IntPtr") { @@ -910,7 +930,7 @@ void ForEnumConstantDecl(ImplicitCastExpr implicitCastExpr, EnumConstantDecl enu { var type = implicitCastExpr.Type; - var typeName = GetRemappedTypeName(implicitCastExpr, context: null, type, out _, skipUsing: false); + var typeName = GetRemappedTypeName(implicitCastExpr, context: null, type, out _); outputBuilder.Write('('); outputBuilder.Write(typeName); @@ -987,7 +1007,7 @@ long CalculateRootSize(InitListExpr initListExpr, ArrayType arrayType, bool isUn void ForArrayType(InitListExpr initListExpr, ArrayType arrayType) { var type = initListExpr.Type; - var typeName = GetRemappedTypeName(initListExpr, context: null, type, out _, skipUsing: false); + var typeName = GetRemappedTypeName(initListExpr, context: null, type, out _); var isUnmanagedConstant = false; var escapedName = ""; @@ -1051,7 +1071,7 @@ void ForBuiltinType(InitListExpr initListExpr, BuiltinType builtinType) void ForRecordType(InitListExpr initListExpr, RecordType recordType) { var type = initListExpr.Type; - var typeName = GetRemappedTypeName(initListExpr, context: null, type, out _, skipUsing: false); + var typeName = GetRemappedTypeName(initListExpr, context: null, type, out _); var isUnmanagedConstant = false; var escapedName = ""; @@ -2224,7 +2244,6 @@ private void VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr unaryExprOrT var outputBuilder = StartCSharpCode(); var argumentType = unaryExprOrTypeTraitExpr.TypeOfArgument; - long alignment32 = -1; long alignment64 = -1; @@ -2310,10 +2329,21 @@ private void VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr unaryExprOrT } var needsCast = false; - var typeName = GetRemappedTypeName(unaryExprOrTypeTraitExpr, context: null, argumentType, out _, skipUsing: false); + var typeName = GetRemappedTypeName(unaryExprOrTypeTraitExpr, context: null, argumentType, out _); if (parentType != null) { + if ((parentType.Handle.SizeOf == 8) && IsPrevContextDecl(out var varDecl, out _)) + { + var cursorName = GetCursorName(varDecl); + + if (cursorName.StartsWith("ClangSharpMacro_")) + { + cursorName = cursorName["ClangSharpMacro_".Length..]; + parentTypeIsVariableSized |= _config.WithTypes.TryGetValue(cursorName, out var remappedTypeName) && ((remappedTypeName == "int") || (remappedTypeName == "uint")); + } + } + needsCast = parentType.Kind == CXTypeKind.CXType_UInt; needsCast |= parentType.Kind == CXTypeKind.CXType_ULong; needsCast &= !IsSupportedFixedSizedBufferType(typeName); @@ -2455,7 +2485,7 @@ private void VisitOffsetOfExpr(OffsetOfExpr offsetOfExpr) outputBuilder.AddUsingDirective("System.Runtime.InteropServices"); outputBuilder.Write("Marshal.OffsetOf<"); - outputBuilder.Write(GetRemappedTypeName(offsetOfExpr, context: null, offsetOfExpr.TypeSourceInfoType, out var _, skipUsing: false)); + outputBuilder.Write(GetRemappedTypeName(offsetOfExpr, context: null, offsetOfExpr.TypeSourceInfoType, out var _)); outputBuilder.Write(">(\""); Visit(offsetOfExpr.Referenced ?? offsetOfExpr.CursorChildren[1]); outputBuilder.Write("\")"); diff --git a/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.cs b/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.cs index 841c470c..480dcb63 100644 --- a/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.cs +++ b/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.cs @@ -253,6 +253,14 @@ public void Close() emitNamespaceDeclaration = false; } + if (_config.GenerateHelperTypes && (_config.OutputMode == PInvokeGeneratorOutputMode.CSharp)) + { + GenerateNativeInheritanceAttribute(this); + GenerateNativeTypeNameAttribute(this); + GenerateVtblIndexAttribute(this); + GenerateTransparentStructs(this); + } + if (leaveStreamOpen && _outputBuilderFactory.OutputBuilders.Any()) { if (methodClassOutputBuilder is not null) @@ -286,6 +294,247 @@ public void Close() _outputBuilderFactory.Clear(); _uuidsToGenerate.Clear(); _visitedFiles.Clear(); + + static void GenerateNativeInheritanceAttribute(PInvokeGenerator generator) + { + var config = generator.Config; + var outputPath = Path.Combine(config.OutputLocation, "NativeInheritanceAttribute.cs"); + + using var sw = new StreamWriter(outputPath); + sw.NewLine = "\n"; + + if (config.HeaderText != string.Empty) + { + sw.WriteLine(config.HeaderText); + } + + sw.WriteLine("using System;"); + sw.WriteLine("using System.Diagnostics;"); + sw.WriteLine(); + + sw.Write("namespace "); + sw.WriteLine(config.Namespace); + sw.WriteLine('{'); + + sw.WriteLine(" /// Defines the base type of a struct as it was in the native signature."); + sw.WriteLine(" [AttributeUsage(AttributeTargets.Struct, AllowMultiple = false, Inherited = true)]"); + sw.WriteLine(" [Conditional(\"DEBUG\")]"); + sw.WriteLine(" internal sealed partial class NativeInheritanceAttribute : Attribute"); + sw.WriteLine(" {"); + sw.WriteLine(" private readonly string _name;"); + sw.WriteLine(); + sw.WriteLine(" /// Initializes a new instance of the class."); + sw.WriteLine(" /// The name of the base type that was inherited from in the native signature."); + sw.WriteLine(" public NativeInheritanceAttribute(string name)"); + sw.WriteLine(" {"); + sw.WriteLine(" _name = name;"); + sw.WriteLine(" }"); + sw.WriteLine(); + sw.WriteLine(" /// Gets the name of the base type that was inherited from in the native signature."); + sw.WriteLine(" public string Name => _name;"); + sw.WriteLine(" }"); + + sw.WriteLine('}'); + } + + static void GenerateNativeTypeNameAttribute(PInvokeGenerator generator) + { + var config = generator.Config; + var outputPath = Path.Combine(config.OutputLocation, "NativeTypeNameAttribute.cs"); + + using var sw = new StreamWriter(outputPath); + sw.NewLine = "\n"; + + if (config.HeaderText != string.Empty) + { + sw.WriteLine(config.HeaderText); + } + + sw.WriteLine("using System;"); + sw.WriteLine("using System.Diagnostics;"); + sw.WriteLine(); + + sw.Write("namespace "); + sw.WriteLine(config.Namespace); + sw.WriteLine('{'); + + sw.WriteLine(" /// Defines the type of a member as it was used in the native signature."); + sw.WriteLine(" [AttributeUsage(AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.ReturnValue, AllowMultiple = false, Inherited = true)]"); + sw.WriteLine(" [Conditional(\"DEBUG\")]"); + sw.WriteLine(" internal sealed partial class NativeTypeNameAttribute : Attribute"); + sw.WriteLine(" {"); + sw.WriteLine(" private readonly string _name;"); + sw.WriteLine(); + sw.WriteLine(" /// Initializes a new instance of the class."); + sw.WriteLine(" /// The name of the type that was used in the native signature."); + sw.WriteLine(" public NativeTypeNameAttribute(string name)"); + sw.WriteLine(" {"); + sw.WriteLine(" _name = name;"); + sw.WriteLine(" }"); + sw.WriteLine(); + sw.WriteLine(" /// Gets the name of the type that was used in the native signature."); + sw.WriteLine(" public string Name => _name;"); + sw.WriteLine(" }"); + + sw.WriteLine('}'); + } + + static void GenerateVtblIndexAttribute(PInvokeGenerator generator) + { + var config = generator.Config; + var outputPath = Path.Combine(config.OutputLocation, "VtblIndexAttribute.cs"); + + using var sw = new StreamWriter(outputPath); + sw.NewLine = "\n"; + + if (config.HeaderText != string.Empty) + { + sw.WriteLine(config.HeaderText); + } + + sw.WriteLine("using System;"); + sw.WriteLine("using System.Diagnostics;"); + sw.WriteLine(); + + sw.Write("namespace "); + sw.WriteLine(config.Namespace); + sw.WriteLine('{'); + + sw.WriteLine(" /// Defines the vtbl index of a method as it was in the native signature."); + sw.WriteLine(" [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]"); + sw.WriteLine(" [Conditional(\"DEBUG\")]"); + sw.WriteLine(" internal sealed partial class VtblIndexAttribute : Attribute"); + sw.WriteLine(" {"); + sw.WriteLine(" private readonly uint _index;"); + sw.WriteLine(); + sw.WriteLine(" /// Initializes a new instance of the class."); + sw.WriteLine(" /// The vtbl index of a method as it was in the native signature."); + sw.WriteLine(" public VtblIndexAttribute(uint index)"); + sw.WriteLine(" {"); + sw.WriteLine(" _index = index;"); + sw.WriteLine(" }"); + sw.WriteLine(); + sw.WriteLine(" /// Gets the vtbl index of a method as it was in the native signature."); + sw.WriteLine(" public uint Index => _index;"); + sw.WriteLine(" }"); + + sw.WriteLine('}'); + } + + static void GenerateTransparentStructs(PInvokeGenerator generator) + { + var config = generator.Config; + + foreach (var transparentStruct in config.WithTransparentStructs) + { + var outputPath = Path.Combine(config.OutputLocation, $"{transparentStruct.Key}.cs"); + + using var sw = new StreamWriter(outputPath); + sw.NewLine = "\n"; + + if (config.HeaderText != string.Empty) + { + sw.WriteLine(config.HeaderText); + } + + var isUnsafe = transparentStruct.Key.Contains('*'); + + sw.WriteLine("using System;"); + sw.WriteLine(); + + sw.Write("namespace "); + sw.WriteLine(config.Namespace); + sw.WriteLine('{'); + + sw.Write(" public "); + + if (isUnsafe) + { + sw.Write("unsafe "); + } + + sw.Write("partial struct "); + sw.Write(transparentStruct.Key); + sw.Write(" : IEquatable<"); + sw.Write(transparentStruct.Key); + sw.WriteLine('>'); + + sw.WriteLine(" {"); + + sw.Write(" public readonly "); + sw.Write(transparentStruct.Value); + sw.WriteLine(" Value;"); + sw.WriteLine(); + + sw.Write(" public "); + sw.Write(transparentStruct.Key); + sw.Write('('); + sw.Write(transparentStruct.Value); + sw.WriteLine(" value)"); + sw.WriteLine(" {"); + sw.WriteLine(" Value = value;"); + sw.WriteLine(" }"); + sw.WriteLine(); + + sw.Write(" public static bool operator ==("); + sw.Write(transparentStruct.Key); + sw.Write(" left, "); + sw.Write(transparentStruct.Key); + sw.WriteLine(" right) => left.Value == right.Value;"); + sw.WriteLine(); + + sw.Write(" public static bool operator !=("); + sw.Write(transparentStruct.Key); + sw.Write(" left, "); + sw.Write(transparentStruct.Key); + sw.WriteLine(" right) => left.Value != right.Value;"); + sw.WriteLine(); + + sw.Write(" public static implicit operator "); + sw.Write(transparentStruct.Key); + sw.Write('('); + sw.Write(transparentStruct.Value); + sw.Write(" value) => new "); + sw.Write(transparentStruct.Key); + sw.WriteLine("(value);"); + sw.WriteLine(); + + sw.Write(" public static implicit operator "); + sw.Write(transparentStruct.Value); + sw.Write('('); + sw.Write(transparentStruct.Key); + sw.WriteLine(" value) => value.Value;"); + sw.WriteLine(); + + sw.Write(" public override bool Equals(object? obj) => (obj is "); + sw.Write(transparentStruct.Key); + sw.WriteLine(" other) && Equals(other);"); + sw.WriteLine(); + + sw.Write(" public bool Equals("); + sw.Write(transparentStruct.Key); + sw.WriteLine(" other) => (this == other);"); + sw.WriteLine(); + + sw.Write(" public override int GetHashCode() => "); + + if (isUnsafe) + { + sw.Write("((nuint)("); + } + + sw.Write("Value"); + + if (isUnsafe) + { + sw.Write("))"); + } + + sw.WriteLine(".GetHashCode();"); + sw.WriteLine(" }"); + sw.WriteLine('}'); + } + } } public void Dispose() @@ -996,7 +1245,7 @@ private CallingConvention GetCallingConvention(Cursor cursor, Cursor context, Ty private CallingConvention GetCallingConvention(Cursor cursor, Cursor context, Type type, ref bool wasRemapped) { - var remappedName = GetRemappedTypeName(cursor, context, type, out _, skipUsing: true); + var remappedName = GetRemappedTypeName(cursor, context, type, out _, ignoreTransparentStructsWhereRequired: false, skipUsing: true); if (_config.WithCallConvs.TryGetValue(remappedName, out var callConv) || _config.WithCallConvs.TryGetValue("*", out callConv)) { @@ -1140,7 +1389,7 @@ private string GetCursorName(NamedDecl namedDecl) { name = (typeDecl is TagDecl tagDecl) && tagDecl.Handle.IsAnonymous ? GetAnonymousName(tagDecl, tagDecl.TypeForDecl.KindSpelling) - : GetTypeName(namedDecl, context: null, typeDecl.TypeForDecl, out _); + : GetTypeName(namedDecl, context: null, typeDecl.TypeForDecl, ignoreTransparentStructsWhereRequired: false, out _); } else if (namedDecl is ParmVarDecl) { @@ -1381,7 +1630,7 @@ private static CXXRecordDecl GetRecordDeclForBaseSpecifier(CXXBaseSpecifier cxxB private string GetRemappedCursorName(NamedDecl namedDecl) { var name = GetCursorQualifiedName(namedDecl); - var remappedName = GetRemappedName(name, namedDecl, tryRemapOperatorName: true, out var wasRemapped, skipUsing: false); + var remappedName = GetRemappedName(name, namedDecl, tryRemapOperatorName: true, out var wasRemapped); if (wasRemapped) { @@ -1389,7 +1638,7 @@ private string GetRemappedCursorName(NamedDecl namedDecl) } name = name.Replace("::", "."); - remappedName = GetRemappedName(name, namedDecl, tryRemapOperatorName: true, out wasRemapped, skipUsing: false); + remappedName = GetRemappedName(name, namedDecl, tryRemapOperatorName: true, out wasRemapped); if (wasRemapped) { @@ -1397,7 +1646,7 @@ private string GetRemappedCursorName(NamedDecl namedDecl) } name = GetCursorQualifiedName(namedDecl, truncateFunctionParameters: true); - remappedName = GetRemappedName(name, namedDecl, tryRemapOperatorName: true, out wasRemapped, skipUsing: false); + remappedName = GetRemappedName(name, namedDecl, tryRemapOperatorName: true, out wasRemapped); if (wasRemapped) { @@ -1405,7 +1654,7 @@ private string GetRemappedCursorName(NamedDecl namedDecl) } name = name.Replace("::", "."); - remappedName = GetRemappedName(name, namedDecl, tryRemapOperatorName: true, out wasRemapped, skipUsing: false); + remappedName = GetRemappedName(name, namedDecl, tryRemapOperatorName: true, out wasRemapped); if (wasRemapped) { @@ -1413,7 +1662,7 @@ private string GetRemappedCursorName(NamedDecl namedDecl) } name = GetCursorName(namedDecl); - remappedName = GetRemappedName(name, namedDecl, tryRemapOperatorName: true, out wasRemapped, skipUsing: false); + remappedName = GetRemappedName(name, namedDecl, tryRemapOperatorName: true, out wasRemapped); if (wasRemapped) { @@ -1456,7 +1705,7 @@ private string GetRemappedCursorName(NamedDecl namedDecl) return remappedName; } - private string GetRemappedName(string name, Cursor cursor, bool tryRemapOperatorName, out bool wasRemapped, bool skipUsing) + private string GetRemappedName(string name, Cursor cursor, bool tryRemapOperatorName, out bool wasRemapped, bool skipUsing = false) { if (_config.RemappedNames.TryGetValue(name, out var remappedName)) { @@ -1501,9 +1750,9 @@ static string AddUsingDirectiveIfNeeded(IOutputBuilder outputBuilder, string rem } } - private string GetRemappedTypeName(Cursor cursor, Cursor context, Type type, out string nativeTypeName, bool skipUsing) + private string GetRemappedTypeName(Cursor cursor, Cursor context, Type type, out string nativeTypeName, bool skipUsing = false, bool ignoreTransparentStructsWhereRequired = false) { - var name = GetTypeName(cursor, context, type, out nativeTypeName); + var name = GetTypeName(cursor, context, type, ignoreTransparentStructsWhereRequired, out nativeTypeName); var remappedName = GetRemappedName(name, cursor, tryRemapOperatorName: false, out var wasRemapped, skipUsing); if (!wasRemapped) @@ -1579,7 +1828,7 @@ private string GetRemappedTypeName(Cursor cursor, Cursor context, Type type, out } } - if (nativeTypeName.Equals(remappedName) || nativeTypeName.Replace(" ", "").Equals(remappedName)) + if (IsNativeTypeNameEquivalent(nativeTypeName, remappedName)) { nativeTypeName = string.Empty; } @@ -1623,22 +1872,22 @@ private string GetTargetTypeName(Cursor cursor, out string nativeTypeName) { if (enumConstantDecl.DeclContext is EnumDecl enumDecl) { - targetTypeName = GetRemappedTypeName(enumDecl, context: null, enumDecl.IntegerType, out nativeTypeName, skipUsing: false); + targetTypeName = GetRemappedTypeName(enumDecl, context: null, enumDecl.IntegerType, out nativeTypeName); } else { - targetTypeName = GetRemappedTypeName(enumConstantDecl, context: null, enumConstantDecl.Type, out nativeTypeName, skipUsing: false); + targetTypeName = GetRemappedTypeName(enumConstantDecl, context: null, enumConstantDecl.Type, out nativeTypeName); } } else if (decl is TypeDecl previousTypeDecl) { - targetTypeName = GetRemappedTypeName(previousTypeDecl, context: null, previousTypeDecl.TypeForDecl, out nativeTypeName, skipUsing: false); + targetTypeName = GetRemappedTypeName(previousTypeDecl, context: null, previousTypeDecl.TypeForDecl, out nativeTypeName); } else if (decl is VarDecl varDecl) { if (varDecl is ParmVarDecl parmVarDecl) { - targetTypeName = GetRemappedTypeName(parmVarDecl, context: null, parmVarDecl.Type, out nativeTypeName, skipUsing: false); + targetTypeName = GetRemappedTypeName(parmVarDecl, context: null, parmVarDecl.Type, out nativeTypeName); if ((parmVarDecl.ParentFunctionOrMethod is FunctionDecl functionDecl) && ((functionDecl is CXXMethodDecl { IsVirtual: true }) || (functionDecl.Body is null)) && (targetTypeName == "bool")) { @@ -1664,23 +1913,23 @@ private string GetTargetTypeName(Cursor cursor, out string nativeTypeName) type = varDecl.Init.Type; } - targetTypeName = GetRemappedTypeName(varDecl, context: null, type, out nativeTypeName, skipUsing: false); + targetTypeName = GetRemappedTypeName(varDecl, context: null, type, out nativeTypeName); } } } else if ((cursor is Expr expr) && (expr is not MemberExpr)) { - targetTypeName = GetRemappedTypeName(expr, context: null, expr.Type, out nativeTypeName, skipUsing: false); + targetTypeName = GetRemappedTypeName(expr, context: null, expr.Type, out nativeTypeName); } return targetTypeName; } - private string GetTypeName(Cursor cursor, Cursor context, Type type, out string nativeTypeName) - => GetTypeName(cursor, context, type, type, out nativeTypeName); + private string GetTypeName(Cursor cursor, Cursor context, Type type, bool ignoreTransparentStructsWhereRequired, out string nativeTypeName) + => GetTypeName(cursor, context, type, type, ignoreTransparentStructsWhereRequired, out nativeTypeName); - private string GetTypeName(Cursor cursor, Cursor context, Type rootType, Type type, out string nativeTypeName) + private string GetTypeName(Cursor cursor, Cursor context, Type rootType, Type type, bool ignoreTransparentStructsWhereRequired, out string nativeTypeName) { if (!_typeNames.TryGetValue((cursor, context, type), out var result)) { @@ -1700,7 +1949,7 @@ private string GetTypeName(Cursor cursor, Cursor context, Type rootType, Type ty if (type is ArrayType arrayType) { - result.typeName = GetTypeName(cursor, context, rootType, arrayType.ElementType, out _); + result.typeName = GetTypeName(cursor, context, rootType, arrayType.ElementType, ignoreTransparentStructsWhereRequired, out _); if (cursor is FunctionDecl or ParmVarDecl) { @@ -1710,7 +1959,7 @@ private string GetTypeName(Cursor cursor, Cursor context, Type rootType, Type ty } else if (type is AttributedType attributedType) { - result.typeName = GetTypeName(cursor, context, rootType, attributedType.ModifiedType, out _); + result.typeName = GetTypeName(cursor, context, rootType, attributedType.ModifiedType, ignoreTransparentStructsWhereRequired, out _); } else if (type is BuiltinType) { @@ -1844,13 +2093,13 @@ private string GetTypeName(Cursor cursor, Cursor context, Type rootType, Type ty } else if (type is DeducedType deducedType) { - result.typeName = GetTypeName(cursor, context, rootType, deducedType.CanonicalType, out _); + result.typeName = GetTypeName(cursor, context, rootType, deducedType.CanonicalType, ignoreTransparentStructsWhereRequired, out _); } else if (type is DependentNameType dependentNameType) { if (dependentNameType.IsSugared) { - result.typeName = GetTypeName(cursor, context, rootType, dependentNameType.Desugar, out _); + result.typeName = GetTypeName(cursor, context, rootType, dependentNameType.Desugar, ignoreTransparentStructsWhereRequired, out _); } else { @@ -1859,31 +2108,31 @@ private string GetTypeName(Cursor cursor, Cursor context, Type rootType, Type ty } else if (type is ElaboratedType elaboratedType) { - result.typeName = GetTypeName(cursor, context, rootType, elaboratedType.NamedType, out _); + result.typeName = GetTypeName(cursor, context, rootType, elaboratedType.NamedType, ignoreTransparentStructsWhereRequired, out _); } else if (type is FunctionType functionType) { - result.typeName = GetTypeNameForPointeeType(cursor, context, rootType, functionType, out _); + result.typeName = GetTypeNameForPointeeType(cursor, context, rootType, functionType, ignoreTransparentStructsWhereRequired, out _); } else if (type is InjectedClassNameType injectedClassNameType) { - result.typeName = GetTypeName(cursor, context, rootType, injectedClassNameType.InjectedTST, out _); + result.typeName = GetTypeName(cursor, context, rootType, injectedClassNameType.InjectedTST, ignoreTransparentStructsWhereRequired, out _); } else if (type is PackExpansionType packExpansionType) { - result.typeName = GetTypeName(cursor, context, rootType, packExpansionType.Pattern, out _); + result.typeName = GetTypeName(cursor, context, rootType, packExpansionType.Pattern, ignoreTransparentStructsWhereRequired, out _); } else if (type is PointerType pointerType) { - result.typeName = GetTypeNameForPointeeType(cursor, context, rootType, pointerType.PointeeType, out _); + result.typeName = GetTypeNameForPointeeType(cursor, context, rootType, pointerType.PointeeType, ignoreTransparentStructsWhereRequired, out _); } else if (type is ReferenceType referenceType) { - result.typeName = GetTypeNameForPointeeType(cursor, context, rootType, referenceType.PointeeType, out _); + result.typeName = GetTypeNameForPointeeType(cursor, context, rootType, referenceType.PointeeType, ignoreTransparentStructsWhereRequired, out _); } else if (type is SubstTemplateTypeParmType substTemplateTypeParmType) { - result.typeName = GetTypeName(cursor, context, rootType, substTemplateTypeParmType.ReplacementType, out _); + result.typeName = GetTypeName(cursor, context, rootType, substTemplateTypeParmType.ReplacementType, ignoreTransparentStructsWhereRequired, out _); } else if (type is TagType tagType) { @@ -1893,7 +2142,7 @@ private string GetTypeName(Cursor cursor, Cursor context, Type rootType, Type ty } else if (tagType.Handle.IsConstQualified) { - result.typeName = GetTypeName(cursor, context, rootType, tagType.Decl.TypeForDecl, out _); + result.typeName = GetTypeName(cursor, context, rootType, tagType.Decl.TypeForDecl, ignoreTransparentStructsWhereRequired, out _); } else { @@ -1992,7 +2241,7 @@ private string GetTypeName(Cursor cursor, Cursor context, Type rootType, Type ty { if (templateTypeParmType.IsSugared) { - result.typeName = GetTypeName(cursor, context, rootType, templateTypeParmType.Desugar, out _); + result.typeName = GetTypeName(cursor, context, rootType, templateTypeParmType.Desugar, ignoreTransparentStructsWhereRequired, out _); } else { @@ -2006,7 +2255,7 @@ private string GetTypeName(Cursor cursor, Cursor context, Type rootType, Type ty // platform size, based on whatever parameters were passed into clang. var remappedName = GetRemappedName(result.typeName, cursor, tryRemapOperatorName: false, out var wasRemapped, skipUsing: true); - result.typeName = wasRemapped ? remappedName : GetTypeName(cursor, context, rootType, typedefType.Decl.UnderlyingType, out _); + result.typeName = wasRemapped ? remappedName : GetTypeName(cursor, context, rootType, typedefType.Decl.UnderlyingType, ignoreTransparentStructsWhereRequired, out _); } else { @@ -2016,7 +2265,7 @@ private string GetTypeName(Cursor cursor, Cursor context, Type rootType, Type ty Debug.Assert(!string.IsNullOrWhiteSpace(result.typeName)); Debug.Assert(!string.IsNullOrWhiteSpace(result.nativeTypeName)); - if (result.nativeTypeName.Equals(result.typeName)) + if (IsNativeTypeNameEquivalent(result.nativeTypeName, result.typeName)) { result.nativeTypeName = string.Empty; } @@ -2028,18 +2277,18 @@ private string GetTypeName(Cursor cursor, Cursor context, Type rootType, Type ty return result.typeName; } - private string GetTypeNameForPointeeType(Cursor cursor, Cursor context, Type rootType, Type pointeeType, out string nativePointeeTypeName) + private string GetTypeNameForPointeeType(Cursor cursor, Cursor context, Type rootType, Type pointeeType, bool ignoreTransparentStructsWhereRequired, out string nativePointeeTypeName) { var name = pointeeType.AsString; nativePointeeTypeName = name; if (pointeeType is AttributedType attributedType) { - name = GetTypeNameForPointeeType(cursor, context, rootType, attributedType.ModifiedType, out var nativeModifiedTypeName); + name = GetTypeNameForPointeeType(cursor, context, rootType, attributedType.ModifiedType, ignoreTransparentStructsWhereRequired, out var nativeModifiedTypeName); } else if (pointeeType is ElaboratedType elaboratedType) { - name = GetTypeNameForPointeeType(cursor, context, rootType, elaboratedType.NamedType, out var nativeNamedTypeName); + name = GetTypeNameForPointeeType(cursor, context, rootType, elaboratedType.NamedType, ignoreTransparentStructsWhereRequired, out var nativeNamedTypeName); } else if (pointeeType is FunctionType functionType) { @@ -2126,11 +2375,18 @@ private string GetTypeNameForPointeeType(Cursor cursor, Cursor context, Type roo _ = nameBuilder.Append(' '); } - _ = nameBuilder.Append(returnTypeName); - - if (needsReturnFixup) + if (!needsReturnFixup && ignoreTransparentStructsWhereRequired && _config.WithTransparentStructs.TryGetValue(returnTypeName, out var transparentValueTypeName)) { - _ = nameBuilder.Append('*'); + _ = nameBuilder.Append(transparentValueTypeName); + } + else + { + _ = nameBuilder.Append(returnTypeName); + + if (needsReturnFixup) + { + _ = nameBuilder.Append('*'); + } } _ = nameBuilder.Append('>'); @@ -2156,7 +2412,7 @@ private string GetTypeNameForPointeeType(Cursor cursor, Cursor context, Type roo } else { - name = GetTypeNameForPointeeType(cursor, context, rootType, typedefType.Decl.UnderlyingType, out var nativeUnderlyingTypeName); + name = GetTypeNameForPointeeType(cursor, context, rootType, typedefType.Decl.UnderlyingType, ignoreTransparentStructsWhereRequired, out var nativeUnderlyingTypeName); } } else @@ -2355,7 +2611,7 @@ private void GetTypeSize(Cursor cursor, Type type, ref long alignment32, ref lon } else if (type is RecordType recordType) { - var recordTypeAlignOf = recordType.Handle.AlignOf; + var recordTypeAlignOf = Math.Min(recordType.Handle.AlignOf, 8); if (alignment32 == -1) { @@ -2437,63 +2693,94 @@ private void GetTypeSize(Cursor cursor, Type type, ref long alignment32, ref lon } } - var bitfieldPreviousSize = 0L; - var bitfieldRemainingBits = 0L; + var bitfieldPreviousSize32 = 0L; + var bitfieldPreviousSize64 = 0L; + var bitfieldRemainingBits32 = 0L; + var bitfieldRemainingBits64 = 0L; foreach (var fieldDecl in recordType.Decl.Fields) { - long fieldSize32; - long fieldSize64; - long fieldAlignment32 = -1; long fieldAlignment64 = -1; - GetTypeSize(fieldDecl, fieldDecl.Type, ref fieldAlignment32, ref fieldAlignment64, out fieldSize32, out fieldSize64); + GetTypeSize(fieldDecl, fieldDecl.Type, ref fieldAlignment32, ref fieldAlignment64, out var fieldSize32, out var fieldSize64); + + var ignoreFieldSize32 = false; + var ignoreFieldSize64 = false; if (fieldDecl.IsBitField) { - if ((fieldSize32 != bitfieldPreviousSize) || (fieldDecl.BitWidthValue > bitfieldRemainingBits)) + if (fieldSize32 != bitfieldPreviousSize32) { - bitfieldRemainingBits = fieldSize32 * 8; - bitfieldPreviousSize = fieldSize32; - bitfieldRemainingBits -= fieldDecl.BitWidthValue; + bitfieldRemainingBits32 = fieldSize32 * 8; + bitfieldPreviousSize32 = fieldSize32; + bitfieldRemainingBits32 -= fieldDecl.BitWidthValue; + } + else if (fieldDecl.BitWidthValue > bitfieldRemainingBits32) + { + if (bitfieldRemainingBits32 != bitfieldRemainingBits64) + { + ignoreFieldSize32 = true; + } + + bitfieldRemainingBits32 = fieldSize32 * 8; + bitfieldPreviousSize32 = fieldSize32; + bitfieldRemainingBits32 -= fieldDecl.BitWidthValue; } else { - bitfieldPreviousSize = fieldSize32; - bitfieldRemainingBits -= fieldDecl.BitWidthValue; - continue; + bitfieldPreviousSize32 = fieldSize32; + bitfieldRemainingBits32 -= fieldDecl.BitWidthValue; + ignoreFieldSize32 = true; } - } - if ((fieldAlignment32 == -1) || (alignment32 < 4)) - { - fieldAlignment32 = Math.Max(Math.Min(alignment32, fieldSize32), 1); + if ((fieldSize64 != bitfieldPreviousSize64) || (fieldDecl.BitWidthValue > bitfieldRemainingBits64)) + { + bitfieldRemainingBits64 = fieldSize64 * 8; + bitfieldPreviousSize64 = fieldSize64; + bitfieldRemainingBits64 -= fieldDecl.BitWidthValue; + } + else + { + bitfieldPreviousSize64 = fieldSize64; + bitfieldRemainingBits64 -= fieldDecl.BitWidthValue; + ignoreFieldSize64 = true; + } } - if ((fieldAlignment64 == -1) || (alignment64 < 4)) + if (!ignoreFieldSize32) { - fieldAlignment64 = Math.Max(Math.Min(alignment64, fieldSize64), 1); - } + if ((fieldAlignment32 == -1) || (alignment32 < 4)) + { + fieldAlignment32 = Math.Max(Math.Min(alignment32, fieldSize32), 1); + } - if ((size32 % fieldAlignment32) != 0) - { - size32 += fieldAlignment32 - (size32 % fieldAlignment32); - } + if ((size32 % fieldAlignment32) != 0) + { + size32 += fieldAlignment32 - (size32 % fieldAlignment32); + } - if ((size64 % fieldAlignment64) != 0) - { - size64 += fieldAlignment64 - (size64 % fieldAlignment64); + size32 += fieldSize32; + maxFieldAlignment32 = Math.Max(maxFieldAlignment32, fieldAlignment32); + maxFieldSize32 = Math.Max(maxFieldSize32, fieldSize32); } - size32 += fieldSize32; - size64 += fieldSize64; + if (!ignoreFieldSize64) + { + if ((fieldAlignment64 == -1) || (alignment64 < 4)) + { + fieldAlignment64 = Math.Max(Math.Min(alignment64, fieldSize64), 1); + } - maxFieldAlignment32 = Math.Max(maxFieldAlignment32, fieldAlignment32); - maxFieldAlignment64 = Math.Max(maxFieldAlignment64, fieldAlignment64); + if ((size64 % fieldAlignment64) != 0) + { + size64 += fieldAlignment64 - (size64 % fieldAlignment64); + } - maxFieldSize32 = Math.Max(maxFieldSize32, fieldSize32); - maxFieldSize64 = Math.Max(maxFieldSize64, fieldSize64); + size64 += fieldSize64; + maxFieldAlignment64 = Math.Max(maxFieldAlignment64, fieldAlignment64); + maxFieldSize64 = Math.Max(maxFieldSize64, fieldSize64); + } } if (alignment32 == 8) @@ -2528,7 +2815,7 @@ private void GetTypeSize(Cursor cursor, Type type, ref long alignment32, ref lon // can be treated correctly. Otherwise, they will resolve to a particular // platform size, based on whatever parameters were passed into clang. - var name = GetTypeName(cursor, context: null, type, out _); + var name = GetTypeName(cursor, context: null, type, ignoreTransparentStructsWhereRequired: false, out _); if (!_config.RemappedNames.TryGetValue(name, out var remappedName)) { @@ -2899,7 +3186,7 @@ bool IsComProxy(FunctionDecl functionDecl, string name) if ((parmVarDecl != null) && (parmVarDecl.Type is PointerType pointerType)) { - var typeName = GetTypeName(parmVarDecl, context: null, pointerType.PointeeType, out var nativeTypeName); + var typeName = GetTypeName(parmVarDecl, context: null, pointerType.PointeeType, ignoreTransparentStructsWhereRequired: false, out var nativeTypeName); return name.StartsWith($"{nativeTypeName}_") || name.StartsWith($"{typeName}_") || (typeName == "IRpcStubBuffer"); } return false; @@ -3086,7 +3373,7 @@ private bool IsFixedSize(Cursor cursor, Type type) } else if (type is TypedefType typedefType) { - var name = GetTypeName(cursor, context: null, type, out _); + var name = GetTypeName(cursor, context: null, type, ignoreTransparentStructsWhereRequired: false, out _); if (!_config.RemappedNames.TryGetValue(name, out var remappedName)) { @@ -3106,6 +3393,21 @@ private bool IsFixedSize(Cursor cursor, Type type) } } + private bool IsNativeTypeNameEquivalent(string nativeTypeName, string typeName) + { + if (nativeTypeName.Equals(typeName, StringComparison.OrdinalIgnoreCase)) + { + return true; + } + + if (nativeTypeName.Replace(" ", "").Equals(typeName, StringComparison.OrdinalIgnoreCase)) + { + return true; + } + + return false; + } + private bool IsPrevContextDecl(out T cursor, out object userData) where T : Decl { @@ -3223,6 +3525,16 @@ internal static bool IsSupportedFixedSizedBufferType(string typeName) private bool IsUnchecked(string targetTypeName, Stmt stmt) { + if (IsPrevContextDecl(out var parentVarDecl, out _)) + { + var cursorName = GetCursorName(parentVarDecl); + + if (cursorName.StartsWith("ClangSharpMacro_") && _config.WithTransparentStructs.TryGetValue(targetTypeName, out var transparentValueTypeName)) + { + targetTypeName = transparentValueTypeName; + } + } + switch (stmt.StmtClass) { // case CX_StmtClass.CX_StmtClass_BinaryConditionalOperator: @@ -3342,7 +3654,7 @@ private bool IsUnchecked(string targetTypeName, Stmt stmt) case CX_StmtClass.CX_StmtClass_CXXFunctionalCastExpr: { var explicitCastExpr = (ExplicitCastExpr)stmt; - var explicitCastExprTypeName = GetRemappedTypeName(explicitCastExpr, context: null, explicitCastExpr.Type, out _, skipUsing: false); + var explicitCastExprTypeName = GetRemappedTypeName(explicitCastExpr, context: null, explicitCastExpr.Type, out _); return IsUnchecked(targetTypeName, explicitCastExpr.SubExprAsWritten) || IsUnchecked(targetTypeName, explicitCastExpr.Handle.Evaluate) @@ -3578,7 +3890,7 @@ private bool IsUnchecked(string targetTypeName, Stmt stmt) return true; } - var sourceTypeName = GetTypeName(stmt, context: null, unaryOperator.SubExpr.Type, out _); + var sourceTypeName = GetTypeName(stmt, context: null, unaryOperator.SubExpr.Type, ignoreTransparentStructsWhereRequired: false, out _); switch (unaryOperator.Opcode) { @@ -3760,7 +4072,7 @@ private bool IsUnsafe(FieldDecl fieldDecl) if (type.CanonicalType is ConstantArrayType) { - var name = GetTypeName(fieldDecl, context: null, type, out _); + var name = GetTypeName(fieldDecl, context: null, type, ignoreTransparentStructsWhereRequired: false, out _); if (!_config.RemappedNames.TryGetValue(name, out var remappedName)) { @@ -3835,7 +4147,7 @@ private bool IsUnsafe(TypedefDecl typedefDecl, FunctionProtoType functionProtoTy private bool IsUnsafe(NamedDecl namedDecl, Type type) { - var name = GetTypeName(namedDecl, context: null, type, out _); + var name = GetTypeName(namedDecl, context: null, type, ignoreTransparentStructsWhereRequired: false, out _); if (!_config.RemappedNames.TryGetValue(name, out var remappedName)) { @@ -4259,7 +4571,6 @@ private void UncheckStmt(string targetTypeName, Stmt stmt) { var argumentType = unaryExprOrTypeTraitExpr.TypeOfArgument; - long alignment32 = -1; long alignment64 = -1; @@ -4493,7 +4804,7 @@ private void WithType(string remappedName, ref string integerTypeName, ref strin integerTypeName = type; - if (nativeTypeName.Equals(type)) + if (IsNativeTypeNameEquivalent(nativeTypeName, type)) { nativeTypeName = string.Empty; } diff --git a/sources/ClangSharp.PInvokeGenerator/PInvokeGeneratorConfiguration.cs b/sources/ClangSharp.PInvokeGenerator/PInvokeGeneratorConfiguration.cs index 71e4ab75..4456eac5 100644 --- a/sources/ClangSharp.PInvokeGenerator/PInvokeGeneratorConfiguration.cs +++ b/sources/ClangSharp.PInvokeGenerator/PInvokeGeneratorConfiguration.cs @@ -18,12 +18,13 @@ public sealed class PInvokeGeneratorConfiguration private readonly Dictionary> _withAttributes; private readonly Dictionary _withCallConvs; private readonly Dictionary _withLibraryPaths; + private readonly Dictionary _withTransparentStructs; private readonly Dictionary _withTypes; private readonly Dictionary> _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 headerFile = null, string methodClassName = null, string methodPrefixToStrip = null, IReadOnlyDictionary remappedNames = null, string[] traversalNames = null, IReadOnlyDictionary withAccessSpecifiers = null, IReadOnlyDictionary> withAttributes = null, IReadOnlyDictionary withCallConvs = null, IReadOnlyDictionary withLibraryPaths = null, string[] withSetLastErrors = 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, string[] excludedNames = 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 withLibraryPaths = null, string[] withSetLastErrors = null, IReadOnlyDictionary withTransparentStructs = null, IReadOnlyDictionary withTypes = null, IReadOnlyDictionary> withUsings = null) { if (excludedNames is null) { @@ -92,6 +93,7 @@ public PInvokeGeneratorConfiguration(string libraryPath, string namespaceName, s _withAttributes = new Dictionary>(); _withCallConvs = new Dictionary(); _withLibraryPaths = new Dictionary(); + _withTransparentStructs = new Dictionary(); _withTypes = new Dictionary(); _withUsings = new Dictionary>(); @@ -133,6 +135,7 @@ public PInvokeGeneratorConfiguration(string libraryPath, string namespaceName, s AddRange(_withAttributes, withAttributes); AddRange(_withCallConvs, withCallConvs); AddRange(_withLibraryPaths, withLibraryPaths); + AddRange(_withTransparentStructs, withTransparentStructs, RemoveAtPrefix); AddRange(_withTypes, withTypes); AddRange(_withUsings, withUsings); } @@ -201,6 +204,8 @@ public bool ExcludeFnptrCodegen public bool GenerateCppAttributes => _options.HasFlag(PInvokeGeneratorConfigurationOptions.GenerateCppAttributes); + public bool GenerateHelperTypes => _options.HasFlag(PInvokeGeneratorConfigurationOptions.GenerateHelperTypes); + public bool GenerateNativeInheritanceAttribute => _options.HasFlag(PInvokeGeneratorConfigurationOptions.GenerateNativeInheritanceAttribute); public bool GenerateTemplateBindings => _options.HasFlag(PInvokeGeneratorConfigurationOptions.GenerateTemplateBindings); @@ -239,6 +244,8 @@ public bool ExcludeFnptrCodegen public string[] WithSetLastErrors { get; } + public IReadOnlyDictionary WithTransparentStructs => _withTransparentStructs; + public IReadOnlyDictionary WithTypes => _withTypes; public IReadOnlyDictionary> WithUsings => _withUsings; diff --git a/sources/ClangSharp.PInvokeGenerator/PInvokeGeneratorConfigurationOptions.cs b/sources/ClangSharp.PInvokeGenerator/PInvokeGeneratorConfigurationOptions.cs index db363ab1..48ca1e1f 100644 --- a/sources/ClangSharp.PInvokeGenerator/PInvokeGeneratorConfigurationOptions.cs +++ b/sources/ClangSharp.PInvokeGenerator/PInvokeGeneratorConfigurationOptions.cs @@ -62,5 +62,7 @@ public enum PInvokeGeneratorConfigurationOptions GenerateSourceLocationAttribute = 1 << 25, GenerateUnmanagedConstants = 1 << 26, + + GenerateHelperTypes = 1 << 27, } } diff --git a/sources/ClangSharp.PInvokeGenerator/XML/XmlOutputBuilder.Visit.cs b/sources/ClangSharp.PInvokeGenerator/XML/XmlOutputBuilder.Visit.cs index 9efc17c3..ddc89ea1 100644 --- a/sources/ClangSharp.PInvokeGenerator/XML/XmlOutputBuilder.Visit.cs +++ b/sources/ClangSharp.PInvokeGenerator/XML/XmlOutputBuilder.Visit.cs @@ -6,8 +6,12 @@ namespace ClangSharp.XML { internal partial class XmlOutputBuilder { - public void WriteCustomAttribute(string attribute) - => _sb.Append($"{attribute}\n"); + public void WriteCustomAttribute(string attribute, Action callback = null) + { + _ = _sb.Append($"{attribute}"); + callback?.Invoke(); + _ = _sb.Append("\n"); + } public void WriteIid(string name, Guid value) { diff --git a/sources/ClangSharp.PInvokeGenerator/XML/XmlOutputBuilder.VisitDecl.cs b/sources/ClangSharp.PInvokeGenerator/XML/XmlOutputBuilder.VisitDecl.cs index e606df21..39bb4241 100644 --- a/sources/ClangSharp.PInvokeGenerator/XML/XmlOutputBuilder.VisitDecl.cs +++ b/sources/ClangSharp.PInvokeGenerator/XML/XmlOutputBuilder.VisitDecl.cs @@ -154,7 +154,7 @@ public void BeginFunctionOrDelegate( _ = _sb.Append('>'); - desc.WriteCustomAttrs(desc.CustomAttrGeneratorData); + desc.WriteCustomAttrs?.Invoke(desc.CustomAttrGeneratorData); _ = _sb.Append("(in ParameterDesc info) { _ = _sb.Append($""); - info.WriteCustomAttrs(info.CustomAttrGeneratorData); + info.WriteCustomAttrs?.Invoke(info.CustomAttrGeneratorData); _ = _sb.Append(""); _ = _sb.Append(EscapeText(info.Type)); _ = _sb.Append(""); @@ -286,7 +286,7 @@ public void BeginStruct(in StructDesc'); - info.WriteCustomAttrs(info.CustomAttrGeneratorData); + info.WriteCustomAttrs?.Invoke(info.CustomAttrGeneratorData); } public void BeginExplicitVtbl() => _sb.Append(""); diff --git a/sources/ClangSharpPInvokeGenerator/Program.cs b/sources/ClangSharpPInvokeGenerator/Program.cs index 96d00b73..49b4e9ea 100644 --- a/sources/ClangSharpPInvokeGenerator/Program.cs +++ b/sources/ClangSharpPInvokeGenerator/Program.cs @@ -66,6 +66,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-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."), new HelpItem("generate-native-inheritance-attribute", "[NativeInheritance(\"\")] attribute should be generated to document the encountered C++ base type."), new HelpItem("generate-template-bindings", "Bindings for template-definitions should be generated. This is currently experimental."), @@ -112,6 +113,7 @@ public static async Task Main(params string[] args) AddWithCallConvOption(s_rootCommand); AddWithLibraryPathOption(s_rootCommand); AddWithSetLastErrorOption(s_rootCommand); + AddWithTransparentStructOption(s_rootCommand); AddWithTypeOption(s_rootCommand); AddWithUsingOption(s_rootCommand); @@ -145,6 +147,7 @@ public static int Run(InvocationContext context) var withCallConvNameValuePairs = context.ParseResult.ValueForOption("--with-callconv"); var withLibraryPathNameValuePairs = context.ParseResult.ValueForOption("--with-librarypath"); var withSetLastErrors = context.ParseResult.ValueForOption("--with-setlasterror"); + var withTransparentStructNameValuePairs = context.ParseResult.ValueForOption("--with-transparent-struct"); var withTypeNameValuePairs = context.ParseResult.ValueForOption("--with-type"); var withUsingNameValuePairs = context.ParseResult.ValueForOption("--with-using"); @@ -183,9 +186,15 @@ public static int Run(InvocationContext context) ParseKeyValuePairs(withAttributeNameValuePairs, errorList, out Dictionary> withAttributes); ParseKeyValuePairs(withCallConvNameValuePairs, errorList, out Dictionary withCallConvs); ParseKeyValuePairs(withLibraryPathNameValuePairs, errorList, out Dictionary withLibraryPath); + ParseKeyValuePairs(withTransparentStructNameValuePairs, errorList, out Dictionary withTransparentStructs); ParseKeyValuePairs(withTypeNameValuePairs, errorList, out Dictionary withTypes); ParseKeyValuePairs(withUsingNameValuePairs, errorList, out Dictionary> withUsings); + foreach (var key in withTransparentStructs.Keys) + { + remappedNames.Add(key, key); + } + var configOptions = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? PInvokeGeneratorConfigurationOptions.None : PInvokeGeneratorConfigurationOptions.GenerateUnixTypes; var printConfigHelp = false; @@ -370,6 +379,12 @@ public static int Run(InvocationContext context) break; } + case "generate-helper-types": + { + configOptions |= PInvokeGeneratorConfigurationOptions.GenerateHelperTypes; + break; + } + case "generate-macro-bindings": { configOptions |= PInvokeGeneratorConfigurationOptions.GenerateMacroBindings; @@ -495,7 +510,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, headerFile, methodClassName, methodPrefixToStrip, remappedNames, traversalNames, withAccessSpecifiers, withAttributes, withCallConvs, withLibraryPath, withSetLastErrors, withTypes, withUsings); + var config = new PInvokeGeneratorConfiguration(libraryPath, namespaceName, outputLocation, testOutputLocation, outputMode, configOptions, excludedNames, headerFile, methodClassName, methodPrefixToStrip, remappedNames, traversalNames, withAccessSpecifiers, withAttributes, withCallConvs, withLibraryPath, withSetLastErrors, withTransparentStructs, withTypes, withUsings); if (config.GenerateMacroBindings) { @@ -590,7 +605,7 @@ public static int Run(InvocationContext context) return exitCode; } - private static void ParseKeyValuePairs(string[] keyValuePairs, List errorList, out Dictionary result) + private static void ParseKeyValuePairs(IEnumerable keyValuePairs, List errorList, out Dictionary result) { result = new Dictionary(); @@ -616,7 +631,7 @@ private static void ParseKeyValuePairs(string[] keyValuePairs, List erro } } - private static void ParseKeyValuePairs(string[] keyValuePairs, List errorList, out Dictionary> result) + private static void ParseKeyValuePairs(IEnumerable keyValuePairs, List errorList, out Dictionary> result) { result = new Dictionary>(); @@ -969,6 +984,19 @@ private static void AddWithSetLastErrorOption(RootCommand rootCommand) rootCommand.AddOption(option); } + private static void AddWithTransparentStructOption(RootCommand rootCommand) + { + var option = new Option( + aliases: new string[] { "--with-transparent-struct", "-wts" }, + description: "A remapped type name to be treated as a transparent wrapper during binding generation.", + argumentType: typeof(string), + getDefaultValue: Array.Empty, + arity: ArgumentArity.OneOrMore + ); + + rootCommand.AddOption(option); + } + private static void AddWithTypeOption(RootCommand rootCommand) { var option = new Option( diff --git a/tests/ClangSharp.PInvokeGenerator.UnitTests/PInvokeGeneratorTest.cs b/tests/ClangSharp.PInvokeGenerator.UnitTests/PInvokeGeneratorTest.cs index 419f0914..4a7899f0 100644 --- a/tests/ClangSharp.PInvokeGenerator.UnitTests/PInvokeGeneratorTest.cs +++ b/tests/ClangSharp.PInvokeGenerator.UnitTests/PInvokeGeneratorTest.cs @@ -36,23 +36,23 @@ public abstract class PInvokeGeneratorTest protected static string EscapeXml(string value) => new XText(value).ToString(); - protected static Task ValidateGeneratedCSharpLatestWindowsBindingsAsync(string inputContents, string expectedOutputContents, PInvokeGeneratorConfigurationOptions additionalConfigOptions = PInvokeGeneratorConfigurationOptions.None, string[] excludedNames = null, IReadOnlyDictionary remappedNames = null, IReadOnlyDictionary withAccessSpecifiers = null, IReadOnlyDictionary> withAttributes = null, IReadOnlyDictionary withCallConvs = null, IReadOnlyDictionary withLibraryPaths = null, string[] withSetLastErrors = null, IReadOnlyDictionary withTypes = null, IReadOnlyDictionary> withUsings = null, IEnumerable expectedDiagnostics = null, string libraryPath = DefaultLibraryPath, string[] commandlineArgs = null) => ValidateGeneratedBindingsAsync(inputContents, expectedOutputContents, PInvokeGeneratorOutputMode.CSharp, PInvokeGeneratorConfigurationOptions.None | additionalConfigOptions, excludedNames, remappedNames, withAccessSpecifiers, withAttributes, withCallConvs, withLibraryPaths, withSetLastErrors, withTypes, withUsings, expectedDiagnostics, libraryPath, commandlineArgs); + protected static Task ValidateGeneratedCSharpLatestWindowsBindingsAsync(string inputContents, string expectedOutputContents, PInvokeGeneratorConfigurationOptions additionalConfigOptions = PInvokeGeneratorConfigurationOptions.None, string[] excludedNames = null, IReadOnlyDictionary remappedNames = null, IReadOnlyDictionary withAccessSpecifiers = null, IReadOnlyDictionary> withAttributes = null, IReadOnlyDictionary withCallConvs = null, IReadOnlyDictionary withLibraryPaths = null, string[] withSetLastErrors = null, IReadOnlyDictionary withTransparentStructs = null, IReadOnlyDictionary withTypes = null, IReadOnlyDictionary> withUsings = null, IEnumerable expectedDiagnostics = null, string libraryPath = DefaultLibraryPath, string[] commandlineArgs = null) => ValidateGeneratedBindingsAsync(inputContents, expectedOutputContents, PInvokeGeneratorOutputMode.CSharp, PInvokeGeneratorConfigurationOptions.None | additionalConfigOptions, excludedNames, remappedNames, withAccessSpecifiers, withAttributes, withCallConvs, withLibraryPaths, withSetLastErrors, withTransparentStructs, withTypes, withUsings, expectedDiagnostics, libraryPath, commandlineArgs); - protected static Task ValidateGeneratedCSharpLatestUnixBindingsAsync(string inputContents, string expectedOutputContents, PInvokeGeneratorConfigurationOptions additionalConfigOptions = PInvokeGeneratorConfigurationOptions.None, string[] excludedNames = null, IReadOnlyDictionary remappedNames = null, IReadOnlyDictionary withAccessSpecifiers = null, IReadOnlyDictionary> withAttributes = null, IReadOnlyDictionary withCallConvs = null, IReadOnlyDictionary withLibraryPaths = null, string[] withSetLastErrors = null, IReadOnlyDictionary withTypes = null, IReadOnlyDictionary> withUsings = null, IEnumerable expectedDiagnostics = null, string libraryPath = DefaultLibraryPath, string[] commandlineArgs = null) => ValidateGeneratedBindingsAsync(inputContents, expectedOutputContents, PInvokeGeneratorOutputMode.CSharp, PInvokeGeneratorConfigurationOptions.GenerateUnixTypes | additionalConfigOptions, excludedNames, remappedNames, withAccessSpecifiers, withAttributes, withCallConvs, withLibraryPaths, withSetLastErrors, withTypes, withUsings, expectedDiagnostics, libraryPath, commandlineArgs); + protected static Task ValidateGeneratedCSharpLatestUnixBindingsAsync(string inputContents, string expectedOutputContents, PInvokeGeneratorConfigurationOptions additionalConfigOptions = PInvokeGeneratorConfigurationOptions.None, string[] excludedNames = null, IReadOnlyDictionary remappedNames = null, IReadOnlyDictionary withAccessSpecifiers = null, IReadOnlyDictionary> withAttributes = null, IReadOnlyDictionary withCallConvs = null, IReadOnlyDictionary withLibraryPaths = null, string[] withSetLastErrors = null, IReadOnlyDictionary withTransparentStructs = null, IReadOnlyDictionary withTypes = null, IReadOnlyDictionary> withUsings = null, IEnumerable expectedDiagnostics = null, string libraryPath = DefaultLibraryPath, string[] commandlineArgs = null) => ValidateGeneratedBindingsAsync(inputContents, expectedOutputContents, PInvokeGeneratorOutputMode.CSharp, PInvokeGeneratorConfigurationOptions.GenerateUnixTypes | additionalConfigOptions, excludedNames, remappedNames, withAccessSpecifiers, withAttributes, withCallConvs, withLibraryPaths, withSetLastErrors, withTransparentStructs, withTypes, withUsings, expectedDiagnostics, libraryPath, commandlineArgs); - protected static Task ValidateGeneratedCSharpCompatibleWindowsBindingsAsync(string inputContents, string expectedOutputContents, PInvokeGeneratorConfigurationOptions additionalConfigOptions = PInvokeGeneratorConfigurationOptions.None, string[] excludedNames = null, IReadOnlyDictionary remappedNames = null, IReadOnlyDictionary withAccessSpecifiers = null, IReadOnlyDictionary> withAttributes = null, IReadOnlyDictionary withCallConvs = null, IReadOnlyDictionary withLibraryPaths = null, string[] withSetLastErrors = null, IReadOnlyDictionary withTypes = null, IReadOnlyDictionary> withUsings = null, IEnumerable expectedDiagnostics = null, string libraryPath = DefaultLibraryPath, string[] commandlineArgs = null) => ValidateGeneratedBindingsAsync(inputContents, expectedOutputContents, PInvokeGeneratorOutputMode.CSharp, PInvokeGeneratorConfigurationOptions.GenerateCompatibleCode | additionalConfigOptions, excludedNames, remappedNames, withAccessSpecifiers, withAttributes, withCallConvs, withLibraryPaths, withSetLastErrors, withTypes, withUsings, expectedDiagnostics, libraryPath, commandlineArgs); + protected static Task ValidateGeneratedCSharpCompatibleWindowsBindingsAsync(string inputContents, string expectedOutputContents, PInvokeGeneratorConfigurationOptions additionalConfigOptions = PInvokeGeneratorConfigurationOptions.None, string[] excludedNames = null, IReadOnlyDictionary remappedNames = null, IReadOnlyDictionary withAccessSpecifiers = null, IReadOnlyDictionary> withAttributes = null, IReadOnlyDictionary withCallConvs = null, IReadOnlyDictionary withLibraryPaths = null, string[] withSetLastErrors = null, IReadOnlyDictionary withTransparentStructs = null, IReadOnlyDictionary withTypes = null, IReadOnlyDictionary> withUsings = null, IEnumerable expectedDiagnostics = null, string libraryPath = DefaultLibraryPath, string[] commandlineArgs = null) => ValidateGeneratedBindingsAsync(inputContents, expectedOutputContents, PInvokeGeneratorOutputMode.CSharp, PInvokeGeneratorConfigurationOptions.GenerateCompatibleCode | additionalConfigOptions, excludedNames, remappedNames, withAccessSpecifiers, withAttributes, withCallConvs, withLibraryPaths, withSetLastErrors, withTransparentStructs, withTypes, withUsings, expectedDiagnostics, libraryPath, commandlineArgs); - protected static Task ValidateGeneratedCSharpCompatibleUnixBindingsAsync(string inputContents, string expectedOutputContents, PInvokeGeneratorConfigurationOptions additionalConfigOptions = PInvokeGeneratorConfigurationOptions.None, string[] excludedNames = null, IReadOnlyDictionary remappedNames = null, IReadOnlyDictionary withAccessSpecifiers = null, IReadOnlyDictionary> withAttributes = null, IReadOnlyDictionary withCallConvs = null, IReadOnlyDictionary withLibraryPaths = null, string[] withSetLastErrors = null, IReadOnlyDictionary withTypes = null, IReadOnlyDictionary> withUsings = null, IEnumerable expectedDiagnostics = null, string libraryPath = DefaultLibraryPath, string[] commandlineArgs = null) => ValidateGeneratedBindingsAsync(inputContents, expectedOutputContents, PInvokeGeneratorOutputMode.CSharp, PInvokeGeneratorConfigurationOptions.GenerateCompatibleCode | PInvokeGeneratorConfigurationOptions.GenerateUnixTypes | additionalConfigOptions, excludedNames, remappedNames, withAccessSpecifiers, withAttributes, withCallConvs, withLibraryPaths, withSetLastErrors, withTypes, withUsings, expectedDiagnostics, libraryPath, commandlineArgs); + protected static Task ValidateGeneratedCSharpCompatibleUnixBindingsAsync(string inputContents, string expectedOutputContents, PInvokeGeneratorConfigurationOptions additionalConfigOptions = PInvokeGeneratorConfigurationOptions.None, string[] excludedNames = null, IReadOnlyDictionary remappedNames = null, IReadOnlyDictionary withAccessSpecifiers = null, IReadOnlyDictionary> withAttributes = null, IReadOnlyDictionary withCallConvs = null, IReadOnlyDictionary withLibraryPaths = null, string[] withSetLastErrors = null, IReadOnlyDictionary withTransparentStructs = null, IReadOnlyDictionary withTypes = null, IReadOnlyDictionary> withUsings = null, IEnumerable expectedDiagnostics = null, string libraryPath = DefaultLibraryPath, string[] commandlineArgs = null) => ValidateGeneratedBindingsAsync(inputContents, expectedOutputContents, PInvokeGeneratorOutputMode.CSharp, PInvokeGeneratorConfigurationOptions.GenerateCompatibleCode | PInvokeGeneratorConfigurationOptions.GenerateUnixTypes | additionalConfigOptions, excludedNames, remappedNames, withAccessSpecifiers, withAttributes, withCallConvs, withLibraryPaths, withSetLastErrors, withTransparentStructs, withTypes, withUsings, expectedDiagnostics, libraryPath, commandlineArgs); - protected static Task ValidateGeneratedXmlLatestWindowsBindingsAsync(string inputContents, string expectedOutputContents, PInvokeGeneratorConfigurationOptions additionalConfigOptions = PInvokeGeneratorConfigurationOptions.None, string[] excludedNames = null, IReadOnlyDictionary remappedNames = null, IReadOnlyDictionary withAccessSpecifiers = null, IReadOnlyDictionary> withAttributes = null, IReadOnlyDictionary withCallConvs = null, IReadOnlyDictionary withLibraryPaths = null, string[] withSetLastErrors = null, IReadOnlyDictionary withTypes = null, IReadOnlyDictionary> withUsings = null, IEnumerable expectedDiagnostics = null, string libraryPath = DefaultLibraryPath, string[] commandlineArgs = null, [CallerFilePath] string filePath = "") => ValidateGeneratedBindingsAsync(inputContents, expectedOutputContents, PInvokeGeneratorOutputMode.Xml, PInvokeGeneratorConfigurationOptions.None | additionalConfigOptions, excludedNames, remappedNames, withAccessSpecifiers, withAttributes, withCallConvs, withLibraryPaths, withSetLastErrors, withTypes, withUsings, expectedDiagnostics, libraryPath, commandlineArgs, filePath); + protected static Task ValidateGeneratedXmlLatestWindowsBindingsAsync(string inputContents, string expectedOutputContents, PInvokeGeneratorConfigurationOptions additionalConfigOptions = PInvokeGeneratorConfigurationOptions.None, string[] excludedNames = null, IReadOnlyDictionary remappedNames = null, IReadOnlyDictionary withAccessSpecifiers = null, IReadOnlyDictionary> withAttributes = null, IReadOnlyDictionary withCallConvs = null, IReadOnlyDictionary withLibraryPaths = null, string[] withSetLastErrors = null, IReadOnlyDictionary withTransparentStructs = null, IReadOnlyDictionary withTypes = null, IReadOnlyDictionary> withUsings = null, IEnumerable expectedDiagnostics = null, string libraryPath = DefaultLibraryPath, string[] commandlineArgs = null, [CallerFilePath] string filePath = "") => ValidateGeneratedBindingsAsync(inputContents, expectedOutputContents, PInvokeGeneratorOutputMode.Xml, PInvokeGeneratorConfigurationOptions.None | additionalConfigOptions, excludedNames, remappedNames, withAccessSpecifiers, withAttributes, withCallConvs, withLibraryPaths, withSetLastErrors, withTransparentStructs, withTypes, withUsings, expectedDiagnostics, libraryPath, commandlineArgs, filePath); - protected static Task ValidateGeneratedXmlLatestUnixBindingsAsync(string inputContents, string expectedOutputContents, PInvokeGeneratorConfigurationOptions additionalConfigOptions = PInvokeGeneratorConfigurationOptions.None, string[] excludedNames = null, IReadOnlyDictionary remappedNames = null, IReadOnlyDictionary withAccessSpecifiers = null, IReadOnlyDictionary> withAttributes = null, IReadOnlyDictionary withCallConvs = null, IReadOnlyDictionary withLibraryPaths = null, string[] withSetLastErrors = null, IReadOnlyDictionary withTypes = null, IReadOnlyDictionary> withUsings = null, IEnumerable expectedDiagnostics = null, string libraryPath = DefaultLibraryPath, string[] commandlineArgs = null) => ValidateGeneratedBindingsAsync(inputContents, expectedOutputContents, PInvokeGeneratorOutputMode.Xml, PInvokeGeneratorConfigurationOptions.GenerateUnixTypes | additionalConfigOptions, excludedNames, remappedNames, withAccessSpecifiers, withAttributes, withCallConvs, withLibraryPaths, withSetLastErrors, withTypes, withUsings, expectedDiagnostics, libraryPath, commandlineArgs); + protected static Task ValidateGeneratedXmlLatestUnixBindingsAsync(string inputContents, string expectedOutputContents, PInvokeGeneratorConfigurationOptions additionalConfigOptions = PInvokeGeneratorConfigurationOptions.None, string[] excludedNames = null, IReadOnlyDictionary remappedNames = null, IReadOnlyDictionary withAccessSpecifiers = null, IReadOnlyDictionary> withAttributes = null, IReadOnlyDictionary withCallConvs = null, IReadOnlyDictionary withLibraryPaths = null, string[] withSetLastErrors = null, IReadOnlyDictionary withTransparentStructs = null, IReadOnlyDictionary withTypes = null, IReadOnlyDictionary> withUsings = null, IEnumerable expectedDiagnostics = null, string libraryPath = DefaultLibraryPath, string[] commandlineArgs = null) => ValidateGeneratedBindingsAsync(inputContents, expectedOutputContents, PInvokeGeneratorOutputMode.Xml, PInvokeGeneratorConfigurationOptions.GenerateUnixTypes | additionalConfigOptions, excludedNames, remappedNames, withAccessSpecifiers, withAttributes, withCallConvs, withLibraryPaths, withSetLastErrors, withTransparentStructs, withTypes, withUsings, expectedDiagnostics, libraryPath, commandlineArgs); - protected static Task ValidateGeneratedXmlCompatibleWindowsBindingsAsync(string inputContents, string expectedOutputContents, PInvokeGeneratorConfigurationOptions additionalConfigOptions = PInvokeGeneratorConfigurationOptions.None, string[] excludedNames = null, IReadOnlyDictionary remappedNames = null, IReadOnlyDictionary withAccessSpecifiers = null, IReadOnlyDictionary> withAttributes = null, IReadOnlyDictionary withCallConvs = null, IReadOnlyDictionary withLibraryPaths = null, string[] withSetLastErrors = null, IReadOnlyDictionary withTypes = null, IReadOnlyDictionary> withUsings = null, IEnumerable expectedDiagnostics = null, string libraryPath = DefaultLibraryPath, string[] commandlineArgs = null) => ValidateGeneratedBindingsAsync(inputContents, expectedOutputContents, PInvokeGeneratorOutputMode.Xml, PInvokeGeneratorConfigurationOptions.GenerateCompatibleCode | additionalConfigOptions, excludedNames, remappedNames, withAccessSpecifiers, withAttributes, withCallConvs, withLibraryPaths, withSetLastErrors, withTypes, withUsings, expectedDiagnostics, libraryPath, commandlineArgs); + protected static Task ValidateGeneratedXmlCompatibleWindowsBindingsAsync(string inputContents, string expectedOutputContents, PInvokeGeneratorConfigurationOptions additionalConfigOptions = PInvokeGeneratorConfigurationOptions.None, string[] excludedNames = null, IReadOnlyDictionary remappedNames = null, IReadOnlyDictionary withAccessSpecifiers = null, IReadOnlyDictionary> withAttributes = null, IReadOnlyDictionary withCallConvs = null, IReadOnlyDictionary withLibraryPaths = null, string[] withSetLastErrors = null, IReadOnlyDictionary withTransparentStructs = null, IReadOnlyDictionary withTypes = null, IReadOnlyDictionary> withUsings = null, IEnumerable expectedDiagnostics = null, string libraryPath = DefaultLibraryPath, string[] commandlineArgs = null) => ValidateGeneratedBindingsAsync(inputContents, expectedOutputContents, PInvokeGeneratorOutputMode.Xml, PInvokeGeneratorConfigurationOptions.GenerateCompatibleCode | additionalConfigOptions, excludedNames, remappedNames, withAccessSpecifiers, withAttributes, withCallConvs, withLibraryPaths, withSetLastErrors, withTransparentStructs, withTypes, withUsings, expectedDiagnostics, libraryPath, commandlineArgs); - protected static Task ValidateGeneratedXmlCompatibleUnixBindingsAsync(string inputContents, string expectedOutputContents, PInvokeGeneratorConfigurationOptions additionalConfigOptions = PInvokeGeneratorConfigurationOptions.None, string[] excludedNames = null, IReadOnlyDictionary remappedNames = null, IReadOnlyDictionary withAccessSpecifiers = null, IReadOnlyDictionary> withAttributes = null, IReadOnlyDictionary withCallConvs = null, IReadOnlyDictionary withLibraryPaths = null, string[] withSetLastErrors = null, IReadOnlyDictionary withTypes = null, IReadOnlyDictionary> withUsings = null, IEnumerable expectedDiagnostics = null, string libraryPath = DefaultLibraryPath, string[] commandlineArgs = null) => ValidateGeneratedBindingsAsync(inputContents, expectedOutputContents, PInvokeGeneratorOutputMode.Xml, PInvokeGeneratorConfigurationOptions.GenerateCompatibleCode | PInvokeGeneratorConfigurationOptions.GenerateUnixTypes | additionalConfigOptions, excludedNames, remappedNames, withAccessSpecifiers, withAttributes, withCallConvs, withLibraryPaths, withSetLastErrors, withTypes, withUsings, expectedDiagnostics, libraryPath, commandlineArgs); + protected static Task ValidateGeneratedXmlCompatibleUnixBindingsAsync(string inputContents, string expectedOutputContents, PInvokeGeneratorConfigurationOptions additionalConfigOptions = PInvokeGeneratorConfigurationOptions.None, string[] excludedNames = null, IReadOnlyDictionary remappedNames = null, IReadOnlyDictionary withAccessSpecifiers = null, IReadOnlyDictionary> withAttributes = null, IReadOnlyDictionary withCallConvs = null, IReadOnlyDictionary withLibraryPaths = null, string[] withSetLastErrors = null, IReadOnlyDictionary withTransparentStructs = null, IReadOnlyDictionary withTypes = null, IReadOnlyDictionary> withUsings = null, IEnumerable expectedDiagnostics = null, string libraryPath = DefaultLibraryPath, string[] commandlineArgs = null) => ValidateGeneratedBindingsAsync(inputContents, expectedOutputContents, PInvokeGeneratorOutputMode.Xml, PInvokeGeneratorConfigurationOptions.GenerateCompatibleCode | PInvokeGeneratorConfigurationOptions.GenerateUnixTypes | additionalConfigOptions, excludedNames, remappedNames, withAccessSpecifiers, withAttributes, withCallConvs, withLibraryPaths, withSetLastErrors, withTransparentStructs, withTypes, withUsings, expectedDiagnostics, libraryPath, commandlineArgs); - private static async Task ValidateGeneratedBindingsAsync(string inputContents, string expectedOutputContents, PInvokeGeneratorOutputMode outputMode, PInvokeGeneratorConfigurationOptions configOptions, string[] excludedNames, IReadOnlyDictionary remappedNames, IReadOnlyDictionary withAccessSpecifiers, IReadOnlyDictionary> withAttributes, IReadOnlyDictionary withCallConvs, IReadOnlyDictionary withLibraryPaths, string[] withSetLastErrors, IReadOnlyDictionary withTypes, IReadOnlyDictionary> withUsings, IEnumerable expectedDiagnostics, string libraryPath, string[] commandlineArgs, [CallerFilePath] string filePath = "") + private static async Task ValidateGeneratedBindingsAsync(string inputContents, string expectedOutputContents, PInvokeGeneratorOutputMode outputMode, PInvokeGeneratorConfigurationOptions configOptions, string[] excludedNames, IReadOnlyDictionary remappedNames, IReadOnlyDictionary withAccessSpecifiers, IReadOnlyDictionary> withAttributes, IReadOnlyDictionary withCallConvs, IReadOnlyDictionary withLibraryPaths, string[] withSetLastErrors, IReadOnlyDictionary withTransparentStructs, IReadOnlyDictionary withTypes, IReadOnlyDictionary> withUsings, IEnumerable expectedDiagnostics, string libraryPath, string[] commandlineArgs, [CallerFilePath] string filePath = "") { Assert.True(File.Exists(DefaultInputFileName)); @@ -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, headerFile: null, methodClassName: null, methodPrefixToStrip: null, remappedNames, traversalNames: null, withAccessSpecifiers, withAttributes, withCallConvs, withLibraryPaths, withSetLastErrors, withTypes, withUsings); + var config = new PInvokeGeneratorConfiguration(libraryPath, DefaultNamespaceName, Path.GetRandomFileName(), testOutputLocation: null, outputMode, configOptions, excludedNames, headerFile: null, methodClassName: null, methodPrefixToStrip: null, remappedNames, traversalNames: null, withAccessSpecifiers, withAttributes, withCallConvs, withLibraryPaths, withSetLastErrors, withTransparentStructs, withTypes, withUsings); using (var pinvokeGenerator = new PInvokeGenerator(config, (path) => outputStream)) {