|
|
@ -30,6 +30,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms |
|
|
|
{ |
|
|
|
{ |
|
|
|
/// <summary>
|
|
|
|
/// <summary>
|
|
|
|
/// Converts LINQ Expression Trees to ILFunctions/ILAst instructions.
|
|
|
|
/// Converts LINQ Expression Trees to ILFunctions/ILAst instructions.
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// We build a tree of Func{ILInstruction}s, which are only executed, if the whole transform succeeds.
|
|
|
|
/// </summary>
|
|
|
|
/// </summary>
|
|
|
|
public class TransformExpressionTrees : IStatementTransform |
|
|
|
public class TransformExpressionTrees : IStatementTransform |
|
|
|
{ |
|
|
|
{ |
|
|
@ -122,9 +124,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms |
|
|
|
if (MightBeExpressionTree(instruction, statement)) { |
|
|
|
if (MightBeExpressionTree(instruction, statement)) { |
|
|
|
var (lambda, type) = ConvertLambda((CallInstruction)instruction); |
|
|
|
var (lambda, type) = ConvertLambda((CallInstruction)instruction); |
|
|
|
if (lambda != null) { |
|
|
|
if (lambda != null) { |
|
|
|
SetExpressionTreeFlag((ILFunction)lambda, (CallInstruction)instruction); |
|
|
|
|
|
|
|
context.Step("Convert Expression Tree", instruction); |
|
|
|
context.Step("Convert Expression Tree", instruction); |
|
|
|
instruction.ReplaceWith(lambda); |
|
|
|
var newLambda = (ILFunction)lambda(); |
|
|
|
|
|
|
|
SetExpressionTreeFlag(newLambda, (CallInstruction)instruction); |
|
|
|
|
|
|
|
instruction.ReplaceWith(newLambda); |
|
|
|
return true; |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
return false; |
|
|
|
return false; |
|
|
@ -142,7 +145,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms |
|
|
|
/// Converts a Expression.Lambda call into an ILFunction.
|
|
|
|
/// Converts a Expression.Lambda call into an ILFunction.
|
|
|
|
/// If the conversion fails, null is returned.
|
|
|
|
/// If the conversion fails, null is returned.
|
|
|
|
/// </summary>
|
|
|
|
/// </summary>
|
|
|
|
(ILInstruction, IType) ConvertLambda(CallInstruction instruction) |
|
|
|
(Func<ILInstruction>, IType) ConvertLambda(CallInstruction instruction) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (instruction.Method.Name != "Lambda" || instruction.Arguments.Count != 2 || instruction.Method.ReturnType.FullName != "System.Linq.Expressions.Expression" || instruction.Method.ReturnType.TypeArguments.Count != 1) |
|
|
|
if (instruction.Method.Name != "Lambda" || instruction.Arguments.Count != 2 || instruction.Method.ReturnType.FullName != "System.Linq.Expressions.Expression" || instruction.Method.ReturnType.TypeArguments.Count != 1) |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
@ -164,8 +167,15 @@ namespace ICSharpCode.Decompiler.IL.Transforms |
|
|
|
lambdaStack.Pop(); |
|
|
|
lambdaStack.Pop(); |
|
|
|
if (bodyInstruction == null) |
|
|
|
if (bodyInstruction == null) |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
container.ExpectedResultType = bodyInstruction.ResultType; |
|
|
|
return (BuildFunction, function.DelegateType); |
|
|
|
container.Blocks.Add(new Block() { Instructions = { new Leave(container, bodyInstruction) } }); |
|
|
|
|
|
|
|
|
|
|
|
ILFunction BuildFunction() |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
lambdaStack.Push(function); |
|
|
|
|
|
|
|
var convertedBody = bodyInstruction(); |
|
|
|
|
|
|
|
lambdaStack.Pop(); |
|
|
|
|
|
|
|
container.ExpectedResultType = convertedBody.ResultType; |
|
|
|
|
|
|
|
container.Blocks.Add(new Block() { Instructions = { new Leave(container, convertedBody) } }); |
|
|
|
// Replace all other usages of the parameter variable
|
|
|
|
// Replace all other usages of the parameter variable
|
|
|
|
foreach (var mapping in parameterMapping) { |
|
|
|
foreach (var mapping in parameterMapping) { |
|
|
|
foreach (var load in mapping.Key.LoadInstructions.ToArray()) { |
|
|
|
foreach (var load in mapping.Key.LoadInstructions.ToArray()) { |
|
|
@ -174,24 +184,32 @@ namespace ICSharpCode.Decompiler.IL.Transforms |
|
|
|
load.ReplaceWith(new LdLoc(mapping.Value)); |
|
|
|
load.ReplaceWith(new LdLoc(mapping.Value)); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
return (function, function.DelegateType); |
|
|
|
return function; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
(ILInstruction, IType) ConvertQuote(CallInstruction invocation) |
|
|
|
(Func<ILInstruction>, IType) ConvertQuote(CallInstruction invocation) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (invocation.Arguments.Count != 1) |
|
|
|
if (invocation.Arguments.Count != 1) |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
var argument = invocation.Arguments.Single(); |
|
|
|
var argument = invocation.Arguments.Single(); |
|
|
|
if (argument is ILFunction function) { |
|
|
|
if (argument is ILFunction function) { |
|
|
|
return (function, function.DelegateType); |
|
|
|
return (() => function, function.DelegateType); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
var converted = ConvertInstruction(argument); |
|
|
|
var (converted, type) = ConvertInstruction(argument); |
|
|
|
|
|
|
|
if (converted == null) |
|
|
|
|
|
|
|
return (converted, type); |
|
|
|
|
|
|
|
return (BuildQuote, type); |
|
|
|
|
|
|
|
|
|
|
|
if (converted.Item1 is ILFunction lambda && argument is CallInstruction call) { |
|
|
|
ILInstruction BuildQuote() |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
var f = converted(); |
|
|
|
|
|
|
|
if (f is ILFunction lambda && argument is CallInstruction call) { |
|
|
|
SetExpressionTreeFlag(lambda, call); |
|
|
|
SetExpressionTreeFlag(lambda, call); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return converted; |
|
|
|
return f; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -232,22 +250,28 @@ namespace ICSharpCode.Decompiler.IL.Transforms |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
(ILInstruction, IType) ConvertInstruction(ILInstruction instruction, IType typeHint = null) |
|
|
|
(Func<ILInstruction>, IType) ConvertInstruction(ILInstruction instruction, IType typeHint = null) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
var (inst, type) = Convert(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (inst == null) |
|
|
|
|
|
|
|
return (null, type); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ILInstruction DoConvert() |
|
|
|
{ |
|
|
|
{ |
|
|
|
var result = Convert(); |
|
|
|
var result = inst(); |
|
|
|
if (result.Item1 != null) { |
|
|
|
Debug.Assert(type != null, "IType must be non-null!"); |
|
|
|
Debug.Assert(result.Item2 != null, "IType must be non-null!"); |
|
|
|
Debug.Assert(result.ResultType == type.GetStackType(), "StackTypes must match!"); |
|
|
|
Debug.Assert(result.Item1.ResultType == result.Item2.GetStackType(), "StackTypes must match!"); |
|
|
|
|
|
|
|
if (typeHint != null) { |
|
|
|
if (typeHint != null) { |
|
|
|
var inst = result.Item1; |
|
|
|
if (result.ResultType != typeHint.GetStackType()) { |
|
|
|
if (inst.ResultType != typeHint.GetStackType()) { |
|
|
|
return new Conv(result, typeHint.GetStackType().ToPrimitiveType(), false, typeHint.GetSign()); |
|
|
|
return (new Conv(inst, typeHint.GetStackType().ToPrimitiveType(), false, typeHint.GetSign()), typeHint); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
return result; |
|
|
|
return result; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return (DoConvert, typeHint ?? type); |
|
|
|
|
|
|
|
|
|
|
|
(ILInstruction, IType) Convert() { |
|
|
|
(Func<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") |
|
|
@ -348,19 +372,23 @@ namespace ICSharpCode.Decompiler.IL.Transforms |
|
|
|
} |
|
|
|
} |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
case ILFunction function: |
|
|
|
case ILFunction function: |
|
|
|
|
|
|
|
ILFunction ApplyChangesToILFunction() |
|
|
|
|
|
|
|
{ |
|
|
|
if (function.Kind == ILFunctionKind.ExpressionTree) { |
|
|
|
if (function.Kind == ILFunctionKind.ExpressionTree) { |
|
|
|
function.DelegateType = UnwrapExpressionTree(function.DelegateType); |
|
|
|
function.DelegateType = UnwrapExpressionTree(function.DelegateType); |
|
|
|
function.Kind = ILFunctionKind.Delegate; |
|
|
|
function.Kind = ILFunctionKind.Delegate; |
|
|
|
} |
|
|
|
} |
|
|
|
return (function, function.DelegateType); |
|
|
|
return function; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return (ApplyChangesToILFunction, function.DelegateType); |
|
|
|
case LdLoc ldloc: |
|
|
|
case LdLoc ldloc: |
|
|
|
if (IsExpressionTreeParameter(ldloc.Variable)) { |
|
|
|
if (IsExpressionTreeParameter(ldloc.Variable)) { |
|
|
|
// Replace an already mapped parameter with the actual ILVariable,
|
|
|
|
// Replace an already mapped parameter with the actual ILVariable,
|
|
|
|
// we generated earlier.
|
|
|
|
// we generated earlier.
|
|
|
|
if (parameterMapping.TryGetValue(ldloc.Variable, out var v)) { |
|
|
|
if (parameterMapping.TryGetValue(ldloc.Variable, out var v)) { |
|
|
|
if (typeHint.SkipModifiers() is ByReferenceType && !v.Type.IsByRefLike) |
|
|
|
if (typeHint.SkipModifiers() is ByReferenceType && !v.Type.IsByRefLike) |
|
|
|
return (new LdLoca(v), typeHint); |
|
|
|
return (() => new LdLoca(v), typeHint); |
|
|
|
return (new LdLoc(v), v.Type); |
|
|
|
return (() => new LdLoc(v), v.Type); |
|
|
|
} |
|
|
|
} |
|
|
|
// This is a parameter variable from an outer scope.
|
|
|
|
// This is a parameter variable from an outer scope.
|
|
|
|
// We can't replace these variables just yet, because the transform works backwards.
|
|
|
|
// We can't replace these variables just yet, because the transform works backwards.
|
|
|
@ -368,9 +396,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms |
|
|
|
// so our transform can continue normally.
|
|
|
|
// so our transform can continue normally.
|
|
|
|
// Later, we will replace all references to unmapped variables,
|
|
|
|
// Later, we will replace all references to unmapped variables,
|
|
|
|
// with references to mapped parameters.
|
|
|
|
// with references to mapped parameters.
|
|
|
|
if (ldloc.Variable.IsSingleDefinition && ldloc.Variable.StoreInstructions[0] is ILInstruction inst) { |
|
|
|
if (ldloc.Variable.IsSingleDefinition && ldloc.Variable.StoreInstructions[0] is ILInstruction instr) { |
|
|
|
if (MatchParameterVariableAssignment(inst, out _, out var type, out _)) |
|
|
|
if (MatchParameterVariableAssignment(instr, out _, out var t, out _)) |
|
|
|
return (new ExpressionTreeCast(type, ldloc, false), type); |
|
|
|
return (() => new ExpressionTreeCast(t, ldloc, false), t); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
@ -392,7 +420,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms |
|
|
|
return delegateType; |
|
|
|
return delegateType; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
(ILInstruction, IType) ConvertArrayIndex(CallInstruction invocation) |
|
|
|
(Func<ILInstruction>, IType) ConvertArrayIndex(CallInstruction invocation) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (invocation.Arguments.Count != 2) |
|
|
|
if (invocation.Arguments.Count != 2) |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
@ -403,26 +431,32 @@ namespace ICSharpCode.Decompiler.IL.Transforms |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
if (!MatchArgumentList(invocation.Arguments[1], out var arguments)) |
|
|
|
if (!MatchArgumentList(invocation.Arguments[1], out var arguments)) |
|
|
|
arguments = new[] { invocation.Arguments[1] }; |
|
|
|
arguments = new[] { invocation.Arguments[1] }; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ILInstruction Convert() |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
Func<ILInstruction>[] toBeConverted = new Func<ILInstruction>[arguments.Count]; |
|
|
|
for (int i = 0; i < arguments.Count; i++) { |
|
|
|
for (int i = 0; i < arguments.Count; i++) { |
|
|
|
var (converted, indexType) = ConvertInstruction(arguments[i]); |
|
|
|
var (converted, indexType) = ConvertInstruction(arguments[i]); |
|
|
|
if (converted == null) |
|
|
|
if (converted == null) |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return null; |
|
|
|
arguments[i] = converted; |
|
|
|
toBeConverted[i] = converted; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return new LdObj(new LdElema(type.ElementType, array(), toBeConverted.SelectArray(f => f())), type.ElementType); |
|
|
|
} |
|
|
|
} |
|
|
|
return (new LdObj(new LdElema(type.ElementType, array, arguments.ToArray()), type.ElementType), type.ElementType); |
|
|
|
return (Convert, type.ElementType); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
(ILInstruction, IType) ConvertArrayLength(CallInstruction invocation) |
|
|
|
(Func<ILInstruction>, IType) ConvertArrayLength(CallInstruction invocation) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (invocation.Arguments.Count != 1) |
|
|
|
if (invocation.Arguments.Count != 1) |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
var (converted, arrayType) = ConvertInstruction(invocation.Arguments[0]); |
|
|
|
var (converted, _) = ConvertInstruction(invocation.Arguments[0]); |
|
|
|
if (converted == null) |
|
|
|
if (converted == null) |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (new LdLen(StackType.I4, converted), context.TypeSystem.FindType(KnownTypeCode.Int32)); |
|
|
|
return (() => new LdLen(StackType.I4, converted()), context.TypeSystem.FindType(KnownTypeCode.Int32)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
(ILInstruction, IType) ConvertBinaryNumericOperator(CallInstruction invocation, BinaryNumericOperator op, bool? isChecked = null) |
|
|
|
(Func<ILInstruction>, IType) ConvertBinaryNumericOperator(CallInstruction invocation, BinaryNumericOperator op, bool? isChecked = null) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (invocation.Arguments.Count < 2) |
|
|
|
if (invocation.Arguments.Count < 2) |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
@ -442,12 +476,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms |
|
|
|
if (!rightType.Equals(leftType)) |
|
|
|
if (!rightType.Equals(leftType)) |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
} |
|
|
|
} |
|
|
|
return (new BinaryNumericInstruction(op, left, right, isChecked == true, leftType.GetSign()), leftType); |
|
|
|
return (() => new BinaryNumericInstruction(op, left(), right(), isChecked == true, leftType.GetSign()), leftType); |
|
|
|
case 3: |
|
|
|
case 3: |
|
|
|
if (!MatchGetMethodFromHandle(invocation.Arguments[2], out method)) |
|
|
|
if (!MatchGetMethodFromHandle(invocation.Arguments[2], out method)) |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (new Call((IMethod)method) { |
|
|
|
return (() => new Call((IMethod)method) { |
|
|
|
Arguments = { left, right } |
|
|
|
Arguments = { left(), right() } |
|
|
|
}, method.ReturnType); |
|
|
|
}, method.ReturnType); |
|
|
|
case 4: |
|
|
|
case 4: |
|
|
|
if (!invocation.Arguments[2].MatchLdcI4(out var isLifted)) |
|
|
|
if (!invocation.Arguments[2].MatchLdcI4(out var isLifted)) |
|
|
@ -456,15 +490,15 @@ namespace ICSharpCode.Decompiler.IL.Transforms |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
if (isLifted != 0) |
|
|
|
if (isLifted != 0) |
|
|
|
method = CSharpOperators.LiftUserDefinedOperator((IMethod)method); |
|
|
|
method = CSharpOperators.LiftUserDefinedOperator((IMethod)method); |
|
|
|
return (new Call((IMethod)method) { |
|
|
|
return (() => new Call((IMethod)method) { |
|
|
|
Arguments = { left, right } |
|
|
|
Arguments = { left(), right() } |
|
|
|
}, method.ReturnType); |
|
|
|
}, method.ReturnType); |
|
|
|
default: |
|
|
|
default: |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
(ILInstruction, IType) ConvertBind(CallInstruction invocation, ILVariable targetVariable) |
|
|
|
(Func<ILVariable, ILInstruction>, IType) ConvertBind(CallInstruction invocation) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (invocation.Arguments.Count != 2) |
|
|
|
if (invocation.Arguments.Count != 2) |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
@ -478,19 +512,19 @@ namespace ICSharpCode.Decompiler.IL.Transforms |
|
|
|
} |
|
|
|
} |
|
|
|
switch (member) { |
|
|
|
switch (member) { |
|
|
|
case IMethod method: |
|
|
|
case IMethod method: |
|
|
|
return (new Call(method) { Arguments = { new LdLoc(targetVariable), value } }, method.ReturnType); |
|
|
|
return (targetVariable => new Call(method) { Arguments = { new LdLoc(targetVariable), value() } }, method.ReturnType); |
|
|
|
case IField field: |
|
|
|
case IField field: |
|
|
|
return (new StObj(new LdFlda(new LdLoc(targetVariable), (IField)member), value, member.ReturnType), field.ReturnType); |
|
|
|
return (targetVariable => new StObj(new LdFlda(new LdLoc(targetVariable), (IField)member), value(), member.ReturnType), field.ReturnType); |
|
|
|
} |
|
|
|
} |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
(ILInstruction, IType) ConvertCall(CallInstruction invocation) |
|
|
|
(Func<ILInstruction>, IType) ConvertCall(CallInstruction invocation) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (invocation.Arguments.Count < 2) |
|
|
|
if (invocation.Arguments.Count < 2) |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
IList<ILInstruction> arguments = null; |
|
|
|
IList<ILInstruction> arguments = null; |
|
|
|
ILInstruction target = null; |
|
|
|
Func<ILInstruction> targetConverter = null; |
|
|
|
IType targetType = null; |
|
|
|
IType targetType = null; |
|
|
|
if (MatchGetMethodFromHandle(invocation.Arguments[0], out var member)) { |
|
|
|
if (MatchGetMethodFromHandle(invocation.Arguments[0], out var member)) { |
|
|
|
// static method
|
|
|
|
// static method
|
|
|
@ -502,36 +536,42 @@ namespace ICSharpCode.Decompiler.IL.Transforms |
|
|
|
arguments = new List<ILInstruction>(invocation.Arguments.Skip(2)); |
|
|
|
arguments = new List<ILInstruction>(invocation.Arguments.Skip(2)); |
|
|
|
} |
|
|
|
} |
|
|
|
if (!invocation.Arguments[0].MatchLdNull()) { |
|
|
|
if (!invocation.Arguments[0].MatchLdNull()) { |
|
|
|
(target, targetType) = ConvertInstruction(invocation.Arguments[0]); |
|
|
|
(targetConverter, targetType) = ConvertInstruction(invocation.Arguments[0]); |
|
|
|
if (target == null) |
|
|
|
if (targetConverter == null) |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
if (arguments == null) |
|
|
|
if (arguments == null) |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
IMethod method = (IMethod)member; |
|
|
|
IMethod method = (IMethod)member; |
|
|
|
if (!ConvertCallArguments(arguments, method)) |
|
|
|
var convertedArguments = ConvertCallArguments(arguments, method); |
|
|
|
|
|
|
|
if (convertedArguments == null) |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
if (method.FullName == "System.Reflection.MethodInfo.CreateDelegate" && method.Parameters.Count == 2) { |
|
|
|
if (method.FullName == "System.Reflection.MethodInfo.CreateDelegate" && method.Parameters.Count == 2) { |
|
|
|
if (!MatchGetMethodFromHandle(target, out var targetMethod)) |
|
|
|
if (!MatchGetMethodFromHandle(UnpackConstant(invocation.Arguments[0]), out var targetMethod)) |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
if (!MatchGetTypeFromHandle(arguments[0], out var delegateType)) |
|
|
|
if (!MatchGetTypeFromHandle(UnpackConstant(arguments[0]), out var delegateType)) |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (new NewObj(delegateType.GetConstructors().Single()) { |
|
|
|
return (() => new NewObj(delegateType.GetConstructors().Single()) { |
|
|
|
Arguments = { arguments[1], new LdFtn((IMethod)targetMethod) } |
|
|
|
Arguments = { convertedArguments[1](), new LdFtn((IMethod)targetMethod) } |
|
|
|
}, delegateType); |
|
|
|
}, delegateType); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CallInstruction BuildCall() |
|
|
|
|
|
|
|
{ |
|
|
|
CallInstruction call; |
|
|
|
CallInstruction call; |
|
|
|
if (method.IsAbstract || method.IsVirtual || method.IsOverride) { |
|
|
|
if (method.IsAbstract || method.IsVirtual || method.IsOverride) { |
|
|
|
call = new CallVirt(method); |
|
|
|
call = new CallVirt(method); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
call = new Call(method); |
|
|
|
call = new Call(method); |
|
|
|
} |
|
|
|
} |
|
|
|
if (target != null) { |
|
|
|
if (targetConverter != null) { |
|
|
|
call.Arguments.Add(PrepareCallTarget(method.DeclaringType, target, targetType)); |
|
|
|
call.Arguments.Add(PrepareCallTarget(method.DeclaringType, targetConverter(), targetType)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
call.Arguments.AddRange(convertedArguments.Select(f => f())); |
|
|
|
|
|
|
|
return call; |
|
|
|
} |
|
|
|
} |
|
|
|
call.Arguments.AddRange(arguments); |
|
|
|
return (BuildCall, method.ReturnType); |
|
|
|
return (call, method.ReturnType); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
ILInstruction PrepareCallTarget(IType expectedType, ILInstruction target, IType targetType) |
|
|
|
ILInstruction PrepareCallTarget(IType expectedType, ILInstruction target, IType targetType) |
|
|
@ -556,20 +596,28 @@ namespace ICSharpCode.Decompiler.IL.Transforms |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
bool ConvertCallArguments(IList<ILInstruction> arguments, IMethod method) |
|
|
|
ILInstruction UnpackConstant(ILInstruction inst) |
|
|
|
{ |
|
|
|
{ |
|
|
|
|
|
|
|
if (!(inst is CallInstruction call && call.Method.FullName == "System.Linq.Expressions.Expression.Constant" && call.Arguments.Count == 2)) |
|
|
|
|
|
|
|
return inst; |
|
|
|
|
|
|
|
return call.Arguments[0]; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Func<ILInstruction>[] ConvertCallArguments(IList<ILInstruction> arguments, IMethod method) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
var converted = new Func<ILInstruction>[arguments.Count]; |
|
|
|
Debug.Assert(arguments.Count == method.Parameters.Count); |
|
|
|
Debug.Assert(arguments.Count == method.Parameters.Count); |
|
|
|
for (int i = 0; i < arguments.Count; i++) { |
|
|
|
for (int i = 0; i < arguments.Count; i++) { |
|
|
|
var expectedType = method.Parameters[i].Type; |
|
|
|
var expectedType = method.Parameters[i].Type; |
|
|
|
var argument = ConvertInstruction(arguments[i], expectedType).Item1; |
|
|
|
var argument = ConvertInstruction(arguments[i], expectedType).Item1; |
|
|
|
if (argument == null) |
|
|
|
if (argument == null) |
|
|
|
return false; |
|
|
|
return null; |
|
|
|
arguments[i] = argument; |
|
|
|
converted[i] = argument; |
|
|
|
} |
|
|
|
} |
|
|
|
return true; |
|
|
|
return converted; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
(ILInstruction, IType) ConvertCast(CallInstruction invocation, bool isChecked) |
|
|
|
(Func<ILInstruction>, IType) ConvertCast(CallInstruction invocation, bool isChecked) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (invocation.Arguments.Count < 2) |
|
|
|
if (invocation.Arguments.Count < 2) |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
@ -580,10 +628,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
if (exprType.IsSmallIntegerType() && targetType.IsKnownType(KnownTypeCode.Int32)) |
|
|
|
if (exprType.IsSmallIntegerType() && targetType.IsKnownType(KnownTypeCode.Int32)) |
|
|
|
return (expr, targetType); |
|
|
|
return (expr, targetType); |
|
|
|
return (new ExpressionTreeCast(targetType, expr, isChecked), targetType); |
|
|
|
return (() => new ExpressionTreeCast(targetType, expr(), isChecked), targetType); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
(ILInstruction, IType) ConvertCoalesce(CallInstruction invocation) |
|
|
|
(Func<ILInstruction>, IType) ConvertCoalesce(CallInstruction invocation) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (invocation.Arguments.Count != 2) |
|
|
|
if (invocation.Arguments.Count != 2) |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
@ -604,12 +652,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
targetType = fallbackInstType; |
|
|
|
targetType = fallbackInstType; |
|
|
|
} |
|
|
|
} |
|
|
|
return (new NullCoalescingInstruction(kind, trueInst, fallbackInst) { |
|
|
|
return (() => new NullCoalescingInstruction(kind, trueInst(), fallbackInst()) { |
|
|
|
UnderlyingResultType = trueInstTypeNonNullable.GetStackType() |
|
|
|
UnderlyingResultType = trueInstTypeNonNullable.GetStackType() |
|
|
|
}, targetType); |
|
|
|
}, targetType); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
(ILInstruction, IType) ConvertComparison(CallInstruction invocation, ComparisonKind kind) |
|
|
|
(Func<ILInstruction>, IType) ConvertComparison(CallInstruction invocation, ComparisonKind kind) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (invocation.Arguments.Count < 2) |
|
|
|
if (invocation.Arguments.Count < 2) |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
@ -623,11 +671,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms |
|
|
|
if (isLifted != 0) { |
|
|
|
if (isLifted != 0) { |
|
|
|
method = CSharpOperators.LiftUserDefinedOperator((IMethod)method); |
|
|
|
method = CSharpOperators.LiftUserDefinedOperator((IMethod)method); |
|
|
|
} |
|
|
|
} |
|
|
|
return (new Call((IMethod)method) { Arguments = { left, right } }, method.ReturnType); |
|
|
|
return (() => new Call((IMethod)method) { Arguments = { left(), right() } }, method.ReturnType); |
|
|
|
} |
|
|
|
} |
|
|
|
var rr = resolver.ResolveBinaryOperator(kind.ToBinaryOperatorType(), new ResolveResult(leftType), new ResolveResult(rightType)) as OperatorResolveResult; |
|
|
|
var rr = resolver.ResolveBinaryOperator(kind.ToBinaryOperatorType(), new ResolveResult(leftType), new ResolveResult(rightType)) as OperatorResolveResult; |
|
|
|
if (rr != null && !rr.IsError && rr.UserDefinedOperatorMethod != null) { |
|
|
|
if (rr != null && !rr.IsError && rr.UserDefinedOperatorMethod != null) { |
|
|
|
return (new Call(rr.UserDefinedOperatorMethod) { Arguments = { left, right } }, rr.UserDefinedOperatorMethod.ReturnType); |
|
|
|
return (() => new Call(rr.UserDefinedOperatorMethod) { Arguments = { left(), right() } }, rr.UserDefinedOperatorMethod.ReturnType); |
|
|
|
} |
|
|
|
} |
|
|
|
if (leftType.IsKnownType(KnownTypeCode.String) && rightType.IsKnownType(KnownTypeCode.String)) { |
|
|
|
if (leftType.IsKnownType(KnownTypeCode.String) && rightType.IsKnownType(KnownTypeCode.String)) { |
|
|
|
IMethod operatorMethod; |
|
|
|
IMethod operatorMethod; |
|
|
@ -645,15 +693,15 @@ namespace ICSharpCode.Decompiler.IL.Transforms |
|
|
|
default: |
|
|
|
default: |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
} |
|
|
|
} |
|
|
|
return (new Call(operatorMethod) { Arguments = { left, right } }, operatorMethod.ReturnType); |
|
|
|
return (() => new Call(operatorMethod) { Arguments = { left(), right() } }, operatorMethod.ReturnType); |
|
|
|
} |
|
|
|
} |
|
|
|
var resultType = context.TypeSystem.FindType(KnownTypeCode.Boolean); |
|
|
|
var resultType = context.TypeSystem.FindType(KnownTypeCode.Boolean); |
|
|
|
var lifting = NullableType.IsNullable(leftType) ? ComparisonLiftingKind.CSharp : ComparisonLiftingKind.None; |
|
|
|
var lifting = NullableType.IsNullable(leftType) ? ComparisonLiftingKind.CSharp : ComparisonLiftingKind.None; |
|
|
|
var utype = NullableType.GetUnderlyingType(leftType); |
|
|
|
var utype = NullableType.GetUnderlyingType(leftType); |
|
|
|
return (new Comp(kind, lifting, utype.GetStackType(), utype.GetSign(), left, right), resultType); |
|
|
|
return (() => new Comp(kind, lifting, utype.GetStackType(), utype.GetSign(), left(), right()), resultType); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
(ILInstruction, IType) ConvertCondition(CallInstruction invocation) |
|
|
|
(Func<ILInstruction>, IType) ConvertCondition(CallInstruction invocation) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (invocation.Arguments.Count != 3) |
|
|
|
if (invocation.Arguments.Count != 3) |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
@ -668,23 +716,22 @@ namespace ICSharpCode.Decompiler.IL.Transforms |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
if (!trueInstType.Equals(falseInstType)) |
|
|
|
if (!trueInstType.Equals(falseInstType)) |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (new IfInstruction(condition, trueInst, falseInst), trueInstType); |
|
|
|
return (() => new IfInstruction(condition(), trueInst(), falseInst()), trueInstType); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
(ILInstruction, IType) ConvertConstant(CallInstruction invocation) |
|
|
|
(Func<ILInstruction>, IType) ConvertConstant(CallInstruction invocation) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (!MatchConstantCall(invocation, out var value, out var type)) |
|
|
|
if (!MatchConstantCall(invocation, out var value, out var type)) |
|
|
|
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), false), boxType); |
|
|
|
return (() => new ExpressionTreeCast(boxType, ConvertValue(arg, invocation), false), boxType); |
|
|
|
value = ConvertValue(arg, invocation); |
|
|
|
return (() => ConvertValue(arg, invocation), type); |
|
|
|
return (value, type); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
return (ConvertValue(value, invocation), type); |
|
|
|
return (() => ConvertValue(value, invocation), type); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
(ILInstruction, IType) ConvertElementInit(CallInstruction invocation) |
|
|
|
(Func<ILInstruction>, IType) ConvertElementInit(CallInstruction invocation) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (invocation.Arguments.Count != 2) |
|
|
|
if (invocation.Arguments.Count != 2) |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
@ -692,77 +739,97 @@ namespace ICSharpCode.Decompiler.IL.Transforms |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
if (!MatchArgumentList(invocation.Arguments[1], out var arguments)) |
|
|
|
if (!MatchArgumentList(invocation.Arguments[1], out var arguments)) |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
CallInstruction call = new Call((IMethod)member); |
|
|
|
var args = new Func<ILInstruction>[arguments.Count]; |
|
|
|
for (int i = 0; i < arguments.Count; i++) { |
|
|
|
for (int i = 0; i < arguments.Count; i++) { |
|
|
|
ILInstruction arg = ConvertInstruction(arguments[i]).Item1; |
|
|
|
var arg = ConvertInstruction(arguments[i]).Item1; |
|
|
|
if (arg == null) |
|
|
|
if (arg == null) |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
arguments[i] = arg; |
|
|
|
args[i] = arg; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ILInstruction BuildCall() |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
CallInstruction call = new Call((IMethod)member); |
|
|
|
|
|
|
|
call.Arguments.AddRange(args.Select(f => f())); |
|
|
|
|
|
|
|
return call; |
|
|
|
} |
|
|
|
} |
|
|
|
call.Arguments.AddRange(arguments); |
|
|
|
return (BuildCall, member.ReturnType); |
|
|
|
return (call, member.ReturnType); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
(ILInstruction, IType) ConvertField(CallInstruction invocation, IType typeHint) |
|
|
|
(Func<ILInstruction>, IType) ConvertField(CallInstruction invocation, IType typeHint) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (invocation.Arguments.Count != 2) |
|
|
|
if (invocation.Arguments.Count != 2) |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
ILInstruction target = null; |
|
|
|
Func<ILInstruction> targetConverter = null; |
|
|
|
if (!invocation.Arguments[0].MatchLdNull()) { |
|
|
|
if (!invocation.Arguments[0].MatchLdNull()) { |
|
|
|
target = ConvertInstruction(invocation.Arguments[0]).Item1; |
|
|
|
targetConverter = ConvertInstruction(invocation.Arguments[0]).Item1; |
|
|
|
if (target == null) |
|
|
|
if (targetConverter == null) |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
} |
|
|
|
} |
|
|
|
if (!MatchGetFieldFromHandle(invocation.Arguments[1], out var member)) |
|
|
|
if (!MatchGetFieldFromHandle(invocation.Arguments[1], out var member)) |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
IType type = member.ReturnType; |
|
|
|
IType type = member.ReturnType; |
|
|
|
|
|
|
|
if (typeHint.SkipModifiers() is ByReferenceType && !member.ReturnType.IsByRefLike) { |
|
|
|
|
|
|
|
type = typeHint; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return (BuildField, type); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ILInstruction BuildField() |
|
|
|
|
|
|
|
{ |
|
|
|
ILInstruction inst; |
|
|
|
ILInstruction inst; |
|
|
|
if (target == null) { |
|
|
|
if (targetConverter == null) { |
|
|
|
inst = new LdsFlda((IField)member); |
|
|
|
inst = new LdsFlda((IField)member); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
|
|
|
|
var target = targetConverter(); |
|
|
|
if (member.DeclaringType.IsReferenceType == true) { |
|
|
|
if (member.DeclaringType.IsReferenceType == true) { |
|
|
|
inst = new LdFlda(target, (IField)member); |
|
|
|
inst = new LdFlda(target, (IField)member); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
inst = new LdFlda(new AddressOf(target, member.DeclaringType), (IField)member); |
|
|
|
inst = new LdFlda(new AddressOf(target, member.DeclaringType), (IField)member); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
if (typeHint.SkipModifiers() is ByReferenceType brt && !member.ReturnType.IsByRefLike) { |
|
|
|
if (!(typeHint.SkipModifiers() is ByReferenceType && !member.ReturnType.IsByRefLike)) { |
|
|
|
type = typeHint; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
inst = new LdObj(inst, member.ReturnType); |
|
|
|
inst = new LdObj(inst, member.ReturnType); |
|
|
|
} |
|
|
|
} |
|
|
|
return (inst, type); |
|
|
|
return inst; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
(ILInstruction, IType) ConvertInvoke(CallInstruction invocation) |
|
|
|
(Func<ILInstruction>, IType) ConvertInvoke(CallInstruction invocation) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (invocation.Arguments.Count != 2) |
|
|
|
if (invocation.Arguments.Count != 2) |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
var (target, targetType) = ConvertInstruction(invocation.Arguments[0]); |
|
|
|
var (targetConverter, targetType) = ConvertInstruction(invocation.Arguments[0]); |
|
|
|
if (target == null) |
|
|
|
if (targetConverter == null) |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
var invokeMethod = targetType.GetDelegateInvokeMethod(); |
|
|
|
var invokeMethod = targetType.GetDelegateInvokeMethod(); |
|
|
|
if (invokeMethod == null) |
|
|
|
if (invokeMethod == null) |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
if (!MatchArgumentList(invocation.Arguments[1], out var arguments)) |
|
|
|
if (!MatchArgumentList(invocation.Arguments[1], out var arguments)) |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
if (!ConvertCallArguments(arguments, invokeMethod)) |
|
|
|
var convertedArguments = ConvertCallArguments(arguments, invokeMethod); |
|
|
|
|
|
|
|
if (convertedArguments == null) |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ILInstruction BuildCall() |
|
|
|
|
|
|
|
{ |
|
|
|
var call = new CallVirt(invokeMethod); |
|
|
|
var call = new CallVirt(invokeMethod); |
|
|
|
call.Arguments.Add(target); |
|
|
|
call.Arguments.Add(targetConverter()); |
|
|
|
call.Arguments.AddRange(arguments); |
|
|
|
call.Arguments.AddRange(convertedArguments.Select(f => f())); |
|
|
|
return (call, invokeMethod.ReturnType); |
|
|
|
return call; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return (BuildCall, invokeMethod.ReturnType); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
(ILInstruction, IType) ConvertListInit(CallInstruction invocation) |
|
|
|
(Func<ILInstruction>, IType) ConvertListInit(CallInstruction invocation) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (invocation.Arguments.Count < 2) |
|
|
|
if (invocation.Arguments.Count < 2) |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
var newObj = ConvertInstruction(invocation.Arguments[0]).Item1 as NewObj; |
|
|
|
var newObj = ConvertInstruction(invocation.Arguments[0]).Item1; |
|
|
|
if (newObj == null) |
|
|
|
if (newObj == null) |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
IList<ILInstruction> arguments = null; |
|
|
|
if (!MatchNew((CallInstruction)invocation.Arguments[0], out var ctor)) |
|
|
|
ILFunction function = lambdaStack.Peek(); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
|
|
|
|
IList<ILInstruction> arguments; |
|
|
|
if (!MatchGetMethodFromHandle(invocation.Arguments[1], out var member)) { |
|
|
|
if (!MatchGetMethodFromHandle(invocation.Arguments[1], out var member)) { |
|
|
|
if (!MatchArgumentList(invocation.Arguments[1], out arguments)) |
|
|
|
if (!MatchArgumentList(invocation.Arguments[1], out arguments)) |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
@ -772,29 +839,37 @@ namespace ICSharpCode.Decompiler.IL.Transforms |
|
|
|
} |
|
|
|
} |
|
|
|
if (arguments == null || arguments.Count == 0) |
|
|
|
if (arguments == null || arguments.Count == 0) |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
var initializer = function.RegisterVariable(VariableKind.InitializerTarget, newObj.Method.DeclaringType); |
|
|
|
Func<ILVariable, ILInstruction>[] convertedArguments = new Func<ILVariable, ILInstruction>[arguments.Count]; |
|
|
|
for (int i = 0; i < arguments.Count; i++) { |
|
|
|
for (int i = 0; i < arguments.Count; i++) { |
|
|
|
ILInstruction arg; |
|
|
|
|
|
|
|
if (arguments[i] is CallInstruction elementInit && elementInit.Method.FullName == "System.Linq.Expressions.Expression.ElementInit") { |
|
|
|
if (arguments[i] is CallInstruction elementInit && elementInit.Method.FullName == "System.Linq.Expressions.Expression.ElementInit") { |
|
|
|
arg = ConvertElementInit(elementInit).Item1; |
|
|
|
var arg = ConvertElementInit(elementInit).Item1; |
|
|
|
if (arg == null) |
|
|
|
if (arg == null) |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
((CallInstruction)arg).Arguments.Insert(0, new LdLoc(initializer)); |
|
|
|
|
|
|
|
|
|
|
|
convertedArguments[i] = v => { var a = arg(); ((CallInstruction)a).Arguments.Insert(0, new LdLoc(v)); return a; }; |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
arg = ConvertInstruction(arguments[i]).Item1; |
|
|
|
var arg = ConvertInstruction(arguments[i]).Item1; |
|
|
|
if (arg == null) |
|
|
|
if (arg == null) |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
|
|
|
|
convertedArguments[i] = v => arg(); |
|
|
|
} |
|
|
|
} |
|
|
|
arguments[i] = arg; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Block BuildBlock() |
|
|
|
|
|
|
|
{ |
|
|
|
var initializerBlock = new Block(BlockKind.CollectionInitializer); |
|
|
|
var initializerBlock = new Block(BlockKind.CollectionInitializer); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ILFunction function = lambdaStack.Peek(); |
|
|
|
|
|
|
|
var initializer = function.RegisterVariable(VariableKind.InitializerTarget, ctor.DeclaringType); |
|
|
|
initializerBlock.FinalInstruction = new LdLoc(initializer); |
|
|
|
initializerBlock.FinalInstruction = new LdLoc(initializer); |
|
|
|
initializerBlock.Instructions.Add(new StLoc(initializer, newObj)); |
|
|
|
initializerBlock.Instructions.Add(new StLoc(initializer, newObj())); |
|
|
|
initializerBlock.Instructions.AddRange(arguments); |
|
|
|
initializerBlock.Instructions.AddRange(convertedArguments.Select(f => f(initializer))); |
|
|
|
return (initializerBlock, initializer.Type); |
|
|
|
return initializerBlock; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return (BuildBlock, ctor.DeclaringType); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
(ILInstruction, IType) ConvertLogicOperator(CallInstruction invocation, bool and) |
|
|
|
(Func<ILInstruction>, IType) ConvertLogicOperator(CallInstruction invocation, bool and) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (invocation.Arguments.Count < 2) |
|
|
|
if (invocation.Arguments.Count < 2) |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
@ -808,12 +883,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms |
|
|
|
switch (invocation.Arguments.Count) { |
|
|
|
switch (invocation.Arguments.Count) { |
|
|
|
case 2: |
|
|
|
case 2: |
|
|
|
var resultType = context.TypeSystem.FindType(KnownTypeCode.Boolean); |
|
|
|
var resultType = context.TypeSystem.FindType(KnownTypeCode.Boolean); |
|
|
|
return (and ? IfInstruction.LogicAnd(left, right) : IfInstruction.LogicOr(left, right), resultType); |
|
|
|
return (() => and ? IfInstruction.LogicAnd(left(), right()) : IfInstruction.LogicOr(left(), right()), resultType); |
|
|
|
case 3: |
|
|
|
case 3: |
|
|
|
if (!MatchGetMethodFromHandle(invocation.Arguments[2], out method)) |
|
|
|
if (!MatchGetMethodFromHandle(invocation.Arguments[2], out method)) |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (new Call((IMethod)method) { |
|
|
|
return (() => new Call((IMethod)method) { |
|
|
|
Arguments = { left, right } |
|
|
|
Arguments = { left(), right() } |
|
|
|
}, method.ReturnType); |
|
|
|
}, method.ReturnType); |
|
|
|
case 4: |
|
|
|
case 4: |
|
|
|
if (!invocation.Arguments[2].MatchLdcI4(out var isLifted)) |
|
|
|
if (!invocation.Arguments[2].MatchLdcI4(out var isLifted)) |
|
|
@ -822,46 +897,59 @@ namespace ICSharpCode.Decompiler.IL.Transforms |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
if (isLifted != 0) |
|
|
|
if (isLifted != 0) |
|
|
|
method = CSharpOperators.LiftUserDefinedOperator((IMethod)method); |
|
|
|
method = CSharpOperators.LiftUserDefinedOperator((IMethod)method); |
|
|
|
return (new Call((IMethod)method) { |
|
|
|
return (() => new Call((IMethod)method) { |
|
|
|
Arguments = { left, right } |
|
|
|
Arguments = { left(), right() } |
|
|
|
}, method.ReturnType); |
|
|
|
}, method.ReturnType); |
|
|
|
default: |
|
|
|
default: |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
(ILInstruction, IType) ConvertMemberInit(CallInstruction invocation) |
|
|
|
(Func<ILInstruction>, IType) ConvertMemberInit(CallInstruction invocation) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (invocation.Arguments.Count != 2) |
|
|
|
if (invocation.Arguments.Count != 2) |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
var newObj = ConvertInstruction(invocation.Arguments[0]).Item1 as NewObj; |
|
|
|
var newObj = ConvertInstruction(invocation.Arguments[0]).Item1; |
|
|
|
if (newObj == null) |
|
|
|
if (newObj == null) |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
|
|
|
|
if (!MatchNew((CallInstruction)invocation.Arguments[0], out var ctor)) |
|
|
|
|
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
if (!MatchArgumentList(invocation.Arguments[1], out var arguments)) |
|
|
|
if (!MatchArgumentList(invocation.Arguments[1], out var arguments)) |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
if (arguments == null || arguments.Count == 0) |
|
|
|
if (arguments == null || arguments.Count == 0) |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
var function = lambdaStack.Peek(); |
|
|
|
|
|
|
|
var initializer = function.RegisterVariable(VariableKind.InitializerTarget, newObj.Method.DeclaringType); |
|
|
|
Func<ILVariable, ILInstruction>[] convertedArguments = new Func<ILVariable, ILInstruction>[arguments.Count]; |
|
|
|
for (int i = 0; i < arguments.Count; i++) { |
|
|
|
for (int i = 0; i < arguments.Count; i++) { |
|
|
|
ILInstruction arg; |
|
|
|
Func<ILVariable, ILInstruction> arg; |
|
|
|
if (arguments[i] is CallInstruction bind && bind.Method.FullName == "System.Linq.Expressions.Expression.Bind") { |
|
|
|
if (arguments[i] is CallInstruction bind && bind.Method.FullName == "System.Linq.Expressions.Expression.Bind") { |
|
|
|
arg = ConvertBind(bind, initializer).Item1; |
|
|
|
arg = ConvertBind(bind).Item1; |
|
|
|
if (arg == null) |
|
|
|
if (arg == null) |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
} |
|
|
|
} |
|
|
|
arguments[i] = arg; |
|
|
|
convertedArguments[i] = arg; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ILInstruction BuildBlock() |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
var function = lambdaStack.Peek(); |
|
|
|
|
|
|
|
var initializer = function.RegisterVariable(VariableKind.InitializerTarget, ctor.DeclaringType); |
|
|
|
|
|
|
|
|
|
|
|
var initializerBlock = new Block(BlockKind.CollectionInitializer); |
|
|
|
var initializerBlock = new Block(BlockKind.CollectionInitializer); |
|
|
|
initializerBlock.FinalInstruction = new LdLoc(initializer); |
|
|
|
initializerBlock.FinalInstruction = new LdLoc(initializer); |
|
|
|
initializerBlock.Instructions.Add(new StLoc(initializer, newObj)); |
|
|
|
initializerBlock.Instructions.Add(new StLoc(initializer, newObj())); |
|
|
|
initializerBlock.Instructions.AddRange(arguments); |
|
|
|
initializerBlock.Instructions.AddRange(convertedArguments.Select(f => f(initializer))); |
|
|
|
return (initializerBlock, initializer.Type); |
|
|
|
|
|
|
|
|
|
|
|
return initializerBlock; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
(ILInstruction, IType) ConvertNewArrayBounds(CallInstruction invocation) |
|
|
|
|
|
|
|
|
|
|
|
return (BuildBlock, ctor.DeclaringType); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(Func<ILInstruction>, IType) ConvertNewArrayBounds(CallInstruction invocation) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (invocation.Arguments.Count != 2) |
|
|
|
if (invocation.Arguments.Count != 2) |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
@ -871,17 +959,17 @@ namespace ICSharpCode.Decompiler.IL.Transforms |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
if (arguments.Count == 0) |
|
|
|
if (arguments.Count == 0) |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
var indices = new ILInstruction[arguments.Count]; |
|
|
|
var indices = new Func<ILInstruction>[arguments.Count]; |
|
|
|
for (int i = 0; i < arguments.Count; i++) { |
|
|
|
for (int i = 0; i < arguments.Count; i++) { |
|
|
|
var index = ConvertInstruction(arguments[i]).Item1; |
|
|
|
var index = ConvertInstruction(arguments[i]).Item1; |
|
|
|
if (index == null) |
|
|
|
if (index == null) |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
indices[i] = index; |
|
|
|
indices[i] = index; |
|
|
|
} |
|
|
|
} |
|
|
|
return (new NewArr(type, indices), new ArrayType(context.TypeSystem, type, arguments.Count)); |
|
|
|
return (() => new NewArr(type, indices.SelectArray(f => f())), new ArrayType(context.TypeSystem, type, arguments.Count)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
(ILInstruction, IType) ConvertNewArrayInit(CallInstruction invocation) |
|
|
|
(Func<ILInstruction>, IType) ConvertNewArrayInit(CallInstruction invocation) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (invocation.Arguments.Count != 2) |
|
|
|
if (invocation.Arguments.Count != 2) |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
@ -891,67 +979,107 @@ namespace ICSharpCode.Decompiler.IL.Transforms |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
ArrayType arrayType = new ArrayType(context.BlockContext.TypeSystem, type); |
|
|
|
ArrayType arrayType = new ArrayType(context.BlockContext.TypeSystem, type); |
|
|
|
if (arguments.Count == 0) |
|
|
|
if (arguments.Count == 0) |
|
|
|
return (new NewArr(type, new LdcI4(0)), arrayType); |
|
|
|
return (() => new NewArr(type, new LdcI4(0)), arrayType); |
|
|
|
|
|
|
|
var convertedArguments = new Func<ILInstruction>[arguments.Count]; |
|
|
|
|
|
|
|
for (int i = 0; i < arguments.Count; i++) { |
|
|
|
|
|
|
|
ILInstruction item = arguments[i]; |
|
|
|
|
|
|
|
var value = ConvertInstruction(item).Item1; |
|
|
|
|
|
|
|
if (value == null) |
|
|
|
|
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
|
|
|
|
convertedArguments[i] = value; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ILInstruction BuildInitializer() |
|
|
|
|
|
|
|
{ |
|
|
|
var block = (Block)invocation.Arguments[1]; |
|
|
|
var block = (Block)invocation.Arguments[1]; |
|
|
|
var function = lambdaStack.Peek(); |
|
|
|
var function = lambdaStack.Peek(); |
|
|
|
var variable = function.RegisterVariable(VariableKind.InitializerTarget, arrayType); |
|
|
|
var variable = function.RegisterVariable(VariableKind.InitializerTarget, arrayType); |
|
|
|
Block initializer = new Block(BlockKind.ArrayInitializer); |
|
|
|
Block initializer = new Block(BlockKind.ArrayInitializer); |
|
|
|
int i = 0; |
|
|
|
initializer.Instructions.Add(new StLoc(variable, new NewArr(type, new LdcI4(convertedArguments.Length)))); |
|
|
|
initializer.Instructions.Add(new StLoc(variable, new NewArr(type, new LdcI4(arguments.Count)))); |
|
|
|
for (int i = 0; i < convertedArguments.Length; i++) { |
|
|
|
foreach (var item in arguments) { |
|
|
|
initializer.Instructions.Add(new StObj(new LdElema(type, new LdLoc(variable), new LdcI4(i)), convertedArguments[i](), type)); |
|
|
|
var value = ConvertInstruction(item).Item1; |
|
|
|
|
|
|
|
if (value == null) |
|
|
|
|
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
|
|
|
|
initializer.Instructions.Add(new StObj(new LdElema(type, new LdLoc(variable), new LdcI4(i)), value, type)); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
initializer.FinalInstruction = new LdLoc(variable); |
|
|
|
initializer.FinalInstruction = new LdLoc(variable); |
|
|
|
return (initializer, variable.Type); |
|
|
|
return initializer; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return (BuildInitializer, arrayType); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
(ILInstruction, IType) ConvertNewObject(CallInstruction invocation) |
|
|
|
bool MatchNew(CallInstruction invocation, out IMethod ctor) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
ctor = null; |
|
|
|
|
|
|
|
if (invocation.Method.Name != "New") |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
switch (invocation.Arguments.Count) { |
|
|
|
|
|
|
|
case 1: |
|
|
|
|
|
|
|
if (MatchGetTypeFromHandle(invocation.Arguments[0], out var type)) { |
|
|
|
|
|
|
|
ctor = type.GetConstructors(c => c.Parameters.Count == 0).FirstOrDefault(); |
|
|
|
|
|
|
|
return ctor != null; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (MatchGetConstructorFromHandle(invocation.Arguments[0], out var member)) { |
|
|
|
|
|
|
|
ctor = (IMethod)member; |
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
case 2: |
|
|
|
|
|
|
|
case 3: |
|
|
|
|
|
|
|
if (!MatchGetConstructorFromHandle(invocation.Arguments[0], out member)) |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
ctor = (IMethod)member; |
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
default: |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(Func<ILInstruction>, IType) ConvertNewObject(CallInstruction invocation) |
|
|
|
{ |
|
|
|
{ |
|
|
|
IMember member; |
|
|
|
|
|
|
|
IList<ILInstruction> arguments; |
|
|
|
|
|
|
|
NewObj newObj; |
|
|
|
|
|
|
|
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 ctor = type.GetConstructors(c => c.Parameters.Count == 0).FirstOrDefault(); |
|
|
|
var ctor = type.GetConstructors(c => c.Parameters.Count == 0).FirstOrDefault(); |
|
|
|
if (ctor == null) |
|
|
|
if (ctor == null) |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (new NewObj(ctor), type); |
|
|
|
return (() => new NewObj(ctor), type); |
|
|
|
} |
|
|
|
} |
|
|
|
if (MatchGetConstructorFromHandle(invocation.Arguments[0], out member)) { |
|
|
|
if (MatchGetConstructorFromHandle(invocation.Arguments[0], out var member)) { |
|
|
|
return (new NewObj((IMethod)member), member.DeclaringType); |
|
|
|
return (() => new NewObj((IMethod)member), member.DeclaringType); |
|
|
|
} |
|
|
|
} |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
case 2: |
|
|
|
case 2: |
|
|
|
if (!MatchGetConstructorFromHandle(invocation.Arguments[0], out member)) |
|
|
|
if (!MatchGetConstructorFromHandle(invocation.Arguments[0], out member)) |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
if (!MatchArgumentList(invocation.Arguments[1], out arguments)) |
|
|
|
if (!MatchArgumentList(invocation.Arguments[1], out var arguments)) |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
IMethod method = (IMethod)member; |
|
|
|
IMethod method = (IMethod)member; |
|
|
|
if (!ConvertCallArguments(arguments, method)) |
|
|
|
Func<ILInstruction>[] convertedArguments = ConvertCallArguments(arguments, method); |
|
|
|
|
|
|
|
if (convertedArguments == null) |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
newObj = new NewObj(method); |
|
|
|
return (() => BuildNewObj(method, convertedArguments), member.DeclaringType); |
|
|
|
newObj.Arguments.AddRange(arguments); |
|
|
|
|
|
|
|
return (newObj, member.DeclaringType); |
|
|
|
|
|
|
|
case 3: |
|
|
|
case 3: |
|
|
|
if (!MatchGetConstructorFromHandle(invocation.Arguments[0], out member)) |
|
|
|
if (!MatchGetConstructorFromHandle(invocation.Arguments[0], out member)) |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
if (!MatchArgumentList(invocation.Arguments[1], out arguments)) |
|
|
|
if (!MatchArgumentList(invocation.Arguments[1], out arguments)) |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
method = (IMethod)member; |
|
|
|
method = (IMethod)member; |
|
|
|
if (!ConvertCallArguments(arguments, method)) |
|
|
|
convertedArguments = ConvertCallArguments(arguments, method); |
|
|
|
|
|
|
|
if (convertedArguments == null) |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
newObj = new NewObj(method); |
|
|
|
return (() => BuildNewObj(method, convertedArguments), member.DeclaringType); |
|
|
|
newObj.Arguments.AddRange(arguments); |
|
|
|
} |
|
|
|
return (newObj, member.DeclaringType); |
|
|
|
|
|
|
|
|
|
|
|
ILInstruction BuildNewObj(IMethod method, Func<ILInstruction>[] args) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
var newObj = new NewObj(method); |
|
|
|
|
|
|
|
newObj.Arguments.AddRange(args.Select(f => f())); |
|
|
|
|
|
|
|
return newObj; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
(ILInstruction, IType) ConvertNotOperator(CallInstruction invocation) |
|
|
|
(Func<ILInstruction>, IType) ConvertNotOperator(CallInstruction invocation) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (invocation.Arguments.Count < 1) |
|
|
|
if (invocation.Arguments.Count < 1) |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
@ -960,27 +1088,27 @@ namespace ICSharpCode.Decompiler.IL.Transforms |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
switch (invocation.Arguments.Count) { |
|
|
|
switch (invocation.Arguments.Count) { |
|
|
|
case 1: |
|
|
|
case 1: |
|
|
|
return (argumentType.IsKnownType(KnownTypeCode.Boolean) ? Comp.LogicNot(argument) : (ILInstruction)new BitNot(argument), argumentType); |
|
|
|
return (() => argumentType.IsKnownType(KnownTypeCode.Boolean) ? Comp.LogicNot(argument()) : (ILInstruction)new BitNot(argument()), argumentType); |
|
|
|
case 2: |
|
|
|
case 2: |
|
|
|
if (!MatchGetMethodFromHandle(invocation.Arguments[1], out var method)) |
|
|
|
if (!MatchGetMethodFromHandle(invocation.Arguments[1], out var method)) |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (new Call((IMethod)method) { |
|
|
|
return (() => new Call((IMethod)method) { |
|
|
|
Arguments = { argument } |
|
|
|
Arguments = { argument() } |
|
|
|
}, method.ReturnType); |
|
|
|
}, method.ReturnType); |
|
|
|
default: |
|
|
|
default: |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
(ILInstruction, IType) ConvertProperty(CallInstruction invocation) |
|
|
|
(Func<ILInstruction>, IType) ConvertProperty(CallInstruction invocation) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (invocation.Arguments.Count < 2) |
|
|
|
if (invocation.Arguments.Count < 2) |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
ILInstruction target = null; |
|
|
|
Func<ILInstruction> targetConverter = null; |
|
|
|
IType targetType = null; |
|
|
|
IType targetType = null; |
|
|
|
if (!invocation.Arguments[0].MatchLdNull()) { |
|
|
|
if (!invocation.Arguments[0].MatchLdNull()) { |
|
|
|
(target, targetType) = ConvertInstruction(invocation.Arguments[0]); |
|
|
|
(targetConverter, targetType) = ConvertInstruction(invocation.Arguments[0]); |
|
|
|
if (target == null) |
|
|
|
if (targetConverter == null) |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
} |
|
|
|
} |
|
|
|
if (!MatchGetMethodFromHandle(invocation.Arguments[1], out var member)) |
|
|
|
if (!MatchGetMethodFromHandle(invocation.Arguments[1], out var member)) |
|
|
@ -988,24 +1116,28 @@ namespace ICSharpCode.Decompiler.IL.Transforms |
|
|
|
IList<ILInstruction> arguments; |
|
|
|
IList<ILInstruction> arguments; |
|
|
|
if (invocation.Arguments.Count != 3 || !MatchArgumentList(invocation.Arguments[2], out arguments)) { |
|
|
|
if (invocation.Arguments.Count != 3 || !MatchArgumentList(invocation.Arguments[2], out arguments)) { |
|
|
|
arguments = new List<ILInstruction>(); |
|
|
|
arguments = new List<ILInstruction>(); |
|
|
|
} else { |
|
|
|
|
|
|
|
if (!ConvertCallArguments(arguments, (IMethod)member)) |
|
|
|
|
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
var convertedArguments = ConvertCallArguments(arguments, (IMethod)member); |
|
|
|
|
|
|
|
if (convertedArguments == null) |
|
|
|
|
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
|
|
|
|
ILInstruction BuildProperty() |
|
|
|
|
|
|
|
{ |
|
|
|
CallInstruction call; |
|
|
|
CallInstruction call; |
|
|
|
if (member.IsAbstract || member.IsVirtual || member.IsOverride) { |
|
|
|
if (member.IsAbstract || member.IsVirtual || member.IsOverride) { |
|
|
|
call = new CallVirt((IMethod)member); |
|
|
|
call = new CallVirt((IMethod)member); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
call = new Call((IMethod)member); |
|
|
|
call = new Call((IMethod)member); |
|
|
|
} |
|
|
|
} |
|
|
|
if (target != null) { |
|
|
|
if (targetConverter != null) { |
|
|
|
call.Arguments.Add(PrepareCallTarget(member.DeclaringType, target, targetType)); |
|
|
|
call.Arguments.Add(PrepareCallTarget(member.DeclaringType, targetConverter(), targetType)); |
|
|
|
} |
|
|
|
} |
|
|
|
call.Arguments.AddRange(arguments); |
|
|
|
call.Arguments.AddRange(convertedArguments.Select(f => f())); |
|
|
|
return (call, member.ReturnType); |
|
|
|
return call; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return (BuildProperty, member.ReturnType); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
(ILInstruction, IType) ConvertTypeAs(CallInstruction invocation) |
|
|
|
(Func<ILInstruction>, IType) ConvertTypeAs(CallInstruction invocation) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (invocation.Arguments.Count != 2) |
|
|
|
if (invocation.Arguments.Count != 2) |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
@ -1014,16 +1146,19 @@ namespace ICSharpCode.Decompiler.IL.Transforms |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
if (converted == null) |
|
|
|
if (converted == null) |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
|
|
|
|
ILInstruction BuildTypeAs() |
|
|
|
ILInstruction inst = new IsInst(converted, type); |
|
|
|
{ |
|
|
|
|
|
|
|
ILInstruction inst = new IsInst(converted(), type); |
|
|
|
// We must follow ECMA-335, III.4.6:
|
|
|
|
// We must follow ECMA-335, III.4.6:
|
|
|
|
// If typeTok is a nullable type, Nullable<T>, it is interpreted as "boxed" T.
|
|
|
|
// If typeTok is a nullable type, Nullable<T>, it is interpreted as "boxed" T.
|
|
|
|
if (type.IsKnownType(KnownTypeCode.NullableOfT)) |
|
|
|
if (type.IsKnownType(KnownTypeCode.NullableOfT)) |
|
|
|
inst = new UnboxAny(inst, type); |
|
|
|
inst = new UnboxAny(inst, type); |
|
|
|
return (inst, type); |
|
|
|
return inst; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return (BuildTypeAs, type); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
(ILInstruction, IType) ConvertTypeIs(CallInstruction invocation) |
|
|
|
(Func<ILInstruction>, IType) ConvertTypeIs(CallInstruction invocation) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (invocation.Arguments.Count != 2) |
|
|
|
if (invocation.Arguments.Count != 2) |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
@ -1032,11 +1167,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
var resultType = context.TypeSystem.FindType(KnownTypeCode.Boolean); |
|
|
|
var resultType = context.TypeSystem.FindType(KnownTypeCode.Boolean); |
|
|
|
if (converted != null) |
|
|
|
if (converted != null) |
|
|
|
return (new Comp(ComparisonKind.Inequality, Sign.None, new IsInst(converted, type), new LdNull()), resultType); |
|
|
|
return (() => new Comp(ComparisonKind.Inequality, Sign.None, new IsInst(converted(), type), new LdNull()), resultType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
(ILInstruction, IType) ConvertUnaryNumericOperator(CallInstruction invocation, BinaryNumericOperator op, bool? isChecked = null) |
|
|
|
(Func<ILInstruction>, IType) ConvertUnaryNumericOperator(CallInstruction invocation, BinaryNumericOperator op, bool? isChecked = null) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (invocation.Arguments.Count < 1) |
|
|
|
if (invocation.Arguments.Count < 1) |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
@ -1046,7 +1181,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms |
|
|
|
switch (invocation.Arguments.Count) { |
|
|
|
switch (invocation.Arguments.Count) { |
|
|
|
case 1: |
|
|
|
case 1: |
|
|
|
ILInstruction left; |
|
|
|
ILInstruction left; |
|
|
|
switch (argument.ResultType) { |
|
|
|
switch (argumentType.GetStackType()) { |
|
|
|
case StackType.I4: |
|
|
|
case StackType.I4: |
|
|
|
left = new LdcI4(0); |
|
|
|
left = new LdcI4(0); |
|
|
|
break; |
|
|
|
break; |
|
|
@ -1065,12 +1200,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms |
|
|
|
default: |
|
|
|
default: |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
} |
|
|
|
} |
|
|
|
return (new BinaryNumericInstruction(op, left, argument, isChecked == true, argumentType.GetSign()), argumentType); |
|
|
|
return (() => new BinaryNumericInstruction(op, left, argument(), isChecked == true, argumentType.GetSign()), argumentType); |
|
|
|
case 2: |
|
|
|
case 2: |
|
|
|
if (!MatchGetMethodFromHandle(invocation.Arguments[1], out var method)) |
|
|
|
if (!MatchGetMethodFromHandle(invocation.Arguments[1], out var method)) |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (new Call((IMethod)method) { |
|
|
|
return (() => new Call((IMethod)method) { |
|
|
|
Arguments = { argument } |
|
|
|
Arguments = { argument() } |
|
|
|
}, method.ReturnType); |
|
|
|
}, method.ReturnType); |
|
|
|
} |
|
|
|
} |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
|
return (null, SpecialType.UnknownType); |
|
|
@ -1082,11 +1217,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms |
|
|
|
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 ldloc; |
|
|
|
return ldloc.Clone(); |
|
|
|
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); |
|
|
|
return new LdLoca(v).WithILRange(ldloc); |
|
|
|
return null; |
|
|
|
return null; |
|
|
|
} else if (IsClosureReference(ldloc.Variable)) { |
|
|
|
} else if (IsClosureReference(ldloc.Variable)) { |
|
|
|
if (ldloc.Variable.Kind == VariableKind.Local) { |
|
|
|
if (ldloc.Variable.Kind == VariableKind.Local) { |
|
|
|