Browse Source

Merged Delegate Pass and pass for Anonymous Delegates and added the following improvements alongwith.

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
Mohit Mohta 8 years ago committed by Dimitar Dobrev
parent
commit
8a2e813445
  1. 4
      src/AST/Function.cs
  2. 1
      src/AST/Type.cs
  3. 5
      src/Generator/BindingContext.cs
  4. 3
      src/Generator/Driver.cs
  5. 28
      src/Generator/Generators/CLI/CLIHeaders.cs
  6. 4
      src/Generator/Generators/CSharp/CSharpMarshal.cs
  7. 4
      src/Generator/Generators/CSharp/CSharpSources.cs
  8. 3
      src/Generator/Generators/CSharp/CSharpTypePrinter.cs
  9. 290
      src/Generator/Passes/DelegatesPass.cs
  10. 129
      src/Generator/Passes/GenerateAnonymousDelegatesPass.cs
  11. 6
      tests/CSharp/CSharp.cpp
  12. 6
      tests/CSharp/CSharp.h
  13. 2
      tests/Common/Common.Tests.cs

4
src/AST/Function.cs

@ -258,7 +258,7 @@ namespace CppSharp.AST @@ -258,7 +258,7 @@ namespace CppSharp.AST
return visitor.VisitFunctionDecl(this);
}
public Type Type => OriginalReturnType.Type;
public QualifiedType QualifiedType => OriginalReturnType;
public Type Type => ReturnType.Type;
public QualifiedType QualifiedType => ReturnType;
}
}

1
src/AST/Type.cs

@ -260,6 +260,7 @@ namespace CppSharp.AST @@ -260,6 +260,7 @@ namespace CppSharp.AST
ReturnType = new QualifiedType((Type) type.ReturnType.Type.Clone(), type.ReturnType.Qualifiers);
Parameters.AddRange(type.Parameters.Select(p => new Parameter(p)).ToList());
CallingConvention = type.CallingConvention;
IsDependent = type.IsDependent;
}
public override T Visit<T>(ITypeVisitor<T> visitor, TypeQualifiers quals = new TypeQualifiers())

5
src/Generator/BindingContext.cs

@ -2,7 +2,6 @@ using CppSharp.AST; @@ -2,7 +2,6 @@ using CppSharp.AST;
using CppSharp.Passes;
using CppSharp.Types;
using CppSharp.Parser;
using System.Collections.Generic;
namespace CppSharp.Generators
{
@ -20,16 +19,12 @@ namespace CppSharp.Generators @@ -20,16 +19,12 @@ namespace CppSharp.Generators
public PassBuilder<TranslationUnitPass> TranslationUnitPasses { get; private set; }
public PassBuilder<GeneratorOutputPass> GeneratorOutputPasses { get; private set; }
public Dictionary<Declaration, DelegatesPass.DelegateDefinition> Delegates { get; private set; }
public BindingContext(DriverOptions options, ParserOptions parserOptions = null)
{
Options = options;
ParserOptions = parserOptions;
Symbols = new SymbolContext();
Delegates = new Dictionary<Declaration, DelegatesPass.DelegateDefinition>();
TypeMaps = new TypeMapDatabase();
TranslationUnitPasses = new PassBuilder<TranslationUnitPass>(this);

3
src/Generator/Driver.cs

@ -295,7 +295,6 @@ namespace CppSharp @@ -295,7 +295,6 @@ namespace CppSharp
TranslationUnitPasses.AddPass(new CheckStaticClass());
TranslationUnitPasses.AddPass(new MoveOperatorToClassPass());
TranslationUnitPasses.AddPass(new MoveFunctionToClassPass());
TranslationUnitPasses.AddPass(new GenerateAnonymousDelegatesPass());
TranslationUnitPasses.AddPass(new ConstructorToConversionOperatorPass());
TranslationUnitPasses.AddPass(new MarshalPrimitivePointersAsRefTypePass());
TranslationUnitPasses.AddPass(new CheckAmbiguousFunctions());
@ -321,8 +320,8 @@ namespace CppSharp @@ -321,8 +320,8 @@ namespace CppSharp
}
TranslationUnitPasses.AddPass(new MultipleInheritancePass());
TranslationUnitPasses.AddPass(new ParamTypeToInterfacePass());
TranslationUnitPasses.AddPass(new DelegatesPass());
}
TranslationUnitPasses.AddPass(new DelegatesPass());
TranslationUnitPasses.AddPass(new GetterSetterToPropertyPass());
TranslationUnitPasses.AddPass(new StripUnusedSystemTypesPass());

28
src/Generator/Generators/CLI/CLIHeaders.cs

@ -745,31 +745,27 @@ namespace CppSharp.Generators.CLI @@ -745,31 +745,27 @@ namespace CppSharp.Generators.CLI
if (!typedef.IsGenerated)
return false;
FunctionType function;
if (typedef.Type.IsPointerTo(out function))
var functionType = typedef.Type as FunctionType;
if (functionType != null || typedef.Type.IsPointerTo(out functionType))
{
PushBlock(BlockKind.Typedef, typedef);
GenerateDeclarationCommon(typedef);
var insideClass = typedef.Namespace is Class;
var attributedType = typedef.Type.GetPointee() as AttributedType;
if (attributedType != null)
{
var equivalentFunctionType = attributedType.Equivalent.Type as FunctionType;
var callingConvention = equivalentFunctionType.CallingConvention.ToInteropCallConv();
if (callingConvention != System.Runtime.InteropServices.CallingConvention.Winapi)
{
WriteLine("[{0}({1}::{2})] ",
"System::Runtime::InteropServices::UnmanagedFunctionPointer",
"System::Runtime::InteropServices::CallingConvention",
callingConvention);
}
}
var attributedType = typedef.Type.GetPointee().Desugar();
var callingConvention = attributedType == null && functionType != null
? functionType.CallingConvention
: ((FunctionType)attributedType).CallingConvention;
var interopCallConv = callingConvention.ToInteropCallConv();
if (interopCallConv != System.Runtime.InteropServices.CallingConvention.Winapi)
WriteLine("[System::Runtime::InteropServices::UnmanagedFunctionPointer" +
"(System::Runtime::InteropServices::CallingConvention::{0})] ",
interopCallConv);
WriteLine("{0}{1};",
!insideClass ? "public " : "",
string.Format(TypePrinter.VisitDelegate(function).ToString(),
string.Format(TypePrinter.VisitDelegate(functionType).ToString(),
typedef.Name));
PopBlock(NewLineKind.BeforeNextBlock);

4
src/Generator/Generators/CSharp/CSharpMarshal.cs

@ -256,8 +256,8 @@ namespace CppSharp.Generators.CSharp @@ -256,8 +256,8 @@ namespace CppSharp.Generators.CSharp
var decl = typedef.Declaration;
FunctionType function;
if (decl.Type.IsPointerTo(out function))
var functionType = decl.Type as FunctionType;
if (functionType != null || decl.Type.IsPointerTo(out functionType))
{
var ptrName = Generator.GeneratedIdentifier("ptr") +
Context.ParameterIndex;

4
src/Generator/Generators/CSharp/CSharpSources.cs

@ -1688,7 +1688,7 @@ namespace CppSharp.Generators.CSharp @@ -1688,7 +1688,7 @@ namespace CppSharp.Generators.CSharp
TypePrinter.PopMarshalKind();
WriteLine("private static {0} {1}Instance;",
Context.Delegates[method].Signature,
method.FunctionType.ToString(),
vTableMethodDelegateName);
NewLine();
@ -2490,7 +2490,7 @@ namespace CppSharp.Generators.CSharp @@ -2490,7 +2490,7 @@ namespace CppSharp.Generators.CSharp
var delegateId = Generator.GeneratedIdentifier(@delegate);
WriteLine("var {0} = ({1}) Marshal.GetDelegateForFunctionPointer(new IntPtr({2}), typeof({1}));",
delegateId, Context.Delegates[method].Signature,
delegateId, method.FunctionType.ToString(),
Helpers.SlotIdentifier);
return delegateId;

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

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

290
src/Generator/Passes/DelegatesPass.cs

@ -3,32 +3,15 @@ using System.Linq; @@ -3,32 +3,15 @@ using System.Linq;
using System.Text;
using CppSharp.AST;
using CppSharp.AST.Extensions;
using CppSharp.Generators;
using CppSharp.Generators.CSharp;
namespace CppSharp.Passes
{
public class DelegatesPass : TranslationUnitPass
{
public const string DelegatesNamespace = "Delegates";
public class DelegateDefinition
{
public DelegateDefinition(string @namespace, string signature)
{
Namespace = @namespace;
Signature = signature;
}
public string Namespace { get; }
public string Signature { get; }
}
public DelegatesPass()
{
VisitOptions.VisitClassBases = false;
VisitOptions.VisitFunctionParameters = false;
VisitOptions.VisitFunctionReturnType = false;
VisitOptions.VisitNamespaceEnums = false;
VisitOptions.VisitNamespaceTemplates = false;
@ -37,177 +20,194 @@ namespace CppSharp.Passes @@ -37,177 +20,194 @@ namespace CppSharp.Passes
public override bool VisitASTContext(ASTContext context)
{
foreach (var module in Options.Modules)
libsDelegates[module] = new Dictionary<string, DelegateDefinition>();
bool result = base.VisitASTContext(context);
foreach (var @delegate in delegates)
@delegate.Namespace.Declarations.Add(@delegate);
delegates.Clear();
var unit = context.TranslationUnits.GetGenerated().LastOrDefault();
if (!Options.IsCSharpGenerator)
return result;
var generatedUnits = context.TranslationUnits.GetGenerated();
var unit = generatedUnits.LastOrDefault();
if (unit == null)
return false;
var result = base.VisitASTContext(context);
foreach (var module in Options.Modules.Where(m => namespacesDelegates.ContainsKey(m)))
namespacesDelegates[module].Namespace.Declarations.Add(namespacesDelegates[module]);
foreach (var module in Options.Modules.Where(namespacesDelegates.ContainsKey))
{
var @namespace = namespacesDelegates[module];
@namespace.Namespace.Declarations.Add(@namespace);
}
return result;
}
private void AddDelegatesToDictionary(Declaration decl, Module module)
public override bool VisitMethodDecl(Method method)
{
CallingConvention callingConvention;
bool isDependent = false;
QualifiedType returnType;
List<Parameter> @params;
if (decl is Method)
{
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;
}
if (!base.VisitMethodDecl(method) || !method.IsVirtual || method.Ignore)
return false;
var delegateName = GenerateDelegateSignature(@params, returnType);
Namespace namespaceDelegates;
method.FunctionType = CheckForDelegate(method.FunctionType, method);
if (namespacesDelegates.ContainsKey(module))
{
namespaceDelegates = namespacesDelegates[module];
}
else
{
Namespace parent = null;
if (string.IsNullOrEmpty(module.OutputNamespace))
{
var group = module.Units.SelectMany(u => u.Declarations).OfType<Namespace>(
).GroupBy(d => d.Name).Where(g => g.Any(d => d.HasDeclarations)).ToList();
if (group.Count == 1)
parent = group.Last().Last();
}
if (parent == null)
parent = module.Units.Last();
namespaceDelegates = new Namespace
{
Name = DelegatesNamespace,
Namespace = parent
};
namespacesDelegates.Add(module, namespaceDelegates);
}
return true;
}
var functionType = new FunctionType
{
CallingConvention = callingConvention,
IsDependent = isDependent,
ReturnType = returnType
};
functionType.Parameters.AddRange(@params);
var @delegate = new TypedefDecl
{
Name = delegateName,
QualifiedType = new QualifiedType(
new PointerType(new QualifiedType(functionType))),
Namespace = namespaceDelegates,
IsSynthetized = true,
Access = decl is Method ? AccessSpecifier.Private : AccessSpecifier.Public
};
public override bool VisitFunctionDecl(Function function)
{
if (!base.VisitFunctionDecl(function) || function.Ignore)
return false;
var delegateString = @delegate.Visit(TypePrinter).Type;
var existingDelegate = GetExistingDelegate(
module, delegateString);
function.ReturnType = CheckForDelegate(function.ReturnType, function);
return true;
}
if (existingDelegate != null)
{
Context.Delegates.Add(decl, existingDelegate);
return;
}
public override bool VisitParameterDecl(Parameter parameter)
{
if (!base.VisitParameterDecl(parameter) || parameter.Namespace == null ||
parameter.Namespace.Ignore)
return false;
parameter.QualifiedType = CheckForDelegate(parameter.QualifiedType, parameter);
return true;
}
private QualifiedType CheckForDelegate(QualifiedType type, ITypedDecl decl)
{
if (type.Type is TypedefType)
return type;
var desugared = type.Type.Desugar();
if (desugared.IsDependent)
return type;
existingDelegate = new DelegateDefinition(module.OutputNamespace, delegateString);
Context.Delegates.Add(decl, existingDelegate);
Type pointee = desugared.GetPointee() ?? desugared;
if (pointee is TypedefType)
return type;
libsDelegates[module].Add(delegateString, existingDelegate);
var functionType = pointee.Desugar() as FunctionType;
if (functionType == null)
return type;
namespaceDelegates.Declarations.Add(@delegate);
TypedefDecl @delegate = GetDelegate(type, decl);
return new QualifiedType(new TypedefType { Declaration = @delegate });
}
private void VisitFunctionTypeParameters(Function function)
private TypedefDecl GetDelegate(QualifiedType type, ITypedDecl decl)
{
foreach (var param in from param in function.Parameters
where !(param.Type is TypedefType)
let paramType = param.Type.Desugar()
where paramType.IsAddress() &&
paramType.GetPointee() is FunctionType
select param)
FunctionType newFunctionType = GetNewFunctionType(decl, type);
var delegateName = GetDelegateName(newFunctionType);
var access = decl is Method ? AccessSpecifier.Private : AccessSpecifier.Public;
var existingDelegate = delegates.SingleOrDefault(t => t.Name == delegateName);
if (existingDelegate != null)
{
var module = function.TranslationUnit.Module;
AddDelegatesToDictionary(param, module);
// Ensure a delegate used for a virtual method and a type is public
if (existingDelegate.Access == AccessSpecifier.Private &&
access == AccessSpecifier.Public)
existingDelegate.Access = access;
// Check if there is an existing delegate with a different calling convention
if (((FunctionType) existingDelegate.Type.GetPointee()).CallingConvention ==
newFunctionType.CallingConvention)
return existingDelegate;
// Add a new delegate with the calling convention appended to its name
delegateName += newFunctionType.CallingConvention;
}
var namespaceDelegates = GetDeclContextForDelegates(((Declaration) decl).Namespace);
var delegateType = new QualifiedType(new PointerType(new QualifiedType(newFunctionType)));
existingDelegate = new TypedefDecl
{
Access = access,
Name = delegateName,
Namespace = namespaceDelegates,
QualifiedType = delegateType,
IsSynthetized = true
};
delegates.Add(existingDelegate);
return existingDelegate;
}
public override bool VisitFunctionDecl(Function function)
private FunctionType GetNewFunctionType(ITypedDecl decl, QualifiedType type)
{
if (!base.VisitFunctionDecl(function) || function.Ignore)
return false;
var functionType = new FunctionType();
var method = decl as Method;
if (method != null && method.FunctionType == type)
{
functionType.Parameters.AddRange(
method.GatherInternalParams(Context.ParserOptions.IsItaniumLikeAbi, true));
functionType.CallingConvention = method.CallingConvention;
functionType.IsDependent = method.IsDependent;
functionType.ReturnType = method.ReturnType;
}
else
{
var funcTypeParam = (FunctionType) decl.Type.Desugar().GetFinalPointee().Desugar();
functionType = new FunctionType(funcTypeParam);
}
// 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);
for (int i = 0; i < functionType.Parameters.Count; i++)
functionType.Parameters[i].Name = $"_{i}";
return true;
return functionType;
}
public override bool VisitMethodDecl(Method method)
private DeclarationContext GetDeclContextForDelegates(DeclarationContext @namespace)
{
if (!base.VisitMethodDecl(method) || !method.IsVirtual || method.Ignore)
return false;
var module = method.TranslationUnit.Module;
AddDelegatesToDictionary(method, module);
if (Options.IsCLIGenerator)
return @namespace is Function ? @namespace.Namespace : @namespace;
return true;
}
private DelegateDefinition GetExistingDelegate(Module module, string delegateString)
{
if (module.Libraries.Count == 0)
return Context.Delegates.Values.FirstOrDefault(t => t.Signature == delegateString);
var module = @namespace.TranslationUnit.Module;
if (namespacesDelegates.ContainsKey(module))
return namespacesDelegates[module];
DelegateDefinition @delegate = null;
if (new[] { module }.Union(module.Dependencies).Any(
m => libsDelegates.ContainsKey(m) && libsDelegates[m].TryGetValue(
delegateString, out @delegate)))
return @delegate;
Namespace parent = null;
if (string.IsNullOrEmpty(module.OutputNamespace))
{
var groups = module.Units.SelectMany(u => u.Declarations).OfType<Namespace>(
).GroupBy(d => d.Name).Where(g => g.Any(d => d.HasDeclarations)).ToList();
if (groups.Count == 1)
parent = groups.Last().Last();
}
if (parent == null)
parent = module.Units.Last();
return null;
var namespaceDelegates = new Namespace
{
Name = "Delegates",
Namespace = parent
};
namespacesDelegates.Add(module, namespaceDelegates);
return namespaceDelegates;
}
private string GenerateDelegateSignature(IEnumerable<Parameter> @params, QualifiedType returnType)
private string GetDelegateName(FunctionType functionType)
{
var typesBuilder = new StringBuilder();
if (!returnType.Type.IsPrimitiveType(PrimitiveType.Void))
if (!functionType.ReturnType.Type.IsPrimitiveType(PrimitiveType.Void))
{
typesBuilder.Insert(0, returnType.Visit(TypePrinter));
typesBuilder.Insert(0, functionType.ReturnType.Visit(TypePrinter));
typesBuilder.Append('_');
}
foreach (var parameter in @params)
foreach (var parameter in functionType.Parameters)
{
typesBuilder.Append(parameter.Visit(TypePrinter));
typesBuilder.Append('_');
}
if (typesBuilder.Length > 0)
typesBuilder.Remove(typesBuilder.Length - 1, 1);
var delegateName = FormatTypesStringForIdentifier(typesBuilder);
if (returnType.Type.IsPrimitiveType(PrimitiveType.Void))
if (functionType.ReturnType.Type.IsPrimitiveType(PrimitiveType.Void))
delegateName.Insert(0, "Action_");
else
delegateName.Insert(0, "Func_");
@ -239,9 +239,13 @@ namespace CppSharp.Passes @@ -239,9 +239,13 @@ namespace CppSharp.Passes
}
}
private Dictionary<Module, Namespace> namespacesDelegates = new Dictionary<Module, Namespace>();
private Dictionary<Module, DeclarationContext> namespacesDelegates = new Dictionary<Module, DeclarationContext>();
private CSharpTypePrinter typePrinter;
private static readonly Dictionary<Module, Dictionary<string, DelegateDefinition>> libsDelegates =
new Dictionary<Module, Dictionary<string, DelegateDefinition>>();
/// <summary>
/// The generated typedefs. 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 List<TypedefDecl> delegates = new List<TypedefDecl>();
}
}

129
src/Generator/Passes/GenerateAnonymousDelegatesPass.cs

@ -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();
}
}
}

6
tests/CSharp/CSharp.cpp

@ -1382,6 +1382,12 @@ int funcWithTypedefedFuncPtrAsParam(typedefedFuncPtr* func) @@ -1382,6 +1382,12 @@ int funcWithTypedefedFuncPtrAsParam(typedefedFuncPtr* func)
return func(a, b);
}
typedefedFuncPtr* TestDuplicateDelegate::testDuplicateDelegate(int a)
{
typedefedFuncPtr* func;
return func;
}
void InlineNamespace::FunctionInsideInlineNamespace()
{
}

6
tests/CSharp/CSharp.h

@ -1225,6 +1225,12 @@ void useStdStringJustAsParameter(std::string s); @@ -1225,6 +1225,12 @@ void useStdStringJustAsParameter(std::string s);
typedef int (typedefedFuncPtr)(Foo* a, Bar b);
int DLL_API funcWithTypedefedFuncPtrAsParam(typedefedFuncPtr* func);
class DLL_API TestDuplicateDelegate
{
public:
virtual typedefedFuncPtr* testDuplicateDelegate(int a);
};
inline namespace InlineNamespace
{

2
tests/Common/Common.Tests.cs

@ -556,7 +556,7 @@ public class CommonTests : GeneratorTestFixture @@ -556,7 +556,7 @@ public class CommonTests : GeneratorTestFixture
new TestDelegates().MarshalUnattributedDelegate(i => i);
}
[Test, Platform(Exclude = "Win", Reason = "This test crashes our Windows build, possibly a problem with the NUnit runner there.")]
[Test]
public void TestPassAnonymousDelegate()
{
var testDelegates = new TestDelegates();

Loading…
Cancel
Save