Browse Source

Fixed the C# generation for functions with typedefed function pointers as params (#903)

pull/890/head
Mohit Mohta 8 years ago committed by Dimitar Dobrev
parent
commit
db522c0295
  1. 4
      src/Generator/BindingContext.cs
  2. 3
      src/Generator/Generators/CSharp/CSharpTypePrinter.cs
  3. 83
      src/Generator/Passes/DelegatesPass.cs
  4. 8
      tests/CSharp/CSharp.Tests.cs
  5. 7
      tests/CSharp/CSharp.cpp
  6. 3
      tests/CSharp/CSharp.h

4
src/Generator/BindingContext.cs

@ -20,7 +20,7 @@ namespace CppSharp.Generators
public PassBuilder<TranslationUnitPass> TranslationUnitPasses { get; private set; } public PassBuilder<TranslationUnitPass> TranslationUnitPasses { get; private set; }
public PassBuilder<GeneratorOutputPass> GeneratorOutputPasses { get; private set; } public PassBuilder<GeneratorOutputPass> GeneratorOutputPasses { get; private set; }
public Dictionary<Function, DelegatesPass.DelegateDefinition> Delegates { get; private set; } public Dictionary<Declaration, DelegatesPass.DelegateDefinition> Delegates { get; private set; }
public BindingContext(DriverOptions options, ParserOptions parserOptions = null) public BindingContext(DriverOptions options, ParserOptions parserOptions = null)
{ {
@ -28,7 +28,7 @@ namespace CppSharp.Generators
ParserOptions = parserOptions; ParserOptions = parserOptions;
Symbols = new SymbolContext(); Symbols = new SymbolContext();
Delegates = new Dictionary<Function, DelegatesPass.DelegateDefinition>(); Delegates = new Dictionary<Declaration, DelegatesPass.DelegateDefinition>();
TypeMaps = new TypeMapDatabase(); TypeMaps = new TypeMapDatabase();

3
src/Generator/Generators/CSharp/CSharpTypePrinter.cs

@ -655,6 +655,9 @@ namespace CppSharp.Generators.CSharp
typeBuilder.Append(printedType.NameSuffix); typeBuilder.Append(printedType.NameSuffix);
var type = typeBuilder.ToString(); var type = typeBuilder.ToString();
if (Context.Delegates.ContainsKey(param))
return $"{Context.Delegates[param].Signature} {param.Name}";
if (ContextKind == TypePrinterContextKind.Native) if (ContextKind == TypePrinterContextKind.Native)
return $"{type} {param.Name}"; return $"{type} {param.Name}";

83
src/Generator/Passes/DelegatesPass.cs

@ -53,17 +53,33 @@ namespace CppSharp.Passes
return result; return result;
} }
public override bool VisitMethodDecl(Method method) private void AddDelegatesToDictionary(Declaration decl, Module module)
{ {
if (!base.VisitMethodDecl(method) || !method.IsVirtual || method.Ignore) CallingConvention callingConvention;
return false; bool isDependent = false;
QualifiedType returnType;
var @params = method.GatherInternalParams(Context.ParserOptions.IsItaniumLikeAbi, true).ToList(); List<Parameter> @params;
var delegateName = GenerateDelegateSignature(@params, method.ReturnType); if (decl is Method)
{
var module = method.TranslationUnit.Module; var method = (Method) decl;
@params = method.GatherInternalParams(Context.ParserOptions.IsItaniumLikeAbi, true).ToList();
callingConvention = method.CallingConvention;
isDependent = method.IsDependent;
returnType = method.ReturnType;
}
else
{
var param = (Parameter) decl;
var funcTypeParam = param.Type.Desugar().GetFinalPointee().Desugar() as FunctionType;
@params = funcTypeParam.Parameters;
callingConvention = funcTypeParam.CallingConvention;
isDependent = funcTypeParam.IsDependent;
returnType = funcTypeParam.ReturnType;
}
var delegateName = GenerateDelegateSignature(@params, returnType);
Namespace namespaceDelegates; Namespace namespaceDelegates;
if (namespacesDelegates.ContainsKey(module)) if (namespacesDelegates.ContainsKey(module))
{ {
namespaceDelegates = namespacesDelegates[module]; namespaceDelegates = namespacesDelegates[module];
@ -96,36 +112,71 @@ namespace CppSharp.Passes
new QualifiedType( new QualifiedType(
new FunctionType new FunctionType
{ {
CallingConvention = method.CallingConvention, CallingConvention = callingConvention,
IsDependent = method.IsDependent, IsDependent = isDependent,
Parameters = @params, Parameters = @params,
ReturnType = method.ReturnType ReturnType = returnType
}))), }))),
Namespace = namespaceDelegates, Namespace = namespaceDelegates,
IsSynthetized = true, IsSynthetized = true,
Access = AccessSpecifier.Private Access = decl is Method ? AccessSpecifier.Private : AccessSpecifier.Public
}; };
var delegateString = @delegate.Visit(TypePrinter).Type; var delegateString = @delegate.Visit(TypePrinter).Type;
var existingDelegate = GetExistingDelegate( var existingDelegate = GetExistingDelegate(
method.TranslationUnit.Module, delegateString); module, delegateString);
if (existingDelegate != null) if (existingDelegate != null)
{ {
Context.Delegates.Add(method, existingDelegate); Context.Delegates.Add(decl, existingDelegate);
return true; return;
} }
existingDelegate = new DelegateDefinition(module.OutputNamespace, delegateString); existingDelegate = new DelegateDefinition(module.OutputNamespace, delegateString);
Context.Delegates.Add(method, existingDelegate); Context.Delegates.Add(decl, existingDelegate);
libsDelegates[module].Add(delegateString, existingDelegate); libsDelegates[module].Add(delegateString, existingDelegate);
namespaceDelegates.Declarations.Add(@delegate); namespaceDelegates.Declarations.Add(@delegate);
}
private void VisitFunctionTypeParameters(Function function)
{
foreach (var param in from param in function.Parameters
let paramType = param.Type.Desugar()
where paramType.IsAddress() &&
paramType.GetFinalPointee().Desugar() is FunctionType
select param)
{
var module = function.TranslationUnit.Module;
AddDelegatesToDictionary(param, module);
}
}
public override bool VisitFunctionDecl(Function function)
{
if (!base.VisitFunctionDecl(function) || function.Ignore)
return false;
// HACK : We should shift this call to VisitFunctionTypeParameters in VisitParameter. We can't do it now
// because we need to use the module and a since a parameter's namespace is null, we can't reach the
// translation unit and thus the module
VisitFunctionTypeParameters(function);
return true; return true;
} }
public override bool VisitMethodDecl(Method method)
{
if (!base.VisitMethodDecl(method) || !method.IsVirtual || method.Ignore)
return false;
var module = method.TranslationUnit.Module;
AddDelegatesToDictionary(method, module);
return true;
}
private DelegateDefinition GetExistingDelegate(Module module, string delegateString) private DelegateDefinition GetExistingDelegate(Module module, string delegateString)
{ {
if (module.Libraries.Count == 0) if (module.Libraries.Count == 0)

8
tests/CSharp/CSharp.Tests.cs

@ -5,6 +5,7 @@ using System.Runtime.InteropServices;
using CppSharp.Utils; using CppSharp.Utils;
using CSharp; using CSharp;
using NUnit.Framework; using NUnit.Framework;
using CSharp.Delegates;
public unsafe class CSharpTests : GeneratorTestFixture public unsafe class CSharpTests : GeneratorTestFixture
{ {
@ -854,4 +855,11 @@ public unsafe class CSharpTests : GeneratorTestFixture
Assert.That(*((int*) indexproperty[n]), Is.EqualTo(21)); Assert.That(*((int*) indexproperty[n]), Is.EqualTo(21));
} }
} }
[Test, Platform(Exclude = "Win", Reason = "This test crashes our Windows build, possibly a problem with the NUnit runner there.")]
public void TestFuncWithTypedefedFuncPtrAsParam()
{
Func_int_IntPtr_CSharp_Bar___Internal function = (a, b) => 5;
Assert.That(CSharp.CSharp.FuncWithTypedefedFuncPtrAsParam(function), Is.EqualTo(5));
}
} }

7
tests/CSharp/CSharp.cpp

@ -1354,3 +1354,10 @@ DLL_API int useDuplicateDeclaredStruct(DuplicateDeclaredStruct* s)
void useStdStringJustAsParameter(std::string s) void useStdStringJustAsParameter(std::string s)
{ {
} }
int funcWithTypedefedFuncPtrAsParam(typedefedFuncPtr *func)
{
Foo* a = 0;
Bar b;
return func(a, b);
}

3
tests/CSharp/CSharp.h

@ -1217,3 +1217,6 @@ void* TestIndexedProperties::operator[](size_t n) const
extern const ComplexArrayElement ArrayOfVariableSize[]; extern const ComplexArrayElement ArrayOfVariableSize[];
void useStdStringJustAsParameter(std::string s); void useStdStringJustAsParameter(std::string s);
typedef int (typedefedFuncPtr)(Foo *a, Bar b);
int DLL_API funcWithTypedefedFuncPtrAsParam(typedefedFuncPtr *func);

Loading…
Cancel
Save