Browse Source

Fix #1630: Do not convert while to for statement, if any iterator variables are to be declared in the loop body. This causes problems with ref-typed variables.

pull/1633/head
Siegfried Pammer 6 years ago
parent
commit
13fa499c35
  1. 19
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/RefLocalsAndReturns.cs
  2. 2
      ICSharpCode.Decompiler/CSharp/Transforms/DeclareVariables.cs
  3. 21
      ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs

19
ICSharpCode.Decompiler.Tests/TestCases/Pretty/RefLocalsAndReturns.cs

@ -26,6 +26,25 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -26,6 +26,25 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
internal class RefLocalsAndReturns
{
public struct Issue1630
{
private object data;
private int next;
public static void Test()
{
Issue1630[] array = new Issue1630[1];
int num = 0;
while (num >= 0) {
ref Issue1630 reference = ref array[num];
Console.WriteLine(reference.data);
num = reference.next;
}
}
}
public delegate ref T RefFunc<T>();
public delegate ref readonly T ReadOnlyRefFunc<T>();
public delegate ref TReturn RefFunc<T1, TReturn>(T1 param1);

2
ICSharpCode.Decompiler/CSharp/Transforms/DeclareVariables.cs

@ -291,7 +291,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -291,7 +291,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
}
}
bool VariableNeedsDeclaration(VariableKind kind)
internal static bool VariableNeedsDeclaration(VariableKind kind)
{
switch (kind) {
case VariableKind.PinnedLocal:

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

@ -153,7 +153,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -153,7 +153,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
Statements = {
new Repeat(new AnyNode("statement")),
new NamedNode(
"increment",
"iterator",
new ExpressionStatement(
new AssignmentExpression {
Left = new Backreference("ident"),
@ -180,6 +180,11 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -180,6 +180,11 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
if (variable != m3.Get<IdentifierExpression>("ident").Single().GetILVariable())
return null;
WhileStatement loop = (WhileStatement)next;
// Cannot convert to for loop, if any variable that is used in the "iterator" part of the pattern,
// will be declared in the body of the while-loop.
var iteratorStatement = m3.Get<Statement>("iterator").Single();
if (IteratorVariablesDeclaredInsideLoopBody(iteratorStatement))
return null;
// Cannot convert to for loop, because that would change the semantics of the program.
// continue in while jumps to the condition block.
// Whereas continue in for jumps to the increment block.
@ -193,7 +198,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -193,7 +198,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
forStatement.CopyAnnotationsFrom(loop);
forStatement.Initializers.Add(node);
forStatement.Condition = loop.Condition.Detach();
forStatement.Iterators.Add(m3.Get<Statement>("increment").Single().Detach());
forStatement.Iterators.Add(iteratorStatement.Detach());
forStatement.EmbeddedStatement = newBody;
loop.ReplaceWith(forStatement);
return forStatement;
@ -216,6 +221,18 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -216,6 +221,18 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
return true;
return false;
}
bool IteratorVariablesDeclaredInsideLoopBody(Statement iteratorStatement)
{
foreach (var id in iteratorStatement.DescendantsAndSelf.OfType<IdentifierExpression>()) {
var v = id.GetILVariable();
if (v == null || !DeclareVariables.VariableNeedsDeclaration(v.Kind))
continue;
if (declareVariables.GetDeclarationPoint(v).Parent == iteratorStatement.Parent)
return true;
}
return false;
}
#endregion
#region foreach

Loading…
Cancel
Save