Browse Source

Allow static class conversion for classes with implicitly defined constructor

pull/1923/head
duckdoom5 4 months ago
parent
commit
3145490573
  1. 23
      src/Generator.Tests/Passes/TestPasses.cs
  2. 2
      src/Generator/Driver.cs
  3. 43
      src/Generator/Passes/CheckStaticClassPass.cs
  4. 54
      tests/dotnet/Native/Passes.h

23
src/Generator.Tests/Passes/TestPasses.cs

@ -66,6 +66,29 @@ namespace CppSharp.Generator.Tests.Passes @@ -66,6 +66,29 @@ namespace CppSharp.Generator.Tests.Passes
Assert.IsTrue(ucharClassEnum.BuiltinType.Type == PrimitiveType.UChar);
}
[Test]
public void TestCheckStaticClassPass()
{
var staticClass = AstContext.Class("TestCheckStaticClass");
var staticStruct = AstContext.Class("TestCheckStaticStruct");
var staticClassDeletedCtor = AstContext.Class("TestCheckStaticClassDeleted");
var nonStaticClass = AstContext.Class("TestCheckNonStaticClass");
Assert.IsFalse(staticClass.IsStatic);
Assert.IsFalse(staticStruct.IsStatic);
Assert.IsFalse(staticClassDeletedCtor.IsStatic);
Assert.IsFalse(nonStaticClass.IsStatic);
passBuilder.AddPass(new CheckStaticClassPass());
passBuilder.RunPasses(pass => pass.VisitASTContext(AstContext));
Assert.IsTrue(staticClass.IsStatic, "`TestCheckStaticClass` should be static");
Assert.IsTrue(staticStruct.IsStatic, "`TestCheckStaticStruct` should be static");
Assert.IsTrue(staticClassDeletedCtor.IsStatic, "`TestCheckStaticClassDeleted` should be static");
Assert.IsFalse(nonStaticClass.IsStatic, "`TestCheckNonStaticClass` should NOT be static, since it has a private data field with default ctor");
}
[Test]
public void TestFunctionToInstancePass()
{

2
src/Generator/Driver.cs

@ -230,7 +230,7 @@ namespace CppSharp @@ -230,7 +230,7 @@ namespace CppSharp
passes.AddPass(new FindSymbolsPass());
passes.AddPass(new CheckMacroPass());
passes.AddPass(new CheckStaticClass());
passes.AddPass(new CheckStaticClassPass());
if (Options.IsCLIGenerator || Options.IsCSharpGenerator || Options.IsCppGenerator)
{

43
src/Generator/Passes/CheckStaticClass.cs → src/Generator/Passes/CheckStaticClassPass.cs

@ -7,9 +7,9 @@ namespace CppSharp.Passes @@ -7,9 +7,9 @@ namespace CppSharp.Passes
/// <summary>
/// Checks for classes that should be bound as static classes.
/// </summary>
public class CheckStaticClass : TranslationUnitPass
public class CheckStaticClassPass : TranslationUnitPass
{
public CheckStaticClass()
public CheckStaticClassPass()
=> VisitOptions.ResetFlags(VisitFlags.ClassMethods);
public override bool VisitDeclaration(Declaration decl)
@ -69,13 +69,34 @@ namespace CppSharp.Passes @@ -69,13 +69,34 @@ namespace CppSharp.Passes
public override bool VisitClassDecl(Class @class)
{
// If the class has any non-private constructors then it cannot
// be bound as a static class and we bail out early.
// If the class is to be used as an opaque type, then it cannot be
// bound as static.
if (@class.IsOpaque)
return false;
if (@class.IsDependent)
return false;
if (@class.Constructors.Any(m =>
!(m.IsCopyConstructor || m.IsMoveConstructor)
&& m.Access != AccessSpecifier.Private))
{
// Implicit constructors are not user-defined, so assume this was unintentional.
if (m.IsImplicit)
return false;
// Ignore deleted constructors.
if (m.IsDeleted)
return false;
// If the class has a copy or move constructor, it cannot be static.
if (m.IsCopyConstructor || m.IsMoveConstructor)
return true;
// If the class has any (user defined) non-private constructors then it cannot be static
return m.Access != AccessSpecifier.Private;
}))
{
return false;
}
// Check for any non-static fields or methods, in which case we
// assume the class is not meant to be static.
// Note: Static fields are represented as variables in the AST.
@ -86,20 +107,12 @@ namespace CppSharp.Passes @@ -86,20 +107,12 @@ namespace CppSharp.Passes
// Check for any static function that return a pointer to the class.
// If one exists, we assume it's a factory function and the class is
// not meant to be static. It's a simple heuristic but it should be
// not meant to be static. It's a simple heuristic, but it should be
// good enough for the time being.
if (@class.Functions.Any(m => !m.IsOperator && ReturnsClassInstance(m)) ||
@class.Methods.Any(m => !m.IsOperator && ReturnsClassInstance(m)))
return false;
// If the class is to be used as an opaque type, then it cannot be
// bound as static.
if (@class.IsOpaque)
return false;
if (@class.IsDependent)
return false;
// TODO: We should take C++ friends into account here, they might allow
// a class to be instantiated even it if's not possible to instantiate
// it using just its regular members.

54
tests/dotnet/Native/Passes.h

@ -130,6 +130,60 @@ struct TestCheckAmbiguousFunctionsPass @@ -130,6 +130,60 @@ struct TestCheckAmbiguousFunctionsPass
int Method(int x) const;
};
class TestCheckStaticClass
{
public:
static int Method();
static int Method(int x);
constexpr static float ConstExprStatic = 3.0f;
inline static float InlineStatic = 1.0f;
private:
inline static float PrivateInlineStatic = 1.0f;
};
struct TestCheckStaticStruct
{
static int Method();
static int Method(int x);
constexpr static float ConstExprStatic = 3.0f;
inline static float InlineStatic = 1.0f;
};
class TestCheckStaticClassDeleted
{
public:
TestCheckStaticClassDeleted() = delete;
static int Method();
static int Method(int x);
constexpr static float ConstExprStatic = 3.0f;
inline static float InlineStatic = 1.0f;
private:
inline static float PrivateInlineStatic = 1.0f;
};
class TestCheckNonStaticClass
{
public:
TestCheckNonStaticClass() = default;
static int Method();
static int Method(int x);
constexpr static float ConstExprStatic = 3.0f;
inline static float InlineStatic = 1.0f;
private:
inline static float PrivateInlineStatic = 1.0f;
float NonStatic = 1.0f;
};
#define CS_INTERNAL
struct TestMethodAsInternal
{

Loading…
Cancel
Save