Browse Source

DelegateConstruction:

- add support for unknown delegate construction pattern. The method is compiler-generated, but has no compiler-generated name, we should be able to infer lambda usage from anonymous types used in the signature (i. e., the method can only be used as lambda, because that's where type names are optional).
- Add CombineExitsTransform in DelegateConstruction: this allows combining lambdas with multiple return statements into a single expression (as it is expected by query expressions).
pull/1405/head
Siegfried Pammer 6 years ago
parent
commit
008a3c71e5
  1. 3
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  2. 32
      ICSharpCode.Decompiler/IL/Transforms/CombineExitsTransform.cs
  3. 20
      ICSharpCode.Decompiler/IL/Transforms/DelegateConstruction.cs

3
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -74,7 +74,7 @@ @@ -74,7 +74,7 @@
<Compile Include="CSharp\Syntax\ErrorNode.cs" />
<Compile Include="CSharp\Syntax\Expressions\AnonymousMethodExpression.cs" />
<Compile Include="CSharp\Syntax\Expressions\AnonymousTypeCreateExpression.cs" />
<Compile Include="CSharp\Syntax\Expressions\ArrayCreateExpression.cs" />
<Compile Include="CSharp\Syntax\Expressions\ArrayCreateExpression.cs" />
<Compile Include="CSharp\Syntax\Expressions\ArrayInitializerExpression.cs" />
<Compile Include="CSharp\Syntax\Expressions\AsExpression.cs" />
<Compile Include="CSharp\Syntax\Expressions\AssignmentExpression.cs" />
@ -265,6 +265,7 @@ @@ -265,6 +265,7 @@
<Compile Include="CSharp\Transforms\AddXmlDocumentationTransform.cs" />
<Compile Include="DecompileRun.cs" />
<Compile Include="Disassembler\ILParser.cs" />
<Compile Include="IL\Transforms\CombineExitsTransform.cs" />
<Compile Include="IL\Transforms\ReduceNestingTransform.cs" />
<Compile Include="IL\Transforms\LocalFunctionDecompiler.cs" />
<Compile Include="IL\Transforms\UserDefinedLogicTransform.cs" />

32
ICSharpCode.Decompiler/IL/Transforms/CombineExitsTransform.cs

@ -0,0 +1,32 @@ @@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace ICSharpCode.Decompiler.IL.Transforms
{
class CombineExitsTransform : IILTransform
{
public void Run(ILFunction function, ILTransformContext context)
{
if (!(function.Body is BlockContainer container && container.Blocks.Count == 1))
return;
var block = container.EntryPoint;
if (block.Kind != BlockKind.ControlFlow)
return;
if (!(block.Instructions.SecondToLastOrDefault() is IfInstruction ifInst && block.Instructions.LastOrDefault() is Leave leave))
return;
if (!ifInst.FalseInst.MatchNop())
return;
if (!(Block.Unwrap(ifInst.TrueInst) is Leave leave2))
return;
if (!(leave.IsLeavingFunction && leave2.IsLeavingFunction))
return;
if (leave.Value.MatchNop() || leave2.Value.MatchNop())
return;
IfInstruction value = new IfInstruction(ifInst.Condition, leave.Value, leave2.Value);
Leave combinedLeave = new Leave(leave.TargetContainer, value);
ifInst.ReplaceWith(combinedLeave);
block.Instructions.RemoveAt(combinedLeave.ChildIndex + 1);
}
}
}

20
ICSharpCode.Decompiler/IL/Transforms/DelegateConstruction.cs

@ -105,13 +105,24 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -105,13 +105,24 @@ namespace ICSharpCode.Decompiler.IL.Transforms
static bool IsAnonymousMethod(ITypeDefinition decompiledTypeDefinition, IMethod method)
{
if (method == null || !(method.HasGeneratedName() || method.Name.Contains("$")))
if (method == null || !(method.HasGeneratedName() || method.Name.Contains("$") || ContainsAnonymousType(method)))
return false;
if (!(method.IsCompilerGeneratedOrIsInCompilerGeneratedClass() || IsPotentialClosure(decompiledTypeDefinition, method.DeclaringTypeDefinition)))
return false;
return true;
}
static bool ContainsAnonymousType(IMethod method)
{
if (method.ReturnType.ContainsAnonymousType())
return true;
foreach (var p in method.Parameters) {
if (p.Type.ContainsAnonymousType())
return true;
}
return false;
}
static bool IsPotentialClosure(ITypeDefinition decompiledTypeDefinition, ITypeDefinition potentialDisplayClass)
{
if (potentialDisplayClass == null || !potentialDisplayClass.IsCompilerGeneratedOrIsInCompilerGeneratedClass())
@ -178,7 +189,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -178,7 +189,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
}
var nestedContext = new ILTransformContext(context, function);
function.RunTransforms(CSharpDecompiler.GetILTransforms().TakeWhile(t => !(t is DelegateConstruction)), nestedContext);
function.RunTransforms(CSharpDecompiler.GetILTransforms().TakeWhile(t => !(t is DelegateConstruction)).Concat(GetTransforms()), nestedContext);
function.AcceptVisitor(new ReplaceDelegateTargetVisitor(target, function.Variables.SingleOrDefault(v => v.Index == -1 && v.Kind == VariableKind.Parameter)));
// handle nested lambdas
((IILTransform)new DelegateConstruction()).Run(function, nestedContext);
@ -187,6 +198,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -187,6 +198,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return function;
}
private IEnumerable<IILTransform> GetTransforms()
{
yield return new CombineExitsTransform();
}
/// <summary>
/// Replaces loads of 'this' with the target expression.
/// Async delegates use: ldobj(ldloca this).

Loading…
Cancel
Save