Skip to content

Commit 5bfb99d

Browse files
authored
Merge pull request #12 from samblackburn/delegate-signatures
Support for delegates with different method signatures
2 parents 59fd077 + 1a01a42 commit 5bfb99d

3 files changed

Lines changed: 27 additions & 9 deletions

File tree

NetDoc/Call.cs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,20 @@ namespace NetDoc
1010
public class Call
1111
{
1212
private readonly MemberReference m_Operand;
13+
private readonly MethodReference? m_Delegate;
1314
private IEnumerable<string> ReferencedDlls { get; }
1415

1516
public Call(Instruction instruction, IEnumerable<string> referencedDlls)
1617
{
1718
ReferencedDlls = referencedDlls;
1819
m_Operand = (MemberReference) instruction.Operand;
19-
if (instruction.OpCode == OpCodes.Ldfld || instruction.OpCode == OpCodes.Stfld)
20+
if (instruction.OpCode == OpCodes.Newobj &&
21+
MethodReference?.Parameters.Select(x => x.ParameterType.Name).SequenceEqual([nameof(Object), nameof(IntPtr)]) == true &&
22+
instruction.Previous.OpCode == OpCodes.Ldftn)
23+
{
24+
m_Delegate = (MethodReference)instruction.Previous.Operand;
25+
}
26+
else if (instruction.OpCode == OpCodes.Ldfld || instruction.OpCode == OpCodes.Stfld)
2027
{
2128
IsStatic = false;
2229
}
@@ -85,10 +92,13 @@ private string BuildInvocation()
8592

8693
if (m_Operand.Name == ".ctor")
8794
{
88-
if (parameterDefs.Select(x => x.Name).SequenceEqual(["object", "method"]))
95+
if (m_Delegate != null)
8996
{
90-
// not sure how to infer the delegate signature
91-
return AssignToRandomVariable(MethodReference.DeclaringType, "_ => default");
97+
var args = string.Join(", ", m_Delegate.Parameters.Select((p, i) => $"{GetTypeName(p.ParameterType)} arg{i}"));
98+
var expression = m_Delegate.ReturnType.FullName == "System.Void"
99+
? "{}"
100+
: CallToFactory(m_Delegate.ReturnType);
101+
return AssignToRandomVariable(MethodReference.DeclaringType, $"({args}) => {expression}");
92102
}
93103

94104
return AssignToRandomVariable(MethodReference.DeclaringType, $"new {TypeWithGenerics}({parameters})");

Tests/DelegatesTests.cs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,23 +10,31 @@ internal class DelegatesTests : TestMethods
1010
public void DelegateWithOneArgument()
1111
{
1212
var referenced = "public delegate bool MyDelegate(int i);";
13-
var referencing = Class("MyDelegate MakeDelegate() => i => i > 3;", "ReferencingClass");
13+
var referencing = Class("MyDelegate MakeDelegate() => Foo; bool Foo(int i) => i > 3;", "ReferencingClass");
1414
ContractAssertionShouldCompile(referencing, referenced);
1515
}
1616

17-
[Test, Ignore("Not sure how to infer the delegate's signature")]
17+
[Test]
1818
public void DelegateWithTwoArguments()
1919
{
2020
var referenced = "public delegate bool MyDelegate(int i, int j);";
2121
var referencing = Class("MyDelegate MakeDelegate() => (i, j) => i > j;", "ReferencingClass");
2222
ContractAssertionShouldCompile(referencing, referenced);
2323
}
2424

25-
[Test, Ignore("Not sure how to infer the delegate's signature")]
25+
[Test]
2626
public void VoidDelegate()
2727
{
2828
var referenced = "public delegate void MyDelegate(int i);";
2929
var referencing = Class("MyDelegate MakeDelegate() => i => {};", "ReferencingClass");
3030
ContractAssertionShouldCompile(referencing, referenced);
3131
}
32+
33+
[Test]
34+
public void ReusedDelegate()
35+
{
36+
var referenced = "public delegate bool MyDelegate(int i);";
37+
var referencing = Class("MyDelegate[] MakeDelegates() => new MyDelegate[] {Foo, Foo}; bool Foo(int i) => i > 3;", "ReferencingClass");
38+
ContractAssertionShouldCompile(referencing, referenced);
39+
}
3240
}

Tests/TestFramework/ClrAssemblyCompiler.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,8 @@ private static string GetReferenceAssemblyPath(NetFrameworkVersion frameworkVers
4747
var packageDir = new DirectoryInfo(Path.Combine(PackagesFolder, "microsoft.netframework.referenceassemblies." + moniker));
4848
Assert.That(packageDir.Exists, $"Directory {packageDir.FullName} does not exist");
4949
var versions = packageDir.GetDirectories();
50-
Assert.That(versions.Length, Is.EqualTo(1), $"Directory {packageDir.FullName} does not contain exactly one version");
51-
var referenceDir = new DirectoryInfo(Path.Combine(versions.Single().FullName, "build", ".NETFramework", version));
50+
Assert.That(versions.Length, Is.GreaterThanOrEqualTo(1), $"Directory {packageDir.FullName} does not contain exactly one version");
51+
var referenceDir = new DirectoryInfo(Path.Combine(versions.First().FullName, "build", ".NETFramework", version));
5252
Assert.That(referenceDir.Exists, $"Directory {referenceDir.FullName} does not exist");
5353

5454
return referenceDir.FullName;

0 commit comments

Comments
 (0)