diff --git a/src/AST/ASTVisitor.cs b/src/AST/ASTVisitor.cs index c133af79..2a39e31f 100644 --- a/src/AST/ASTVisitor.cs +++ b/src/AST/ASTVisitor.cs @@ -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); diff --git a/src/Generator/Generators/CSharp/CSharpMarshal.cs b/src/Generator/Generators/CSharp/CSharpMarshal.cs index 5fdfdd77..9eedc810 100644 --- a/src/Generator/Generators/CSharp/CSharpMarshal.cs +++ b/src/Generator/Generators/CSharp/CSharpMarshal.cs @@ -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; diff --git a/src/Generator/Passes/CheckIgnoredDecls.cs b/src/Generator/Passes/CheckIgnoredDecls.cs index 0c14635f..2773acd3 100644 --- a/src/Generator/Passes/CheckIgnoredDecls.cs +++ b/src/Generator/Passes/CheckIgnoredDecls.cs @@ -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 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 || 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 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", diff --git a/src/Generator/Passes/GenerateSymbolsPass.cs b/src/Generator/Passes/GenerateSymbolsPass.cs index 3e1fe975..dc6c5b0b 100644 --- a/src/Generator/Passes/GenerateSymbolsPass.cs +++ b/src/Generator/Passes/GenerateSymbolsPass.cs @@ -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 specs = specializations[specialization.TranslationUnit.Module]; else specs = specializations[specialization.TranslationUnit.Module] = new HashSet(); - GetSymbolsCodeGenerator(specialization.TranslationUnit.Module); specs.Add(specialization); } diff --git a/src/Generator/Passes/ResolveIncompleteDeclsPass.cs b/src/Generator/Passes/ResolveIncompleteDeclsPass.cs index 3d801a0d..c5ab7156 100644 --- a/src/Generator/Passes/ResolveIncompleteDeclsPass.cs +++ b/src/Generator/Passes/ResolveIncompleteDeclsPass.cs @@ -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 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; } diff --git a/src/Generator/Types/TypeIgnoreChecker.cs b/src/Generator/Types/TypeIgnoreChecker.cs index a08cad0a..99596068 100644 --- a/src/Generator/Types/TypeIgnoreChecker.cs +++ b/src/Generator/Types/TypeIgnoreChecker.cs @@ -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) diff --git a/tests/CSharp/CSharp.Tests.cs b/tests/CSharp/CSharp.Tests.cs index 5ad94355..bfa9be04 100644 --- a/tests/CSharp/CSharp.Tests.cs +++ b/tests/CSharp/CSharp.Tests.cs @@ -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(5)) + { + using (var copy = new IndependentFields(original)) + { + Assert.That(copy.Independent, Is.EqualTo(original.Independent)); + } + } + } + + [Test] + public void TestTemplateWithIndependentFields() + { + using (var independentFields = new IndependentFields()) + { + var t = 5; + Assert.That(independentFields.GetDependent(ref t), Is.EqualTo(5)); + Assert.That(independentFields.Independent, Is.EqualTo(1)); + } + using (var independentFields = new IndependentFields()) + { + 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()) + { + 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()) + { + hasDefaultTemplateArgument.Property = 10; + Assert.That(hasDefaultTemplateArgument.Property, Is.EqualTo(10)); + } + } + + [Test] + public void TestTemplateStaticProperty() + { + HasDefaultTemplateArgument.StaticProperty = 5; + Assert.That(HasDefaultTemplateArgument.StaticProperty, Is.EqualTo(5)); + } + + [Test] + public void TestIndependentConstInIndependentTemplate() + { + Assert.That(IndependentFields.IndependentConst, Is.EqualTo(15)); + Assert.That(IndependentFields.IndependentConst, Is.EqualTo(15)); + Assert.That(IndependentFields.IndependentConst, Is.EqualTo(15)); + } + [Test] public void TestAbstractImplementatonsInPrimaryAndSecondaryBases() { @@ -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 + { + public override int Function + { + get { return 10; } + } + } } diff --git a/tests/CSharp/CSharp.cpp b/tests/CSharp/CSharp.cpp index 0f97f529..799d37f0 100644 --- a/tests/CSharp/CSharp.cpp +++ b/tests/CSharp/CSharp.cpp @@ -700,12 +700,12 @@ void HasOverridesWithIncreasedAccess::privateOverride(int i) { } -IgnoredType PropertyWithIgnoredType::ignoredType() +IgnoredType PropertyWithIgnoredType::ignoredType() { return _ignoredType; } -void PropertyWithIgnoredType::setIgnoredType(const IgnoredType &value) +void PropertyWithIgnoredType::setIgnoredType(const IgnoredType& value) { _ignoredType = value; } diff --git a/tests/CSharp/CSharp.cs b/tests/CSharp/CSharp.cs index 5a29ce17..6f62ee5e 100644 --- a/tests/CSharp/CSharp.cs +++ b/tests/CSharp/CSharp.cs @@ -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 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 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) diff --git a/tests/CSharp/CSharp.h b/tests/CSharp/CSharp.h index 5eb32c59..c05d018b 100644 --- a/tests/CSharp/CSharp.h +++ b/tests/CSharp/CSharp.h @@ -481,7 +481,6 @@ public: virtual int property() = 0; }; -template class DLL_API IgnoredType { }; @@ -493,10 +492,10 @@ class DLL_API IgnoredTypeInheritingNonIgnoredWithNoEmptyCtor : public P class DLL_API PropertyWithIgnoredType { public: - IgnoredType ignoredType(); - void setIgnoredType(const IgnoredType& value); + IgnoredType ignoredType(); + void setIgnoredType(const IgnoredType& value); private: - IgnoredType _ignoredType; + IgnoredType _ignoredType; }; // --- Multiple inheritance diff --git a/tests/CSharp/CSharpTemplates.cpp b/tests/CSharp/CSharpTemplates.cpp index 0be43c42..3342e39e 100644 --- a/tests/CSharp/CSharpTemplates.cpp +++ b/tests/CSharp/CSharpTemplates.cpp @@ -1,9 +1,85 @@ #include "CSharpTemplates.h" +T1::T1() +{ +} + +T1::T1(int f) +{ + field = f; +} + +T1::~T1() +{ +} + +int T1::getField() const +{ + return field; +} + +HasDefaultTemplateArgument::HasDefaultTemplateArgument() +{ +} + +HasDefaultTemplateArgument::~HasDefaultTemplateArgument() +{ +} + +bool HasDefaultTemplateArgument::property() +{ + return field; +} + +void HasDefaultTemplateArgument::setProperty(const bool& t) +{ + field = t; +} + +bool HasDefaultTemplateArgument::staticProperty() +{ + return staticField; +} + +void HasDefaultTemplateArgument::setStaticProperty(const bool& t) +{ + staticField = t; +} + +bool HasDefaultTemplateArgument::staticField; + +HasVirtualTemplate::HasVirtualTemplate() +{ +} + +HasVirtualTemplate::~HasVirtualTemplate() +{ +} + +VirtualTemplate HasVirtualTemplate::getVCopy() +{ + return *v; +} + +void HasVirtualTemplate::setV(VirtualTemplate* value) +{ + v = value; +} + +int HasVirtualTemplate::function() +{ + return v->function(); +} + TemplateSpecializer::TemplateSpecializer() { } +IndependentFields TemplateSpecializer::getIndependentFields() +{ + return IndependentFields(); +} + void TemplateSpecializer::completeSpecializationInParameter(DependentValueFields p1, DependentValueFields p2, DependentValueFields p3) @@ -15,3 +91,10 @@ void TemplateSpecializer::completeSpecializationInParameter(TwoTemplateArgs p3) { } + +void forceUseSpecializations(IndependentFields _1, IndependentFields _2, + IndependentFields _3, IndependentFields _4, + VirtualTemplate _5, VirtualTemplate _6, + HasDefaultTemplateArgument _7, std::string s) +{ +} diff --git a/tests/CSharp/CSharpTemplates.h b/tests/CSharp/CSharpTemplates.h index 1f600a48..d6851ad9 100644 --- a/tests/CSharp/CSharpTemplates.h +++ b/tests/CSharp/CSharpTemplates.h @@ -1,8 +1,17 @@ #include "../Tests.h" #include "AnotherUnit.h" +#include + 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 template class DLL_API IndependentFields : public T1 { +public: + IndependentFields(); + IndependentFields(const IndependentFields& 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 + void usesAdditionalDependentType(AdditionalDependentType additionalDependentType); + static const int independentConst; private: - int field; + int independent; }; +template +const int IndependentFields::independentConst = 15; + +template +IndependentFields::IndependentFields() : independent(1) +{ +} + +template +IndependentFields::IndependentFields(const IndependentFields& other) +{ + independent = other.independent; +} + +template +IndependentFields::IndependentFields(const T& t) : independent(1) +{ +} + +template +IndependentFields::IndependentFields(int i) +{ + independent = i; +} + +template +IndependentFields::~IndependentFields() +{ +} + +template +const T* IndependentFields::returnTakeDependentPointer(const T* p) +{ + return p; +} + +template +T IndependentFields::getDependent(const T& t) +{ + return t; +} + +template +T IndependentFields::staticDependent(const T& t) +{ + return t; +} + +template +int IndependentFields::getIndependent() +{ + return independent; +} + template class DLL_API DependentValueFields { @@ -44,7 +120,106 @@ private: template > 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 +{ +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 +HasDefaultTemplateArgument::HasDefaultTemplateArgument() +{ +} + +template +HasDefaultTemplateArgument::~HasDefaultTemplateArgument() +{ +} + +template +T HasDefaultTemplateArgument::property() +{ + return field; +} + +template +void HasDefaultTemplateArgument::setProperty(const T& t) +{ + field = t; +} + +template +T HasDefaultTemplateArgument::staticProperty() +{ + return staticField; +} + +template +void HasDefaultTemplateArgument::setStaticProperty(const T& t) +{ + staticField = t; +} + +template +T HasDefaultTemplateArgument::staticField; + +template +class VirtualTemplate +{ +public: + VirtualTemplate(); + virtual ~VirtualTemplate(); + virtual int function(); +}; + +template +VirtualTemplate::VirtualTemplate() +{ +} + +template +VirtualTemplate::~VirtualTemplate() +{ +} + +template +int VirtualTemplate::function() +{ + return 5; +} + +class DLL_API HasVirtualTemplate +{ +public: + HasVirtualTemplate(); + ~HasVirtualTemplate(); + VirtualTemplate getVCopy(); + void setV(VirtualTemplate* value); + int function(); +private: + VirtualTemplate* v; + HasDefaultTemplateArgument explicitSpecialization; }; template @@ -58,6 +233,7 @@ public: class NestedTemplate { }; + IndependentFields getIndependentFields(); private: IndependentFields independentFields; DependentValueFields dependentValueFields; @@ -121,3 +297,18 @@ struct MapResultType, MapFunctor> { typedef InputSequence::Type> ResultType; }; + +// we optimise specialisations so that only actually used ones are wrapped +void forceUseSpecializations(IndependentFields _1, IndependentFields _2, + IndependentFields _3, IndependentFields _4, + VirtualTemplate _5, VirtualTemplate _6, + HasDefaultTemplateArgument _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; +template class DLL_API IndependentFields; +template class DLL_API IndependentFields; +template class DLL_API IndependentFields; +template class DLL_API VirtualTemplate; +template class DLL_API VirtualTemplate; +template class DLL_API HasDefaultTemplateArgument;