From dea81a685d1939c51bd4c76e7b5dde07ccdbc9b9 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Fri, 22 Sep 2017 21:32:56 +0200 Subject: [PATCH] Add UsingInstruction to ILAst. --- ICSharpCode.Decompiler/IL/Instructions.cs | 140 ++++++++++++++++++ ICSharpCode.Decompiler/IL/Instructions.tt | 7 +- .../IL/Instructions/LockInstruction.cs | 30 ++-- 3 files changed, 166 insertions(+), 11 deletions(-) diff --git a/ICSharpCode.Decompiler/IL/Instructions.cs b/ICSharpCode.Decompiler/IL/Instructions.cs index 802fe237c..4f8ab96eb 100644 --- a/ICSharpCode.Decompiler/IL/Instructions.cs +++ b/ICSharpCode.Decompiler/IL/Instructions.cs @@ -73,6 +73,8 @@ namespace ICSharpCode.Decompiler.IL TryFault, /// Lock statement LockInstruction, + /// Using statement + UsingInstruction, /// Breakpoint instruction DebugBreak, /// Comparison. The inputs must be both integers; or both floats; or both object references. Object references can only be compared for equality or inequality. Floating-point comparisons evaluate to 0 (false) when an input is NaN, except for 'NaN != NaN' which evaluates to 1 (true). @@ -1667,6 +1669,16 @@ namespace ICSharpCode.Decompiler.IL clone.Body = this.body.Clone(); return clone; } + public override StackType ResultType { get { return StackType.Void; } } + protected override InstructionFlags ComputeFlags() + { + return onExpression.Flags | body.Flags | InstructionFlags.ControlFlow | InstructionFlags.SideEffect; + } + public override InstructionFlags DirectFlags { + get { + return InstructionFlags.ControlFlow | InstructionFlags.SideEffect; + } + } public override void AcceptVisitor(ILVisitor visitor) { visitor.VisitLockInstruction(this); @@ -1687,6 +1699,109 @@ namespace ICSharpCode.Decompiler.IL } } namespace ICSharpCode.Decompiler.IL +{ + /// Using statement + public sealed partial class UsingInstruction : ILInstruction + { + public UsingInstruction(ILInstruction resourceExpression, ILInstruction body) : base(OpCode.UsingInstruction) + { + this.ResourceExpression = resourceExpression; + this.Body = body; + } + public static readonly SlotInfo ResourceExpressionSlot = new SlotInfo("ResourceExpression", canInlineInto: true); + ILInstruction resourceExpression; + public ILInstruction ResourceExpression { + get { return this.resourceExpression; } + set { + ValidateChild(value); + SetChildInstruction(ref this.resourceExpression, value, 0); + } + } + public static readonly SlotInfo BodySlot = new SlotInfo("Body"); + ILInstruction body; + public ILInstruction Body { + get { return this.body; } + set { + ValidateChild(value); + SetChildInstruction(ref this.body, value, 1); + } + } + protected sealed override int GetChildCount() + { + return 2; + } + protected sealed override ILInstruction GetChild(int index) + { + switch (index) { + case 0: + return this.resourceExpression; + case 1: + return this.body; + default: + throw new IndexOutOfRangeException(); + } + } + protected sealed override void SetChild(int index, ILInstruction value) + { + switch (index) { + case 0: + this.ResourceExpression = value; + break; + case 1: + this.Body = value; + break; + default: + throw new IndexOutOfRangeException(); + } + } + protected sealed override SlotInfo GetChildSlot(int index) + { + switch (index) { + case 0: + return ResourceExpressionSlot; + case 1: + return BodySlot; + default: + throw new IndexOutOfRangeException(); + } + } + public sealed override ILInstruction Clone() + { + var clone = (UsingInstruction)ShallowClone(); + clone.ResourceExpression = this.resourceExpression.Clone(); + clone.Body = this.body.Clone(); + return clone; + } + public override StackType ResultType { get { return StackType.Void; } } + protected override InstructionFlags ComputeFlags() + { + return resourceExpression.Flags | body.Flags | InstructionFlags.ControlFlow | InstructionFlags.SideEffect; + } + public override InstructionFlags DirectFlags { + get { + return InstructionFlags.ControlFlow | InstructionFlags.SideEffect; + } + } + public override void AcceptVisitor(ILVisitor visitor) + { + visitor.VisitUsingInstruction(this); + } + public override T AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitUsingInstruction(this); + } + public override T AcceptVisitor(ILVisitor visitor, C context) + { + return visitor.VisitUsingInstruction(this, context); + } + protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match) + { + var o = other as UsingInstruction; + return o != null && this.resourceExpression.PerformMatch(o.resourceExpression, ref match) && this.body.PerformMatch(o.body, ref match); + } + } +} +namespace ICSharpCode.Decompiler.IL { /// Breakpoint instruction public sealed partial class DebugBreak : SimpleInstruction @@ -4310,6 +4425,10 @@ namespace ICSharpCode.Decompiler.IL { Default(inst); } + protected internal virtual void VisitUsingInstruction(UsingInstruction inst) + { + Default(inst); + } protected internal virtual void VisitDebugBreak(DebugBreak inst) { Default(inst); @@ -4592,6 +4711,10 @@ namespace ICSharpCode.Decompiler.IL { return Default(inst); } + protected internal virtual T VisitUsingInstruction(UsingInstruction inst) + { + return Default(inst); + } protected internal virtual T VisitDebugBreak(DebugBreak inst) { return Default(inst); @@ -4874,6 +4997,10 @@ namespace ICSharpCode.Decompiler.IL { return Default(inst, context); } + protected internal virtual T VisitUsingInstruction(UsingInstruction inst, C context) + { + return Default(inst, context); + } protected internal virtual T VisitDebugBreak(DebugBreak inst, C context) { return Default(inst, context); @@ -5085,6 +5212,7 @@ namespace ICSharpCode.Decompiler.IL "try.finally", "try.fault", "lock", + "using", "debug.break", "comp", "call", @@ -5209,6 +5337,18 @@ namespace ICSharpCode.Decompiler.IL body = default(ILInstruction); return false; } + public bool MatchUsingInstruction(out ILInstruction resourceExpression, out ILInstruction body) + { + var inst = this as UsingInstruction; + if (inst != null) { + resourceExpression = inst.ResourceExpression; + body = inst.Body; + return true; + } + resourceExpression = default(ILInstruction); + body = default(ILInstruction); + return false; + } public bool MatchDebugBreak() { var inst = this as DebugBreak; diff --git a/ICSharpCode.Decompiler/IL/Instructions.tt b/ICSharpCode.Decompiler/IL/Instructions.tt index 332e43ff9..3e1d0299c 100644 --- a/ICSharpCode.Decompiler/IL/Instructions.tt +++ b/ICSharpCode.Decompiler/IL/Instructions.tt @@ -118,7 +118,12 @@ CustomChildren(new [] { new ArgumentInfo("onExpression"), new ChildInfo("body") - }), CustomWriteTo, CustomComputeFlags), + }), CustomWriteTo, ControlFlow, SideEffect, ResultType("Void")), + new OpCode("using", "Using statement", CustomClassName("UsingInstruction"), + CustomChildren(new [] { + new ArgumentInfo("resourceExpression"), + new ChildInfo("body") + }), CustomWriteTo, ControlFlow, SideEffect, ResultType("Void")), new OpCode("debug.break", "Breakpoint instruction", NoArguments, VoidResult, SideEffect), new OpCode("comp", "Comparison. The inputs must be both integers; or both floats; or both object references. " diff --git a/ICSharpCode.Decompiler/IL/Instructions/LockInstruction.cs b/ICSharpCode.Decompiler/IL/Instructions/LockInstruction.cs index 4b6f8087b..a02b160b6 100644 --- a/ICSharpCode.Decompiler/IL/Instructions/LockInstruction.cs +++ b/ICSharpCode.Decompiler/IL/Instructions/LockInstruction.cs @@ -8,21 +8,31 @@ namespace ICSharpCode.Decompiler.IL { partial class LockInstruction { - protected override InstructionFlags ComputeFlags() + public override void WriteTo(ITextOutput output) { - return Body.Flags | OnExpression.Flags | InstructionFlags.ControlFlow | InstructionFlags.SideEffect; + output.Write("lock ("); + OnExpression.WriteTo(output); + output.WriteLine(") {"); + output.Indent(); + Body.WriteTo(output); + output.Unindent(); + output.WriteLine(); + output.Write("}"); } + } - public override InstructionFlags DirectFlags => InstructionFlags.ControlFlow | InstructionFlags.SideEffect; - - public override StackType ResultType => StackType.Void; - + partial class UsingInstruction + { public override void WriteTo(ITextOutput output, ILAstWritingOptions options) { - output.Write("lock ("); - OnExpression.WriteTo(output, options); - output.WriteLine(") "); - Body.WriteTo(output, options); + output.Write("using ("); + ResourceExpression.WriteTo(output); + output.WriteLine(") {"); + output.Indent(); + Body.WriteTo(output); + output.Unindent(); + output.WriteLine(); + output.Write("}"); } } }