Browse Source

Added support for class templates which do not specialise types external to them.

Signed-off-by: Dimitar Dobrev <dpldobrev@protonmail.com>
pull/890/head
Dimitar Dobrev 8 years ago
parent
commit
cd548059e9
  1. 5
      src/AST/ASTVisitor.cs
  2. 2
      src/Generator/Generators/CSharp/CSharpMarshal.cs
  3. 34
      src/Generator/Passes/CheckIgnoredDecls.cs
  4. 3
      src/Generator/Passes/GenerateSymbolsPass.cs
  5. 6
      src/Generator/Passes/ResolveIncompleteDeclsPass.cs
  6. 6
      src/Generator/Types/TypeIgnoreChecker.cs
  7. 91
      tests/CSharp/CSharp.Tests.cs
  8. 4
      tests/CSharp/CSharp.cpp
  9. 23
      tests/CSharp/CSharp.cs
  10. 7
      tests/CSharp/CSharp.h
  11. 83
      tests/CSharp/CSharpTemplates.cpp
  12. 193
      tests/CSharp/CSharpTemplates.h

5
src/AST/ASTVisitor.cs

@ -184,7 +184,12 @@ namespace CppSharp.AST @@ -184,7 +184,12 @@ namespace CppSharp.AST
}
if (template.IsDependent && template.Template != null)
{
var @class = template.Template.TemplatedDecl as Class;
if (@class != null)
return @class.Specializations.Any(s => s.Visit(this));
return template.Template.Visit(this);
}
var specialization = template.GetClassTemplateSpecialization();
return specialization != null && specialization.Visit(this);

2
src/Generator/Generators/CSharp/CSharpMarshal.cs

@ -732,7 +732,7 @@ namespace CppSharp.Generators.CSharp @@ -732,7 +732,7 @@ namespace CppSharp.Generators.CSharp
}
string param = Context.Parameter.Name;
Type type = Context.Parameter.Type.Desugar();
Type type = Context.Parameter.Type.Desugar(false);
string paramInstance;
Class @interface;
var finalType = type.GetFinalPointee() ?? type;

34
src/Generator/Passes/CheckIgnoredDecls.cs

@ -39,9 +39,18 @@ namespace CppSharp.Passes @@ -39,9 +39,18 @@ namespace CppSharp.Passes
if (!@class.IsDependent)
return false;
// templates are not supported yet
foreach (var specialization in @class.Specializations.Where(s => !s.IsExplicitlyGenerated))
specialization.ExplicitlyIgnore();
if (Options.IsCLIGenerator || @class.TranslationUnit.IsSystemHeader ||
@class.Specializations.Count == 0)
{
bool hasExplicitlyGeneratedSpecializations = false;
foreach (var specialization in @class.Specializations)
if (specialization.IsExplicitlyGenerated)
hasExplicitlyGeneratedSpecializations = true;
else
specialization.ExplicitlyIgnore();
if (!hasExplicitlyGeneratedSpecializations)
@class.ExplicitlyIgnore();
}
return true;
}
@ -62,14 +71,6 @@ namespace CppSharp.Passes @@ -62,14 +71,6 @@ namespace CppSharp.Passes
return true;
}
if (decl.IsDependent && !decl.IsExplicitlyGenerated)
{
decl.GenerationKind = decl is Field ? GenerationKind.Internal : GenerationKind.None;
Diagnostics.Debug("Decl '{0}' was ignored due to dependent context",
decl.Name);
return true;
}
return true;
}
@ -107,6 +108,14 @@ namespace CppSharp.Passes @@ -107,6 +108,14 @@ namespace CppSharp.Passes
|| function.IsExplicitlyGenerated)
return false;
if (function.IsDependent && !(function.Namespace is Class))
{
function.GenerationKind = GenerationKind.None;
Diagnostics.Debug("Function '{0}' was ignored due to dependent context",
function.Name);
return false;
}
var ret = function.OriginalReturnType;
string msg;
@ -231,7 +240,8 @@ namespace CppSharp.Passes @@ -231,7 +240,8 @@ namespace CppSharp.Passes
return false;
string msg;
if (HasInvalidType(typedef.Type, typedef.TranslationUnit.Module, out msg))
if (HasInvalidType(typedef.Type, typedef.TranslationUnit.Module, out msg) &&
!(typedef.Type.Desugar() is MemberPointerType))
{
typedef.ExplicitlyIgnore();
Diagnostics.Debug("Typedef '{0}' was ignored due to {1} type",

3
src/Generator/Passes/GenerateSymbolsPass.cs

@ -78,7 +78,7 @@ namespace CppSharp.Passes @@ -78,7 +78,7 @@ namespace CppSharp.Passes
if (@class.IsDependent)
foreach (var specialization in @class.Specializations.Where(
s => s.IsExplicitlyGenerated))
Add(specialization);
specialization.Visit(this);
else
foreach (var @base in @class.Bases.Where(b => b.IsClass))
{
@ -203,7 +203,6 @@ namespace CppSharp.Passes @@ -203,7 +203,6 @@ namespace CppSharp.Passes
specs = specializations[specialization.TranslationUnit.Module];
else specs = specializations[specialization.TranslationUnit.Module] =
new HashSet<ClassTemplateSpecialization>();
GetSymbolsCodeGenerator(specialization.TranslationUnit.Module);
specs.Add(specialization);
}

6
src/Generator/Passes/ResolveIncompleteDeclsPass.cs

@ -21,6 +21,7 @@ namespace CppSharp.Passes @@ -21,6 +21,7 @@ namespace CppSharp.Passes
if (!base.VisitClassTemplateDecl(template))
return false;
bool complete = !template.TemplatedDecl.IsIncomplete;
EnsureCompleteDeclaration(template.TemplatedDecl);
template.TemplatedDecl = template.TemplatedDecl.CompleteDeclaration ?? template.TemplatedDecl;
@ -29,8 +30,11 @@ namespace CppSharp.Passes @@ -29,8 +30,11 @@ namespace CppSharp.Passes
s => !s.IsIncomplete && !template.TemplatedClass.Specializations.Contains(s)))
template.TemplatedClass.Specializations.Add(specialization);
if (template.TemplatedClass.TemplateParameters.Count == 0)
if (template.TemplatedClass.TemplateParameters.Count == 0 || complete)
{
template.TemplatedClass.TemplateParameters.Clear();
template.TemplatedClass.TemplateParameters.AddRange(template.Parameters);
}
return true;
}

6
src/Generator/Types/TypeIgnoreChecker.cs

@ -123,10 +123,10 @@ namespace CppSharp @@ -123,10 +123,10 @@ namespace CppSharp
return false;
}
var specialization = template.GetClassTemplateSpecialization();
if (specialization == null || specialization.Ignore)
var result = base.VisitTemplateSpecializationType(template, quals);
if (!result)
Ignore();
return base.VisitTemplateSpecializationType(template, quals);
return result;
}
public override bool VisitArrayType(ArrayType array, TypeQualifiers quals)

91
tests/CSharp/CSharp.Tests.cs

@ -656,6 +656,89 @@ public unsafe class CSharpTests : GeneratorTestFixture @@ -656,6 +656,89 @@ public unsafe class CSharpTests : GeneratorTestFixture
}
}
[Test]
public void TestTemplateWithPointerToTypeParameter()
{
int staticT = 5;
Assert.That(IndependentFieldsExtensions.StaticDependent(ref staticT), Is.EqualTo(5));
}
[Test]
public void TestTemplateCopyConstructor()
{
using (var original = new IndependentFields<int>(5))
{
using (var copy = new IndependentFields<int>(original))
{
Assert.That(copy.Independent, Is.EqualTo(original.Independent));
}
}
}
[Test]
public void TestTemplateWithIndependentFields()
{
using (var independentFields = new IndependentFields<int>())
{
var t = 5;
Assert.That(independentFields.GetDependent(ref t), Is.EqualTo(5));
Assert.That(independentFields.Independent, Is.EqualTo(1));
}
using (var independentFields = new IndependentFields<bool>())
{
var t = true;
Assert.That(independentFields.GetDependent(ref t), Is.EqualTo(true));
Assert.That(independentFields.Independent, Is.EqualTo(1));
}
}
[Test]
public void TestVirtualTemplate()
{
using (var virtualTemplate = new VirtualTemplate<int>())
{
Assert.That(virtualTemplate.Function, Is.EqualTo(5));
}
}
[Test]
public void TestOverrideOfTemplate()
{
using (var hasVirtualTemplate = new HasVirtualTemplate())
{
using (var overrideVirtualTemplate = new OverrideVirtualTemplate())
{
hasVirtualTemplate.SetV(overrideVirtualTemplate);
Assert.That(hasVirtualTemplate.Function, Is.EqualTo(10));
}
}
}
[Test]
public void TestDefaultTemplateArgument()
{
using (var hasDefaultTemplateArgument = new HasDefaultTemplateArgument<int, int>())
{
hasDefaultTemplateArgument.Property = 10;
Assert.That(hasDefaultTemplateArgument.Property, Is.EqualTo(10));
}
}
[Test]
public void TestTemplateStaticProperty()
{
HasDefaultTemplateArgument<int, int>.StaticProperty = 5;
Assert.That(HasDefaultTemplateArgument<int, int>.StaticProperty, Is.EqualTo(5));
}
[Test]
public void TestIndependentConstInIndependentTemplate()
{
Assert.That(IndependentFields<int>.IndependentConst, Is.EqualTo(15));
Assert.That(IndependentFields<bool>.IndependentConst, Is.EqualTo(15));
Assert.That(IndependentFields<T1>.IndependentConst, Is.EqualTo(15));
}
[Test]
public void TestAbstractImplementatonsInPrimaryAndSecondaryBases()
{
@ -862,4 +945,12 @@ public unsafe class CSharpTests : GeneratorTestFixture @@ -862,4 +945,12 @@ public unsafe class CSharpTests : GeneratorTestFixture
TypedefedFuncPtr function = (a, b) => 5;
Assert.That(CSharp.CSharp.FuncWithTypedefedFuncPtrAsParam(function), Is.EqualTo(5));
}
private class OverrideVirtualTemplate : VirtualTemplate<int>
{
public override int Function
{
get { return 10; }
}
}
}

4
tests/CSharp/CSharp.cpp

@ -700,12 +700,12 @@ void HasOverridesWithIncreasedAccess::privateOverride(int i) @@ -700,12 +700,12 @@ void HasOverridesWithIncreasedAccess::privateOverride(int i)
{
}
IgnoredType<int> PropertyWithIgnoredType::ignoredType()
IgnoredType PropertyWithIgnoredType::ignoredType()
{
return _ignoredType;
}
void PropertyWithIgnoredType::setIgnoredType(const IgnoredType<int> &value)
void PropertyWithIgnoredType::setIgnoredType(const IgnoredType& value)
{
_ignoredType = value;
}

23
tests/CSharp/CSharp.cs

@ -131,9 +131,14 @@ namespace CppSharp.Tests @@ -131,9 +131,14 @@ namespace CppSharp.Tests
ClassTemplateSpecialization classTemplateSpecialization;
var templateSpecializationType = type as TemplateSpecializationType;
if (templateSpecializationType != null)
{
classTemplateSpecialization = templateSpecializationType.GetClassTemplateSpecialization();
else
classTemplateSpecialization = (ClassTemplateSpecialization)((TagType)type).Declaration;
return classTemplateSpecialization.Arguments[0].Type.Type;
}
var declaration = ((TagType) type).Declaration;
if (declaration.IsDependent)
return new TagType(((Class) declaration).TemplateParameters[0]);
classTemplateSpecialization = (ClassTemplateSpecialization) declaration;
return classTemplateSpecialization.Arguments[0].Type.Type;
}
}
@ -185,8 +190,14 @@ namespace CppSharp.Tests @@ -185,8 +190,14 @@ namespace CppSharp.Tests
public override string CSharpSignature(TypePrinterContext ctx)
{
if (ctx.Kind == TypePrinterContextKind.Native)
return string.Format("QList.{0}{1}", Helpers.InternalStruct,
{
var type = (TemplateSpecializationType) ctx.Type.Desugar();
var specialization = type.GetClassTemplateSpecialization();
var typePrinter = new CSharpTypePrinter(null);
typePrinter.PushContext(TypePrinterContextKind.Native);
return string.Format($"{specialization.Visit(typePrinter)}{(Type.IsAddress() ? "*" : string.Empty)}", specialization.Visit(typePrinter),
Type.IsAddress() ? "*" : string.Empty);
}
return string.Format("System.Collections.Generic.{0}<{1}>",
ctx.MarshalKind == MarshalKind.DefaultExpression ? "List" : "IList",
@ -196,7 +207,11 @@ namespace CppSharp.Tests @@ -196,7 +207,11 @@ namespace CppSharp.Tests
public override void CSharpMarshalToNative(CSharpMarshalContext ctx)
{
// pointless, put just so that the generated code compiles
ctx.Return.Write("new QList.{0}()", Helpers.InternalStruct);
var type = (TemplateSpecializationType) ctx.Parameter.Type.Desugar();
var specialization = type.GetClassTemplateSpecialization();
var typePrinter = new CSharpTypePrinter(null);
typePrinter.PushContext(TypePrinterContextKind.Native);
ctx.Return.Write("new {0}()", specialization.Visit(typePrinter));
}
public override void CSharpMarshalToManaged(CSharpMarshalContext ctx)

7
tests/CSharp/CSharp.h

@ -481,7 +481,6 @@ public: @@ -481,7 +481,6 @@ public:
virtual int property() = 0;
};
template <typename T>
class DLL_API IgnoredType
{
};
@ -493,10 +492,10 @@ class DLL_API IgnoredTypeInheritingNonIgnoredWithNoEmptyCtor : public P @@ -493,10 +492,10 @@ class DLL_API IgnoredTypeInheritingNonIgnoredWithNoEmptyCtor : public P
class DLL_API PropertyWithIgnoredType
{
public:
IgnoredType<int> ignoredType();
void setIgnoredType(const IgnoredType<int>& value);
IgnoredType ignoredType();
void setIgnoredType(const IgnoredType& value);
private:
IgnoredType<int> _ignoredType;
IgnoredType _ignoredType;
};
// --- Multiple inheritance

83
tests/CSharp/CSharpTemplates.cpp

@ -1,9 +1,85 @@ @@ -1,9 +1,85 @@
#include "CSharpTemplates.h"
T1::T1()
{
}
T1::T1(int f)
{
field = f;
}
T1::~T1()
{
}
int T1::getField() const
{
return field;
}
HasDefaultTemplateArgument<bool, bool>::HasDefaultTemplateArgument()
{
}
HasDefaultTemplateArgument<bool, bool>::~HasDefaultTemplateArgument()
{
}
bool HasDefaultTemplateArgument<bool, bool>::property()
{
return field;
}
void HasDefaultTemplateArgument<bool, bool>::setProperty(const bool& t)
{
field = t;
}
bool HasDefaultTemplateArgument<bool, bool>::staticProperty()
{
return staticField;
}
void HasDefaultTemplateArgument<bool, bool>::setStaticProperty(const bool& t)
{
staticField = t;
}
bool HasDefaultTemplateArgument<bool, bool>::staticField;
HasVirtualTemplate::HasVirtualTemplate()
{
}
HasVirtualTemplate::~HasVirtualTemplate()
{
}
VirtualTemplate<int> HasVirtualTemplate::getVCopy()
{
return *v;
}
void HasVirtualTemplate::setV(VirtualTemplate<int>* value)
{
v = value;
}
int HasVirtualTemplate::function()
{
return v->function();
}
TemplateSpecializer::TemplateSpecializer()
{
}
IndependentFields<bool> TemplateSpecializer::getIndependentFields()
{
return IndependentFields<bool>();
}
void TemplateSpecializer::completeSpecializationInParameter(DependentValueFields<float> p1,
DependentValueFields<int*> p2,
DependentValueFields<float*> p3)
@ -15,3 +91,10 @@ void TemplateSpecializer::completeSpecializationInParameter(TwoTemplateArgs<int @@ -15,3 +91,10 @@ void TemplateSpecializer::completeSpecializationInParameter(TwoTemplateArgs<int
TwoTemplateArgs<int *, float> p3)
{
}
void forceUseSpecializations(IndependentFields<int> _1, IndependentFields<bool> _2,
IndependentFields<T1> _3, IndependentFields<std::string> _4,
VirtualTemplate<int> _5, VirtualTemplate<bool> _6,
HasDefaultTemplateArgument<int, int> _7, std::string s)
{
}

193
tests/CSharp/CSharpTemplates.h

@ -1,8 +1,17 @@ @@ -1,8 +1,17 @@
#include "../Tests.h"
#include "AnotherUnit.h"
#include <string>
class DLL_API T1
{
public:
T1();
T1(int f);
~T1();
int getField() const;
private:
int field;
};
class DLL_API T2
@ -12,10 +21,77 @@ class DLL_API T2 @@ -12,10 +21,77 @@ class DLL_API T2
template <typename T>
class DLL_API IndependentFields : public T1
{
public:
IndependentFields();
IndependentFields(const IndependentFields<T>& other);
IndependentFields(const T& t);
IndependentFields(int i);
~IndependentFields();
int getIndependent();
const T* returnTakeDependentPointer(const T* p);
T getDependent(const T& t);
static T staticDependent(const T& t);
template <typename AdditionalDependentType>
void usesAdditionalDependentType(AdditionalDependentType additionalDependentType);
static const int independentConst;
private:
int field;
int independent;
};
template <typename T>
const int IndependentFields<T>::independentConst = 15;
template <typename T>
IndependentFields<T>::IndependentFields() : independent(1)
{
}
template <typename T>
IndependentFields<T>::IndependentFields(const IndependentFields<T>& other)
{
independent = other.independent;
}
template <typename T>
IndependentFields<T>::IndependentFields(const T& t) : independent(1)
{
}
template <typename T>
IndependentFields<T>::IndependentFields(int i)
{
independent = i;
}
template <typename T>
IndependentFields<T>::~IndependentFields()
{
}
template <typename T>
const T* IndependentFields<T>::returnTakeDependentPointer(const T* p)
{
return p;
}
template <typename T>
T IndependentFields<T>::getDependent(const T& t)
{
return t;
}
template <typename T>
T IndependentFields<T>::staticDependent(const T& t)
{
return t;
}
template <typename T>
int IndependentFields<T>::getIndependent()
{
return independent;
}
template <typename T>
class DLL_API DependentValueFields
{
@ -44,7 +120,106 @@ private: @@ -44,7 +120,106 @@ private:
template <typename T, typename D = IndependentFields<T>>
class HasDefaultTemplateArgument
{
public:
HasDefaultTemplateArgument();
~HasDefaultTemplateArgument();
T property();
void setProperty(const T& t);
static T staticProperty();
static void setStaticProperty(const T& t);
private:
T field;
static T staticField;
};
template <>
class HasDefaultTemplateArgument<bool, bool>
{
public:
HasDefaultTemplateArgument();
~HasDefaultTemplateArgument();
bool property();
void setProperty(const bool& t);
static bool staticProperty();
static void setStaticProperty(const bool& t);
private:
bool field;
static bool staticField;
};
template <typename T, typename D>
HasDefaultTemplateArgument<T, D>::HasDefaultTemplateArgument()
{
}
template <typename T, typename D>
HasDefaultTemplateArgument<T, D>::~HasDefaultTemplateArgument()
{
}
template <typename T, typename D>
T HasDefaultTemplateArgument<T, D>::property()
{
return field;
}
template <typename T, typename D>
void HasDefaultTemplateArgument<T, D>::setProperty(const T& t)
{
field = t;
}
template <typename T, typename D>
T HasDefaultTemplateArgument<T, D>::staticProperty()
{
return staticField;
}
template <typename T, typename D>
void HasDefaultTemplateArgument<T, D>::setStaticProperty(const T& t)
{
staticField = t;
}
template <typename T, typename D>
T HasDefaultTemplateArgument<T, D>::staticField;
template <typename T>
class VirtualTemplate
{
public:
VirtualTemplate();
virtual ~VirtualTemplate();
virtual int function();
};
template <typename T>
VirtualTemplate<T>::VirtualTemplate()
{
}
template <typename T>
VirtualTemplate<T>::~VirtualTemplate()
{
}
template <typename T>
int VirtualTemplate<T>::function()
{
return 5;
}
class DLL_API HasVirtualTemplate
{
public:
HasVirtualTemplate();
~HasVirtualTemplate();
VirtualTemplate<int> getVCopy();
void setV(VirtualTemplate<int>* value);
int function();
private:
VirtualTemplate<int>* v;
HasDefaultTemplateArgument<bool, bool> explicitSpecialization;
};
template <typename T>
@ -58,6 +233,7 @@ public: @@ -58,6 +233,7 @@ public:
class NestedTemplate
{
};
IndependentFields<bool> getIndependentFields();
private:
IndependentFields<int> independentFields;
DependentValueFields<bool> dependentValueFields;
@ -121,3 +297,18 @@ struct MapResultType<InputSequence<T>, MapFunctor> @@ -121,3 +297,18 @@ struct MapResultType<InputSequence<T>, MapFunctor>
{
typedef InputSequence<typename LazyResultType<MapFunctor>::Type> ResultType;
};
// we optimise specialisations so that only actually used ones are wrapped
void forceUseSpecializations(IndependentFields<int> _1, IndependentFields<bool> _2,
IndependentFields<T1> _3, IndependentFields<std::string> _4,
VirtualTemplate<int> _5, VirtualTemplate<bool> _6,
HasDefaultTemplateArgument<int, int> _7, std::string s);
// force the symbols for the template instantiations because we do not have the auto-compilation for the generated C++ source
template class DLL_API IndependentFields<int>;
template class DLL_API IndependentFields<bool>;
template class DLL_API IndependentFields<T1>;
template class DLL_API IndependentFields<std::string>;
template class DLL_API VirtualTemplate<int>;
template class DLL_API VirtualTemplate<bool>;
template class DLL_API HasDefaultTemplateArgument<int, int>;

Loading…
Cancel
Save