Browse Source

Fix #1404: local variables with init flag are not declared in the correct scope

pull/1425/head
Daniel Grunwald 6 years ago
parent
commit
ba8b453b36
  1. 6
      ICSharpCode.Decompiler.Tests/CorrectnessTestRunner.cs
  2. 1
      ICSharpCode.Decompiler.Tests/Helpers/Tester.VB.cs
  3. 1
      ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj
  4. 21
      ICSharpCode.Decompiler.Tests/TestCases/Correctness/Uninit.vb
  5. 27
      ICSharpCode.Decompiler/CSharp/Transforms/DeclareVariables.cs

6
ICSharpCode.Decompiler.Tests/CorrectnessTestRunner.cs

@ -166,6 +166,12 @@ namespace ICSharpCode.Decompiler.Tests @@ -166,6 +166,12 @@ namespace ICSharpCode.Decompiler.Tests
RunCS(options: options);
}
[Test]
public void Uninit([ValueSource("noMonoOptions")] CompilerOptions options)
{
RunVB(options: options);
}
[Test]
public void MemberLookup([ValueSource("defaultOptions")] CompilerOptions options)
{

1
ICSharpCode.Decompiler.Tests/Helpers/Tester.VB.cs

@ -54,6 +54,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -54,6 +54,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
options.CompilerOptions = "/o" + (flags.HasFlag(CompilerOptions.Optimize) ? "+" : "-");
options.CompilerOptions += (flags.HasFlag(CompilerOptions.UseDebug) ? " /debug" : "");
options.CompilerOptions += (flags.HasFlag(CompilerOptions.Force32Bit) ? " /platform:anycpu32bitpreferred" : "");
options.CompilerOptions += "/optioninfer+ /optionexplicit+";
if (preprocessorSymbols.Count > 0) {
options.CompilerOptions += " /d:" + string.Join(",", preprocessorSymbols.Select(p => $"{p.Key}={p.Value}"));
}

1
ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj

@ -52,6 +52,7 @@ @@ -52,6 +52,7 @@
<ItemGroup>
<None Include="TestCases\Correctness\Jmp.il" />
<None Include="TestCases\Correctness\StackTypes.il" />
<None Include="TestCases\Correctness\Uninit.vb" />
<None Include="TestCases\ILPretty\FSharpLoops.fs" />
<None Include="TestCases\ILPretty\FSharpLoops_Debug.il" />
<None Include="TestCases\ILPretty\FSharpLoops_Release.il" />

21
ICSharpCode.Decompiler.Tests/TestCases/Correctness/Uninit.vb

@ -0,0 +1,21 @@ @@ -0,0 +1,21 @@
Imports System
Module UninitTest
Sub Main()
Dim i = 0
Dim result As Integer = -5
Dim num As Integer
Do
If num > result Then
num += 5
result += 5
End If
result += 1
i += 1
If i > 10 Then
Exit Do
End If
Loop
Console.WriteLine(result)
End Sub
End Module

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

@ -187,10 +187,10 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -187,10 +187,10 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
private static bool IsValidInStatementExpression(Expression expr)
{
switch (expr) {
case InvocationExpression ie:
case ObjectCreateExpression oce:
case AssignmentExpression ae:
case ErrorExpression ee:
case InvocationExpression _:
case ObjectCreateExpression _:
case AssignmentExpression _:
case ErrorExpression _:
return true;
case UnaryOperatorExpression uoe:
switch (uoe.Operator) {
@ -249,12 +249,27 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -249,12 +249,27 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
newPoint = scopeTracking[startIndex + 1].InsertionPoint;
} else {
newPoint = new InsertionPoint { level = nodeLevel, nextNode = identExpr };
if (variable.HasInitialValue) {
// Uninitialized variables are logically initialized at the beginning of the functin
// Because it's possible that the variable has a loop-carried dependency,
// declare it outside of any loops.
while (startIndex >= 0) {
if (scopeTracking[startIndex].Scope.EntryPoint.IncomingEdgeCount > 1) {
// declare variable outside of loop
newPoint = scopeTracking[startIndex].InsertionPoint;
} else if (scopeTracking[startIndex].Scope.Parent is ILFunction) {
// stop at beginning of function
break;
}
startIndex--;
}
}
}
VariableToDeclare v;
if (variableDict.TryGetValue(rr.Variable, out v)) {
if (variableDict.TryGetValue(variable, out v)) {
v.InsertionPoint = FindCommonParent(v.InsertionPoint, newPoint);
} else {
v = new VariableToDeclare(rr.Variable, rr.Variable.HasInitialValue,
v = new VariableToDeclare(variable, variable.HasInitialValue,
newPoint, identExpr, sourceOrder: variableDict.Count);
variableDict.Add(rr.Variable, v);
}

Loading…
Cancel
Save