Skip to content

CSharp: More default parameter fixes #1747

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am blocking StatementClass.Any here since such statements will be generated without any kind of modification and may contain code that is invalid in C#.

Otherwise, defaultMappedToEnumAssignedWithCtor fails because nullptr is not valid C#.

It would be better if CppSharp is aware that Arguments[0] has been defaulted away and instead report 0 arguments to avoid this mess altogether.

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
4 changes: 4 additions & 0 deletions tests/dotnet/CSharp/CSharp.Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,10 @@ public void TestDefaultArguments()
methodsWithDefaultValues.DefaultWithSpecialization();
methodsWithDefaultValues.DefaultOverloadedImplicitCtor();
methodsWithDefaultValues.DefaultWithParamNamedSameAsMethod(5);
Assert.That(methodsWithDefaultValues.DefaultIntAssignedAnEnumWithBinaryOperatorAndFlags(), Is.EqualTo((int)(Bar.Items.Item1 | Bar.Items.Item2)));
Assert.That(methodsWithDefaultValues.DefaultWithConstantFlags(), Is.EqualTo(CSharp.CSharp.ConstFlag1 | CSharp.CSharp.ConstFlag2 | CSharp.CSharp.ConstFlag3));
Assert.IsTrue(methodsWithDefaultValues.DefaultWithPointerToEnum());
Assert.AreEqual(CSharp.CSharp.DefaultSmallPODInstance.__Instance, methodsWithDefaultValues.DefaultWithNonPrimitiveType().__Instance);
}
}

Expand Down
40 changes: 31 additions & 9 deletions tests/dotnet/CSharp/CSharp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,8 @@ MethodsWithDefaultValues::QMargins::QMargins(int left, int top, int right, int b
{
}

struct SmallPOD DefaultSmallPODInstance;

const char* MethodsWithDefaultValues::stringConstant = "test";
int MethodsWithDefaultValues::intConstant = 5;

Expand Down Expand Up @@ -808,6 +810,26 @@ int MethodsWithDefaultValues::DefaultWithParamNamedSameAsMethod(int DefaultWithP
return 1;
}

int MethodsWithDefaultValues::defaultIntAssignedAnEnumWithBinaryOperatorAndFlags(int f)
{
return f;
}

int MethodsWithDefaultValues::defaultWithConstantFlags(int f)
{
return f;
}

bool MethodsWithDefaultValues::defaultWithPointerToEnum(UntypedFlags* f1, int* f2)
{
return (f1 == NULL || *f1 == (UntypedFlags)0) && (f2 == NULL || *f2 == 0);
}

SmallPOD* MethodsWithDefaultValues::defaultWithNonPrimitiveType(SmallPOD& pod)
{
return &pod;
}

int MethodsWithDefaultValues::getA()
{
return m_foo.A;
Expand Down Expand Up @@ -1299,36 +1321,36 @@ TestString::TestString() : unicodeConst(L"ქართული ენა"), uni
{
}

TestChar32String::TestChar32String() :
TestChar32String::TestChar32String() :
thirtyTwoBitConst(U"ქართული ენა")
{
static std::u32string nonConst = U"Test String";
thirtyTwoBitNonConst = &nonConst[0];
}

TestChar32String::~TestChar32String() {}
void TestChar32String::UpdateString(const char32_t* s)
{
void TestChar32String::UpdateString(const char32_t* s)
{
static std::u32string nativeOwnedMemory = s;
thirtyTwoBitConst = nativeOwnedMemory.data();
}

const char32_t* TestChar32String::RetrieveString() { return thirtyTwoBitConst; }
void TestChar32String::functionPointerUTF32(void(*ptr)(const char32_t*)) {}

TestChar16String::TestChar16String() :
sixteenBitConst(u"ქართული ენა")
TestChar16String::TestChar16String() :
sixteenBitConst(u"ქართული ენა")
{
static std::u16string nonConst = u"Test String";
sixteenBitNonConst = &nonConst[0];
}

TestChar16String::~TestChar16String() {}

void TestChar16String::UpdateString(const char16_t* s)
{
void TestChar16String::UpdateString(const char16_t* s)
{
static std::u16string nativeOwnedMemory = s;
sixteenBitConst = nativeOwnedMemory.data();
sixteenBitConst = nativeOwnedMemory.data();
}
const char16_t* TestChar16String::RetrieveString() { return sixteenBitConst; }

Expand Down Expand Up @@ -1667,7 +1689,7 @@ const unsigned ClassCustomTypeAlignmentOffsets[5]
offsetof(ClassCustomTypeAlignment, align8),
};

const unsigned ClassCustomObjectAlignmentOffsets[2] {
const unsigned ClassCustomObjectAlignmentOffsets[2] {
offsetof(ClassCustomObjectAlignment, boolean),
offsetof(ClassCustomObjectAlignment, charAligned8),
};
Expand Down
26 changes: 18 additions & 8 deletions tests/dotnet/CSharp/CSharp.h
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,12 @@ enum class Empty : unsigned long long int
class _ClassWithLeadingUnderscore {
};

const int ConstFlag1 = 1;
const int ConstFlag2 = 2;
const int ConstFlag3 = 4;

extern DLL_API struct SmallPOD DefaultSmallPODInstance;

class DLL_API MethodsWithDefaultValues : public Quux
{
public:
Expand Down Expand Up @@ -480,6 +486,10 @@ class DLL_API MethodsWithDefaultValues : public Quux
void defaultWithSpecialization(IndependentFields<int> specialization = IndependentFields<int>());
void defaultOverloadedImplicitCtor(P p);
void defaultOverloadedImplicitCtor(Qux q = Qux());
int defaultIntAssignedAnEnumWithBinaryOperatorAndFlags(int f = Bar::Item1 | Bar::Item2);
int defaultWithConstantFlags(int f = ConstFlag1 | ConstFlag2 | ConstFlag3);
bool defaultWithPointerToEnum(UntypedFlags* f1 = NULL, int* f2 = NULL);
SmallPOD* defaultWithNonPrimitiveType(SmallPOD& pod = DefaultSmallPODInstance);
int DefaultWithParamNamedSameAsMethod(int DefaultWithParamNamedSameAsMethod, const Foo& defaultArg = Foo());
int getA();
private:
Expand Down Expand Up @@ -1082,9 +1092,9 @@ class DLL_API VariablesWithInitializer {
static constexpr const char* StringArray1[1] { "Str" "F,\"or" };
static constexpr const char* StringArray3[3] { "Str" "F,\"or", "C#", String };
static constexpr const char* StringArray30[30] {
"Str", "Str", "Str", "Str", "Str", "Str", "Str", "Str", "Str", "Str",
"Str", "Str", "Str", "Str", "Str", "Str", "Str", "Str", "Str", "Str",
"Str", "Str", "Str", "Str", "Str", "Str", "Str", "Str", "Str", "Str",
"Str", "Str", "Str", "Str", "Str", "Str", "Str", "Str", "Str", "Str",
"Str", "Str", "Str", "Str", "Str", "Str", "Str", "Str", "Str", "Str",
"Str", "Str", "Str", "Str", "Str", "Str", "Str", "Str", "Str", "Str",
};
static constexpr const char* StringArray3EmptyInitList[3] { };
static constexpr const wchar_t* WideStringArray[2] { L"Str", L"C#" };
Expand Down Expand Up @@ -1278,7 +1288,7 @@ struct StructTestArrayTypeFromTypedef
#define MY_MACRO_TEST2_4 (1 << 3)
#define MY_MACRO_TEST2_ALL (1 << 4) - 1

#define SIGNED_MACRO_VALUES_TO_ENUM_TEST_1 1 << 5
#define SIGNED_MACRO_VALUES_TO_ENUM_TEST_1 1 << 5
#define SIGNED_MACRO_VALUES_TO_ENUM_TEST_2 1 << 22
#define SIGNED_MACRO_VALUES_TO_ENUM_TEST_3 1L << 32
#define SIGNED_MACRO_VALUES_TO_ENUM_TEST_4 -1
Expand Down Expand Up @@ -1465,9 +1475,9 @@ struct DLL_API ConversionFunctions
short field = 100;
};

struct DLL_API ClassCustomTypeAlignment
struct DLL_API ClassCustomTypeAlignment
{
struct alignas(1) Align1 { };
struct alignas(1) Align1 { };
struct alignas(8) Align8 { };
struct alignas(16) Align16 {
double a;
Expand All @@ -1476,7 +1486,7 @@ struct DLL_API ClassCustomTypeAlignment

bool boolean;
Align16 align16;
Align1 align1;
Align1 align1;
double dbl;
Align8 align8;
};
Expand Down Expand Up @@ -1524,7 +1534,7 @@ DLL_API extern const unsigned StructWithEmbeddedArrayOfStructObjectAlignmentOffs

DLL_API const char* TestCSharpString(const char* in, CS_OUT const char** out);
DLL_API const wchar_t* TestCSharpStringWide(const wchar_t* in, CS_OUT const wchar_t** out);
DLL_API const char16_t* TestCSharpString16(const char16_t* in, CS_OUT const char16_t** out);
DLL_API const char16_t* TestCSharpString16(const char16_t* in, CS_OUT const char16_t** out);
DLL_API const char32_t* TestCSharpString32(const char32_t* in, CS_OUT const char32_t** out);

struct DLL_API FTIStruct { int a; };
Expand Down
8 changes: 0 additions & 8 deletions tests/dotnet/Common/Common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1274,11 +1274,3 @@ extern "C"
return s;
}
} // extern "C"

void DLL_API FunctionWithFlagsAsDefaultParameter(int defaultParam)
{
}

void DLL_API FunctionWithConstFlagsAsDefaultParameter(int defaultParam)
{
}
8 changes: 0 additions & 8 deletions tests/dotnet/Common/Common.h
Original file line number Diff line number Diff line change
Expand Up @@ -1567,11 +1567,3 @@ extern "C"
DLL_API void takeConflictName(struct system* self);
DLL_API struct system freeFunctionReturnByValue();
} // 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);