Skip to content

Commit 52c754c

Browse files
committed
Extended the multiple inheritance to work for templates.
Signed-off-by: Dimitar Dobrev <[email protected]>
1 parent 1e6c881 commit 52c754c

File tree

8 files changed

+89
-36
lines changed

8 files changed

+89
-36
lines changed

src/Generator/Generators/CSharp/CSharpMarshal.cs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -275,12 +275,13 @@ public override bool VisitTypedefType(TypedefType typedef, TypeQualifiers quals)
275275
Context.Before.WriteLine($"var {ptrName} = {Context.ReturnVarName};");
276276

277277
var specialization = decl.Namespace as ClassTemplateSpecialization;
278+
Type returnType = Context.ReturnType.Type.Desugar();
279+
var finalType = (returnType.GetFinalPointee() ?? returnType).Desugar();
278280
var res = string.Format(
279281
"{0} == IntPtr.Zero? null : {1}({2}) Marshal.GetDelegateForFunctionPointer({0}, typeof({2}))",
280282
ptrName,
281-
specialization == null ? string.Empty :
282-
$@"({specialization.TemplatedDecl.TemplatedClass.Typedefs.First(
283-
t => t.Name == decl.Name).Visit(this.typePrinter)}) (object) ",
283+
finalType.IsDependent ? $@"({specialization.TemplatedDecl.TemplatedClass.Typedefs.First(
284+
t => t.Name == decl.Name).Visit(this.typePrinter)}) (object) " : string.Empty,
284285
typedef);
285286
Context.Return.Write(res);
286287
return true;
@@ -359,7 +360,10 @@ public override bool VisitParameterDecl(Parameter parameter)
359360

360361
public override bool VisitTemplateParameterSubstitutionType(TemplateParameterSubstitutionType param, TypeQualifiers quals)
361362
{
362-
Context.Return.Write($"({param.ReplacedParameter.Parameter.Name}) (object) ");
363+
Type returnType = Context.ReturnType.Type.Desugar();
364+
Type finalType = (returnType.GetFinalPointee() ?? returnType).Desugar();
365+
if (finalType.IsDependent)
366+
Context.Return.Write($"({param.ReplacedParameter.Parameter.Name}) (object) ");
363367
if (param.Replacement.Type.Desugar().IsPointerToPrimitiveType())
364368
Context.Return.Write($"({CSharpTypePrinter.IntPtrType}) ");
365369
return base.VisitTemplateParameterSubstitutionType(param, quals);

src/Generator/Generators/CSharp/CSharpSources.cs

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -680,7 +680,7 @@ public override void GenerateClassSpecifier(Class @class)
680680

681681
if (@class.NeedsBase)
682682
{
683-
foreach (var @base in @class.Bases.Where(b => b.IsClass))
683+
foreach (var @base in @class.Bases.Where(b => b.IsClass && b.Class.IsGenerated))
684684
{
685685
var typeMaps = new List<System.Type>();
686686
var keys = new List<string>();
@@ -868,7 +868,7 @@ private void GenerateFunctionSetter(Class @class, Property property)
868868
GenerateInternalFunctionCall(property.SetMethod, parameters, @void);
869869
}
870870

871-
private void GenerateFieldSetter(Field field, Class @class)
871+
private void GenerateFieldSetter(Field field, Class @class, QualifiedType fieldType)
872872
{
873873
var param = new Parameter
874874
{
@@ -1153,7 +1153,7 @@ private static Property GetActualProperty(Property property, Class c)
11531153
p.GetMethod.InstantiatedFrom == property.GetMethod);
11541154
}
11551155

1156-
private void GenerateFieldGetter(Field field, Class @class)
1156+
private void GenerateFieldGetter(Field field, Class @class, QualifiedType returnType)
11571157
{
11581158
var name = @class.Layout.Fields.First(f => f.FieldPtr == field.OriginalPtr).Name;
11591159
var ctx = new CSharpMarshalContext(Context)
@@ -1163,7 +1163,7 @@ private void GenerateFieldGetter(Field field, Class @class)
11631163
ReturnVarName = $@"{(@class.IsValueType ? Helpers.InstanceField :
11641164
$"(({TypePrinter.PrintNative(@class)}*) {Helpers.InstanceIdentifier})")}{
11651165
(@class.IsValueType ? "." : "->")}{SafeIdentifier(name)}",
1166-
ReturnType = field.QualifiedType
1166+
ReturnType = returnType
11671167
};
11681168
ctx.PushMarshalKind(MarshalKind.NativeField);
11691169

@@ -3167,13 +3167,6 @@ public void GenerateInternalFunction(Function function)
31673167
if (function.IsPure)
31683168
return;
31693169

3170-
if (function.OriginalFunction != null)
3171-
{
3172-
var @class = function.OriginalNamespace as Class;
3173-
if (@class != null && @class.IsInterface)
3174-
function = function.OriginalFunction;
3175-
}
3176-
31773170
PushBlock(BlockKind.InternalsClassMethod);
31783171
WriteLine("[SuppressUnmanagedCodeSecurity]");
31793172
Write("[DllImport(\"{0}\", ", GetLibraryOf(function));

src/Generator/Generators/CSharp/CSharpSourcesExtensions.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public static void GenerateNativeConstructorsByValue(
3131
}
3232

3333
public static void GenerateField(this CSharpSources gen, Class @class,
34-
Field field, Action<Field, Class> generate, bool isVoid)
34+
Field field, Action<Field, Class, QualifiedType> generate, bool isVoid)
3535
{
3636
if (@class.IsDependent)
3737
{
@@ -46,7 +46,7 @@ public static void GenerateField(this CSharpSources gen, Class @class,
4646
gen.WriteStartBraceIndent();
4747
var specializedField = specialization.Fields.First(
4848
f => f.OriginalName == field.OriginalName);
49-
generate(specializedField, specialization);
49+
generate(specializedField, specialization, field.QualifiedType);
5050
if (isVoid)
5151
gen.WriteLine("return;");
5252
gen.WriteCloseBraceIndent();
@@ -58,12 +58,13 @@ public static void GenerateField(this CSharpSources gen, Class @class,
5858
var specialization = @class.Specializations[0];
5959
var specializedField = specialization.Fields.First(
6060
f => f.OriginalName == field.OriginalName);
61-
generate(specializedField, specialization);
61+
generate(specializedField, specialization, field.QualifiedType);
6262
}
6363
}
6464
else
6565
{
66-
generate(field, @class.IsDependent ? @class.Specializations[0] : @class);
66+
generate(field, @class.IsDependent ? @class.Specializations[0] : @class,
67+
field.QualifiedType);
6768
}
6869
}
6970

src/Generator/Passes/MultipleInheritancePass.cs

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ public override bool VisitClassDecl(Class @class)
4646
{
4747
var @base = @class.Bases[i];
4848
var baseClass = @base.Class;
49-
if (baseClass == null || baseClass.IsInterface) continue;
49+
if (baseClass == null || baseClass.IsInterface || !baseClass.IsGenerated) continue;
5050

5151
var @interface = GetInterface(baseClass);
5252
@class.Bases[i] = new BaseClassSpecifier(@base) { Type = new TagType(@interface) };
@@ -70,14 +70,35 @@ private Class GetInterface(Class @base)
7070

7171
private Class GetNewInterface(string name, Class @base)
7272
{
73-
var @interface = new Class
74-
{
75-
Name = name,
76-
Namespace = @base.Namespace,
77-
Access = @base.Access,
78-
Type = ClassType.Interface,
79-
OriginalClass = @base
80-
};
73+
var specialization = @base as ClassTemplateSpecialization;
74+
Class @interface;
75+
if (specialization == null)
76+
{
77+
@interface = new Class();
78+
}
79+
else
80+
{
81+
Class template = specialization.TemplatedDecl.TemplatedClass;
82+
Class templatedInterface;
83+
if (templatedInterfaces.ContainsKey(template))
84+
templatedInterface = templatedInterfaces[template];
85+
else
86+
templatedInterfaces[template] = templatedInterface = GetInterface(template);
87+
var specializedInterface = new ClassTemplateSpecialization();
88+
specializedInterface.Arguments.AddRange(specialization.Arguments);
89+
specializedInterface.TemplatedDecl = new ClassTemplate { TemplatedDecl = templatedInterface };
90+
@interface = specializedInterface;
91+
}
92+
@interface.Name = name;
93+
@interface.Namespace = @base.Namespace;
94+
@interface.Access = @base.Access;
95+
@interface.Type = ClassType.Interface;
96+
@interface.OriginalClass = @base;
97+
if (@base.IsTemplate)
98+
{
99+
@interface.IsDependent = true;
100+
@interface.TemplateParameters.AddRange(@base.TemplateParameters);
101+
}
81102

82103
@interface.Bases.AddRange(
83104
from b in @base.Bases
@@ -136,7 +157,8 @@ where property.IsDeclared
136157

137158
@base.Bases.Add(new BaseClassSpecifier { Type = new TagType(@interface) });
138159

139-
interfaces.Add(@base, @interface);
160+
if (specialization == null)
161+
interfaces.Add(@base, @interface);
140162
return @interface;
141163
}
142164

@@ -204,5 +226,7 @@ private static void ImplementInterfaceProperties(Class @class, Class @interface)
204226
foreach (var @base in @interface.Bases)
205227
ImplementInterfaceProperties(@class, @base.Class);
206228
}
229+
230+
private readonly Dictionary<Class, Class> templatedInterfaces = new Dictionary<Class, Class>();
207231
}
208232
}

src/Generator/Passes/TrimSpecializationsPass.cs

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.Linq;
44
using CppSharp.AST;
55
using CppSharp.AST.Extensions;
6+
using CppSharp.Types;
67
using CppSharp.Utils;
78

89
namespace CppSharp.Passes
@@ -78,7 +79,14 @@ public override bool VisitFieldDecl(Field field)
7879
if (!base.VisitDeclaration(field))
7980
return false;
8081

81-
if (field.Access == AccessSpecifier.Private ||
82+
if (field.Access == AccessSpecifier.Private)
83+
{
84+
CheckForInternalSpecialization(field, field.Type);
85+
return true;
86+
}
87+
88+
TypeMap typeMap;
89+
if (!Context.TypeMaps.FindTypeMap(field.Type, out typeMap) &&
8290
!ASTUtils.CheckTypeForSpecialization(field.Type,
8391
field, AddSpecialization, Context.TypeMaps))
8492
CheckForInternalSpecialization(field, field.Type);
@@ -200,12 +208,10 @@ private void CheckBasesForSpecialization(Class @class)
200208
foreach (var @base in @class.Bases.Where(b => b.IsClass))
201209
{
202210
var specialization = @base.Class as ClassTemplateSpecialization;
203-
if (specialization != null)
204-
{
205-
if (!ASTUtils.CheckTypeForSpecialization(@base.Type, @class,
206-
AddSpecialization, Context.TypeMaps))
207-
CheckForInternalSpecialization(@class, @base.Type);
208-
}
211+
if (specialization != null &&
212+
!ASTUtils.CheckTypeForSpecialization(@base.Type, @class,
213+
AddSpecialization, Context.TypeMaps))
214+
CheckForInternalSpecialization(@class, @base.Type);
209215
CheckBasesForSpecialization(@base.Class);
210216
}
211217
}

tests/CSharp/CSharp.Tests.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -885,6 +885,16 @@ public void TestFieldWithSpecializationType()
885885
}
886886
}
887887

888+
[Test]
889+
public void TestSpecializationForSecondaryBase()
890+
{
891+
using (var hasSpecializationForSecondaryBase = new HasSpecializationForSecondaryBase())
892+
{
893+
hasSpecializationForSecondaryBase.DependentValue = 5;
894+
Assert.That(hasSpecializationForSecondaryBase.DependentValue, Is.EqualTo(5));
895+
}
896+
}
897+
888898
[Test]
889899
public void TestAbstractImplementatonsInPrimaryAndSecondaryBases()
890900
{

tests/CSharp/CSharpTemplates.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,14 @@ int HasVirtualTemplate::function()
8787
return v->function();
8888
}
8989

90+
HasSpecializationForSecondaryBase::HasSpecializationForSecondaryBase()
91+
{
92+
}
93+
94+
HasSpecializationForSecondaryBase::~HasSpecializationForSecondaryBase()
95+
{
96+
}
97+
9098
TemplateSpecializer::TemplateSpecializer()
9199
{
92100
}

tests/CSharp/CSharpTemplates.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,13 @@ class DLL_API HasVirtualTemplate
425425
HasDefaultTemplateArgument<bool, bool> explicitSpecialization;
426426
};
427427

428+
class DLL_API HasSpecializationForSecondaryBase : T1, DependentValueFields<int>
429+
{
430+
public:
431+
HasSpecializationForSecondaryBase();
432+
~HasSpecializationForSecondaryBase();
433+
};
434+
428435
template <typename T>
429436
class TemplateInAnotherUnit;
430437

0 commit comments

Comments
 (0)