From 21dfa43dab1edba060f14ba44ff35e149c57b694 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Thu, 23 Nov 2017 10:24:03 +0100 Subject: [PATCH] Add ExpressionTreeCast instruction --- .../CSharp/ExpressionBuilder.cs | 7 ++- .../ICSharpCode.Decompiler.csproj | 1 + ICSharpCode.Decompiler/IL/Instructions.cs | 55 +++++++++++++++++++ ICSharpCode.Decompiler/IL/Instructions.tt | 4 ++ .../IL/Transforms/ExpressionTreeCast.cs | 31 +++++++++++ 5 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 ICSharpCode.Decompiler/IL/Transforms/ExpressionTreeCast.cs diff --git a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs index dc7dbb8b4..a46e34568 100644 --- a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs @@ -1701,7 +1701,12 @@ namespace ICSharpCode.Decompiler.CSharp { return Translate(inst.Argument).ConvertTo(inst.Type, this); } - + + protected internal override TranslatedExpression VisitExpressionTreeCast(ExpressionTreeCast inst, TranslationContext context) + { + return Translate(inst.Argument).ConvertTo(inst.Type, this, inst.IsChecked); + } + protected internal override TranslatedExpression VisitArglist(Arglist inst, TranslationContext context) { return new UndocumentedExpression { UndocumentedExpressionType = UndocumentedExpressionType.ArgListAccess } diff --git a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj index 5d4782630..3283989fa 100644 --- a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj +++ b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj @@ -283,6 +283,7 @@ + diff --git a/ICSharpCode.Decompiler/IL/Instructions.cs b/ICSharpCode.Decompiler/IL/Instructions.cs index 58941eba3..0ea2866d3 100644 --- a/ICSharpCode.Decompiler/IL/Instructions.cs +++ b/ICSharpCode.Decompiler/IL/Instructions.cs @@ -168,6 +168,8 @@ namespace ICSharpCode.Decompiler.IL ArrayToPointer, /// Maps a string value to an integer. This is used in switch(string). StringToInt, + /// ILAst representation of Expression.Convert. + ExpressionTreeCast, /// Push a typed reference of type class onto the stack. MakeRefAny, /// Push the type token stored in a typed reference. @@ -4493,6 +4495,46 @@ namespace ICSharpCode.Decompiler.IL } } namespace ICSharpCode.Decompiler.IL +{ + /// ILAst representation of Expression.Convert. + public sealed partial class ExpressionTreeCast : UnaryInstruction + { + IType type; + /// Returns the type operand. + public IType Type { + get { return type; } + set { type = value; InvalidateFlags(); } + } + public override StackType ResultType { get { return type.GetStackType(); } } + protected override InstructionFlags ComputeFlags() + { + return base.ComputeFlags() | InstructionFlags.MayThrow; + } + public override InstructionFlags DirectFlags { + get { + return base.DirectFlags | InstructionFlags.MayThrow; + } + } + public override void AcceptVisitor(ILVisitor visitor) + { + visitor.VisitExpressionTreeCast(this); + } + public override T AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitExpressionTreeCast(this); + } + public override T AcceptVisitor(ILVisitor visitor, C context) + { + return visitor.VisitExpressionTreeCast(this, context); + } + protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match) + { + var o = other as ExpressionTreeCast; + return o != null && this.Argument.PerformMatch(o.Argument, ref match) && type.Equals(o.type) && this.IsChecked == o.IsChecked; + } + } +} +namespace ICSharpCode.Decompiler.IL { /// Push a typed reference of type class onto the stack. public sealed partial class MakeRefAny : UnaryInstruction @@ -5132,6 +5174,10 @@ namespace ICSharpCode.Decompiler.IL { Default(inst); } + protected internal virtual void VisitExpressionTreeCast(ExpressionTreeCast inst) + { + Default(inst); + } protected internal virtual void VisitMakeRefAny(MakeRefAny inst) { Default(inst); @@ -5434,6 +5480,10 @@ namespace ICSharpCode.Decompiler.IL { return Default(inst); } + protected internal virtual T VisitExpressionTreeCast(ExpressionTreeCast inst) + { + return Default(inst); + } protected internal virtual T VisitMakeRefAny(MakeRefAny inst) { return Default(inst); @@ -5736,6 +5786,10 @@ namespace ICSharpCode.Decompiler.IL { return Default(inst, context); } + protected internal virtual T VisitExpressionTreeCast(ExpressionTreeCast inst, C context) + { + return Default(inst, context); + } protected internal virtual T VisitMakeRefAny(MakeRefAny inst, C context) { return Default(inst, context); @@ -5829,6 +5883,7 @@ namespace ICSharpCode.Decompiler.IL "ldelema", "array.to.pointer", "string.to.int", + "expression.tree.cast", "mkrefany", "refanytype", "refanyval", diff --git a/ICSharpCode.Decompiler/IL/Instructions.tt b/ICSharpCode.Decompiler/IL/Instructions.tt index bab9fd9ea..04a85831d 100644 --- a/ICSharpCode.Decompiler/IL/Instructions.tt +++ b/ICSharpCode.Decompiler/IL/Instructions.tt @@ -240,6 +240,10 @@ new OpCode("string.to.int", "Maps a string value to an integer. This is used in switch(string).", CustomArguments("argument"), CustomConstructor, CustomWriteTo, ResultType("I4")), + new OpCode("expression.tree.cast", "ILAst representation of Expression.Convert.", + CustomClassName("ExpressionTreeCast"), Unary, HasTypeOperand, MayThrow, CustomConstructor, CustomWriteTo, ResultType("type.GetStackType()"), + MatchCondition("this.IsChecked == o.IsChecked")), + new OpCode("mkrefany", "Push a typed reference of type class onto the stack.", CustomClassName("MakeRefAny"), Unary, HasTypeOperand, ResultType("O")), new OpCode("refanytype", "Push the type token stored in a typed reference.", diff --git a/ICSharpCode.Decompiler/IL/Transforms/ExpressionTreeCast.cs b/ICSharpCode.Decompiler/IL/Transforms/ExpressionTreeCast.cs new file mode 100644 index 000000000..3fa452e24 --- /dev/null +++ b/ICSharpCode.Decompiler/IL/Transforms/ExpressionTreeCast.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Text; +using ICSharpCode.Decompiler.TypeSystem; + +namespace ICSharpCode.Decompiler.IL +{ + partial class ExpressionTreeCast + { + public bool IsChecked { get; set; } + + public ExpressionTreeCast(IType type, ILInstruction argument, bool isChecked) + : base(OpCode.ExpressionTreeCast, argument) + { + this.Type = type; + this.IsChecked = isChecked; + } + + public override void WriteTo(ITextOutput output, ILAstWritingOptions options) + { + ILRange.WriteTo(output, options); + output.Write(OpCode); + if (IsChecked) output.Write(".checked"); + output.Write(' '); + type.WriteTo(output); + output.Write('('); + Argument.WriteTo(output, options); + output.Write(')'); + } + } +}