From 4f7ca654086be609b02962c05fbc3aba208ea234 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Sun, 17 May 2020 09:07:24 +0200 Subject: [PATCH] Fix #1913: Make sure to declare local variables captured by local functions before the first invocation of the local function. --- ICSharpCode.Decompiler/CSharp/CallBuilder.cs | 1 + .../CSharp/Transforms/DeclareVariables.cs | 14 +++++++++++--- .../IL/Instructions/ILFunction.cs | 6 ++++++ 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/ICSharpCode.Decompiler/CSharp/CallBuilder.cs b/ICSharpCode.Decompiler/CSharp/CallBuilder.cs index 267a757fe..12da7ce17 100644 --- a/ICSharpCode.Decompiler/CSharp/CallBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/CallBuilder.cs @@ -200,6 +200,7 @@ namespace ICSharpCode.Decompiler.CSharp int skipCount = localFunction.ReducedMethod.NumberOfCompilerGeneratedTypeParameters; ide.TypeArguments.AddRange(method.TypeArguments.Skip(skipCount).Select(expressionBuilder.ConvertType)); } + ide.AddAnnotation(localFunction); target = ide.WithoutILInstruction() .WithRR(ToMethodGroup(method, localFunction)); } else { diff --git a/ICSharpCode.Decompiler/CSharp/Transforms/DeclareVariables.cs b/ICSharpCode.Decompiler/CSharp/Transforms/DeclareVariables.cs index e531b23d0..2aad6a16d 100644 --- a/ICSharpCode.Decompiler/CSharp/Transforms/DeclareVariables.cs +++ b/ICSharpCode.Decompiler/CSharp/Transforms/DeclareVariables.cs @@ -21,7 +21,6 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; using ICSharpCode.Decompiler.CSharp.Syntax; -using ICSharpCode.Decompiler.CSharp.Syntax.PatternMatching; using ICSharpCode.Decompiler.IL; using ICSharpCode.Decompiler.IL.Transforms; using ICSharpCode.Decompiler.Semantics; @@ -257,7 +256,16 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms if (node is IdentifierExpression identExpr) { var rr = identExpr.GetResolveResult() as ILVariableResolveResult; if (rr != null && VariableNeedsDeclaration(rr.Variable.Kind)) { - var variable = rr.Variable; + FindInsertionPointForVariable(rr.Variable); + } else if (identExpr.Annotation() is ILFunction localFunction && localFunction.Kind == ILFunctionKind.LocalFunction) { + foreach (var v in localFunction.CapturedVariables) { + if (VariableNeedsDeclaration(v.Kind)) + FindInsertionPointForVariable(v); + } + } + + void FindInsertionPointForVariable(ILVariable variable) + { InsertionPoint newPoint; int startIndex = scopeTracking.Count - 1; if (variable.CaptureScope != null && startIndex > 0 && variable.CaptureScope != scopeTracking[startIndex].Scope) { @@ -287,7 +295,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms } else { v = new VariableToDeclare(variable, variable.HasInitialValue, newPoint, identExpr, sourceOrder: variableDict.Count); - variableDict.Add(rr.Variable, v); + variableDict.Add(variable, v); } } } diff --git a/ICSharpCode.Decompiler/IL/Instructions/ILFunction.cs b/ICSharpCode.Decompiler/IL/Instructions/ILFunction.cs index ab3caa5cf..984c3fec8 100644 --- a/ICSharpCode.Decompiler/IL/Instructions/ILFunction.cs +++ b/ICSharpCode.Decompiler/IL/Instructions/ILFunction.cs @@ -73,6 +73,12 @@ namespace ICSharpCode.Decompiler.IL /// public BlockContainer DeclarationScope { get; internal set; } + /// + /// Gets the set of captured variables by this ILFunction. + /// + /// This is populated by the step. + public HashSet CapturedVariables { get; } = new HashSet(ILVariableEqualityComparer.Instance); + /// /// List of warnings of ILReader. ///