diff --git a/ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs b/ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs index 1d58a021f..85ac9da1e 100644 --- a/ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs +++ b/ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs @@ -115,7 +115,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms internal static bool IsAnonymousMethod(DecompilerContext context, MethodDefinition method) { - if (method == null || !method.Name.StartsWith("<", StringComparison.Ordinal)) + if (method == null || !(method.Name.StartsWith("<", StringComparison.Ordinal) || method.Name.Contains("$"))) return false; if (!(method.IsCompilerGenerated() || IsPotentialClosure(context, method.DeclaringType))) return false; @@ -388,10 +388,13 @@ namespace ICSharpCode.Decompiler.Ast.Transforms continue; // skip static fields if (dict.ContainsKey(field)) // skip field if it already was handled as parameter continue; - EnsureVariableNameIsAvailable(blockStatement, field.Name); - currentlyUsedVariableNames.Add(field.Name); - variablesToDeclare.Add(Tuple.Create(AstBuilder.ConvertType(field.FieldType, field), field.Name)); - dict[field] = new IdentifierExpression(field.Name); + string capturedVariableName = field.Name; + if (capturedVariableName.StartsWith("$VB$Local_", StringComparison.Ordinal) && capturedVariableName.Length > 10) + capturedVariableName = capturedVariableName.Substring(10); + EnsureVariableNameIsAvailable(blockStatement, capturedVariableName); + currentlyUsedVariableNames.Add(capturedVariableName); + variablesToDeclare.Add(Tuple.Create(AstBuilder.ConvertType(field.FieldType, field), capturedVariableName)); + dict[field] = new IdentifierExpression(capturedVariableName); } // Now figure out where the closure was accessed and use the simpler replacement expression there: diff --git a/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs b/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs index 1e4ebeddd..8a3cc466f 100644 --- a/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs +++ b/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs @@ -308,6 +308,8 @@ namespace ICSharpCode.Decompiler.ILAst /// Converts call and callvirt instructions that read/write properties into CallGetter/CallSetter instructions. /// /// CallGetter/CallSetter is used to allow the ILAst to represent "while ((SomeProperty = value) != null)". + /// + /// Also simplifies 'newobj(SomeDelegate, target, ldvirtftn(F, target))' to 'newobj(SomeDelegate, target, ldvirtftn(F))' /// void IntroducePropertyAccessInstructions(ILNode node) { @@ -365,6 +367,20 @@ namespace ICSharpCode.Decompiler.ILAst expr.Code = (expr.Code == ILCode.Call) ? ILCode.CallSetter : ILCode.CallvirtSetter; } } + } else if (expr.Code == ILCode.Newobj && expr.Arguments.Count == 2) { + // Might be 'newobj(SomeDelegate, target, ldvirtftn(F, target))'. + ILVariable target; + ILExpression ldvirtftnArg; + if (expr.Arguments[0].Match(ILCode.Ldloc, out target) + && expr.Arguments[1].Code == ILCode.Ldvirtftn + && expr.Arguments[1].Arguments.Count == 1 + && expr.Arguments[1].Arguments[0].MatchLdloc(target)) + { + // Remove the 'target' argument from the ldvirtftn instruction. + // It's not needed in the translation to C#, and needs to be eliminated so that the target expression + // can be inlined. + expr.Arguments[1].Arguments.Clear(); + } } }