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 11 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
/// </summary> /// </summary>
public class GenerateAnonymousDelegatesPass : TranslationUnitPass public class GenerateAnonymousDelegatesPass : TranslationUnitPass
{ {
private struct Typedef
{
public DeclarationContext Context;
public TypedefDecl Declaration;
}
/// <summary> /// <summary>
/// The generated typedefs. The tree can't be modified while iterating over it, so we collect all the typedefs /// The generated typedefs keyed by the qualified declaration context name. The tree can't be modified while
/// and add them at the end. /// iterating over it, so we collect all the typedefs and add them at the end.
/// </summary> /// </summary>
private readonly Dictionary<DeclarationContext, List<TypedefDecl>> allTypedefs = private readonly Dictionary<string, List<Typedef>> allTypedefs = new Dictionary<string, List<Typedef>>();
new Dictionary<DeclarationContext, List<TypedefDecl>>();
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) 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(); allTypedefs.Clear();
return result; return result;
@ -61,11 +71,11 @@ namespace CppSharp.Passes
if (functionType == null) if (functionType == null)
return type; return type;
List<TypedefDecl> typedefs; List<Typedef> typedefs;
if (!allTypedefs.TryGetValue(@namespace, out typedefs)) if (!allTypedefs.TryGetValue(@namespace.QualifiedName, out typedefs))
{ {
typedefs = new List<TypedefDecl>(); typedefs = new List<Typedef>();
allTypedefs.Add(@namespace, typedefs); allTypedefs.Add(@namespace.QualifiedName, typedefs);
} }
var typedef = FindMatchingTypedef(typedefs, functionType); var typedef = FindMatchingTypedef(typedefs, functionType);
@ -84,7 +94,11 @@ namespace CppSharp.Passes
QualifiedType = type, QualifiedType = type,
IsSynthetized = true IsSynthetized = true
}; };
typedefs.Add(typedef); typedefs.Add(new Typedef
{
Context = @namespace,
Declaration = typedef
});
} }
var typedefType = new TypedefType var typedefType = new TypedefType
@ -100,13 +114,13 @@ namespace CppSharp.Passes
/// <param name="typedefs">The typedef list to search.</param> /// <param name="typedefs">The typedef list to search.</param>
/// <param name="functionType">The function to match.</param> /// <param name="functionType">The function to match.</param>
/// <returns>The matching typedef, or null if not found.</returns> /// <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 return (from typedef in typedefs
let type = (FunctionType)typedef.Type.GetPointee() let type = (FunctionType)typedef.Declaration.Type.GetPointee()
where type.ReturnType == functionType.ReturnType && where type.ReturnType == functionType.ReturnType &&
type.Parameters.SequenceEqual(functionType.Parameters, new ParameterTypeComparer()) type.Parameters.SequenceEqual(functionType.Parameters, new ParameterTypeComparer())
select typedef).SingleOrDefault(); select typedef.Declaration).SingleOrDefault();
} }
} }
} }

8
tests/Basic/AnotherUnit.cpp

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

12
tests/Basic/AnotherUnit.h

@ -1,3 +1,15 @@
#include "../Tests.h" #include "../Tests.h"
// Verifies the header is included when the delegate is defined in a different file
typedef void (*DelegateInAnotherUnit)(); 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 @@
using System; using System;
using CppSharp.Utils; using CppSharp.Utils;
using NUnit.Framework; using NUnit.Framework;
using Basic; using BasicTest;
using Enum = Basic.Enum; using Enum = BasicTest.Enum;
public class BasicTests : GeneratorTestFixture public class BasicTests : GeneratorTestFixture
{ {
@ -349,7 +349,7 @@ public class BasicTests : GeneratorTestFixture
[Test] [Test]
public void TestFunctions() public void TestFunctions()
{ {
var ret = Basic.basic.Function(); var ret = BasicTest.basic.Function();
Assert.That(ret, Is.EqualTo(5)); Assert.That(ret, Is.EqualTo(5));
} }

8
tests/Basic/Basic.cpp

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

7
tests/Basic/Basic.cs

@ -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) public override void SetupPasses(Driver driver)
{ {
if (driver.Options.IsCSharpGenerator) if (driver.Options.IsCSharpGenerator)

10
tests/Basic/Basic.h

@ -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 // Tests memory leaks in constructors
// C#: Marshal.FreeHGlobal(arg0); // C#: Marshal.FreeHGlobal(arg0);
struct DLL_API TestMemoryLeaks struct DLL_API TestMemoryLeaks

Loading…
Cancel
Save