mirror of https://github.com/icsharpcode/ILSpy.git
12 changed files with 5868 additions and 2 deletions
@ -0,0 +1,118 @@
@@ -0,0 +1,118 @@
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Threading.Tasks; |
||||
|
||||
namespace ICSharpCode.Decompiler.Tests.TestCases.ILPretty |
||||
{ |
||||
internal class A |
||||
{ |
||||
protected internal virtual Task<string> Test(string test) |
||||
{ |
||||
return Task.Run((Func<string>)(() => test.ToUpper())); |
||||
} |
||||
} |
||||
|
||||
internal class B : A |
||||
{ |
||||
protected internal override async Task<string> Test(string test) |
||||
{ |
||||
return await base.Test(test); |
||||
} |
||||
} |
||||
|
||||
internal class C |
||||
{ |
||||
protected internal virtual string Test(string test) |
||||
{ |
||||
return string.Join(test, "fsdf"); |
||||
} |
||||
} |
||||
|
||||
internal class D : C |
||||
{ |
||||
protected internal IEnumerable<string> Test2(string test) |
||||
{ |
||||
yield return base.Test(test); |
||||
} |
||||
} |
||||
|
||||
internal class E |
||||
{ |
||||
protected internal virtual string Test(string test) |
||||
{ |
||||
return string.Join(test, "fsdf"); |
||||
} |
||||
} |
||||
|
||||
internal class F : E |
||||
{ |
||||
protected internal override string Test(string test) |
||||
{ |
||||
Func<string, string> func = (Func<string, string>)((string a) => base.Test(a)); |
||||
test = string.Join(test, "aa"); |
||||
return func(test); |
||||
} |
||||
} |
||||
|
||||
internal class G |
||||
{ |
||||
protected internal virtual void Test(string test) |
||||
{ |
||||
string.Join(test, "fsdf"); |
||||
} |
||||
} |
||||
|
||||
internal class H : G |
||||
{ |
||||
protected internal override void Test(string test) |
||||
{ |
||||
Action<string> action = (Action<string>)delegate(string a) { |
||||
base.Test(a); |
||||
}; |
||||
if (test.Equals(1)) { |
||||
throw new Exception("roslyn optimize is inlining the assignment which lets the test fail"); |
||||
} |
||||
action(test); |
||||
} |
||||
} |
||||
|
||||
internal class I |
||||
{ |
||||
protected internal virtual void Test(int a) |
||||
{ |
||||
|
||||
} |
||||
} |
||||
|
||||
internal class J : I |
||||
{ |
||||
protected internal override void Test(int a) |
||||
{ |
||||
Action action = (Action)delegate() { |
||||
base.Test(a); |
||||
}; |
||||
if (a.Equals(1)) { |
||||
throw new Exception("roslyn optimize is inlining the assignment which lets the test fail"); |
||||
} |
||||
action(); |
||||
|
||||
} |
||||
} |
||||
|
||||
internal class K |
||||
{ |
||||
protected internal virtual IEnumerable<int> Test(int p) |
||||
{ |
||||
yield return p + 1; |
||||
yield return p + 2; |
||||
} |
||||
} |
||||
|
||||
internal class L : K |
||||
{ |
||||
protected internal override IEnumerable<int> Test(int p) |
||||
{ |
||||
yield return base.Test(base.Test(0).GetEnumerator().Current).GetEnumerator().Current; |
||||
} |
||||
} |
||||
} |
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,102 @@
@@ -0,0 +1,102 @@
|
||||
using System.Diagnostics; |
||||
using System.Linq; |
||||
using ICSharpCode.Decompiler.TypeSystem; |
||||
using Mono.Cecil; |
||||
|
||||
namespace ICSharpCode.Decompiler.IL.Transforms |
||||
{ |
||||
class ProxyCallReplacer : IILTransform |
||||
{ |
||||
ILTransformContext context; |
||||
|
||||
public void Run(ILFunction function, ILTransformContext context) |
||||
{ |
||||
this.context = context; |
||||
foreach (var inst in function.Descendants.OfType<CallInstruction>()) { |
||||
MethodDefinition methodDef = context.TypeSystem.GetCecil(inst.Method) as MethodDefinition; |
||||
if (methodDef != null && methodDef.Body != null) { |
||||
if (inst.Method.IsCompilerGeneratedOrIsInCompilerGeneratedClass()) { |
||||
// partially copied from CSharpDecompiler
|
||||
var specializingTypeSystem = this.context.TypeSystem.GetSpecializingTypeSystem(this.context.TypeSystem.Compilation.TypeResolveContext); |
||||
var ilReader = new ILReader(specializingTypeSystem); |
||||
System.Threading.CancellationToken cancellationToken = new System.Threading.CancellationToken(); |
||||
var proxyFunction = ilReader.ReadIL(methodDef.Body, cancellationToken); |
||||
var transformContext = new ILTransformContext(proxyFunction, specializingTypeSystem, this.context.Settings) { |
||||
CancellationToken = cancellationToken |
||||
}; |
||||
foreach (var transform in CSharp.CSharpDecompiler.GetILTransforms()) { |
||||
if (transform.GetType() != typeof(ProxyCallReplacer)) { // don't call itself on itself
|
||||
cancellationToken.ThrowIfCancellationRequested(); |
||||
transform.Run(proxyFunction, transformContext); |
||||
} |
||||
} |
||||
|
||||
if (!(proxyFunction.Body is BlockContainer blockContainer)) |
||||
return; |
||||
if (blockContainer.Blocks.Count != 1) |
||||
return; |
||||
var block = blockContainer.Blocks[0]; |
||||
Call call = null; |
||||
if (block.Instructions.Count == 1) { |
||||
// leave IL_0000 (call Test(ldloc this, ldloc A_1))
|
||||
if (!block.Instructions[0].MatchLeave(blockContainer, out ILInstruction returnValue)) |
||||
return; |
||||
call = returnValue as Call; |
||||
} else if (block.Instructions.Count == 2) { |
||||
// call Test(ldloc this, ldloc A_1)
|
||||
// leave IL_0000(nop)
|
||||
call = block.Instructions[0] as Call; |
||||
if (!block.Instructions[1].MatchLeave(blockContainer, out ILInstruction returnValue)) |
||||
return; |
||||
if (!returnValue.MatchNop()) |
||||
return; |
||||
} |
||||
if (call == null) { |
||||
return; |
||||
} |
||||
if (call.Method.IsConstructor) |
||||
return; |
||||
|
||||
// check if original arguments are only correct ldloc calls
|
||||
for (int i = 0; i < call.Arguments.Count; i++) { |
||||
var originalArg = call.Arguments[i]; |
||||
if (!originalArg.MatchLdLoc(out ILVariable var) || |
||||
var.Kind != VariableKind.Parameter || |
||||
var.Index != i - 1) { |
||||
return; |
||||
} |
||||
} |
||||
|
||||
Call newInst = (Call)call.Clone(); |
||||
|
||||
newInst.Arguments.Clear(); |
||||
|
||||
if (inst.Arguments.Count > 0) { |
||||
ILInstruction thisArg = inst.Arguments[0]; |
||||
|
||||
// special handling for first argument (this) - the underlying issue may be somewhere else
|
||||
// normally
|
||||
// leave IL_0000(await(callvirt<> n__0(ldobj xxHandler(ldloca this), ldobj System.Net.Http.HttpRequestMessage(ldloca request), ldobj System.Threading.CancellationToken(ldloca cancellationToken))))
|
||||
// would be decompiled to
|
||||
// return await((DelegatingHandler)this).SendAsync(request, cancellationToken);
|
||||
// this changes it to
|
||||
// return await base.SendAsync(request, cancellationToken);
|
||||
if (thisArg.MatchLdObj(out ILInstruction loadedObject, out IType objectType) && |
||||
loadedObject.MatchLdLoca(out ILVariable loadedVar)) { |
||||
thisArg = new LdLoc(loadedVar); |
||||
} |
||||
|
||||
newInst.Arguments.Add(thisArg); |
||||
|
||||
// add everything except first argument
|
||||
for (int i = 1; i < inst.Arguments.Count; i++) { |
||||
newInst.Arguments.Add(inst.Arguments[i]); |
||||
} |
||||
} |
||||
inst.ReplaceWith(newInst); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue