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
// True if the class is final / sealed. // True if the class is final / sealed.
public bool IsFinal { get; set; } public bool IsFinal { get; set; }
private bool? isOpaque = null;
// True if the type is to be treated as opaque. // 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. // True if the class is dynamic.
public bool IsDynamic; public bool IsDynamic;
@ -127,7 +139,6 @@ namespace CppSharp.AST
IsAbstract = false; IsAbstract = false;
IsUnion = false; IsUnion = false;
IsFinal = false; IsFinal = false;
IsOpaque = false;
IsPOD = false; IsPOD = false;
Type = ClassType.RefType; Type = ClassType.RefType;
Layout = new ClassLayout(); Layout = new ClassLayout();

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

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

13
src/Generator/Passes/CheckIgnoredDecls.cs

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

3
src/Generator/Passes/ResolveIncompleteDeclsPass.cs

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

2
src/Parser/ASTConverter.cs

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

8
tests/CSharp/CSharp.Tests.cs

@ -698,4 +698,12 @@ public unsafe class CSharpTests : GeneratorTestFixture
return base.HasPointerToEnumInParam(pointerToEnum); 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)
void hasArrayOfConstChar(const char* const arrayOfConstChar[]) 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:
}; };
void DLL_API hasArrayOfConstChar(const char* const arrayOfConstChar[]); 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