/// <summary> /// stloc obj(resourceExpression) /// .try BlockContainer { /// Block IL_0003(incoming: 1) { /// call WriteLine(ldstr "using (null)") /// leave IL_0003(nop) /// } /// } finally BlockContainer { /// Block IL_0012(incoming: 1) { /// if (comp(ldloc obj != ldnull)) Block IL_001a { /// callvirt Dispose(ldnull) /// } /// leave IL_0012(nop) /// } /// } /// leave IL_0000(nop) /// => /// using (resourceExpression) { /// BlockContainer { /// Block IL_0003(incoming: 1) { /// call WriteLine(ldstr "using (null)") /// leave IL_0003(nop) /// } /// } /// } /// </summary> bool TransformUsing(Block block, int i) { if (i < 1) { return(false); } if (!(block.Instructions[i] is TryFinally tryFinally) || !(block.Instructions[i - 1] is StLoc storeInst)) { return(false); } if (!(storeInst.Value.MatchLdNull() || CheckResourceType(storeInst.Variable.Type))) { return(false); } if (storeInst.Variable.LoadInstructions.Any(ld => !ld.IsDescendantOf(tryFinally))) { return(false); } if (storeInst.Variable.AddressInstructions.Any(la => !la.IsDescendantOf(tryFinally) || (la.IsDescendantOf(tryFinally.TryBlock) && !ILInlining.IsUsedAsThisPointerInCall(la)))) { return(false); } if (storeInst.Variable.StoreInstructions.Count > 1) { return(false); } if (!(tryFinally.FinallyBlock is BlockContainer container) || !MatchDisposeBlock(container, storeInst.Variable, storeInst.Value.MatchLdNull())) { return(false); } context.Step("UsingTransform", tryFinally); storeInst.Variable.Kind = VariableKind.UsingLocal; block.Instructions.RemoveAt(i); block.Instructions[i - 1] = new UsingInstruction(storeInst.Variable, storeInst.Value, tryFinally.TryBlock) { ILRange = storeInst.ILRange }; return(true); }
/// <summary> /// stloc obj(resourceExpression) /// .try BlockContainer { /// Block IL_0003(incoming: 1) { /// call WriteLine(ldstr "using (null)") /// leave IL_0003(nop) /// } /// } finally BlockContainer { /// Block IL_0012(incoming: 1) { /// if (comp(ldloc obj != ldnull)) Block IL_001a { /// callvirt Dispose(ldnull) /// } /// leave IL_0012(nop) /// } /// } /// leave IL_0000(nop) /// => /// using (resourceExpression) { /// BlockContainer { /// Block IL_0003(incoming: 1) { /// call WriteLine(ldstr "using (null)") /// leave IL_0003(nop) /// } /// } /// } /// </summary> bool TransformUsing(Block block, int i) { if (i + 1 >= block.Instructions.Count) { return(false); } if (!(block.Instructions[i + 1] is TryFinally tryFinally) || !(block.Instructions[i] is StLoc storeInst)) { return(false); } if (!(storeInst.Value.MatchLdNull() || CheckResourceType(storeInst.Variable.Type))) { return(false); } if (storeInst.Variable.Kind != VariableKind.Local) { return(false); } if (storeInst.Variable.LoadInstructions.Any(ld => !ld.IsDescendantOf(tryFinally))) { return(false); } if (storeInst.Variable.AddressInstructions.Any(la => !la.IsDescendantOf(tryFinally) || (la.IsDescendantOf(tryFinally.TryBlock) && !ILInlining.IsUsedAsThisPointerInCall(la)))) { return(false); } if (storeInst.Variable.StoreInstructions.Count > 1) { return(false); } if (!(tryFinally.FinallyBlock is BlockContainer container)) { return(false); } if (!MatchDisposeBlock(container, storeInst.Variable, storeInst.Value.MatchLdNull())) { return(false); } context.Step("UsingTransform", tryFinally); storeInst.Variable.Kind = VariableKind.UsingLocal; block.Instructions.RemoveAt(i + 1); block.Instructions[i] = new UsingInstruction(storeInst.Variable, storeInst.Value, tryFinally.TryBlock) { IsRefStruct = context.Settings.IntroduceRefModifiersOnStructs && storeInst.Variable.Type.Kind == TypeKind.Struct && storeInst.Variable.Type.IsByRefLike }.WithILRange(storeInst); return(true); }