Skip to content

Commit

Permalink
CSharp: More default parameter fixes
Browse files Browse the repository at this point in the history
- Expression generation for `ConstructorReference` now also recursively
calls `VisitExpression` for the argument if only one argument is
detected. This allows correct overload generation for functions taking
a variable as the default parameter value.
- Default parameters of pointer-to-enumeration types are now correctly
generated similar to primitive types.
  • Loading branch information
trungnt2910 committed Jul 14, 2023
1 parent 1ce9cb7 commit 9612652
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 8 deletions.
19 changes: 19 additions & 0 deletions src/AST/TypeExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,25 @@ public static bool IsPointerToPrimitiveType(this Type t, PrimitiveType primitive
return ptr.Pointee.IsPrimitiveType(primitive);
}

public static bool IsPointerToEnum(this Type t)
{
var ptr = t as PointerType;
if (ptr == null)
return false;
return ptr.Pointee.IsEnumType();
}

public static bool IsPointerToEnum(this Type t, out Enumeration @enum)
{
var ptr = t as PointerType;
if (ptr == null)
{
@enum = null;
return false;
}
return ptr.Pointee.TryGetEnum(out @enum);
}

public static bool IsPointerTo<T>(this Type t, out T type) where T : Type
{
var pointee = t.GetPointee();
Expand Down
4 changes: 2 additions & 2 deletions src/Generator/Generators/CSharp/CSharpExpressionPrinter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ public string VisitExpression(ExpressionObsolete expr)
case StatementClass.ConstructorReference:
var constructorExpr = (CXXConstructExprObsolete)expr;
if (constructorExpr.Arguments.Count == 1 &&
constructorExpr.Arguments[0].Declaration is Enumeration.Item)
return constructorExpr.Arguments[0].Declaration.Visit(typePrinter).Type;
constructorExpr.Arguments[0].Class != StatementClass.Any)
return VisitExpression(constructorExpr.Arguments[0]);
goto default;
default:
return expr.String;
Expand Down
10 changes: 6 additions & 4 deletions src/Generator/Generators/CSharp/CSharpSources.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2783,7 +2783,7 @@ private bool GenerateMethodBody(Class @class, Method method,

private string OverloadParamNameWithDefValue(Parameter p, ref int index)
{
return p.Type.IsPointerToPrimitiveType() && p.Usage == ParameterUsage.InOut && p.HasDefaultValue
return (p.Type.IsPointerToPrimitiveType() || p.Type.IsPointerToEnum()) && p.Usage == ParameterUsage.InOut && p.HasDefaultValue
? "ref param" + index++
: ExpressionPrinter.VisitParameter(p);
}
Expand All @@ -2802,13 +2802,15 @@ private void GenerateOverloadCall(Function function)
for (int i = 0, j = 0; i < function.Parameters.Count; i++)
{
var parameter = function.Parameters[i];
PrimitiveType primitiveType;
PrimitiveType primitiveType = PrimitiveType.Null;
Enumeration enumeration = null;
if (parameter.Kind == ParameterKind.Regular && parameter.Ignore &&
parameter.Type.IsPointerToPrimitiveType(out primitiveType) &&
(parameter.Type.IsPointerToPrimitiveType(out primitiveType) ||
parameter.Type.IsPointerToEnum(out enumeration)) &&
parameter.Usage == ParameterUsage.InOut && parameter.HasDefaultValue)
{
var pointeeType = ((PointerType)parameter.Type).Pointee.ToString();
WriteLine($@"{pointeeType} param{j++} = {(primitiveType == PrimitiveType.Bool ? "false" : "0")};");
WriteLine($@"{pointeeType} param{j++} = {(primitiveType == PrimitiveType.Bool ? "false" : $"({pointeeType})0")};");
}
}

Expand Down
15 changes: 13 additions & 2 deletions tests/dotnet/Common/Common.Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -929,7 +929,7 @@ public void TestStdString()
// when C++ memory is deleted, it's only marked as free but not immediadely freed
// this can hide memory bugs while marshalling
// so let's use a long string to increase the chance of a crash right away
const string t = @"This is a very long string. This is a very long string. This is a very long string. This is a very long string. This is a very long string. This is a very long string. This is a very long string. This is a very long string.
const string t = @"This is a very long string. This is a very long string. This is a very long string. This is a very long string. This is a very long string. This is a very long string. This is a very long string. This is a very long string.
This is a very long string. This is a very long string. This is a very long string. This is a very long string. This is a very long string. This is a very long string. This is a very long string. This is a very long string. This is a very long string.
This is a very long string. This is a very long string. This is a very long string. This is a very long string. This is a very long string. This is a very long string. This is a very long string. This is a very long string. This is a very long string.
This is a very long string. This is a very long string. This is a very long string. This is a very long string. This is a very long string. This is a very long string. This is a very long string. This is a very long string. This is a very long string.
Expand All @@ -951,7 +951,7 @@ public void TestStdStringPassedByValue()
// when C++ memory is deleted, it's only marked as free but not immediadely freed
// this can hide memory bugs while marshalling
// so let's use a long string to increase the chance of a crash right away
const string t = @"This is a very long string. This is a very long string. This is a very long string. This is a very long string. This is a very long string. This is a very long string. This is a very long string. This is a very long string.
const string t = @"This is a very long string. This is a very long string. This is a very long string. This is a very long string. This is a very long string. This is a very long string. This is a very long string. This is a very long string.
This is a very long string. This is a very long string. This is a very long string. This is a very long string. This is a very long string. This is a very long string. This is a very long string. This is a very long string. This is a very long string.
This is a very long string. This is a very long string. This is a very long string. This is a very long string. This is a very long string. This is a very long string. This is a very long string. This is a very long string. This is a very long string.
This is a very long string. This is a very long string. This is a very long string. This is a very long string. This is a very long string. This is a very long string. This is a very long string. This is a very long string. This is a very long string.
Expand Down Expand Up @@ -1147,6 +1147,17 @@ public void TestReturnByValueWithReturnParam()
}
}

[Test]
public void TestDefaultParams()
{
Common.FunctionWithFlagsAsDefaultParameter();
Common.FunctionWithConstFlagsAsDefaultParameter();
Common.FunctionWithPointerToEnumAsDefaultParameter();

Assert.That(Common.FunctionWithNonPrimitiveAsDefaultParameter(),
Is.EqualTo(Common.FunctionWithNonPrimitiveAsDefaultParameter(Common.DefaultBar)));
}

[Test, Ignore("This was exposed by another bug and doesn't work yet.")]
public void TestFreeFunctionReturnByValue()
{
Expand Down
11 changes: 11 additions & 0 deletions tests/dotnet/Common/Common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1282,3 +1282,14 @@ void DLL_API FunctionWithFlagsAsDefaultParameter(int defaultParam)
void DLL_API FunctionWithConstFlagsAsDefaultParameter(int defaultParam)
{
}

void DLL_API FunctionWithPointerToEnumAsDefaultParameter(Enum* defaultParam1, int* defaultParam2)
{
}

DLL_API struct Bar DefaultBar;

struct Bar* DLL_API FunctionWithNonPrimitiveAsDefaultParameter(struct Bar& defaultParam)
{
return defaultParam.returnPointerToValueType();
}
6 changes: 6 additions & 0 deletions tests/dotnet/Common/Common.h
Original file line number Diff line number Diff line change
Expand Up @@ -1575,3 +1575,9 @@ const int ConstFlag2 = 2;
const int ConstFlag3 = 4;

void DLL_API FunctionWithConstFlagsAsDefaultParameter(int defaultParam = ConstFlag1 | ConstFlag2 | ConstFlag3);

void DLL_API FunctionWithPointerToEnumAsDefaultParameter(Enum* defaultParam1 = NULL, int* defaultParam2 = NULL);

extern DLL_API struct Bar DefaultBar;

struct Bar* DLL_API FunctionWithNonPrimitiveAsDefaultParameter(struct Bar& defaultParam = DefaultBar);

0 comments on commit 9612652

Please sign in to comment.