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. 272
      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}";

272
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)
{
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
public override bool VisitMethodDecl(Method method)
{
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];
return true;
}
else
{
Namespace parent = null;
if (string.IsNullOrEmpty(module.OutputNamespace))
public override bool VisitFunctionDecl(Function function)
{
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 (!base.VisitFunctionDecl(function) || function.Ignore)
return false;
function.ReturnType = CheckForDelegate(function.ReturnType, function);
return true;
}
if (parent == null)
parent = module.Units.Last();
namespaceDelegates = new Namespace
public override bool VisitParameterDecl(Parameter parameter)
{
Name = DelegatesNamespace,
Namespace = parent
};
namespacesDelegates.Add(module, namespaceDelegates);
if (!base.VisitParameterDecl(parameter) || parameter.Namespace == null ||
parameter.Namespace.Ignore)
return false;
parameter.QualifiedType = CheckForDelegate(parameter.QualifiedType, parameter);
return true;
}
var functionType = new FunctionType
private QualifiedType CheckForDelegate(QualifiedType type, ITypedDecl decl)
{
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
};
if (type.Type is TypedefType)
return type;
var desugared = type.Type.Desugar();
if (desugared.IsDependent)
return type;
var delegateString = @delegate.Visit(TypePrinter).Type;
var existingDelegate = GetExistingDelegate(
module, delegateString);
Type pointee = desugared.GetPointee() ?? desugared;
if (pointee is TypedefType)
return type;
var functionType = pointee.Desugar() as FunctionType;
if (functionType == null)
return type;
TypedefDecl @delegate = GetDelegate(type, decl);
return new QualifiedType(new TypedefType { Declaration = @delegate });
}
private TypedefDecl GetDelegate(QualifiedType type, ITypedDecl decl)
{
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)
{
Context.Delegates.Add(decl, existingDelegate);
return;
}
// Ensure a delegate used for a virtual method and a type is public
if (existingDelegate.Access == AccessSpecifier.Private &&
access == AccessSpecifier.Public)
existingDelegate.Access = access;
existingDelegate = new DelegateDefinition(module.OutputNamespace, delegateString);
Context.Delegates.Add(decl, existingDelegate);
// Check if there is an existing delegate with a different calling convention
if (((FunctionType) existingDelegate.Type.GetPointee()).CallingConvention ==
newFunctionType.CallingConvention)
return existingDelegate;
libsDelegates[module].Add(delegateString, 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);
namespaceDelegates.Declarations.Add(@delegate);
return existingDelegate;
}
private void VisitFunctionTypeParameters(Function function)
private FunctionType GetNewFunctionType(ITypedDecl decl, QualifiedType type)
{
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)
var functionType = new FunctionType();
var method = decl as Method;
if (method != null && method.FunctionType == type)
{
var module = function.TranslationUnit.Module;
AddDelegatesToDictionary(param, module);
functionType.Parameters.AddRange(
method.GatherInternalParams(Context.ParserOptions.IsItaniumLikeAbi, true));
functionType.CallingConvention = method.CallingConvention;
functionType.IsDependent = method.IsDependent;
functionType.ReturnType = method.ReturnType;
}
}
public override bool VisitFunctionDecl(Function function)
else
{
if (!base.VisitFunctionDecl(function) || function.Ignore)
return false;
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;
if (Options.IsCLIGenerator)
return @namespace is Function ? @namespace.Namespace : @namespace;
var module = method.TranslationUnit.Module;
AddDelegatesToDictionary(method, module);
var module = @namespace.TranslationUnit.Module;
if (namespacesDelegates.ContainsKey(module))
return namespacesDelegates[module];
return true;
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();
}
private DelegateDefinition GetExistingDelegate(Module module, string delegateString)
{
if (module.Libraries.Count == 0)
return Context.Delegates.Values.FirstOrDefault(t => t.Signature == delegateString);
if (parent == null)
parent = module.Units.Last();
DelegateDefinition @delegate = null;
if (new[] { module }.Union(module.Dependencies).Any(
m => libsDelegates.ContainsKey(m) && libsDelegates[m].TryGetValue(
delegateString, out @delegate)))
return @delegate;
var namespaceDelegates = new Namespace
{
Name = "Delegates",
Namespace = parent
};
namespacesDelegates.Add(module, namespaceDelegates);
return null;
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