Browse Source

Fix the anonymous delegates pass so it doesn't generate duplicate delegates when the same namespace is used in multiple translation units.

pull/440/head
Chris Spencer 10 years ago
parent
commit
e3a88f9136
  1. 44
      src/Generator/Passes/GenerateAnonymousDelegatesPass.cs
  2. 8
      tests/Basic/AnotherUnit.cpp
  3. 12
      tests/Basic/AnotherUnit.h
  4. 6
      tests/Basic/Basic.Tests.cs
  5. 8
      tests/Basic/Basic.cpp
  6. 7
      tests/Basic/Basic.cs
  7. 10
      tests/Basic/Basic.h

44
src/Generator/Passes/GenerateAnonymousDelegatesPass.cs

@ -14,19 +14,29 @@ namespace CppSharp.Passes @@ -14,19 +14,29 @@ namespace CppSharp.Passes
/// </summary>
public class GenerateAnonymousDelegatesPass : TranslationUnitPass
{
private struct Typedef
{
public DeclarationContext Context;
public TypedefDecl Declaration;
}
/// <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.
/// 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<DeclarationContext, List<TypedefDecl>> allTypedefs =
new Dictionary<DeclarationContext, List<TypedefDecl>>();
private readonly Dictionary<string, List<Typedef>> allTypedefs = new Dictionary<string, List<Typedef>>();
public override bool VisitTranslationUnit(TranslationUnit unit)
public override bool VisitLibrary(ASTContext context)
{
bool result = base.VisitTranslationUnit(unit);
bool result = base.VisitLibrary(context);
foreach (var typedef in allTypedefs)
typedef.Key.Declarations.AddRange(typedef.Value);
{
foreach (var foo in typedef.Value)
{
foo.Context.Declarations.Add(foo.Declaration);
}
}
allTypedefs.Clear();
return result;
@ -61,11 +71,11 @@ namespace CppSharp.Passes @@ -61,11 +71,11 @@ namespace CppSharp.Passes
if (functionType == null)
return type;
List<TypedefDecl> typedefs;
if (!allTypedefs.TryGetValue(@namespace, out typedefs))
List<Typedef> typedefs;
if (!allTypedefs.TryGetValue(@namespace.QualifiedName, out typedefs))
{
typedefs = new List<TypedefDecl>();
allTypedefs.Add(@namespace, typedefs);
typedefs = new List<Typedef>();
allTypedefs.Add(@namespace.QualifiedName, typedefs);
}
var typedef = FindMatchingTypedef(typedefs, functionType);
@ -84,7 +94,11 @@ namespace CppSharp.Passes @@ -84,7 +94,11 @@ namespace CppSharp.Passes
QualifiedType = type,
IsSynthetized = true
};
typedefs.Add(typedef);
typedefs.Add(new Typedef
{
Context = @namespace,
Declaration = typedef
});
}
var typedefType = new TypedefType
@ -100,13 +114,13 @@ namespace CppSharp.Passes @@ -100,13 +114,13 @@ namespace CppSharp.Passes
/// <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 TypedefDecl FindMatchingTypedef(List<TypedefDecl> typedefs, FunctionType functionType)
private TypedefDecl FindMatchingTypedef(List<Typedef> typedefs, FunctionType functionType)
{
return (from typedef in typedefs
let type = (FunctionType)typedef.Type.GetPointee()
let type = (FunctionType)typedef.Declaration.Type.GetPointee()
where type.ReturnType == functionType.ReturnType &&
type.Parameters.SequenceEqual(functionType.Parameters, new ParameterTypeComparer())
select typedef).SingleOrDefault();
select typedef.Declaration).SingleOrDefault();
}
}
}

8
tests/Basic/AnotherUnit.cpp

@ -1 +1,9 @@ @@ -1 +1,9 @@
#include "AnotherUnit.h"
void DelegateNamespace::Nested::f3(void (*)())
{
}
void DelegateNamespace::f4(void (*)())
{
}

12
tests/Basic/AnotherUnit.h

@ -1,3 +1,15 @@ @@ -1,3 +1,15 @@
#include "../Tests.h"
// Verifies the header is included when the delegate is defined in a different file
typedef void (*DelegateInAnotherUnit)();
// Tests automatic generation of anonymous delegates in different translation units
namespace DelegateNamespace
{
namespace Nested
{
void DLL_API f3(void (*)());
}
void DLL_API f4(void (*)());
}

6
tests/Basic/Basic.Tests.cs

@ -1,8 +1,8 @@ @@ -1,8 +1,8 @@
using System;
using CppSharp.Utils;
using NUnit.Framework;
using Basic;
using Enum = Basic.Enum;
using BasicTest;
using Enum = BasicTest.Enum;
public class BasicTests : GeneratorTestFixture
{
@ -349,7 +349,7 @@ public class BasicTests : GeneratorTestFixture @@ -349,7 +349,7 @@ public class BasicTests : GeneratorTestFixture
[Test]
public void TestFunctions()
{
var ret = Basic.basic.Function();
var ret = BasicTest.basic.Function();
Assert.That(ret, Is.EqualTo(5));
}

8
tests/Basic/Basic.cpp

@ -346,10 +346,18 @@ int (*TestDelegates::MarshalAnonymousDelegate4())(int n) @@ -346,10 +346,18 @@ int (*TestDelegates::MarshalAnonymousDelegate4())(int n)
return f;
}
void DelegateNamespace::Nested::f1(void (*)())
{
}
void TestDelegates::MarshalDelegateInAnotherUnit(DelegateInAnotherUnit del)
{
}
void DelegateNamespace::f2(void (*)())
{
}
std::string HasStdString::testStdString(std::string s)
{
return s + "_test";

7
tests/Basic/Basic.cs

@ -13,6 +13,13 @@ namespace CppSharp.Tests @@ -13,6 +13,13 @@ namespace CppSharp.Tests
}
public override void Setup(Driver driver)
{
base.Setup(driver);
driver.Options.OutputNamespace = "BasicTest";
}
public override void SetupPasses(Driver driver)
{
if (driver.Options.IsCSharpGenerator)

10
tests/Basic/Basic.h

@ -326,6 +326,16 @@ TestDelegates::TestDelegates() : A(Double), B(Double), C(&TestDelegates::Triple) @@ -326,6 +326,16 @@ TestDelegates::TestDelegates() : A(Double), B(Double), C(&TestDelegates::Triple)
{
}
namespace DelegateNamespace
{
namespace Nested
{
void DLL_API f1(void (*)());
}
void DLL_API f2(void (*)());
}
// Tests memory leaks in constructors
// C#: Marshal.FreeHGlobal(arg0);
struct DLL_API TestMemoryLeaks

Loading…
Cancel
Save