Browse Source

Implement some dynamic instructions in ExpressionBuilder

pull/1165/head
Siegfried Pammer 7 years ago
parent
commit
ae018846d6
  1. 11
      ICSharpCode.Decompiler/CSharp/CallBuilder.cs
  2. 138
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

11
ICSharpCode.Decompiler/CSharp/CallBuilder.cs

@ -149,15 +149,8 @@ namespace ICSharpCode.Decompiler.CSharp @@ -149,15 +149,8 @@ namespace ICSharpCode.Decompiler.CSharp
arguments.Add(arg.ConvertTo(parameter.Type, expressionBuilder, allowImplicitConversion: true));
if (parameter.IsOut && arguments[i].Expression is DirectionExpression dirExpr && arguments[i].ResolveResult is ByReferenceResolveResult brrr) {
dirExpr.FieldDirection = FieldDirection.Out;
dirExpr.RemoveAnnotations<ByReferenceResolveResult>();
if (brrr.ElementResult == null)
brrr = new ByReferenceResolveResult(brrr.ElementType, isOut: true);
else
brrr = new ByReferenceResolveResult(brrr.ElementResult, isOut: true);
dirExpr.AddAnnotation(brrr);
arguments[i] = new TranslatedExpression(dirExpr);
if (parameter.IsOut) {
arguments[i] = ExpressionBuilder.ChangeDirectionExpressionToOut(arguments[i]);
}
}

138
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -614,7 +614,8 @@ namespace ICSharpCode.Decompiler.CSharp @@ -614,7 +614,8 @@ namespace ICSharpCode.Decompiler.CSharp
as OperatorResolveResult;
}
if (rr == null || rr.IsError || rr.UserDefinedOperatorMethod != null
|| NullableType.GetUnderlyingType(rr.Operands[0].Type).GetStackType() != inst.InputType)
|| NullableType.GetUnderlyingType(rr.Operands[0].Type).GetStackType() != inst.InputType
|| !rr.Type.IsKnownType(KnownTypeCode.Boolean))
{
IType targetType;
if (inst.InputType == StackType.O) {
@ -641,7 +642,8 @@ namespace ICSharpCode.Decompiler.CSharp @@ -641,7 +642,8 @@ namespace ICSharpCode.Decompiler.CSharp
rr = resolver.ResolveBinaryOperator(inst.Kind.ToBinaryOperatorType(),
left.ResolveResult, right.ResolveResult) as OperatorResolveResult;
if (rr == null || rr.IsError || rr.UserDefinedOperatorMethod != null
|| NullableType.GetUnderlyingType(rr.Operands[0].Type).GetStackType() != inst.InputType)
|| NullableType.GetUnderlyingType(rr.Operands[0].Type).GetStackType() != inst.InputType
|| !rr.Type.IsKnownType(KnownTypeCode.Boolean))
{
// If converting one input wasn't sufficient, convert both:
left = left.ConvertTo(targetType, this);
@ -2340,15 +2342,16 @@ namespace ICSharpCode.Decompiler.CSharp @@ -2340,15 +2342,16 @@ namespace ICSharpCode.Decompiler.CSharp
protected internal override TranslatedExpression VisitDynamicGetIndexInstruction(DynamicGetIndexInstruction inst, TranslationContext context)
{
var target = Translate(inst.Arguments[0], SpecialType.Dynamic);
return new IndexerExpression(target, inst.Arguments.Skip(1).Select(arg => Translate(arg, SpecialType.Dynamic).Expression))
var target = TranslateDynamicTarget(inst.Arguments[0], inst.ArgumentInfo[0]);
var arguments = TranslateDynamicArguments(inst.Arguments.Skip(1), inst.ArgumentInfo.Skip(1));
return new IndexerExpression(target, arguments)
.WithILInstruction(inst)
.WithRR(new ResolveResult(SpecialType.Dynamic));
}
protected internal override TranslatedExpression VisitDynamicGetMemberInstruction(DynamicGetMemberInstruction inst, TranslationContext context)
{
var target = Translate(inst.Target, SpecialType.Dynamic);
var target = TranslateDynamicTarget(inst.Target, inst.TargetArgumentInfo);
return new MemberReferenceExpression(target, inst.Name)
.WithILInstruction(inst)
.WithRR(new ResolveResult(SpecialType.Dynamic));
@ -2363,33 +2366,94 @@ namespace ICSharpCode.Decompiler.CSharp @@ -2363,33 +2366,94 @@ namespace ICSharpCode.Decompiler.CSharp
protected internal override TranslatedExpression VisitDynamicInvokeMemberInstruction(DynamicInvokeMemberInstruction inst, TranslationContext context)
{
TranslatedExpression target;
if (!IL.Transforms.TransformExpressionTrees.MatchGetTypeFromHandle(inst.Arguments[0], out var callTargetType))
target = Translate(inst.Arguments[0], SpecialType.Dynamic);
else
target = new TypeReferenceExpression(ConvertType(callTargetType))
.WithoutILInstruction()
.WithRR(new TypeResolveResult(callTargetType));
return new InvocationExpression(new MemberReferenceExpression(target, inst.Name, inst.TypeArguments.Select(ConvertType)), inst.Arguments.Skip(1).Select(arg => Translate(arg, SpecialType.Dynamic).Expression))
var target = TranslateDynamicTarget(inst.Arguments[0], inst.ArgumentInfo[0]);
var arguments = TranslateDynamicArguments(inst.Arguments.Skip(1), inst.ArgumentInfo.Skip(1));
return new InvocationExpression(new MemberReferenceExpression(target, inst.Name, inst.TypeArguments.Select(ConvertType)), arguments)
.WithILInstruction(inst)
.WithRR(new ResolveResult(SpecialType.Dynamic));
}
protected internal override TranslatedExpression VisitDynamicInvokeInstruction(DynamicInvokeInstruction inst, TranslationContext context)
{
return base.VisitDynamicInvokeInstruction(inst, context);
}
TranslatedExpression TranslateDynamicTarget(ILInstruction inst, CSharpArgumentInfo argumentInfo)
{
Debug.Assert(!argumentInfo.Flags.HasFlag(CSharpArgumentInfoFlags.NamedArgument));
Debug.Assert(!argumentInfo.Flags.HasFlag(CSharpArgumentInfoFlags.IsOut));
Debug.Assert(!argumentInfo.Flags.HasFlag(CSharpArgumentInfoFlags.IsRef));
Debug.Assert(!argumentInfo.Flags.HasFlag(CSharpArgumentInfoFlags.Constant));
if (argumentInfo.Flags.HasFlag(CSharpArgumentInfoFlags.IsStaticType) && IL.Transforms.TransformExpressionTrees.MatchGetTypeFromHandle(inst, out var callTargetType))
return new TypeReferenceExpression(ConvertType(callTargetType))
.WithoutILInstruction()
.WithRR(new TypeResolveResult(callTargetType));
IType targetType = SpecialType.Dynamic;
if (argumentInfo.Flags.HasFlag(CSharpArgumentInfoFlags.UseCompileTimeType))
targetType = argumentInfo.CompileTimeType;
return Translate(inst, targetType).ConvertTo(targetType, this);
}
IEnumerable<Expression> TranslateDynamicArguments(IEnumerable<ILInstruction> arguments, IEnumerable<CSharpArgumentInfo> argumentInfo)
{
foreach (var (argument, info) in arguments.Zip(argumentInfo))
yield return TranslateDynamicArgument(argument, info).Expression;
}
TranslatedExpression TranslateDynamicArgument(ILInstruction argument, CSharpArgumentInfo info)
{
Debug.Assert(!info.Flags.HasFlag(CSharpArgumentInfoFlags.IsStaticType));
IType typeHint = SpecialType.Dynamic;
if (info.Flags.HasFlag(CSharpArgumentInfoFlags.UseCompileTimeType)) {
typeHint = info.CompileTimeType;
}
if (info.Flags.HasFlag(CSharpArgumentInfoFlags.IsRef) || info.Flags.HasFlag(CSharpArgumentInfoFlags.IsOut)) {
typeHint = new ByReferenceType(typeHint);
}
var translatedExpression = Translate(argument, typeHint);
if (!(typeHint.Equals(SpecialType.Dynamic) && translatedExpression.Type.Equals(SpecialType.NullType)))
translatedExpression = translatedExpression.ConvertTo(typeHint, this);
if (info.Flags.HasFlag(CSharpArgumentInfoFlags.IsOut)) {
translatedExpression = ChangeDirectionExpressionToOut(translatedExpression);
}
if (info.Flags.HasFlag(CSharpArgumentInfoFlags.NamedArgument) && !string.IsNullOrWhiteSpace(info.Name))
translatedExpression = new TranslatedExpression(new NamedArgumentExpression(info.Name, translatedExpression.Expression));
return translatedExpression;
}
internal static TranslatedExpression ChangeDirectionExpressionToOut(TranslatedExpression input)
{
if (!(input.Expression is DirectionExpression dirExpr && input.ResolveResult is ByReferenceResolveResult brrr))
return input;
dirExpr.FieldDirection = FieldDirection.Out;
dirExpr.RemoveAnnotations<ByReferenceResolveResult>();
if (brrr.ElementResult == null)
brrr = new ByReferenceResolveResult(brrr.ElementType, isOut: true);
else
brrr = new ByReferenceResolveResult(brrr.ElementResult, isOut: true);
dirExpr.AddAnnotation(brrr);
return new TranslatedExpression(dirExpr);
}
protected internal override TranslatedExpression VisitDynamicSetIndexInstruction(DynamicSetIndexInstruction inst, TranslationContext context)
{
Debug.Assert(inst.Arguments.Count >= 3);
var target = Translate(inst.Arguments[0], SpecialType.Dynamic);
var value = Translate(inst.Arguments.Last(), SpecialType.Dynamic);
var target = TranslateDynamicTarget(inst.Arguments[0], inst.ArgumentInfo[0]).Expression;
var arguments = TranslateDynamicArguments(inst.Arguments.Skip(1), inst.ArgumentInfo.Skip(1));
var value = new TranslatedExpression(arguments.Last());
var indexer = new IndexerExpression(target, arguments.Take(inst.Arguments.Count - 2));
return Assignment(
new IndexerExpression(target, inst.Arguments.Skip(1).Take(inst.Arguments.Count - 2).Select(arg => Translate(arg, SpecialType.Dynamic).Expression)).WithoutILInstruction().WithRR(new ResolveResult(SpecialType.Dynamic)),
indexer.WithoutILInstruction().WithRR(new ResolveResult(SpecialType.Dynamic)),
value
).WithILInstruction(inst);
}
protected internal override TranslatedExpression VisitDynamicSetMemberInstruction(DynamicSetMemberInstruction inst, TranslationContext context)
{
var target = Translate(inst.Target, SpecialType.Dynamic);
var value = Translate(inst.Value, SpecialType.Dynamic);
var target = TranslateDynamicTarget(inst.Target, inst.TargetArgumentInfo);
var value = TranslateDynamicArgument(inst.Value, inst.ValueArgumentInfo);
return Assignment(
new MemberReferenceExpression(target, inst.Name).WithoutILInstruction().WithRR(new ResolveResult(SpecialType.Dynamic)),
value
@ -2400,28 +2464,50 @@ namespace ICSharpCode.Decompiler.CSharp @@ -2400,28 +2464,50 @@ namespace ICSharpCode.Decompiler.CSharp
{
switch (inst.Operation) {
case ExpressionType.Add:
return CreateArithmeticBinaryOperator(BinaryOperatorType.Add);
return CreateBinaryOperator(BinaryOperatorType.Add);
case ExpressionType.Subtract:
return CreateArithmeticBinaryOperator(BinaryOperatorType.Subtract);
return CreateBinaryOperator(BinaryOperatorType.Subtract);
case ExpressionType.Multiply:
return CreateArithmeticBinaryOperator(BinaryOperatorType.Multiply);
return CreateBinaryOperator(BinaryOperatorType.Multiply);
case ExpressionType.Divide:
return CreateArithmeticBinaryOperator(BinaryOperatorType.Divide);
return CreateBinaryOperator(BinaryOperatorType.Divide);
case ExpressionType.Modulo:
return CreateArithmeticBinaryOperator(BinaryOperatorType.Modulus);
return CreateBinaryOperator(BinaryOperatorType.Modulus);
case ExpressionType.Equal:
return CreateBinaryOperator(BinaryOperatorType.Equality);
case ExpressionType.NotEqual:
return CreateBinaryOperator(BinaryOperatorType.InEquality);
case ExpressionType.LessThan:
return CreateBinaryOperator(BinaryOperatorType.LessThan);
case ExpressionType.LessThanOrEqual:
return CreateBinaryOperator(BinaryOperatorType.LessThanOrEqual);
case ExpressionType.GreaterThan:
return CreateBinaryOperator(BinaryOperatorType.GreaterThan);
case ExpressionType.GreaterThanOrEqual:
return CreateBinaryOperator(BinaryOperatorType.GreaterThanOrEqual);
default:
return base.VisitDynamicBinaryOperatorInstruction(inst, context);
}
TranslatedExpression CreateArithmeticBinaryOperator(BinaryOperatorType operatorType)
TranslatedExpression CreateBinaryOperator(BinaryOperatorType operatorType)
{
var left = Translate(inst.Left);
var right = Translate(inst.Right);
var left = TranslateDynamicArgument(inst.Left, inst.LeftArgumentInfo);
var right = TranslateDynamicArgument(inst.Right, inst.RightArgumentInfo);
return new BinaryOperatorExpression(left.Expression, operatorType, right.Expression)
.WithILInstruction(inst).WithRR(new ResolveResult(SpecialType.Dynamic));
}
}
protected internal override TranslatedExpression VisitDynamicCompoundAssign(DynamicCompoundAssign inst, TranslationContext context)
{
var target = TranslateDynamicArgument(inst.Target, inst.TargetArgumentInfo);
var value = TranslateDynamicArgument(inst.Value, inst.ValueArgumentInfo);
return new AssignmentExpression(target, AssignmentExpression.GetAssignmentOperatorTypeFromExpressionType(inst.Operation), value)
.WithILInstruction(inst)
.WithRR(new OperatorResolveResult(SpecialType.Dynamic, inst.Operation, new[] { target.ResolveResult, value.ResolveResult }));
}
protected internal override TranslatedExpression VisitInvalidBranch(InvalidBranch inst, TranslationContext context)
{
string message = "Error";

Loading…
Cancel
Save