diff --git a/src/Generator/Generators/CSharp/CSharpExpressionPrinter.cs b/src/Generator/Generators/CSharp/CSharpExpressionPrinter.cs index c625164a..4302b3c1 100644 --- a/src/Generator/Generators/CSharp/CSharpExpressionPrinter.cs +++ b/src/Generator/Generators/CSharp/CSharpExpressionPrinter.cs @@ -61,13 +61,8 @@ namespace CppSharp.Generators.CSharp case StatementClass.BinaryOperator: var binaryOperator = (BinaryOperatorObsolete)expr; - var lhsResult = binaryOperator.LHS.String; - if (binaryOperator.LHS.Declaration is Enumeration.Item) - lhsResult = binaryOperator.LHS.Declaration.Visit(typePrinter).Type; - - var rhsResult = binaryOperator.RHS.String; - if (binaryOperator.RHS.Declaration is Enumeration.Item) - rhsResult = binaryOperator.RHS.Declaration.Visit(typePrinter).Type; + var lhsResult = VisitExpression(binaryOperator.LHS); + var rhsResult = VisitExpression(binaryOperator.RHS); return $"{lhsResult} {binaryOperator.OpcodeStr} {rhsResult}"; case StatementClass.ConstructorReference: diff --git a/src/Generator/Generators/CSharp/CSharpSources.cs b/src/Generator/Generators/CSharp/CSharpSources.cs index 8cedbf44..621a09b1 100644 --- a/src/Generator/Generators/CSharp/CSharpSources.cs +++ b/src/Generator/Generators/CSharp/CSharpSources.cs @@ -256,9 +256,9 @@ namespace CppSharp.Generators.CSharp .Any(); using (PushWriteBlock(BlockKind.Functions, $"public unsafe partial {(isStruct ? "struct" : "class")} {parentName}", NewLineKind.BeforeNextBlock)) - { + { using (PushWriteBlock(BlockKind.InternalsClass, GetClassInternalHead(new Class { Name = parentName }), NewLineKind.BeforeNextBlock)) - { + { // Generate all the internal function declarations. foreach (var function in context.Functions) { @@ -301,7 +301,7 @@ namespace CppSharp.Generators.CSharp template.Name); using (PushWriteBlock(BlockKind.Namespace, namespaceName, NewLineKind.BeforeNextBlock)) - { + { var generated = GetGeneratedClasses(template, specializations); foreach (var nestedTemplate in template.Classes.Where( @@ -1615,19 +1615,27 @@ internal static bool {Helpers.TryGetNativeToManagedMappingIdentifier}(IntPtr nat var variableType = variable.Type.Visit(TypePrinter); TypePrinter.PopMarshalKind(); - var signature = $"public static {variableType} {variable.Name}"; + bool hasInitializer = variable.Initializer != null && !string.IsNullOrWhiteSpace(variable.Initializer.String); - if (variable.Initializer != null && !string.IsNullOrWhiteSpace(variable.Initializer.String)) - GeneratePropertyGetterForVariableWithInitializer(variable, signature); + if (hasInitializer && variable.QualifiedType.Qualifiers.IsConst && + (variable.Type.Desugar() is BuiltinType || variableType.ToString() == "string")) + Write($"public const {variableType} {variable.Name} = {variable.Initializer.String};"); else { - using (WriteBlock(signature)) + var signature = $"public static {variableType} {variable.Name}"; + + if (hasInitializer) + GeneratePropertyGetterForVariableWithInitializer(variable, signature); + else { - GeneratePropertyGetter(variable, @class); + using (WriteBlock(signature)) + { + GeneratePropertyGetter(variable, @class); - if (!variable.QualifiedType.Qualifiers.IsConst && - !(variable.Type.Desugar() is ArrayType)) - GeneratePropertySetter(variable, @class); + if (!variable.QualifiedType.Qualifiers.IsConst && + !(variable.Type.Desugar() is ArrayType)) + GeneratePropertySetter(variable, @class); + } } } @@ -1780,7 +1788,7 @@ internal static bool {Helpers.TryGetNativeToManagedMappingIdentifier}(IntPtr nat return __vtables; }} - set {{ + set {{ __vtables = value; }}", trimIndentation: true); } @@ -2296,13 +2304,13 @@ internal static bool {Helpers.TryGetNativeToManagedMappingIdentifier}(IntPtr nat // Normally, calling the native dtor should be controlled by whether or not we // we own the underlying instance. (i.e. Helpers.OwnsNativeInstanceIdentifier). // However, there are 2 situations when the caller needs to have direct control - // + // // 1. When we have a virtual dtor on the native side we detour the vtable entry // even when we don't own the underlying native instance. I think we do this // so that the managed side can null out the __Instance pointer and remove the // instance from the NativeToManagedMap. Of course, this is somewhat half-hearted // since we can't/don't do this when there's no virtual dtor available to detour. - // Anyway, we must be able to call the native dtor in this case even if we don't + // Anyway, we must be able to call the native dtor in this case even if we don't /// own the underlying native instance. // // 2. When we we pass a disposable object to a function "by value" then the callee @@ -2313,7 +2321,7 @@ internal static bool {Helpers.TryGetNativeToManagedMappingIdentifier}(IntPtr nat // .... // compiler generates call to f.dtor() at the end of function // } - // + // // IDisposable.Dispose() and Object.Finalize() set callNativeDtor = Helpers.OwnsNativeInstanceIdentifier WriteLine("if (callNativeDtor)"); if (@class.IsDependent || dtor.IsVirtual) @@ -2334,7 +2342,7 @@ internal static bool {Helpers.TryGetNativeToManagedMappingIdentifier}(IntPtr nat } // If we have any fields holding references to unmanaged memory allocated here, free the - // referenced memory. Don't rely on testing if the field's IntPtr is IntPtr.Zero since + // referenced memory. Don't rely on testing if the field's IntPtr is IntPtr.Zero since // unmanaged memory isn't always initialized and/or a reference may be owned by the // native side. // @@ -2540,7 +2548,7 @@ internal static{(@new ? " new" : string.Empty)} {printedClass} __GetInstance({Ty using (WriteBlock($"private static void* __CopyValue({@internal} native)")) { var copyCtorMethod = @class.Methods.FirstOrDefault(method => method.IsCopyConstructor); - + if (@class.HasNonTrivialCopyConstructor && copyCtorMethod != null && copyCtorMethod.IsGenerated) { // Allocate memory for a new native object and call the ctor. @@ -2848,7 +2856,7 @@ internal static{(@new ? " new" : string.Empty)} {printedClass} __GetInstance({Ty private void GenerateGetHashCode(Class @class) { using (WriteBlock("public override int GetHashCode()")) - { + { if (!@class.IsRefType) WriteLine($"return {Helpers.InstanceIdentifier}.GetHashCode();"); else @@ -2999,7 +3007,7 @@ internal static{(@new ? " new" : string.Empty)} {printedClass} __GetInstance({Ty // Copy any string references owned by the source to the new instance so we // don't have to ref count them. // If there is no property or no setter then this instance can never own the native - // memory. Worry about the case where there's only a setter (write-only) when we + // memory. Worry about the case where there's only a setter (write-only) when we // understand the use case and how it can occur. foreach (var prop in @class.GetConstCharFieldProperties()) { diff --git a/tests/dotnet/Common/Common.cpp b/tests/dotnet/Common/Common.cpp index d985b92c..2bdeb3cd 100644 --- a/tests/dotnet/Common/Common.cpp +++ b/tests/dotnet/Common/Common.cpp @@ -1278,3 +1278,7 @@ extern "C" void DLL_API FunctionWithFlagsAsDefaultParameter(int defaultParam) { } + +void DLL_API FunctionWithConstFlagsAsDefaultParameter(int defaultParam) +{ +} diff --git a/tests/dotnet/Common/Common.h b/tests/dotnet/Common/Common.h index 3b4af82c..9b7e2360 100644 --- a/tests/dotnet/Common/Common.h +++ b/tests/dotnet/Common/Common.h @@ -1569,3 +1569,9 @@ extern "C" } // extern "C" void DLL_API FunctionWithFlagsAsDefaultParameter(int defaultParam = A | B); + +const int ConstFlag1 = 1; +const int ConstFlag2 = 2; +const int ConstFlag3 = 4; + +void DLL_API FunctionWithConstFlagsAsDefaultParameter(int defaultParam = ConstFlag1 | ConstFlag2 | ConstFlag3);