Skip to content

Commit 4b31087

Browse files
committed
Enabled classes having specializations for secondary bases to call their extensions.
Signed-off-by: Dimitar Dobrev <[email protected]>
1 parent a119bdb commit 4b31087

File tree

10 files changed

+132
-47
lines changed

10 files changed

+132
-47
lines changed

src/AST/Function.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ public enum FunctionSynthKind
129129
AbstractImplCall,
130130
DefaultValueOverload,
131131
InterfaceInstance,
132+
InterfaceDispose,
132133
FieldAcessor
133134
}
134135

src/AST/Type.cs

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -668,7 +668,9 @@ public TemplateSpecializationType(TemplateSpecializationType type)
668668
Type = new QualifiedType((Type) t.Type.Type.Clone(), t.Type.Qualifiers)
669669
}).ToList();
670670
Template = type.Template;
671-
Desugared = new QualifiedType((Type) type.Desugared.Type.Clone(), type.Desugared.Qualifiers);
671+
if (type.Desugared.Type != null)
672+
Desugared = new QualifiedType((Type) type.Desugared.Type.Clone(),
673+
type.Desugared.Qualifiers);
672674
}
673675

674676
public List<TemplateArgument> Arguments;
@@ -797,11 +799,12 @@ public TemplateParameterType()
797799
public TemplateParameterType(TemplateParameterType type)
798800
: base(type)
799801
{
800-
Parameter = new TypeTemplateParameter
801-
{
802-
Constraint = type.Parameter.Constraint,
803-
Name = type.Parameter.Name
804-
};
802+
if (type.Parameter != null)
803+
Parameter = new TypeTemplateParameter
804+
{
805+
Constraint = type.Parameter.Constraint,
806+
Name = type.Parameter.Name
807+
};
805808
Depth = type.Depth;
806809
Index = type.Index;
807810
IsParameterPack = type.IsParameterPack;
@@ -852,6 +855,7 @@ public TemplateParameterSubstitutionType(TemplateParameterSubstitutionType type)
852855
: base(type)
853856
{
854857
Replacement = new QualifiedType((Type) type.Replacement.Type.Clone(), type.Replacement.Qualifiers);
858+
ReplacedParameter = (TemplateParameterType) type.ReplacedParameter.Clone();
855859
}
856860

857861
public override T Visit<T>(ITypeVisitor<T> visitor,
@@ -895,7 +899,11 @@ public InjectedClassNameType()
895899
public InjectedClassNameType(InjectedClassNameType type)
896900
: base(type)
897901
{
898-
TemplateSpecialization = (TemplateSpecializationType) type.TemplateSpecialization.Clone();
902+
if (type.TemplateSpecialization != null)
903+
TemplateSpecialization = (TemplateSpecializationType) type.TemplateSpecialization.Clone();
904+
InjectedSpecializationType = new QualifiedType(
905+
(Type) type.InjectedSpecializationType.Type.Clone(),
906+
type.InjectedSpecializationType.Qualifiers);
899907
Class = type.Class;
900908
}
901909

src/AST/TypeExtensions.cs

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -111,12 +111,12 @@ public static bool IsClass(this Type t)
111111
return t.TryGetClass(out @class);
112112
}
113113

114-
public static bool TryGetClass(this Type t, out Class @class)
114+
public static bool TryGetClass(this Type t, out Class @class, Class value = null)
115115
{
116-
return TryGetDeclaration(t, out @class);
116+
return TryGetDeclaration(t, out @class, value);
117117
}
118118

119-
public static bool TryGetDeclaration<T>(this Type t, out T decl) where T : Declaration
119+
public static bool TryGetDeclaration<T>(this Type t, out T decl, T value = null) where T : Declaration
120120
{
121121
t = t.Desugar();
122122

@@ -128,9 +128,8 @@ public static bool TryGetDeclaration<T>(this Type t, out T decl) where T : Decla
128128
{
129129
if (type.Template is TypeAliasTemplate)
130130
{
131-
Class @class;
132-
type.Desugared.Type.TryGetClass(out @class);
133-
decl = @class as T;
131+
type.Desugared.Type.TryGetDeclaration(out decl, value);
132+
decl = decl as T;
134133
return decl != null;
135134
}
136135

@@ -141,7 +140,13 @@ public static bool TryGetDeclaration<T>(this Type t, out T decl) where T : Decla
141140
decl = templatedClass.CompleteDeclaration == null
142141
? templatedClass as T
143142
: (T) templatedClass.CompleteDeclaration;
144-
return decl != null;
143+
if (decl != null)
144+
{
145+
if (value != null)
146+
type.Template = new ClassTemplate { TemplatedDecl = value };
147+
return true;
148+
}
149+
return false;
145150
}
146151

147152
var templateTemplateParameter = type.Template as TemplateTemplateParameter;
@@ -158,7 +163,13 @@ public static bool TryGetDeclaration<T>(this Type t, out T decl) where T : Decla
158163
if (tagType != null)
159164
{
160165
decl = tagType.Declaration as T;
161-
return decl != null;
166+
if (decl != null)
167+
{
168+
if (value != null)
169+
tagType.Declaration = value;
170+
return true;
171+
}
172+
return false;
162173
}
163174

164175
decl = null;

src/Generator/Driver.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,15 +258,17 @@ public void SetupPasses(ILibrary library)
258258
TranslationUnitPasses.AddPass(new HandleDefaultParamValuesPass());
259259
}
260260
TranslationUnitPasses.AddPass(new MultipleInheritancePass());
261-
TranslationUnitPasses.AddPass(new ParamTypeToInterfacePass());
262261
}
263262
TranslationUnitPasses.AddPass(new DelegatesPass());
264263

265264
TranslationUnitPasses.AddPass(new GetterSetterToPropertyPass());
266265
TranslationUnitPasses.AddPass(new StripUnusedSystemTypesPass());
267266

268267
if (Options.IsCSharpGenerator)
268+
{
269269
TranslationUnitPasses.AddPass(new SpecializationMethodsWithDependentPointersPass());
270+
TranslationUnitPasses.AddPass(new ParamTypeToInterfacePass());
271+
}
270272

271273
TranslationUnitPasses.AddPass(new MarkUsedClassInternalsPass());
272274

src/Generator/Generators/CSharp/CSharpMarshal.cs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -811,14 +811,13 @@ private void MarshalRefClass(Class @class)
811811
var finalType = type.GetFinalPointee() ?? type;
812812
var templateType = finalType as TemplateParameterSubstitutionType;
813813
type = Context.Parameter.Type.Desugar();
814+
if (templateType != null)
815+
param = $"(({@class.Visit(typePrinter)}) (object) {param})";
814816
if (finalType.TryGetClass(out @interface) &&
815817
@interface.IsInterface)
816818
paramInstance = $"{param}.__PointerTo{@interface.OriginalClass.Name}";
817819
else
818-
paramInstance = $@"{
819-
(templateType != null ? $"(({@class.Visit(typePrinter)}) (object) " : string.Empty)}{
820-
param}{(templateType != null ? ")" : string.Empty)
821-
}.{Helpers.InstanceIdentifier}";
820+
paramInstance = $@"{param}.{Helpers.InstanceIdentifier}";
822821
if (type.IsAddress())
823822
{
824823
Class decl;

src/Generator/Generators/CSharp/CSharpSources.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -459,11 +459,15 @@ private void GenerateInterface(Class @class)
459459

460460
GenerateClassSpecifier(@class);
461461

462+
if (@class.Bases.Count == 0)
463+
Write(" : IDisposable");
464+
462465
NewLine();
463466
WriteStartBraceIndent();
464467

465468
foreach (var method in @class.Methods.Where(m =>
466-
!ASTUtils.CheckIgnoreFunction(m.OriginalFunction) &&
469+
(m.OriginalFunction == null ||
470+
!ASTUtils.CheckIgnoreFunction(m.OriginalFunction)) &&
467471
m.Access == AccessSpecifier.Public))
468472
{
469473
PushBlock(BlockKind.Method);

src/Generator/Passes/MultipleInheritancePass.cs

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ private Class GetNewInterface(string name, Class @base)
8888
@interface = specializedInterface;
8989
}
9090
@interface.Name = name;
91+
@interface.USR = @base.USR;
9192
@interface.Namespace = @base.Namespace;
9293
@interface.Access = @base.Access;
9394
@interface.Type = ClassType.Interface;
@@ -116,18 +117,28 @@ where property.IsDeclared
116117
if (@interface.Bases.Count == 0)
117118
{
118119
var instance = new Property
119-
{
120-
Namespace = @interface,
121-
Name = Helpers.InstanceIdentifier,
122-
QualifiedType = new QualifiedType(new BuiltinType(PrimitiveType.IntPtr)),
123-
GetMethod = new Method
124120
{
125-
SynthKind = FunctionSynthKind.InterfaceInstance,
126-
Namespace = @interface
127-
}
128-
};
121+
Namespace = @interface,
122+
Name = Helpers.InstanceIdentifier,
123+
QualifiedType = new QualifiedType(new BuiltinType(PrimitiveType.IntPtr)),
124+
GetMethod = new Method
125+
{
126+
SynthKind = FunctionSynthKind.InterfaceInstance,
127+
Namespace = @interface
128+
}
129+
};
129130

130131
@interface.Properties.Add(instance);
132+
133+
var dispose = new Method
134+
{
135+
Namespace = @interface,
136+
Name = "Dispose",
137+
ReturnType = new QualifiedType(new BuiltinType(PrimitiveType.Void)),
138+
SynthKind = FunctionSynthKind.InterfaceDispose
139+
};
140+
141+
@interface.Methods.Add(dispose);
131142
}
132143

133144
@interface.Events.AddRange(@base.Events);
@@ -157,7 +168,8 @@ where property.IsDeclared
157168
@interface.TemplateParameters.AddRange(@base.TemplateParameters);
158169
templatedInterfaces[@base] = @interface;
159170
foreach (var spec in @base.Specializations)
160-
GetNewInterface(name, spec);
171+
@interface.Specializations.Add(
172+
(ClassTemplateSpecialization) GetNewInterface(name, spec));
161173
}
162174
return @interface;
163175
}
@@ -184,7 +196,8 @@ private static Property CreateInterfaceProperty(Property property, DeclarationCo
184196

185197
private void ImplementInterfaceMethods(Class @class, Class @interface)
186198
{
187-
foreach (var method in @interface.Methods)
199+
foreach (var method in @interface.Methods.Where(
200+
m => m.SynthKind != FunctionSynthKind.InterfaceDispose))
188201
{
189202
var existingImpl = @class.Methods.FirstOrDefault(
190203
m => m.OriginalName == method.OriginalName &&

src/Generator/Passes/ParamTypeToInterfacePass.cs

Lines changed: 52 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,21 @@ namespace CppSharp.Passes
66
{
77
public class ParamTypeToInterfacePass : TranslationUnitPass
88
{
9+
public ParamTypeToInterfacePass()
10+
{
11+
VisitOptions.VisitClassBases = false;
12+
VisitOptions.VisitClassFields = false;
13+
VisitOptions.VisitEventParameters = false;
14+
VisitOptions.VisitNamespaceEnums = false;
15+
VisitOptions.VisitNamespaceEvents = false;
16+
VisitOptions.VisitTemplateArguments = false;
17+
}
18+
919
public override bool VisitFunctionDecl(Function function)
1020
{
21+
if (!base.VisitFunctionDecl(function))
22+
return false;
23+
1124
if (!function.IsOperator || function.Parameters.Count > 1)
1225
{
1326
var originalReturnType = function.OriginalReturnType;
@@ -17,32 +30,57 @@ public override bool VisitFunctionDecl(Function function)
1730

1831
if (function.OperatorKind != CXXOperatorKind.Conversion &&
1932
function.OperatorKind != CXXOperatorKind.ExplicitConversion)
20-
foreach (var parameter in function.Parameters.Where(p => p.Kind != ParameterKind.OperatorParameter))
33+
foreach (var parameter in function.Parameters.Where(
34+
p => p.Kind != ParameterKind.OperatorParameter))
2135
{
2236
var qualifiedType = parameter.QualifiedType;
2337
ChangeToInterfaceType(ref qualifiedType);
2438
parameter.QualifiedType = qualifiedType;
2539
}
2640

27-
return base.VisitFunctionDecl(function);
41+
return true;
42+
}
43+
44+
public override bool VisitProperty(Property property)
45+
{
46+
if (!base.VisitProperty(property))
47+
return false;
48+
49+
var type = property.QualifiedType;
50+
ChangeToInterfaceType(ref type);
51+
property.QualifiedType = type;
52+
return true;
2853
}
2954

3055
private static void ChangeToInterfaceType(ref QualifiedType type)
3156
{
32-
var tagType = (type.Type.GetFinalPointee() ?? type.Type) as TagType;
33-
if (tagType != null)
57+
var finalType = (type.Type.GetFinalPointee() ?? type.Type).Desugar();
58+
Class @class;
59+
if (!finalType.TryGetClass(out @class))
60+
return;
61+
62+
var specialization = @class as ClassTemplateSpecialization;
63+
Class @interface = null;
64+
if (specialization == null)
3465
{
35-
var @class = tagType.Declaration as Class;
36-
if (@class != null)
37-
{
38-
var @interface = @class.Namespace.Classes.Find(c => c.OriginalClass == @class);
39-
if (@interface != null)
40-
{
41-
type.Type = (Type) type.Type.Clone();
42-
((TagType) (type.Type.GetFinalPointee() ?? type.Type)).Declaration = @interface;
43-
}
44-
}
66+
@interface = @class.Namespace.Classes.Find(
67+
c => c.OriginalClass == @class && c.IsInterface);
4568
}
69+
else
70+
{
71+
Class template = specialization.TemplatedDecl.TemplatedClass;
72+
Class templatedInterface = @class.Namespace.Classes.Find(
73+
c => c.OriginalClass == template && c.IsInterface);
74+
if (templatedInterface != null)
75+
@interface = templatedInterface.Specializations.FirstOrDefault(
76+
s => s.OriginalClass == specialization);
77+
}
78+
if (@interface == null)
79+
return;
80+
81+
type.Type = (Type) type.Type.Clone();
82+
finalType = (type.Type.GetFinalPointee() ?? type.Type).Desugar();
83+
finalType.TryGetClass(out @class, @interface);
4684
}
4785
}
4886
}

src/Generator/Passes/SpecializationMethodsWithDependentPointersPass.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ public override bool VisitASTContext(ASTContext context)
5656

5757
public override bool VisitClassDecl(Class @class)
5858
{
59-
if (!base.VisitClassDecl(@class) || !@class.IsDependent ||
59+
if (!base.VisitClassDecl(@class) || !@class.IsDependent || @class.IsInterface ||
6060
@class.Specializations.All(s => !s.IsGenerated))
6161
return false;
6262

tests/CSharp/CSharp.Tests.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -895,6 +895,15 @@ public void TestSpecializationForSecondaryBase()
895895
}
896896
}
897897

898+
[Test]
899+
public void TestExtensionsOfSpecializationsAsSecondaryBases()
900+
{
901+
using (var hasSpecializationForSecondaryBase = new HasSpecializationForSecondaryBase())
902+
{
903+
Assert.IsTrue(hasSpecializationForSecondaryBase.PropertyReturnDependentPointer() == null);
904+
}
905+
}
906+
898907
[Test]
899908
public void TestAbstractImplementatonsInPrimaryAndSecondaryBases()
900909
{

0 commit comments

Comments
 (0)