Browse Source

#1456: add test case; add additional checks to ensure we only transform normal locals into using/foreach-locals

pull/1612/head
Daniel Grunwald 6 years ago
parent
commit
856cedc95e
  1. 11
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Async.cs
  2. 2
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  3. 3
      ICSharpCode.Decompiler/CSharp/StatementBuilder.cs
  4. 1
      ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs
  5. 10
      ICSharpCode.Decompiler/IL/ILVariable.cs
  6. 2
      ICSharpCode.Decompiler/IL/Transforms/UsingTransform.cs

11
ICSharpCode.Decompiler.Tests/TestCases/Pretty/Async.cs

@ -18,6 +18,7 @@
#pragma warning disable 1998 #pragma warning disable 1998
using System; using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -126,6 +127,16 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
} }
} }
#endif #endif
public static async Task<int> GetIntegerSumAsync(IEnumerable<int> items)
{
await Task.Delay(100);
int num = 0;
foreach (int item in items) {
num += item;
}
return num;
}
} }
public struct HopToThreadPoolAwaitable : INotifyCompletion public struct HopToThreadPoolAwaitable : INotifyCompletion

2
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -65,7 +65,7 @@ namespace ICSharpCode.Decompiler.CSharp
/// * Otherwise, the C# type of the resulting expression shall match the IL stack type, /// * Otherwise, the C# type of the resulting expression shall match the IL stack type,
/// and the evaluated values shall be the same. /// and the evaluated values shall be the same.
/// </remarks> /// </remarks>
class ExpressionBuilder : ILVisitor<TranslationContext, TranslatedExpression> sealed class ExpressionBuilder : ILVisitor<TranslationContext, TranslatedExpression>
{ {
readonly IDecompilerTypeSystem typeSystem; readonly IDecompilerTypeSystem typeSystem;
internal readonly ITypeResolveContext decompilationContext; internal readonly ITypeResolveContext decompilationContext;

3
ICSharpCode.Decompiler/CSharp/StatementBuilder.cs

@ -32,7 +32,7 @@ using ICSharpCode.Decompiler.CSharp.Resolver;
namespace ICSharpCode.Decompiler.CSharp namespace ICSharpCode.Decompiler.CSharp
{ {
class StatementBuilder : ILVisitor<Statement> sealed class StatementBuilder : ILVisitor<Statement>
{ {
internal readonly ExpressionBuilder exprBuilder; internal readonly ExpressionBuilder exprBuilder;
readonly ILFunction currentFunction; readonly ILFunction currentFunction;
@ -412,6 +412,7 @@ namespace ICSharpCode.Decompiler.CSharp
AstNode usingInit = resource; AstNode usingInit = resource;
var var = inst.Variable; var var = inst.Variable;
if (!inst.ResourceExpression.MatchLdNull() && !NullableType.GetUnderlyingType(var.Type).GetAllBaseTypes().Any(b => b.IsKnownType(KnownTypeCode.IDisposable))) { if (!inst.ResourceExpression.MatchLdNull() && !NullableType.GetUnderlyingType(var.Type).GetAllBaseTypes().Any(b => b.IsKnownType(KnownTypeCode.IDisposable))) {
Debug.Assert(var.Kind == VariableKind.UsingLocal);
var.Kind = VariableKind.Local; var.Kind = VariableKind.Local;
var disposeType = exprBuilder.compilation.FindType(KnownTypeCode.IDisposable); var disposeType = exprBuilder.compilation.FindType(KnownTypeCode.IDisposable);
var disposeVariable = currentFunction.RegisterVariable( var disposeVariable = currentFunction.RegisterVariable(

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

@ -467,6 +467,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
statementsToDelete.Add(stmt.GetNextStatement()); statementsToDelete.Add(stmt.GetNextStatement());
var itemVariable = foreachVariable.GetILVariable(); var itemVariable = foreachVariable.GetILVariable();
if (itemVariable == null || !itemVariable.IsSingleDefinition if (itemVariable == null || !itemVariable.IsSingleDefinition
|| (itemVariable.Kind != IL.VariableKind.Local && itemVariable.Kind != IL.VariableKind.StackSlot)
|| !upperBounds.All(ub => ub.IsSingleDefinition && ub.LoadCount == 1) || !upperBounds.All(ub => ub.IsSingleDefinition && ub.LoadCount == 1)
|| !lowerBounds.All(lb => lb.StoreCount == 2 && lb.LoadCount == 3 && lb.AddressCount == 0)) || !lowerBounds.All(lb => lb.StoreCount == 2 && lb.LoadCount == 3 && lb.AddressCount == 0))
return null; return null;

10
ICSharpCode.Decompiler/IL/ILVariable.cs

@ -107,8 +107,12 @@ namespace ICSharpCode.Decompiler.IL
internal set { internal set {
if (kind == VariableKind.Parameter) if (kind == VariableKind.Parameter)
throw new InvalidOperationException("Kind=Parameter cannot be changed!"); throw new InvalidOperationException("Kind=Parameter cannot be changed!");
if (Index != null && value.IsLocal()) if (Index != null && value.IsLocal() && !kind.IsLocal()) {
Debug.Assert(kind.IsLocal()); // For variables, Index has different meaning than for stack slots,
// so we need to reset it to null.
// StackSlot -> ForeachLocal can happen sometimes (e.g. PST.TransformForeachOnArray)
Index = null;
}
kind = value; kind = value;
} }
} }
@ -138,7 +142,7 @@ namespace ICSharpCode.Decompiler.IL
/// For ExceptionStackSlot, the index is the IL offset of the exception handler. /// For ExceptionStackSlot, the index is the IL offset of the exception handler.
/// For other kinds, the index has no meaning, and is usually null. /// For other kinds, the index has no meaning, and is usually null.
/// </summary> /// </summary>
public readonly int? Index; public int? Index { get; private set; }
[Conditional("DEBUG")] [Conditional("DEBUG")]
internal void CheckInvariant() internal void CheckInvariant()

2
ICSharpCode.Decompiler/IL/Transforms/UsingTransform.cs

@ -127,6 +127,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return false; return false;
if (!(storeInst.Value.MatchLdNull() || CheckResourceType(storeInst.Variable.Type))) if (!(storeInst.Value.MatchLdNull() || CheckResourceType(storeInst.Variable.Type)))
return false; return false;
if (storeInst.Variable.Kind != VariableKind.Local)
return false;
if (storeInst.Variable.LoadInstructions.Any(ld => !ld.IsDescendantOf(tryFinally))) if (storeInst.Variable.LoadInstructions.Any(ld => !ld.IsDescendantOf(tryFinally)))
return false; return false;
if (storeInst.Variable.AddressInstructions.Any(la => !la.IsDescendantOf(tryFinally) || (la.IsDescendantOf(tryFinally.TryBlock) && !ILInlining.IsUsedAsThisPointerInCall(la)))) if (storeInst.Variable.AddressInstructions.Any(la => !la.IsDescendantOf(tryFinally) || (la.IsDescendantOf(tryFinally.TryBlock) && !ILInlining.IsUsedAsThisPointerInCall(la))))

Loading…
Cancel
Save