mirror of https://github.com/mono/CppSharp.git
7 changed files with 239 additions and 145 deletions
@ -0,0 +1,76 @@ |
|||||||
|
using System.Collections.Generic; |
||||||
|
using System.Linq; |
||||||
|
|
||||||
|
namespace CppSharp.AST |
||||||
|
{ |
||||||
|
public static class FunctionExtensions |
||||||
|
{ |
||||||
|
public static IEnumerable<Parameter> GatherInternalParams(this Function function, |
||||||
|
bool isItaniumLikeAbi, bool universalDelegate = false) |
||||||
|
{ |
||||||
|
var @params = new List<Parameter>(); |
||||||
|
|
||||||
|
var method = function as Method; |
||||||
|
var isInstanceMethod = method != null && !method.IsStatic; |
||||||
|
|
||||||
|
var pointer = new QualifiedType(new PointerType(new QualifiedType(new BuiltinType(PrimitiveType.Void)))); |
||||||
|
|
||||||
|
if (isInstanceMethod && !isItaniumLikeAbi) |
||||||
|
{ |
||||||
|
@params.Add(new Parameter |
||||||
|
{ |
||||||
|
QualifiedType = pointer, |
||||||
|
Name = "instance" |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
if (!function.HasIndirectReturnTypeParameter && |
||||||
|
isInstanceMethod && isItaniumLikeAbi) |
||||||
|
{ |
||||||
|
@params.Add(new Parameter |
||||||
|
{ |
||||||
|
QualifiedType = pointer, |
||||||
|
Name = "instance" |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
var i = 0; |
||||||
|
foreach (var param in function.Parameters.Where(p => p.Kind != ParameterKind.OperatorParameter)) |
||||||
|
{ |
||||||
|
@params.Add(new Parameter |
||||||
|
{ |
||||||
|
QualifiedType = universalDelegate && param.Kind == ParameterKind.IndirectReturnType ? |
||||||
|
pointer : param.QualifiedType, |
||||||
|
Kind = param.Kind, |
||||||
|
Usage = param.Usage, |
||||||
|
Name = universalDelegate ? "arg" + ++i : param.Name |
||||||
|
}); |
||||||
|
|
||||||
|
if (param.Kind == ParameterKind.IndirectReturnType && |
||||||
|
isInstanceMethod && isItaniumLikeAbi) |
||||||
|
{ |
||||||
|
@params.Add(new Parameter |
||||||
|
{ |
||||||
|
QualifiedType = pointer, |
||||||
|
Name = "instance" |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (method != null && method.IsConstructor) |
||||||
|
{ |
||||||
|
var @class = (Class) method.Namespace; |
||||||
|
if (!isItaniumLikeAbi && @class.Layout.HasVirtualBases) |
||||||
|
{ |
||||||
|
@params.Add(new Parameter |
||||||
|
{ |
||||||
|
QualifiedType = new QualifiedType(new BuiltinType(PrimitiveType.Int)), |
||||||
|
Name = "__forBases" |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return @params; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,131 @@ |
|||||||
|
using System.Collections.Generic; |
||||||
|
using System.Linq; |
||||||
|
using System.Text; |
||||||
|
using CppSharp.AST; |
||||||
|
using CppSharp.AST.Extensions; |
||||||
|
using CppSharp.Generators.CSharp; |
||||||
|
|
||||||
|
namespace CppSharp.Passes |
||||||
|
{ |
||||||
|
public class DelegatesPass : TranslationUnitPass |
||||||
|
{ |
||||||
|
public const string DelegatesNamespace = "Delegates"; |
||||||
|
|
||||||
|
public DelegatesPass() |
||||||
|
{ |
||||||
|
Options.VisitClassBases = false; |
||||||
|
Options.VisitFunctionParameters = false; |
||||||
|
Options.VisitFunctionReturnType = false; |
||||||
|
Options.VisitNamespaceEnums = false; |
||||||
|
Options.VisitNamespaceTemplates = false; |
||||||
|
Options.VisitTemplateArguments = false; |
||||||
|
} |
||||||
|
|
||||||
|
public static Dictionary<Function, TypedefDecl> Delegates |
||||||
|
{ |
||||||
|
get { return delegates; } |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitLibrary(ASTContext context) |
||||||
|
{ |
||||||
|
foreach (var library in Driver.Options.Libraries.Where(l => !libsDelegates.ContainsKey(l))) |
||||||
|
libsDelegates.Add(library, new Dictionary<string, TypedefDecl>()); |
||||||
|
|
||||||
|
var unit = context.TranslationUnits.Last(u => u.IsValid && u.IsGenerated && |
||||||
|
!u.IsSystemHeader && u.HasDeclarations); |
||||||
|
namespaceDelegates = new Namespace { Name = DelegatesNamespace, Namespace = unit }; |
||||||
|
|
||||||
|
var result = base.VisitLibrary(context); |
||||||
|
|
||||||
|
if (namespaceDelegates.Declarations.Count > 0) |
||||||
|
unit.Declarations.Add(namespaceDelegates); |
||||||
|
|
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitMethodDecl(Method method) |
||||||
|
{ |
||||||
|
if (!base.VisitMethodDecl(method) || !method.IsVirtual || method.Ignore) |
||||||
|
return false; |
||||||
|
|
||||||
|
var @params = method.GatherInternalParams(Driver.Options.IsItaniumLikeAbi, true).ToList(); |
||||||
|
var delegateName = GenerateDelegateSignature(@params, method.ReturnType); |
||||||
|
var existingDelegate = GetExistingDelegate(delegateName); |
||||||
|
if (existingDelegate != null) |
||||||
|
{ |
||||||
|
delegates.Add(method, existingDelegate); |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
var @delegate = new TypedefDecl |
||||||
|
{ |
||||||
|
Name = delegateName, |
||||||
|
QualifiedType = new QualifiedType( |
||||||
|
new PointerType( |
||||||
|
new QualifiedType( |
||||||
|
new FunctionType |
||||||
|
{ |
||||||
|
CallingConvention = method.CallingConvention, |
||||||
|
IsDependent = method.IsDependent, |
||||||
|
Parameters = @params, |
||||||
|
ReturnType = method.ReturnType |
||||||
|
}))), |
||||||
|
Namespace = namespaceDelegates |
||||||
|
}; |
||||||
|
delegates.Add(method, @delegate); |
||||||
|
foreach (var library in Driver.Options.Libraries) |
||||||
|
libsDelegates[library].Add(delegateName, @delegate); |
||||||
|
|
||||||
|
namespaceDelegates.Declarations.Add(@delegate); |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
private TypedefDecl GetExistingDelegate(string delegateName) |
||||||
|
{ |
||||||
|
TypedefDecl @delegate = null; |
||||||
|
|
||||||
|
if (Driver.Options.Libraries.Count == 0) |
||||||
|
return @delegates.Values.FirstOrDefault(v => v.Name == delegateName); |
||||||
|
|
||||||
|
if (Driver.Options.Libraries.Union(Driver.Symbols.Libraries.SelectMany(l => l.Dependencies)).Any( |
||||||
|
l => libsDelegates.ContainsKey(l) && libsDelegates[l].TryGetValue(delegateName, out @delegate))) |
||||||
|
return @delegate; |
||||||
|
|
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
private string GenerateDelegateSignature(IEnumerable<Parameter> @params, QualifiedType returnType) |
||||||
|
{ |
||||||
|
var typePrinter = new CSharpTypePrinter(Driver); |
||||||
|
typePrinter.PushContext(CSharpTypePrinterContextKind.Native); |
||||||
|
|
||||||
|
var typesBuilder = new StringBuilder(); |
||||||
|
if (!returnType.Type.IsPrimitiveType(PrimitiveType.Void)) |
||||||
|
{ |
||||||
|
typesBuilder.Insert(0, returnType.Type.CSharpType(typePrinter)); |
||||||
|
typesBuilder.Append('_'); |
||||||
|
} |
||||||
|
foreach (var parameter in @params) |
||||||
|
{ |
||||||
|
typesBuilder.Append(parameter.CSharpType(typePrinter)); |
||||||
|
typesBuilder.Append('_'); |
||||||
|
} |
||||||
|
if (typesBuilder.Length > 0) |
||||||
|
typesBuilder.Remove(typesBuilder.Length - 1, 1); |
||||||
|
var delegateName = typesBuilder.Replace("global::System.", string.Empty).Replace( |
||||||
|
"*", "Ptr").Replace('.', '_').ToString(); |
||||||
|
if (returnType.Type.IsPrimitiveType(PrimitiveType.Void)) |
||||||
|
delegateName = "Action_" + delegateName; |
||||||
|
else |
||||||
|
delegateName = "Func_" + delegateName; |
||||||
|
|
||||||
|
typePrinter.PopContext(); |
||||||
|
return delegateName; |
||||||
|
} |
||||||
|
|
||||||
|
private Namespace namespaceDelegates; |
||||||
|
private static readonly Dictionary<string, Dictionary<string, TypedefDecl>> libsDelegates = new Dictionary<string, Dictionary<string, TypedefDecl>>(); |
||||||
|
private static readonly Dictionary<Function, TypedefDecl> delegates = new Dictionary<Function, TypedefDecl>(); |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue