diff --git a/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs b/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs index 8306ba0bc..a5e2fbdc3 100644 --- a/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs @@ -328,7 +328,7 @@ namespace ICSharpCode.Decompiler.CSharp if (enumeratorVar2 != enumeratorVar) return null; // Detect which foreach-variable transformation is necessary/possible. - var transformation = DetectGetCurrentTransformation(body, enumeratorVar, condition.ILInstructions.Single(), + var transformation = DetectGetCurrentTransformation(container, body, enumeratorVar, condition.ILInstructions.Single(), out var singleGetter, out var foreachVariable); if (transformation == RequiredGetCurrentTransformation.NoForeach) return null; @@ -477,15 +477,16 @@ namespace ICSharpCode.Decompiler.CSharp } /// - /// Determines whether is only used once inside for accessing the Current property. + /// Determines whether is only used once inside for accessing the Current property. /// - /// The foreach/using body. + /// The using body container. This is only used for variable usage checks. + /// The loop body. The first statement of this block is analyzed. /// The current enumerator. /// The call MoveNext(ldloc enumerator) pattern. /// Returns the call instruction invoking Current's getter. - /// Returns the the foreach variable, if a suitable was found. This variable is only assigned once and its assignment is the first statement in . + /// Returns the the foreach variable, if a suitable was found. This variable is only assigned once and its assignment is the first statement in . /// for details. - RequiredGetCurrentTransformation DetectGetCurrentTransformation(Block body, ILVariable enumerator, ILInstruction moveNextUsage, out CallInstruction singleGetter, out ILVariable foreachVariable) + RequiredGetCurrentTransformation DetectGetCurrentTransformation(BlockContainer usingContainer, Block loopBody, ILVariable enumerator, ILInstruction moveNextUsage, out CallInstruction singleGetter, out ILVariable foreachVariable) { singleGetter = null; foreachVariable = null; @@ -497,7 +498,7 @@ namespace ICSharpCode.Decompiler.CSharp singleGetter = (CallInstruction)loads[0].Parent; // singleGetter is not part of the first instruction in body or cannot be uninlined // => no foreach - if (!(singleGetter.IsDescendantOf(body.Instructions[0]) && ILInlining.CanUninline(singleGetter, body.Instructions[0]))) + if (!(singleGetter.IsDescendantOf(loopBody.Instructions[0]) && ILInlining.CanUninline(singleGetter, loopBody.Instructions[0]))) return RequiredGetCurrentTransformation.NoForeach; ILInstruction inst = singleGetter; // in some cases, i.e. foreach variable with explicit type different from the collection-item-type, @@ -516,14 +517,14 @@ namespace ICSharpCode.Decompiler.CSharp // One variable was found. if (nestedStores.Count == 1) { // Must be a plain assignment expression and variable must only be used in 'body' + only assigned once. - if (nestedStores[0].Parent == body && VariableIsOnlyUsedInBlock(nestedStores[0], body)) { + if (nestedStores[0].Parent == loopBody && VariableIsOnlyUsedInBlock(nestedStores[0], usingContainer)) { foreachVariable = nestedStores[0].Variable; return RequiredGetCurrentTransformation.UseExistingVariable; } } else { // Check if any of the variables is usable as foreach variable. foreach (var store in nestedStores) { - if (VariableIsOnlyUsedInBlock(store, body)) { + if (VariableIsOnlyUsedInBlock(store, usingContainer)) { foreachVariable = store.Variable; return RequiredGetCurrentTransformation.UninlineAndUseExistingVariable; } @@ -534,15 +535,15 @@ namespace ICSharpCode.Decompiler.CSharp } /// - /// Determines whether storeInst.Variable is only assigned once and used only inside . + /// Determines whether storeInst.Variable is only assigned once and used only inside . /// Loads by reference (ldloca) are only allowed in the context of this pointer in call instructions. /// (This only applies to value types.) /// - bool VariableIsOnlyUsedInBlock(StLoc storeInst, Block body) + bool VariableIsOnlyUsedInBlock(StLoc storeInst, BlockContainer usingContainer) { - if (storeInst.Variable.LoadInstructions.Any(ld => !ld.IsDescendantOf(body))) + if (storeInst.Variable.LoadInstructions.Any(ld => !ld.IsDescendantOf(usingContainer))) return false; - if (storeInst.Variable.AddressInstructions.Any(la => !la.IsDescendantOf(body) || !ILInlining.IsUsedAsThisPointerInCall(la))) + if (storeInst.Variable.AddressInstructions.Any(la => !la.IsDescendantOf(usingContainer) || !ILInlining.IsUsedAsThisPointerInCall(la))) return false; if (storeInst.Variable.StoreInstructions.OfType().Any(st => st != storeInst)) return false;