Browse Source

Fix #1675: Emit __ldftn/__ldvirtftn pseudo expressions, if delegate construction is not supported.

pull/1725/head
Siegfried Pammer 6 years ago
parent
commit
9fff0438c0
  1. 2
      ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj
  2. 23
      ICSharpCode.Decompiler.Tests/TestCases/Ugly/NoExtensionMethods.Expected.cs
  3. 17
      ICSharpCode.Decompiler.Tests/TestCases/Ugly/NoExtensionMethods.cs
  4. 69
      ICSharpCode.Decompiler.Tests/TestCases/Ugly/NoExtensionMethods.opt.roslyn.il
  5. 81
      ICSharpCode.Decompiler.Tests/TestCases/Ugly/NoExtensionMethods.roslyn.il
  6. 8
      ICSharpCode.Decompiler.Tests/UglyTestRunner.cs
  7. 32
      ICSharpCode.Decompiler/CSharp/CallBuilder.cs
  8. 16
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

2
ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj

@ -82,6 +82,8 @@ @@ -82,6 +82,8 @@
<Compile Include="TestCases\ILPretty\ConstantBlobs.cs" />
<Compile Include="TestCases\Pretty\OutVariables.cs" />
<Compile Include="TestCases\Pretty\CustomTaskType.cs" />
<None Include="TestCases\Ugly\NoExtensionMethods.Expected.cs" />
<Compile Include="TestCases\Ugly\NoExtensionMethods.cs" />
<None Include="TestCases\VBPretty\VBCompoundAssign.cs" />
<Compile Include="TestCases\Pretty\ThrowExpressions.cs" />
<None Include="TestCases\ILPretty\Issue1145.cs" />

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

@ -0,0 +1,23 @@ @@ -0,0 +1,23 @@
using System;
using System.Runtime.CompilerServices;
[assembly: Extension]
namespace ICSharpCode.Decompiler.Tests.TestCases.Ugly
{
[Extension]
internal static class NoExtensionMethods
{
[Extension]
internal static Func<T> AsFunc<T>(T value) where T : class
{
return new Func<T>(value, __ldftn(Return));
}
[Extension]
private static T Return<T>(T value)
{
return value;
}
}
}

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

@ -0,0 +1,17 @@ @@ -0,0 +1,17 @@
using System;
namespace ICSharpCode.Decompiler.Tests.TestCases.Ugly
{
internal static class NoExtensionMethods
{
internal static Func<T> AsFunc<T>(this T value) where T : class
{
return new Func<T>(value.Return);
}
private static T Return<T>(this T value)
{
return value;
}
}
}

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

@ -0,0 +1,69 @@ @@ -0,0 +1,69 @@
// Metadata version: v4.0.30319
.assembly extern mscorlib
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0
}
.assembly NoExtensionMethods
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 )
.custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx
63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 ) // ceptionThrows.
// --- The following custom attribute is added automatically, do not uncomment -------
// .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 02 00 00 00 00 00 )
.permissionset reqmin
= {[mscorlib]System.Security.Permissions.SecurityPermissionAttribute = {property bool 'SkipVerification' = bool(true)}}
.hash algorithm 0x00008004
.ver 0:0:0:0
}
.module NoExtensionMethods.dll
.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 )
.imagebase 0x10000000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
// =============== CLASS MEMBERS DECLARATION ===================
.class private abstract auto ansi sealed beforefieldinit ICSharpCode.Decompiler.Tests.TestCases.Ugly.NoExtensionMethods
extends [mscorlib]System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.method assembly hidebysig static class [mscorlib]System.Func`1<!!T>
AsFunc<class T>(!!T 'value') cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
// Code size 18 (0x12)
.maxstack 8
IL_0000: ldarg.0
IL_0001: box !!T
IL_0006: ldftn !!0 ICSharpCode.Decompiler.Tests.TestCases.Ugly.NoExtensionMethods::Return<!!0>(!!0)
IL_000c: newobj instance void class [mscorlib]System.Func`1<!!T>::.ctor(object,
native int)
IL_0011: ret
} // end of method NoExtensionMethods::AsFunc
.method private hidebysig static !!T Return<T>(!!T 'value') cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
// Code size 2 (0x2)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ret
} // end of method NoExtensionMethods::Return
} // end of class ICSharpCode.Decompiler.Tests.TestCases.Ugly.NoExtensionMethods
// =============================================================
// *********** DISASSEMBLY COMPLETE ***********************

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

@ -0,0 +1,81 @@ @@ -0,0 +1,81 @@
// Metadata version: v4.0.30319
.assembly extern mscorlib
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0
}
.assembly NoExtensionMethods
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 )
.custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx
63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 ) // ceptionThrows.
// --- The following custom attribute is added automatically, do not uncomment -------
// .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 07 01 00 00 00 00 )
.permissionset reqmin
= {[mscorlib]System.Security.Permissions.SecurityPermissionAttribute = {property bool 'SkipVerification' = bool(true)}}
.hash algorithm 0x00008004
.ver 0:0:0:0
}
.module NoExtensionMethods.dll
.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 )
.imagebase 0x10000000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
// =============== CLASS MEMBERS DECLARATION ===================
.class private abstract auto ansi sealed beforefieldinit ICSharpCode.Decompiler.Tests.TestCases.Ugly.NoExtensionMethods
extends [mscorlib]System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.method assembly hidebysig static class [mscorlib]System.Func`1<!!T>
AsFunc<class T>(!!T 'value') cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
// Code size 23 (0x17)
.maxstack 2
.locals init (class [mscorlib]System.Func`1<!!T> V_0)
IL_0000: nop
IL_0001: ldarg.0
IL_0002: box !!T
IL_0007: ldftn !!0 ICSharpCode.Decompiler.Tests.TestCases.Ugly.NoExtensionMethods::Return<!!0>(!!0)
IL_000d: newobj instance void class [mscorlib]System.Func`1<!!T>::.ctor(object,
native int)
IL_0012: stloc.0
IL_0013: br.s IL_0015
IL_0015: ldloc.0
IL_0016: ret
} // end of method NoExtensionMethods::AsFunc
.method private hidebysig static !!T Return<T>(!!T 'value') cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
// Code size 7 (0x7)
.maxstack 1
.locals init (!!T V_0)
IL_0000: nop
IL_0001: ldarg.0
IL_0002: stloc.0
IL_0003: br.s IL_0005
IL_0005: ldloc.0
IL_0006: ret
} // end of method NoExtensionMethods::Return
} // end of class ICSharpCode.Decompiler.Tests.TestCases.Ugly.NoExtensionMethods
// =============================================================
// *********** DISASSEMBLY COMPLETE ***********************

8
ICSharpCode.Decompiler.Tests/UglyTestRunner.cs

@ -83,6 +83,14 @@ namespace ICSharpCode.Decompiler.Tests @@ -83,6 +83,14 @@ namespace ICSharpCode.Decompiler.Tests
});
}
[Test]
public void NoExtensionMethods([ValueSource("roslynOnlyOptions")] CompilerOptions cscOptions)
{
RunForLibrary(cscOptions: cscOptions, decompilerSettings: new DecompilerSettings {
ExtensionMethods = false
});
}
void RunForLibrary([CallerMemberName] string testName = null, AssemblerOptions asmOptions = AssemblerOptions.None, CompilerOptions cscOptions = CompilerOptions.None, DecompilerSettings decompilerSettings = null)
{
Run(testName, asmOptions | AssemblerOptions.Library, cscOptions | CompilerOptions.Library, decompilerSettings);

32
ICSharpCode.Decompiler/CSharp/CallBuilder.cs

@ -1235,6 +1235,11 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1235,6 +1235,11 @@ namespace ICSharpCode.Decompiler.CSharp
default:
throw new ArgumentException($"Unknown instruction type: {func.OpCode}");
}
if (method.IsStatic && !method.IsExtensionMethod) {
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);
}
@ -1243,9 +1248,15 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1243,9 +1248,15 @@ namespace ICSharpCode.Decompiler.CSharp
return HandleDelegateConstruction(inst.Type, inst.Method, new ExpectedTargetDetails { CallOpCode = OpCode.CallVirt }, inst.Argument, inst);
}
TranslatedExpression HandleDelegateConstruction(IType delegateType, IMethod method, ExpectedTargetDetails expectedTargetDetails, ILInstruction thisArg, ILInstruction inst)
internal ExpressionWithResolveResult BuildMethodReference(IMethod method, bool isVirtual)
{
var expr = BuildDelegateReference(method, invokeMethod: null, new ExpectedTargetDetails { CallOpCode = isVirtual ? OpCode.CallVirt : OpCode.Call }, thisArg: null);
expr.Expression.RemoveAnnotations<ResolveResult>();
return expr.Expression.WithRR(new MemberResolveResult(null, method));
}
ExpressionWithResolveResult BuildDelegateReference(IMethod method, IMethod invokeMethod, ExpectedTargetDetails expectedTargetDetails, ILInstruction thisArg)
{
var invokeMethod = delegateType.GetDelegateInvokeMethod();
TranslatedExpression target;
IType targetType;
bool requireTarget;
@ -1331,27 +1342,32 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1331,27 +1342,32 @@ namespace ICSharpCode.Decompiler.CSharp
}
}
requireTarget = !method.IsLocalFunction && (step & 1) != 0;
Expression targetExpression;
ExpressionWithResolveResult targetExpression;
Debug.Assert(result != null);
if (requireTarget) {
Debug.Assert(target.Expression != null);
var mre = new MemberReferenceExpression(target, methodName);
if ((step & 2) != 0)
mre.TypeArguments.AddRange(method.TypeArguments.Select(expressionBuilder.ConvertType));
mre.WithRR(result);
targetExpression = mre;
targetExpression = mre.WithRR(result);
} else {
var ide = new IdentifierExpression(methodName);
if ((step & 2) != 0)
ide.TypeArguments.AddRange(method.TypeArguments.Select(expressionBuilder.ConvertType));
ide.WithRR(result);
targetExpression = ide;
targetExpression = ide.WithRR(result);
}
return targetExpression;
}
TranslatedExpression HandleDelegateConstruction(IType delegateType, IMethod method, ExpectedTargetDetails expectedTargetDetails, ILInstruction thisArg, ILInstruction inst)
{
var invokeMethod = delegateType.GetDelegateInvokeMethod();
var targetExpression = BuildDelegateReference(method, invokeMethod, expectedTargetDetails, thisArg);
var oce = new ObjectCreateExpression(expressionBuilder.ConvertType(delegateType), targetExpression)
.WithILInstruction(inst)
.WithRR(new ConversionResolveResult(
delegateType,
result,
targetExpression.ResolveResult,
Conversion.MethodGroupConversion(method, expectedTargetDetails.CallOpCode == OpCode.CallVirt, false)));
return oce;
}

16
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -3134,6 +3134,22 @@ namespace ICSharpCode.Decompiler.CSharp @@ -3134,6 +3134,22 @@ namespace ICSharpCode.Decompiler.CSharp
.WithRR(new OperatorResolveResult(SpecialType.Dynamic, inst.Operation, new[] { target.ResolveResult, value.ResolveResult }));
}
protected internal override TranslatedExpression VisitLdFtn(LdFtn inst, TranslationContext context)
{
ExpressionWithResolveResult delegateRef = new CallBuilder(this, typeSystem, settings).BuildMethodReference(inst.Method, isVirtual: false);
return new InvocationExpression(new IdentifierExpression("__ldftn"), delegateRef)
.WithRR(new ResolveResult(compilation.FindType(KnownTypeCode.IntPtr)))
.WithILInstruction(inst);
}
protected internal override TranslatedExpression VisitLdVirtFtn(LdVirtFtn inst, TranslationContext context)
{
ExpressionWithResolveResult delegateRef = new CallBuilder(this, typeSystem, settings).BuildMethodReference(inst.Method, isVirtual: true);
return new InvocationExpression(new IdentifierExpression("__ldvirtftn"), delegateRef)
.WithRR(new ResolveResult(compilation.FindType(KnownTypeCode.IntPtr)))
.WithILInstruction(inst);
}
protected internal override TranslatedExpression VisitInvalidBranch(InvalidBranch inst, TranslationContext context)
{
string message = "Error";

Loading…
Cancel
Save