Browse Source

CSharpExpressionPrinter: Recurse into operands (#1745)

* CSharpExpressionPrinter: Recurse into operands

Recursively call `VisitExpression` on the LHS and RHS of a binary
operator expression. This fixes the generation for complex default
parameters involving things other than two enumeration members.

* CSharpSources: Use `const` when possible

Generate `const` instead of `static` members when possible.
This allows generated members to be used when compile-time constants are
required, such as default parameters.
pull/1747/head
Trung Nguyen 2 years ago committed by GitHub
parent
commit
1ce9cb7e7f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 9
      src/Generator/Generators/CSharp/CSharpExpressionPrinter.cs
  2. 46
      src/Generator/Generators/CSharp/CSharpSources.cs
  3. 4
      tests/dotnet/Common/Common.cpp
  4. 6
      tests/dotnet/Common/Common.h

9
src/Generator/Generators/CSharp/CSharpExpressionPrinter.cs

@ -61,13 +61,8 @@ namespace CppSharp.Generators.CSharp @@ -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:

46
src/Generator/Generators/CSharp/CSharpSources.cs

@ -256,9 +256,9 @@ namespace CppSharp.Generators.CSharp @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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())
{

4
tests/dotnet/Common/Common.cpp

@ -1278,3 +1278,7 @@ extern "C" @@ -1278,3 +1278,7 @@ extern "C"
void DLL_API FunctionWithFlagsAsDefaultParameter(int defaultParam)
{
}
void DLL_API FunctionWithConstFlagsAsDefaultParameter(int defaultParam)
{
}

6
tests/dotnet/Common/Common.h

@ -1569,3 +1569,9 @@ extern "C" @@ -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);

Loading…
Cancel
Save