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;
}