/// <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);
 }
Exemplo n.º 2
0
 /// <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);
 }