Browse Source

Incomplete classes and structs are now generated for C#. (#797)

This feature is NOT coming for C++/CLI !
pull/799/head
realvictorprm 8 years ago committed by Dimitar Dobrev
parent
commit
938ccf686b
  1. 15
      src/AST/Class.cs
  2. 80
      src/Generator/Generators/CSharp/CSharpSources.cs
  3. 13
      src/Generator/Passes/CheckIgnoredDecls.cs
  4. 3
      src/Generator/Passes/ResolveIncompleteDeclsPass.cs
  5. 2
      src/Parser/ASTConverter.cs
  6. 8
      tests/CSharp/CSharp.Tests.cs
  7. 12
      tests/CSharp/CSharp.cpp
  8. 7
      tests/CSharp/CSharp.h

15
src/AST/Class.cs

@ -96,8 +96,20 @@ namespace CppSharp.AST @@ -96,8 +96,20 @@ namespace CppSharp.AST
// True if the class is final / sealed.
public bool IsFinal { get; set; }
private bool? isOpaque = null;
// True if the type is to be treated as opaque.
public bool IsOpaque;
public bool IsOpaque
{
get
{
return isOpaque == null ? IsIncomplete && CompleteDeclaration == null : isOpaque.Value;
}
set
{
isOpaque = value;
}
}
// True if the class is dynamic.
public bool IsDynamic;
@ -127,7 +139,6 @@ namespace CppSharp.AST @@ -127,7 +139,6 @@ namespace CppSharp.AST
IsAbstract = false;
IsUnion = false;
IsFinal = false;
IsOpaque = false;
IsPOD = false;
Type = ClassType.RefType;
Layout = new ClassLayout();

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

@ -272,7 +272,7 @@ namespace CppSharp.Generators.CSharp @@ -272,7 +272,7 @@ namespace CppSharp.Generators.CSharp
public override bool VisitClassDecl(Class @class)
{
if (@class.IsIncomplete)
if (@class.IsIncomplete && !@class.IsOpaque)
return false;
if (@class.IsInterface)
@ -308,63 +308,59 @@ namespace CppSharp.Generators.CSharp @@ -308,63 +308,59 @@ namespace CppSharp.Generators.CSharp
}
PushBlock(BlockKind.Class);
GenerateDeclarationCommon(@class);
GenerateDeclarationCommon(@class);
GenerateClassSpecifier(@class);
NewLine();
WriteStartBraceIndent();
if (!@class.IsAbstractImpl)
GenerateClassInternals(@class);
if (!@class.IsOpaque)
{
if (!@class.IsAbstractImpl)
GenerateClassInternals(@class);
VisitDeclContext(@class);
VisitDeclContext(@class);
if (@class.IsDependent || !@class.IsGenerated)
goto exit;
if (@class.IsDependent || !@class.IsGenerated)
goto exit;
if (ShouldGenerateClassNativeField(@class))
if (ShouldGenerateClassNativeField(@class))
{
PushBlock(BlockKind.Field);
if (@class.IsValueType)
{
PushBlock(BlockKind.Field);
if (@class.IsValueType)
{
WriteLine("private {0}.{1} {2};", @class.Name, Helpers.InternalStruct,
Helpers.InstanceField);
WriteLine("internal {0}.{1} {2} {{ get {{ return {3}; }} }}", @class.Name,
Helpers.InternalStruct, Helpers.InstanceIdentifier, Helpers.InstanceField);
}
else
{
WriteLine("public {0} {1} {{ get; protected set; }}",
CSharpTypePrinter.IntPtrType, Helpers.InstanceIdentifier);
WriteLine("private {0}.{1} {2};", @class.Name, Helpers.InternalStruct,
Helpers.InstanceField);
WriteLine("internal {0}.{1} {2} {{ get {{ return {3}; }} }}", @class.Name,
Helpers.InternalStruct, Helpers.InstanceIdentifier, Helpers.InstanceField);
}
else
{
WriteLine("public {0} {1} {{ get; protected set; }}",
CSharpTypePrinter.IntPtrType, Helpers.InstanceIdentifier);
PopBlock(NewLineKind.BeforeNextBlock);
PopBlock(NewLineKind.BeforeNextBlock);
PushBlock(BlockKind.Field);
PushBlock(BlockKind.Field);
WriteLine("protected int {0};", Helpers.PointerAdjustmentIdentifier);
WriteLine("protected int {0};", Helpers.PointerAdjustmentIdentifier);
// use interfaces if any - derived types with a secondary base this class must be compatible with the map
var @interface = @class.Namespace.Classes.Find(c => c.OriginalClass == @class);
var dict = string.Format("global::System.Collections.Concurrent.ConcurrentDictionary<IntPtr, {0}>",
(@interface ?? @class).Visit(TypePrinter));
WriteLine("internal static readonly {0} NativeToManagedMap = new {0}();", dict);
WriteLine("protected void*[] __OriginalVTables;");
}
PopBlock(NewLineKind.BeforeNextBlock);
// use interfaces if any - derived types with a secondary base this class must be compatible with the map
var @interface = @class.Namespace.Classes.Find(c => c.OriginalClass == @class);
var dict = string.Format("global::System.Collections.Concurrent.ConcurrentDictionary<IntPtr, {0}>",
(@interface ?? @class).Visit(TypePrinter));
WriteLine("internal static readonly {0} NativeToManagedMap = new {0}();", dict);
WriteLine("protected void*[] __OriginalVTables;");
}
PopBlock(NewLineKind.BeforeNextBlock);
}
GenerateClassConstructors(@class);
GenerateClassConstructors(@class);
GenerateClassMethods(@class.Methods);
GenerateClassVariables(@class);
GenerateClassProperties(@class);
GenerateClassMethods(@class.Methods);
GenerateClassVariables(@class);
GenerateClassProperties(@class);
if (@class.IsDynamic)
GenerateVTable(@class);
}
if (@class.IsDynamic)
GenerateVTable(@class);
exit:
WriteCloseBraceIndent();
PopBlock(NewLineKind.BeforeNextBlock);

13
src/Generator/Passes/CheckIgnoredDecls.cs

@ -369,6 +369,14 @@ namespace CppSharp.Passes @@ -369,6 +369,14 @@ namespace CppSharp.Passes
return true;
}
var @class = decl as Class;
if (@class != null && @class.IsOpaque && !@class.IsDependent &&
!(@class is ClassTemplateSpecialization))
{
msg = null;
return false;
}
if (decl.IsIncomplete)
{
msg = "incomplete";
@ -400,6 +408,11 @@ namespace CppSharp.Passes @@ -400,6 +408,11 @@ namespace CppSharp.Passes
Declaration decl;
if (!finalType.TryGetDeclaration(out decl)) return true;
var @class = (decl as Class);
if (@class != null && @class.IsOpaque && !@class.IsDependent &&
!(@class is ClassTemplateSpecialization))
return true;
return !decl.IsIncomplete || decl.CompleteDeclaration != null;
}

3
src/Generator/Passes/ResolveIncompleteDeclsPass.cs

@ -67,6 +67,9 @@ namespace CppSharp.Passes @@ -67,6 +67,9 @@ namespace CppSharp.Passes
if (declaration.CompleteDeclaration != null)
return;
var @class = declaration as Class;
if (@class != null && @class.IsOpaque) return;
declaration.CompleteDeclaration =
ASTContext.FindCompleteClass(declaration.QualifiedName);

2
src/Parser/ASTConverter.cs

@ -994,7 +994,7 @@ namespace CppSharp @@ -994,7 +994,7 @@ namespace CppSharp
{
var decl = ctx.GetClasses(i);
var _decl = Visit(decl) as AST.Class;
if (!_decl.IsIncomplete)
if (!_decl.IsIncomplete || _decl.IsOpaque)
_ctx.Classes.Add(_decl);
}

8
tests/CSharp/CSharp.Tests.cs

@ -698,4 +698,12 @@ public unsafe class CSharpTests : GeneratorTestFixture @@ -698,4 +698,12 @@ public unsafe class CSharpTests : GeneratorTestFixture
return base.HasPointerToEnumInParam(pointerToEnum);
}
}
[Test]
public void TestGenerationOfIncompleteClasses()
{
var incompleteStruct = CSharp.CSharp.CreateIncompleteStruct();
Assert.IsNotNull(incompleteStruct);
Assert.DoesNotThrow(() => CSharp.CSharp.UseIncompleteStruct(incompleteStruct));
}
}

12
tests/CSharp/CSharp.cpp

@ -1310,3 +1310,15 @@ void HasGetterAndOverriddenSetter::setBaseSetter(int value) @@ -1310,3 +1310,15 @@ void HasGetterAndOverriddenSetter::setBaseSetter(int value)
void hasArrayOfConstChar(const char* const arrayOfConstChar[])
{
}
struct IncompleteStruct {};
IncompleteStruct* createIncompleteStruct()
{
return new IncompleteStruct();
}
DLL_API void useIncompleteStruct(IncompleteStruct * a)
{
return;
}

7
tests/CSharp/CSharp.h

@ -1151,3 +1151,10 @@ protected: @@ -1151,3 +1151,10 @@ protected:
};
void DLL_API hasArrayOfConstChar(const char* const arrayOfConstChar[]);
struct CompleteIncompleteStruct;
typedef struct IncompleteStruct IncompleteStruct;
DLL_API IncompleteStruct* createIncompleteStruct();
DLL_API void useIncompleteStruct(IncompleteStruct* a);
Loading…
Cancel
Save