Browse Source

Refactoring to reduce code duplication

pull/1574/head
Matt Key 5 years ago committed by João Matos
parent
commit
64ca939eb0
  1. 248
      src/Generator/Passes/ExtractInterfacePass.cs
  2. 4
      src/Generator/Passes/MultipleInheritancePass.cs

248
src/Generator/Passes/ExtractInterfacePass.cs

@ -1,46 +1,12 @@ @@ -1,46 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using CppSharp.AST;
using CppSharp.Generators;
using CppSharp.AST;
namespace CppSharp.Passes
{
public class ExtractInterfacePass : TranslationUnitPass
public class ExtractInterfacePass : MultipleInheritancePass
{
/// <summary>
/// Creates interface from generated classes
/// </summary>
private readonly HashSet<Class> interfaces = new HashSet<Class>();
/// <summary>
/// Classes that require interfaces to be created
/// </summary>
private readonly HashSet<Class> classesNeedingInterface = new HashSet<Class>();
public ExtractInterfacePass()
=> VisitOptions.ResetFlags(VisitFlags.Default);
public override bool VisitASTContext(ASTContext context)
{
bool result = base.VisitASTContext(context);
foreach (var @interface in interfaces.Where(i => !(i is ClassTemplateSpecialization)))
{
int index = @interface.Namespace.Declarations.IndexOf(@interface.OriginalClass);
@interface.Namespace.Declarations.Insert(index, @interface);
}
foreach (Class @class in classesNeedingInterface)
{
Class @interface = interfaces.FirstOrDefault(iface => iface.OriginalClass == @class);
ImplementInterfaceMethods(@class, @interface);
ImplementInterfaceProperties(@class, @interface);
}
interfaces.Clear();
classesNeedingInterface.Clear();
return result;
}
public override bool VisitClassDecl(Class @class)
{
@ -52,217 +18,9 @@ namespace CppSharp.Passes @@ -52,217 +18,9 @@ namespace CppSharp.Passes
return false;
}
classesNeedingInterface.Add(@class);
classesWithSecondaryBases.Add(@class);
GetInterface(@class);
return true;
}
private Class GetInterface(Class @base)
{
if (@base.CompleteDeclaration != null)
@base = (Class) @base.CompleteDeclaration;
return interfaces.FirstOrDefault(i => i.OriginalClass == @base) ??
GetNewInterface("I" + @base.Name, @base);
}
private Class GetNewInterface(string name, Class @base)
{
var specialization = @base as ClassTemplateSpecialization;
Class @interface;
if (specialization == null)
{
@interface = new Class();
}
else
{
Class template = specialization.TemplatedDecl.TemplatedClass;
Class templatedInterface = GetInterface(template);
@interface = interfaces.FirstOrDefault(i => i.OriginalClass == @base);
if (@interface != null)
return @interface;
var specializedInterface = new ClassTemplateSpecialization();
specializedInterface.Arguments.AddRange(specialization.Arguments);
specializedInterface.TemplatedDecl = new ClassTemplate { TemplatedDecl = templatedInterface };
@interface = specializedInterface;
}
@interface.Name = name;
@interface.USR = @base.USR;
@interface.Namespace = @base.Namespace;
@interface.Access = @base.Access;
@interface.Type = ClassType.Interface;
@interface.OriginalClass = @base;
@interface.Bases.AddRange(
from b in @base.Bases
where b.Class != null
let i = GetInterface(b.Class)
select new BaseClassSpecifier(b) { Type = new TagType(i) });
@interface.Methods.AddRange(
from m in @base.Methods
where !m.IsConstructor && !m.IsDestructor && !m.IsStatic &&
(m.IsGenerated || (m.IsInvalid && specialization != null)) && !m.IsOperator
select new Method(m) { Namespace = @interface, OriginalFunction = m });
@interface.Properties.AddRange(
from property in @base.Properties
where property.IsDeclared
select CreateInterfaceProperty(property, @interface));
@interface.Fields.AddRange(@base.Fields);
// avoid conflicts when potentially renaming later
@interface.Declarations.AddRange(@base.Declarations);
if (@interface.Bases.Count == 0)
{
QualifiedType intPtr = new QualifiedType(
new BuiltinType(PrimitiveType.IntPtr));
var instance = new Property
{
Namespace = @interface,
Name = Helpers.InstanceIdentifier,
QualifiedType = intPtr,
GetMethod = new Method
{
Name = Helpers.InstanceIdentifier,
SynthKind = FunctionSynthKind.InterfaceInstance,
Namespace = @interface,
OriginalReturnType = intPtr
}
};
@interface.Properties.Add(instance);
var dispose = new Method
{
Namespace = @interface,
Name = "Dispose",
ReturnType = new QualifiedType(new BuiltinType(PrimitiveType.Void)),
SynthKind = FunctionSynthKind.InterfaceDispose,
Mangled = string.Empty
};
@interface.Methods.Add(dispose);
}
@interface.Declarations.AddRange(@base.Events);
var type = new QualifiedType(new BuiltinType(PrimitiveType.IntPtr));
string pointerAdjustment = "__PointerTo" + @base.Name;
var adjustmentTo = new Property
{
Namespace = @interface,
Name = pointerAdjustment,
QualifiedType = type,
GetMethod = new Method
{
Name = pointerAdjustment,
SynthKind = FunctionSynthKind.InterfaceInstance,
Namespace = @interface,
ReturnType = type
}
};
@interface.Properties.Add(adjustmentTo);
@base.Properties.Add(adjustmentTo);
@base.Bases.Add(new BaseClassSpecifier { Type = new TagType(@interface) });
interfaces.Add(@interface);
if (@base.IsTemplate)
{
@interface.IsDependent = true;
@interface.TemplateParameters.AddRange(@base.TemplateParameters);
templatedInterfaces[@base] = @interface;
foreach (var spec in @base.Specializations)
@interface.Specializations.Add(
(ClassTemplateSpecialization) GetNewInterface(name, spec));
}
return @interface;
}
private static Property CreateInterfaceProperty(Property property, DeclarationContext @namespace)
{
var interfaceProperty = new Property(property) { Namespace = @namespace };
if (property.GetMethod != null)
{
interfaceProperty.GetMethod = new Method(property.GetMethod)
{
OriginalFunction = property.GetMethod,
Namespace = @namespace
};
}
if (property.SetMethod != null)
{
// handle indexers
interfaceProperty.SetMethod = property.GetMethod == property.SetMethod ?
interfaceProperty.GetMethod : new Method(property.SetMethod)
{
OriginalFunction = property.SetMethod,
Namespace = @namespace
};
}
return interfaceProperty;
}
private void ImplementInterfaceMethods(Class @class, Class @interface)
{
foreach (var method in @interface.Methods.Where(
m => m.SynthKind != FunctionSynthKind.InterfaceDispose))
{
var existingImpl = @class.Methods.Find(
m => m.OriginalName == method.OriginalName &&
m.Parameters.Where(p => !p.Ignore).SequenceEqual(
method.Parameters.Where(p => !p.Ignore),
ParameterTypeComparer.Instance));
if (existingImpl != null)
{
if (existingImpl.OriginalFunction == null)
existingImpl.OriginalFunction = method;
continue;
}
var impl = new Method(method)
{
Namespace = @class,
OriginalNamespace = @interface,
OriginalFunction = method.OriginalFunction
};
var rootBaseMethod = @class.GetBaseMethod(method);
if (rootBaseMethod != null && rootBaseMethod.IsDeclared)
impl.ExplicitInterfaceImpl = @interface;
@class.Methods.Add(impl);
}
foreach (var @base in @interface.Bases)
ImplementInterfaceMethods(@class, @base.Class);
}
private static void ImplementInterfaceProperties(Class @class, Class @interface)
{
foreach (var property in @interface.Properties.Where(p => p.Name != Helpers.InstanceIdentifier))
{
var impl = CreateInterfaceProperty(property, @class);
impl.OriginalNamespace = @interface;
var rootBaseProperty = @class.GetBasePropertyByName(property, true);
if (rootBaseProperty != null && rootBaseProperty.IsDeclared)
impl.ExplicitInterfaceImpl = @interface;
@class.Properties.Add(impl);
}
foreach (var @base in @interface.Bases)
ImplementInterfaceProperties(@class, @base.Class);
}
private readonly Dictionary<Class, Class> templatedInterfaces = new Dictionary<Class, Class>();
}
}

4
src/Generator/Passes/MultipleInheritancePass.cs

@ -18,7 +18,7 @@ namespace CppSharp.Passes @@ -18,7 +18,7 @@ namespace CppSharp.Passes
/// <summary>
/// Change and implement secondary bases at the end to avoid processing implementations.
/// </summary>
private readonly HashSet<Class> classesWithSecondaryBases = new HashSet<Class>();
protected readonly HashSet<Class> classesWithSecondaryBases = new HashSet<Class>();
public MultipleInheritancePass()
=> VisitOptions.ResetFlags(VisitFlags.Default);
@ -69,7 +69,7 @@ namespace CppSharp.Passes @@ -69,7 +69,7 @@ namespace CppSharp.Passes
return true;
}
private Class GetInterface(Class @base)
protected Class GetInterface(Class @base)
{
if (@base.CompleteDeclaration != null)
@base = (Class) @base.CompleteDeclaration;

Loading…
Cancel
Save