diff --git a/ICSharpCode.Decompiler/IL/Instructions.cs b/ICSharpCode.Decompiler/IL/Instructions.cs index 4f8ab96eb..2887b0784 100644 --- a/ICSharpCode.Decompiler/IL/Instructions.cs +++ b/ICSharpCode.Decompiler/IL/Instructions.cs @@ -1701,13 +1701,53 @@ namespace ICSharpCode.Decompiler.IL namespace ICSharpCode.Decompiler.IL { /// Using statement - public sealed partial class UsingInstruction : ILInstruction + public sealed partial class UsingInstruction : ILInstruction, IStoreInstruction { - public UsingInstruction(ILInstruction resourceExpression, ILInstruction body) : base(OpCode.UsingInstruction) + public UsingInstruction(ILVariable variable, ILInstruction resourceExpression, ILInstruction body) : base(OpCode.UsingInstruction) { + Debug.Assert(variable != null); + this.variable = variable; this.ResourceExpression = resourceExpression; this.Body = body; } + ILVariable variable; + public ILVariable Variable { + get { return variable; } + set { + Debug.Assert(value != null); + if (IsConnected) + variable.RemoveStoreInstruction(this); + variable = value; + if (IsConnected) + variable.AddStoreInstruction(this); + } + } + + public int IndexInStoreInstructionList { get; set; } = -1; + + int IInstructionWithVariableOperand.IndexInVariableInstructionMapping { + get { return ((IStoreInstruction)this).IndexInStoreInstructionList; } + set { ((IStoreInstruction)this).IndexInStoreInstructionList = value; } + } + + protected override void Connected() + { + base.Connected(); + variable.AddStoreInstruction(this); + } + + protected override void Disconnected() + { + variable.RemoveStoreInstruction(this); + base.Disconnected(); + } + + internal override void CheckInvariant(ILPhase phase) + { + base.CheckInvariant(phase); + Debug.Assert(phase <= ILPhase.InILReader || this.IsDescendantOf(variable.Function)); + Debug.Assert(phase <= ILPhase.InILReader || variable.Function.Variables[variable.IndexInFunction] == variable); + } public static readonly SlotInfo ResourceExpressionSlot = new SlotInfo("ResourceExpression", canInlineInto: true); ILInstruction resourceExpression; public ILInstruction ResourceExpression { @@ -1775,11 +1815,11 @@ namespace ICSharpCode.Decompiler.IL public override StackType ResultType { get { return StackType.Void; } } protected override InstructionFlags ComputeFlags() { - return resourceExpression.Flags | body.Flags | InstructionFlags.ControlFlow | InstructionFlags.SideEffect; + return InstructionFlags.MayWriteLocals | resourceExpression.Flags | body.Flags | InstructionFlags.ControlFlow | InstructionFlags.SideEffect; } public override InstructionFlags DirectFlags { get { - return InstructionFlags.ControlFlow | InstructionFlags.SideEffect; + return InstructionFlags.MayWriteLocals | InstructionFlags.ControlFlow | InstructionFlags.SideEffect; } } public override void AcceptVisitor(ILVisitor visitor) @@ -1797,7 +1837,7 @@ namespace ICSharpCode.Decompiler.IL 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); + return o != null && variable == o.variable && this.resourceExpression.PerformMatch(o.resourceExpression, ref match) && this.body.PerformMatch(o.body, ref match); } } } @@ -5337,14 +5377,16 @@ namespace ICSharpCode.Decompiler.IL body = default(ILInstruction); return false; } - public bool MatchUsingInstruction(out ILInstruction resourceExpression, out ILInstruction body) + public bool MatchUsingInstruction(out ILVariable variable, out ILInstruction resourceExpression, out ILInstruction body) { var inst = this as UsingInstruction; if (inst != null) { + variable = inst.Variable; resourceExpression = inst.ResourceExpression; body = inst.Body; return true; } + variable = default(ILVariable); resourceExpression = default(ILInstruction); body = default(ILInstruction); return false; diff --git a/ICSharpCode.Decompiler/IL/Instructions.tt b/ICSharpCode.Decompiler/IL/Instructions.tt index 3e1d0299c..10ac8995e 100644 --- a/ICSharpCode.Decompiler/IL/Instructions.tt +++ b/ICSharpCode.Decompiler/IL/Instructions.tt @@ -119,7 +119,7 @@ new ArgumentInfo("onExpression"), new ChildInfo("body") }), CustomWriteTo, ControlFlow, SideEffect, ResultType("Void")), - new OpCode("using", "Using statement", CustomClassName("UsingInstruction"), + new OpCode("using", "Using statement", CustomClassName("UsingInstruction"), HasVariableOperand("Store"), CustomChildren(new [] { new ArgumentInfo("resourceExpression"), new ChildInfo("body") diff --git a/ICSharpCode.Decompiler/IL/Instructions/LockInstruction.cs b/ICSharpCode.Decompiler/IL/Instructions/LockInstruction.cs index a955e52ae..1350a68eb 100644 --- a/ICSharpCode.Decompiler/IL/Instructions/LockInstruction.cs +++ b/ICSharpCode.Decompiler/IL/Instructions/LockInstruction.cs @@ -39,11 +39,25 @@ namespace ICSharpCode.Decompiler.IL } } + /// + /// IL using instruction. + /// Equivalent to: + /// + /// stloc v(resourceExpression) + /// try { + /// body + /// } finally { + /// v?.Dispose(); + /// } + /// + /// partial class UsingInstruction { public override void WriteTo(ITextOutput output, ILAstWritingOptions options) { output.Write("using ("); + Variable.WriteTo(output); + output.Write(" = "); ResourceExpression.WriteTo(output, options); output.WriteLine(") {"); output.Indent(); diff --git a/ICSharpCode.Decompiler/IL/Transforms/UsingTransform.cs b/ICSharpCode.Decompiler/IL/Transforms/UsingTransform.cs index 2f932184f..16ad2a45a 100644 --- a/ICSharpCode.Decompiler/IL/Transforms/UsingTransform.cs +++ b/ICSharpCode.Decompiler/IL/Transforms/UsingTransform.cs @@ -76,23 +76,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms return false; if (!(body.FinallyBlock is BlockContainer container) || !MatchDisposeBlock(container, storeInst.Variable, storeInst.Value.MatchLdNull())) return false; - ILInstruction resourceExpression; - if (storeInst.Variable.Type.IsReferenceType != false) { - if (storeInst.Variable.IsSingleDefinition && storeInst.Variable.LoadCount <= 2) { - resourceExpression = storeInst.Value; - } else { - resourceExpression = storeInst; - } - } else { - if (storeInst.Variable.StoreCount == 1 && storeInst.Variable.LoadCount == 0 && storeInst.Variable.AddressCount == 1) { - resourceExpression = storeInst.Value; - } else { - resourceExpression = storeInst; - } - } context.Step("UsingTransform", body); block.Instructions.RemoveAt(i); - block.Instructions[i - 1] = new UsingInstruction(resourceExpression, body.TryBlock); + block.Instructions[i - 1] = new UsingInstruction(storeInst.Variable, storeInst.Value, body.TryBlock); return true; }