Browse Source

#1675: Fix converting static method to method group

pull/1726/head
Daniel Grunwald 6 years ago
parent
commit
b45f21e714
  1. 10
      ICSharpCode.Decompiler.Tests/TestCases/Ugly/NoExtensionMethods.Expected.cs
  2. 10
      ICSharpCode.Decompiler.Tests/TestCases/Ugly/NoExtensionMethods.cs
  3. 24
      ICSharpCode.Decompiler.Tests/TestCases/Ugly/NoExtensionMethods.opt.roslyn.il
  4. 36
      ICSharpCode.Decompiler.Tests/TestCases/Ugly/NoExtensionMethods.roslyn.il
  5. 30
      ICSharpCode.Decompiler/CSharp/CallBuilder.cs

10
ICSharpCode.Decompiler.Tests/TestCases/Ugly/NoExtensionMethods.Expected.cs

@ -19,5 +19,15 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Ugly @@ -19,5 +19,15 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Ugly
{
return value;
}
internal static Func<int, int> ExtensionMethodAsStaticFunc()
{
return Return;
}
internal static Func<object> ExtensionMethodBoundToNull()
{
return new Func<object>(null, __ldftn(Return));
}
}
}

10
ICSharpCode.Decompiler.Tests/TestCases/Ugly/NoExtensionMethods.cs

@ -13,5 +13,15 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Ugly @@ -13,5 +13,15 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Ugly
{
return value;
}
internal static Func<int, int> ExtensionMethodAsStaticFunc()
{
return Return;
}
internal static Func<object> ExtensionMethodBoundToNull()
{
return ((object)null).Return;
}
}
}

24
ICSharpCode.Decompiler.Tests/TestCases/Ugly/NoExtensionMethods.opt.roslyn.il

@ -61,6 +61,30 @@ @@ -61,6 +61,30 @@
IL_0001: ret
} // end of method NoExtensionMethods::Return
.method assembly hidebysig static class [mscorlib]System.Func`2<int32,int32>
ExtensionMethodAsStaticFunc() cil managed
{
// Code size 13 (0xd)
.maxstack 8
IL_0000: ldnull
IL_0001: ldftn !!0 ICSharpCode.Decompiler.Tests.TestCases.Ugly.NoExtensionMethods::Return<int32>(!!0)
IL_0007: newobj instance void class [mscorlib]System.Func`2<int32,int32>::.ctor(object,
native int)
IL_000c: ret
} // end of method NoExtensionMethods::ExtensionMethodAsStaticFunc
.method assembly hidebysig static class [mscorlib]System.Func`1<object>
ExtensionMethodBoundToNull() cil managed
{
// Code size 13 (0xd)
.maxstack 8
IL_0000: ldnull
IL_0001: ldftn !!0 ICSharpCode.Decompiler.Tests.TestCases.Ugly.NoExtensionMethods::Return<object>(!!0)
IL_0007: newobj instance void class [mscorlib]System.Func`1<object>::.ctor(object,
native int)
IL_000c: ret
} // end of method NoExtensionMethods::ExtensionMethodBoundToNull
} // end of class ICSharpCode.Decompiler.Tests.TestCases.Ugly.NoExtensionMethods

36
ICSharpCode.Decompiler.Tests/TestCases/Ugly/NoExtensionMethods.roslyn.il

@ -73,6 +73,42 @@ @@ -73,6 +73,42 @@
IL_0006: ret
} // end of method NoExtensionMethods::Return
.method assembly hidebysig static class [mscorlib]System.Func`2<int32,int32>
ExtensionMethodAsStaticFunc() cil managed
{
// Code size 18 (0x12)
.maxstack 2
.locals init (class [mscorlib]System.Func`2<int32,int32> V_0)
IL_0000: nop
IL_0001: ldnull
IL_0002: ldftn !!0 ICSharpCode.Decompiler.Tests.TestCases.Ugly.NoExtensionMethods::Return<int32>(!!0)
IL_0008: newobj instance void class [mscorlib]System.Func`2<int32,int32>::.ctor(object,
native int)
IL_000d: stloc.0
IL_000e: br.s IL_0010
IL_0010: ldloc.0
IL_0011: ret
} // end of method NoExtensionMethods::ExtensionMethodAsStaticFunc
.method assembly hidebysig static class [mscorlib]System.Func`1<object>
ExtensionMethodBoundToNull() cil managed
{
// Code size 18 (0x12)
.maxstack 2
.locals init (class [mscorlib]System.Func`1<object> V_0)
IL_0000: nop
IL_0001: ldnull
IL_0002: ldftn !!0 ICSharpCode.Decompiler.Tests.TestCases.Ugly.NoExtensionMethods::Return<object>(!!0)
IL_0008: newobj instance void class [mscorlib]System.Func`1<object>::.ctor(object,
native int)
IL_000d: stloc.0
IL_000e: br.s IL_0010
IL_0010: ldloc.0
IL_0011: ret
} // end of method NoExtensionMethods::ExtensionMethodBoundToNull
} // end of class ICSharpCode.Decompiler.Tests.TestCases.Ugly.NoExtensionMethods

30
ICSharpCode.Decompiler/CSharp/CallBuilder.cs

@ -1235,12 +1235,38 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1235,12 +1235,38 @@ namespace ICSharpCode.Decompiler.CSharp
default:
throw new ArgumentException($"Unknown instruction type: {func.OpCode}");
}
if (method.IsStatic && !method.IsExtensionMethod) {
if (CanUseDelegateConstruction(method, thisArg, inst.Method.DeclaringType.GetDelegateInvokeMethod())) {
return HandleDelegateConstruction(inst.Method.DeclaringType, method, expectedTargetDetails, thisArg, inst);
} else {
var argumentList = BuildArgumentList(expectedTargetDetails, null, inst.Method,
0, inst.Arguments, null);
return HandleConstructorCall(new ExpectedTargetDetails { CallOpCode = OpCode.NewObj }, null, inst.Method, argumentList).WithILInstruction(inst);
}
return HandleDelegateConstruction(inst.Method.DeclaringType, method, expectedTargetDetails, thisArg, inst);
}
private bool CanUseDelegateConstruction(IMethod targetMethod, ILInstruction thisArg, IMethod invokeMethod)
{
if (targetMethod.IsStatic) {
// If the invoke method is known, we can compare the parameter counts to figure out whether the
// delegate is static or binds the first argument
if (invokeMethod != null) {
if (invokeMethod.Parameters.Count == targetMethod.Parameters.Count) {
return thisArg.MatchLdNull();
} else if (targetMethod.IsExtensionMethod && invokeMethod.Parameters.Count == targetMethod.Parameters.Count - 1) {
return true;
} else {
return false;
}
} else {
// delegate type unknown:
return thisArg.MatchLdNull() || targetMethod.IsExtensionMethod;
}
} else {
// targetMethod is instance method
if (invokeMethod != null && invokeMethod.Parameters.Count != targetMethod.Parameters.Count)
return false;
return true;
}
}
internal TranslatedExpression Build(LdVirtDelegate inst)

Loading…
Cancel
Save