Browse Source

Rename ExpressionTreeType to DelegateType and use ILFunction.DelegateType instead of the NewObj(LdNull, ILFunction) pattern in DelegateConstruction and ExpressionTrees

pull/988/head
Siegfried Pammer 8 years ago
parent
commit
25eecb90e1
  1. 4
      ICSharpCode.Decompiler/CSharp/CallBuilder.cs
  2. 2
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  3. 18
      ICSharpCode.Decompiler/IL/Instructions/ILFunction.cs
  4. 8
      ICSharpCode.Decompiler/IL/Transforms/DelegateConstruction.cs
  5. 72
      ICSharpCode.Decompiler/IL/Transforms/TransformExpressionTrees.cs

4
ICSharpCode.Decompiler/CSharp/CallBuilder.cs

@ -420,10 +420,6 @@ namespace ICSharpCode.Decompiler.CSharp
case OpCode.LdVirtFtn: case OpCode.LdVirtFtn:
method = ((LdVirtFtn)func).Method; method = ((LdVirtFtn)func).Method;
break; break;
case OpCode.ILFunction:
method = ((ILFunction)func).Method;
return expressionBuilder.TranslateFunction(inst.Method.DeclaringType, (ILFunction)func)
.WithILInstruction(inst);
default: default:
throw new ArgumentException($"Unknown instruction type: {func.OpCode}"); throw new ArgumentException($"Unknown instruction type: {func.OpCode}");
} }

2
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -1422,7 +1422,7 @@ namespace ICSharpCode.Decompiler.CSharp
protected internal override TranslatedExpression VisitILFunction(ILFunction function, TranslationContext context) protected internal override TranslatedExpression VisitILFunction(ILFunction function, TranslationContext context)
{ {
return TranslateFunction(function.ExpressionTreeType, function) return TranslateFunction(function.DelegateType, function)
.WithILInstruction(function); .WithILInstruction(function);
} }

18
ICSharpCode.Decompiler/IL/Instructions/ILFunction.cs

@ -62,12 +62,12 @@ namespace ICSharpCode.Decompiler.IL
public IType AsyncReturnType; public IType AsyncReturnType;
/// <summary> /// <summary>
/// If this is an expression tree, returns Expression{T}, otherwise null. /// If this is an expression tree or delegate, returns the expression tree type Expression{T} or T.
/// T is the delegate type that matches the signature of this method. /// T is the delegate type that matches the signature of this method.
/// </summary> /// </summary>
public IType ExpressionTreeType; public IType DelegateType;
public bool IsExpressionTree => ExpressionTreeType != null; public bool IsExpressionTree => DelegateType != null && DelegateType.FullName == "System.Linq.Expressions.Expression" && DelegateType.TypeParameterCount == 1;
public readonly IType ReturnType; public readonly IType ReturnType;
@ -78,8 +78,8 @@ namespace ICSharpCode.Decompiler.IL
this.Body = body; this.Body = body;
this.Method = method; this.Method = method;
this.CecilMethod = cecilMethod; this.CecilMethod = cecilMethod;
this.ReturnType = Method.ReturnType; this.ReturnType = Method?.ReturnType;
this.Parameters = Method.Parameters; this.Parameters = Method?.Parameters;
this.Variables = new ILVariableCollection(this); this.Variables = new ILVariableCollection(this);
} }
@ -113,6 +113,14 @@ namespace ICSharpCode.Decompiler.IL
output.Write(' '); output.Write(' ');
Method.WriteTo(output); Method.WriteTo(output);
} }
if (IsExpressionTree) {
output.Write(".ET");
}
if (DelegateType != null) {
output.Write("[");
DelegateType.WriteTo(output);
output.Write("]");
}
output.WriteLine(" {"); output.WriteLine(" {");
output.Indent(); output.Indent();

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

@ -44,10 +44,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
foreach (var call in block.Instructions[i].Descendants.OfType<NewObj>()) { foreach (var call in block.Instructions[i].Descendants.OfType<NewObj>()) {
ILFunction f = TransformDelegateConstruction(call, out ILInstruction target); ILFunction f = TransformDelegateConstruction(call, out ILInstruction target);
if (f != null) { if (f != null) {
f.AddILRange(call.Arguments[0].ILRange); call.ReplaceWith(f);
f.AddILRange(call.Arguments[1].ILRange);
call.Arguments[0].ReplaceWith(new LdNull());
call.Arguments[1].ReplaceWith(f);
if (target is IInstructionWithVariableOperand && !target.MatchLdThis()) if (target is IInstructionWithVariableOperand && !target.MatchLdThis())
targetsToReplace.Add((IInstructionWithVariableOperand)target); targetsToReplace.Add((IInstructionWithVariableOperand)target);
} }
@ -144,6 +141,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
var ilReader = new ILReader(localTypeSystem); var ilReader = new ILReader(localTypeSystem);
ilReader.UseDebugSymbols = context.Settings.UseDebugSymbols; ilReader.UseDebugSymbols = context.Settings.UseDebugSymbols;
var function = ilReader.ReadIL(methodDefinition.Body, context.CancellationToken); var function = ilReader.ReadIL(methodDefinition.Body, context.CancellationToken);
function.DelegateType = value.Method.DeclaringType;
function.CheckInvariant(ILPhase.Normal); function.CheckInvariant(ILPhase.Normal);
var contextPrefix = targetMethod.Name; var contextPrefix = targetMethod.Name;
@ -158,6 +156,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms
function.AcceptVisitor(new ReplaceDelegateTargetVisitor(target, function.Variables.SingleOrDefault(v => v.Index == -1 && v.Kind == VariableKind.Parameter))); function.AcceptVisitor(new ReplaceDelegateTargetVisitor(target, function.Variables.SingleOrDefault(v => v.Index == -1 && v.Kind == VariableKind.Parameter)));
// handle nested lambdas // handle nested lambdas
((IILTransform)new DelegateConstruction()).Run(function, nestedContext); ((IILTransform)new DelegateConstruction()).Run(function, nestedContext);
function.AddILRange(target.ILRange);
function.AddILRange(value.Arguments[1].ILRange);
return function; return function;
} }
return null; return null;

72
ICSharpCode.Decompiler/IL/Transforms/TransformExpressionTrees.cs

@ -18,6 +18,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.Linq; using System.Linq;
using ICSharpCode.Decompiler.CSharp.Resolver; using ICSharpCode.Decompiler.CSharp.Resolver;
using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem;
@ -150,7 +151,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms
var functionType = instruction.Method.ReturnType.TypeArguments[0]; var functionType = instruction.Method.ReturnType.TypeArguments[0];
var function = new ILFunction(functionType.TypeArguments.LastOrDefault() ?? context.TypeSystem.Compilation.FindType(KnownTypeCode.Void), parameterList, container); var function = new ILFunction(functionType.TypeArguments.LastOrDefault() ?? context.TypeSystem.Compilation.FindType(KnownTypeCode.Void), parameterList, container);
if (isQuotedLambda || lambdaStack.Count == 0) if (isQuotedLambda || lambdaStack.Count == 0)
function.ExpressionTreeType = instruction.Method.ReturnType; function.DelegateType = instruction.Method.ReturnType;
else
function.DelegateType = functionType;
function.Variables.AddRange(parameterVariablesList); function.Variables.AddRange(parameterVariablesList);
lambdaStack.Push(function); lambdaStack.Push(function);
var (bodyInstruction, type) = ConvertInstruction(instruction.Arguments[0]); var (bodyInstruction, type) = ConvertInstruction(instruction.Arguments[0]);
@ -159,11 +162,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return (null, SpecialType.UnknownType); return (null, SpecialType.UnknownType);
container.ExpectedResultType = bodyInstruction.ResultType; container.ExpectedResultType = bodyInstruction.ResultType;
container.Blocks.Add(new Block() { Instructions = { new Leave(container, bodyInstruction) } }); container.Blocks.Add(new Block() { Instructions = { new Leave(container, bodyInstruction) } });
if (!isQuotedLambda && lambdaStack.Count > 0) return (function, function.DelegateType);
return (new NewObj(functionType.GetConstructors().Single()) {
Arguments = { new LdNull(), function }
}, functionType);
return (function, function.ExpressionTreeType);
} }
bool ReadParameters(ILInstruction initializer, IList<IParameter> parameters, IList<ILVariable> parameterVariables, ITypeResolveContext resolveContext) bool ReadParameters(ILInstruction initializer, IList<IParameter> parameters, IList<ILVariable> parameterVariables, ITypeResolveContext resolveContext)
@ -199,6 +198,14 @@ namespace ICSharpCode.Decompiler.IL.Transforms
(ILInstruction, IType) ConvertInstruction(ILInstruction instruction) (ILInstruction, IType) ConvertInstruction(ILInstruction instruction)
{ {
var result = Convert();
if (result.Item1 != null) {
Debug.Assert(result.Item2 != null, "IType must be non-null!");
Debug.Assert(result.Item1.ResultType == result.Item2.GetStackType(), "StackTypes must match!");
}
return result;
(ILInstruction, IType) Convert() {
switch (instruction) { switch (instruction) {
case CallInstruction invocation: case CallInstruction invocation:
if (invocation.Method.DeclaringType.FullName != "System.Linq.Expressions.Expression") if (invocation.Method.DeclaringType.FullName != "System.Linq.Expressions.Expression")
@ -301,9 +308,30 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return ConvertTypeIs(invocation); return ConvertTypeIs(invocation);
} }
return (null, SpecialType.UnknownType); return (null, SpecialType.UnknownType);
case ILFunction function:
if (function.IsExpressionTree) {
function.DelegateType = UnwrapExpressionTree(function.DelegateType);
}
return (function, function.DelegateType);
case LdLoc ldloc:
if (IsExpressionTreeParameter(ldloc.Variable)) {
if (!parameterMapping.TryGetValue(ldloc.Variable, out var v))
return (null, SpecialType.UnknownType);
return (new LdLoc(v), v.Type);
}
return (null, SpecialType.UnknownType);
default: default:
return ConvertValue(instruction, instruction.Parent); return (null, SpecialType.UnknownType);
}
}
}
IType UnwrapExpressionTree(IType delegateType)
{
if (delegateType is ParameterizedType pt && pt.FullName == "System.Linq.Expressions.Expression" && pt.TypeArguments.Count == 1) {
return pt.TypeArguments[0];
} }
return delegateType;
} }
(ILInstruction, IType) ConvertArrayIndex(CallInstruction invocation) (ILInstruction, IType) ConvertArrayIndex(CallInstruction invocation)
@ -534,11 +562,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return (null, SpecialType.UnknownType); return (null, SpecialType.UnknownType);
if (value.MatchBox(out var arg, out var boxType)) { if (value.MatchBox(out var arg, out var boxType)) {
if (boxType.Kind == TypeKind.Enum || boxType.IsKnownType(KnownTypeCode.Boolean)) if (boxType.Kind == TypeKind.Enum || boxType.IsKnownType(KnownTypeCode.Boolean))
return (new ExpressionTreeCast(boxType, ConvertValue(arg, invocation).Item1, false), boxType); return (new ExpressionTreeCast(boxType, ConvertValue(arg, invocation), false), boxType);
value = ConvertValue(arg, invocation).Item1; value = ConvertValue(arg, invocation);
return (value, type); return (value, type);
} }
return ConvertValue(value, invocation); return (ConvertValue(value, invocation), type);
} }
(ILInstruction, IType) ConvertElementInit(CallInstruction invocation) (ILInstruction, IType) ConvertElementInit(CallInstruction invocation)
@ -727,7 +755,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return (null, SpecialType.UnknownType); return (null, SpecialType.UnknownType);
indices[i] = index; indices[i] = index;
} }
return (new NewArr(type, indices), type); return (new NewArr(type, indices), new ArrayType(context.TypeSystem.Compilation, type, arguments.Count));
} }
(ILInstruction, IType) ConvertNewArrayInit(CallInstruction invocation) (ILInstruction, IType) ConvertNewArrayInit(CallInstruction invocation)
@ -764,10 +792,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms
switch (invocation.Arguments.Count) { switch (invocation.Arguments.Count) {
case 1: case 1:
if (MatchGetTypeFromHandle(invocation.Arguments[0], out var type)) { if (MatchGetTypeFromHandle(invocation.Arguments[0], out var type)) {
var ctors = type.GetConstructors().ToArray(); var ctor = type.GetConstructors(c => c.Parameters.Count == 0).FirstOrDefault();
if (ctors.Length != 1 || ctors[0].Parameters.Count > 0) if (ctor == null)
return (null, SpecialType.UnknownType); return (null, SpecialType.UnknownType);
return (new NewObj(ctors[0]), type); return (new NewObj(ctor), type);
} }
if (MatchGetConstructorFromHandle(invocation.Arguments[0], out member)) { if (MatchGetConstructorFromHandle(invocation.Arguments[0], out member)) {
return (new NewObj((IMethod)member), member.DeclaringType); return (new NewObj((IMethod)member), member.DeclaringType);
@ -917,27 +945,25 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return (null, SpecialType.UnknownType); return (null, SpecialType.UnknownType);
} }
(ILInstruction, IType) ConvertValue(ILInstruction value, ILInstruction context) ILInstruction ConvertValue(ILInstruction value, ILInstruction context)
{ {
switch (value) { switch (value) {
case LdLoc ldloc: case LdLoc ldloc:
if (IsExpressionTreeParameter(ldloc.Variable)) { if (IsExpressionTreeParameter(ldloc.Variable)) {
if (!parameterMapping.TryGetValue(ldloc.Variable, out var v)) if (!parameterMapping.TryGetValue(ldloc.Variable, out var v))
return (null, SpecialType.UnknownType); return null;
if (context is CallInstruction parentCall if (context is CallInstruction parentCall
&& parentCall.Method.FullName == "System.Linq.Expressions.Expression.Call" && parentCall.Method.FullName == "System.Linq.Expressions.Expression.Call"
&& v.StackType.IsIntegerType()) && v.StackType.IsIntegerType())
return (new LdLoca(v), new ByReferenceType(v.Type)); return new LdLoca(v);
return (new LdLoc(v), v.Type); return null;
} else { } else {
if (ldloc.Variable.Kind != VariableKind.StackSlot) if (ldloc.Variable.Kind != VariableKind.StackSlot)
return (new LdLoc(ldloc.Variable), ldloc.Variable.Type); return new LdLoc(ldloc.Variable);
return (null, SpecialType.UnknownType); return null;
} }
default: default:
if (SemanticHelper.IsPure(value.Flags)) return value.Clone();
return (value.Clone(), value.InferType());
return (value, value.InferType());
} }
} }

Loading…
Cancel
Save