Browse Source

Detect foreach loops even if the address of the loop variable is taken for a method call.

pull/734/merge
Daniel Grunwald 8 years ago
parent
commit
90059f956e
  1. 34
      ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs
  2. 2
      ICSharpCode.Decompiler/Tests/PrettyTestRunner.cs

34
ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs

@ -430,19 +430,45 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -430,19 +430,45 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
return false;
}
var blockContainer = loop.Annotation<IL.BlockContainer>();
if (!itemVar.IsSingleDefinition) {
// foreach variable cannot be assigned to
return false;
// foreach variable cannot be assigned to.
// As a special case, we accept taking the address for a method call,
// but only if the call is the only use, so that any mutation by the call
// cannot be observed.
if (!AddressUsedForSingleCall(itemVar, blockContainer)) {
return false;
}
}
if (itemVar.CaptureScope != null && itemVar.CaptureScope != loop.Annotation<IL.BlockContainer>()) {
if (itemVar.CaptureScope != null && itemVar.CaptureScope != blockContainer) {
// captured variables cannot be declared in the loop unless the loop is their capture scope
return false;
}
return true;
}
static bool AddressUsedForSingleCall(IL.ILVariable v, IL.BlockContainer loop)
{
if (v.StoreCount == 1 && v.AddressCount == 1 && v.LoadCount == 0 && v.Type.IsReferenceType == false) {
if (v.AddressInstructions[0].Parent is IL.Call call
&& v.AddressInstructions[0].ChildIndex == 0
&& !call.Method.IsStatic) {
// used as this pointer for a method call
// this is OK iff the call is not within a nested loop
for (var node = call.Parent; node != null; node = node.Parent) {
if (node == loop)
return true;
else if (node is IL.BlockContainer)
break;
}
}
}
return false;
}
#endregion
#region foreach (non-generic)
ExpressionStatement getEnumeratorPattern = new ExpressionStatement(
new AssignmentExpression(

2
ICSharpCode.Decompiler/Tests/PrettyTestRunner.cs

@ -103,7 +103,7 @@ namespace ICSharpCode.Decompiler.Tests @@ -103,7 +103,7 @@ namespace ICSharpCode.Decompiler.Tests
Run(cscOptions: cscOptions);
}
[Test, Ignore("Not fully working yet")]
[Test]
public void Loops([ValueSource("defaultOptions")] CompilerOptions cscOptions)
{
Run(cscOptions: cscOptions);

Loading…
Cancel
Save