mirror of https://github.com/mono/CppSharp.git
Browse Source
1. Got rid of Anonymous Names. 2. Merged the common code for Delegate Generation. 3. The delegate pass also works for C++/CLI now. 4. Fixed the calling conventions of delegates for both, C++/CLI and C#. 5. Ensures that if a delegate is used for a virtual as well as something else, it finally ends up as public. 6. Fixed the code generation when the return type of a method is a function pointer that has been used somewhere else as well. 7. Added Access and Calling convention to the delegate definition. The only thing left is to get rid of the hack used, i.e move the code in VisitFunctionDecl to VisitParametersDecl. Somehow, it's not working right now. Signed-off-by: Dimitar Dobrev <dpldobrev@protonmail.com>pull/921/head
13 changed files with 180 additions and 305 deletions
@ -1,129 +0,0 @@
@@ -1,129 +0,0 @@
|
||||
using System.Collections.Generic; |
||||
using System.Linq; |
||||
using CppSharp.AST; |
||||
using CppSharp.AST.Extensions; |
||||
|
||||
namespace CppSharp.Passes |
||||
{ |
||||
/// <summary>
|
||||
/// C++ function pointers are converted to delegates. If the function pointer is typedef'd then a delegate is
|
||||
/// generated with that name, otherwise the generic Action or Func delegates are used. The delegates are marhsalled
|
||||
/// using the GetDelegateForFunctionPointer and GetFunctionPointerForDelegate methods; unfortunately, these methods
|
||||
/// don't support generic types, so marshalling fails when function pointers are used without typedefs. This pass
|
||||
/// generates explicit delegates for these function pointers when used as function arguments or return types.
|
||||
/// </summary>
|
||||
public class GenerateAnonymousDelegatesPass : TranslationUnitPass |
||||
{ |
||||
private struct Typedef |
||||
{ |
||||
public DeclarationContext Context; |
||||
public TypedefDecl Declaration; |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// The generated typedefs keyed by the qualified declaration context name. The tree can't be modified while
|
||||
/// iterating over it, so we collect all the typedefs and add them at the end.
|
||||
/// </summary>
|
||||
private readonly Dictionary<string, List<Typedef>> allTypedefs = new Dictionary<string, List<Typedef>>(); |
||||
|
||||
public override bool VisitASTContext(ASTContext context) |
||||
{ |
||||
bool result = base.VisitASTContext(context); |
||||
|
||||
foreach (var typedef in allTypedefs) |
||||
{ |
||||
foreach (var foo in typedef.Value) |
||||
{ |
||||
foo.Context.Declarations.Add(foo.Declaration); |
||||
} |
||||
} |
||||
allTypedefs.Clear(); |
||||
|
||||
return result; |
||||
} |
||||
|
||||
public override bool VisitFunctionDecl(Function function) |
||||
{ |
||||
if (!base.VisitFunctionDecl(function) || function.Ignore) |
||||
return false; |
||||
|
||||
function.ReturnType = CheckType(function.Namespace, function.ReturnType); |
||||
foreach (var parameter in function.Parameters) |
||||
{ |
||||
parameter.QualifiedType = CheckType(function.Namespace, parameter.QualifiedType); |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Generates a new typedef for the given type if necessary and returns the new type.
|
||||
/// </summary>
|
||||
/// <param name="namespace">The namespace the typedef will be added to.</param>
|
||||
/// <param name="type">The type to check.</param>
|
||||
/// <returns>The new type.</returns>
|
||||
private QualifiedType CheckType(DeclarationContext @namespace, QualifiedType type) |
||||
{ |
||||
if (type.Type.IsDependent) |
||||
return type; |
||||
|
||||
var pointerType = type.Type as PointerType; |
||||
if (pointerType == null) |
||||
return type; |
||||
|
||||
var functionType = pointerType.Pointee as FunctionType; |
||||
if (functionType == null) |
||||
return type; |
||||
|
||||
List<Typedef> typedefs; |
||||
if (!allTypedefs.TryGetValue(@namespace.QualifiedName, out typedefs)) |
||||
{ |
||||
typedefs = new List<Typedef>(); |
||||
allTypedefs.Add(@namespace.QualifiedName, typedefs); |
||||
} |
||||
|
||||
var typedef = FindMatchingTypedef(typedefs, functionType); |
||||
if (typedef == null) |
||||
{ |
||||
for (int i = 0; i < functionType.Parameters.Count; i++) |
||||
{ |
||||
functionType.Parameters[i].Name = string.Format("_{0}", i); |
||||
} |
||||
|
||||
typedef = new TypedefDecl |
||||
{ |
||||
Access = AccessSpecifier.Public, |
||||
Name = string.Format("__AnonymousDelegate{0}", typedefs.Count), |
||||
Namespace = @namespace, |
||||
QualifiedType = type, |
||||
IsSynthetized = true |
||||
}; |
||||
typedefs.Add(new Typedef |
||||
{ |
||||
Context = @namespace, |
||||
Declaration = typedef |
||||
}); |
||||
} |
||||
|
||||
var typedefType = new TypedefType |
||||
{ |
||||
Declaration = typedef |
||||
}; |
||||
return new QualifiedType(typedefType); |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Finds a typedef with the same return type and parameter types.
|
||||
/// </summary>
|
||||
/// <param name="typedefs">The typedef list to search.</param>
|
||||
/// <param name="functionType">The function to match.</param>
|
||||
/// <returns>The matching typedef, or null if not found.</returns>
|
||||
private static TypedefDecl FindMatchingTypedef(IEnumerable<Typedef> typedefs, FunctionType functionType) |
||||
{ |
||||
return (from typedef in typedefs |
||||
let type = (FunctionType)typedef.Declaration.Type.GetPointee() |
||||
where type.ReturnType == functionType.ReturnType && |
||||
type.Parameters.SequenceEqual(functionType.Parameters, ParameterTypeComparer.Instance) |
||||
select typedef.Declaration).SingleOrDefault(); |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue