From 6ba013d9dd0d3042f03074b5862ec9a8875505e0 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Tue, 14 May 2013 14:54:06 +0200 Subject: [PATCH] Fix bugs in async/await decompiler. --- .../Ast/AstMethodBodyBuilder.cs | 16 +++++++++++----- ICSharpCode.Decompiler/ILAst/AsyncDecompiler.cs | 3 ++- ICSharpCode.Decompiler/ILAst/ILInlining.cs | 1 + ICSharpCode.Decompiler/Tests/Async.cs | 11 +++++++++++ 4 files changed, 25 insertions(+), 6 deletions(-) diff --git a/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs b/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs index 3437af546..078fd4fa7 100644 --- a/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs +++ b/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs @@ -849,7 +849,7 @@ namespace ICSharpCode.Decompiler.Ast args[args.Count - 1].AddAnnotation(new ParameterDeclarationAnnotation(byteCode)); return args[args.Count - 1]; case ILCode.Await: - return new UnaryOperatorExpression(UnaryOperatorType.Await, arg1); + return new UnaryOperatorExpression(UnaryOperatorType.Await, UnpackDirectionExpression(arg1)); case ILCode.NullableOf: case ILCode.ValueOf: return arg1; @@ -975,10 +975,7 @@ namespace ICSharpCode.Decompiler.Ast // Unpack any DirectionExpression that is used as target for the call // (calling methods on value types implicitly passes the first argument by reference) - if (target is DirectionExpression) { - target = ((DirectionExpression)target).Expression; - target.Remove(); // detach from DirectionExpression - } + target = UnpackDirectionExpression(target); if (cecilMethodDef != null) { // convert null.ToLower() to ((string)null).ToLower() @@ -1078,6 +1075,15 @@ namespace ICSharpCode.Decompiler.Ast return target.Invoke(cecilMethod.Name, ConvertTypeArguments(cecilMethod), methodArgs).WithAnnotation(cecilMethod); } + static Expression UnpackDirectionExpression(Expression target) + { + if (target is DirectionExpression) { + return ((DirectionExpression)target).Expression.Detach(); + } else { + return target; + } + } + static void AdjustArgumentsForMethodCall(MethodReference cecilMethod, List methodArgs) { // Convert 'ref' into 'out' where necessary diff --git a/ICSharpCode.Decompiler/ILAst/AsyncDecompiler.cs b/ICSharpCode.Decompiler/ILAst/AsyncDecompiler.cs index 4535c0f82..deed15a8b 100644 --- a/ICSharpCode.Decompiler/ILAst/AsyncDecompiler.cs +++ b/ICSharpCode.Decompiler/ILAst/AsyncDecompiler.cs @@ -475,7 +475,8 @@ namespace ICSharpCode.Decompiler.ILAst newBody.RemoveAt(newBody.Count - 1); // remove AwaitUnsafeOnCompleted call if (callAwaitUnsafeOnCompleted == null || callAwaitUnsafeOnCompleted.Code != ILCode.Call) throw new SymbolicAnalysisFailedException(); - if (((MethodReference)callAwaitUnsafeOnCompleted.Operand).Name != "AwaitUnsafeOnCompleted") + string methodName = ((MethodReference)callAwaitUnsafeOnCompleted.Operand).Name; + if (methodName != "AwaitUnsafeOnCompleted" && methodName != "AwaitOnCompleted") throw new SymbolicAnalysisFailedException(); if (callAwaitUnsafeOnCompleted.Arguments.Count != 3) throw new SymbolicAnalysisFailedException(); diff --git a/ICSharpCode.Decompiler/ILAst/ILInlining.cs b/ICSharpCode.Decompiler/ILAst/ILInlining.cs index 880592b10..2951cfd53 100644 --- a/ICSharpCode.Decompiler/ILAst/ILInlining.cs +++ b/ICSharpCode.Decompiler/ILAst/ILInlining.cs @@ -334,6 +334,7 @@ namespace ICSharpCode.Decompiler.ILAst case ILCode.Stfld: case ILCode.Ldfld: case ILCode.Ldflda: + case ILCode.Await: return true; } } diff --git a/ICSharpCode.Decompiler/Tests/Async.cs b/ICSharpCode.Decompiler/Tests/Async.cs index ccd122255..7629dd5e6 100644 --- a/ICSharpCode.Decompiler/Tests/Async.cs +++ b/ICSharpCode.Decompiler/Tests/Async.cs @@ -20,6 +20,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Runtime.CompilerServices; using System.Threading.Tasks; public class Async @@ -36,6 +37,16 @@ public class Async Console.WriteLine("No Await"); } + public async void AwaitYield() + { + await Task.Yield(); + } + + public async void AwaitDefaultYieldAwaitable() + { + await default(YieldAwaitable); + } + public async Task SimpleVoidTaskMethod() { Console.WriteLine("Before");