private ILVariable ResolveAncestorScopeReference(ILInstruction inst)
 {
     if (!inst.MatchLdFld(out var target, out var field))
     {
         return(null);
     }
     if (field.Type.Kind != TypeKind.Class)
     {
         return(null);
     }
     if (!(TransformDisplayClassUsage.IsPotentialClosure(context, field.Type.GetDefinition()) || context.Function.Method.DeclaringType.Equals(field.Type)))
     {
         return(null);
     }
     foreach (var v in context.Function.Descendants.OfType <ILFunction>().SelectMany(f => f.Variables))
     {
         if (v.Kind != VariableKind.Local && v.Kind != VariableKind.DisplayClassLocal && v.Kind != VariableKind.StackSlot)
         {
             if (!(v.Kind == VariableKind.Parameter && v.Index == -1))
             {
                 continue;
             }
             if (v.Type.Equals(field.Type))
             {
                 return(v);
             }
         }
         if (!(TransformDisplayClassUsage.IsClosure(context, v, out var varType, out _) && varType.Equals(field.Type)))
         {
             continue;
         }
         return(v);
     }
     return(null);
 }
        /// <summary>
        /// The transform works like this:
        ///
        /// <para>
        /// local functions can either be used in method calls, i.e., call and callvirt instructions,
        /// or can be used as part of the "delegate construction" pattern, i.e.,
        /// <c>newobj Delegate(&lt;target-expression&gt;, ldftn &lt;method&gt;)</c>.
        /// </para>
        /// As local functions can be declared practically anywhere, we have to take a look at
        /// all use-sites and infer the declaration location from that. Use-sites can be call,
        /// callvirt and ldftn instructions.
        /// After all use-sites are collected we construct the ILAst of the local function
        /// and add it to the parent function.
        /// Then all use-sites of the local-function are transformed to a call to the
        /// <c>LocalFunctionMethod</c> or a ldftn of the <c>LocalFunctionMethod</c>.
        /// In a next step we handle all nested local functions.
        /// After all local functions are transformed, we move all local functions that capture
        /// any variables to their respective declaration scope.
        /// </summary>
        public void Run(ILFunction function, ILTransformContext context)
        {
            if (!context.Settings.LocalFunctions)
            {
                return;
            }
            // Disable the transform if we are decompiling a display-class or local function method:
            // This happens if a local function or display class is selected in the ILSpy tree view.
            if (IsLocalFunctionMethod(function.Method, context) || IsLocalFunctionDisplayClass(function.Method.ParentModule.PEFile, (TypeDefinitionHandle)function.Method.DeclaringTypeDefinition.MetadataToken, context))
            {
                return;
            }
            this.context        = context;
            this.resolveContext = new SimpleTypeResolveContext(function.Method);
            var localFunctions    = new Dictionary <MethodDefinitionHandle, LocalFunctionInfo>();
            var cancellationToken = context.CancellationToken;

            // Find all local functions declared inside this method, including nested local functions or local functions declared in lambdas.
            FindUseSites(function, context, localFunctions);
            foreach (var(_, info) in localFunctions)
            {
                cancellationToken.ThrowIfCancellationRequested();
                if (info.Definition == null)
                {
                    function.Warnings.Add($"Could not decode local function '{info.Method}'");
                    continue;
                }

                context.StepStartGroup($"Transform " + info.Definition.Name, info.Definition);
                try {
                    var localFunction = info.Definition;
                    if (!localFunction.Method.IsStatic)
                    {
                        var thisVar = localFunction.Variables.SingleOrDefault(VariableKindExtensions.IsThis);
                        var target  = info.UseSites.Where(us => us.Arguments[0].MatchLdLoc(out _)).FirstOrDefault()?.Arguments[0];
                        if (target == null)
                        {
                            target = info.UseSites[0].Arguments[0];
                            if (target.MatchLdFld(out var target1, out var field) && thisVar.Type.Equals(field.Type) && field.Type.Kind == TypeKind.Class && TransformDisplayClassUsage.IsPotentialClosure(context, field.Type.GetDefinition()))
                            {
                                var variable = function.Descendants.OfType <ILFunction>().SelectMany(f => f.Variables).Where(v => !v.IsThis() && TransformDisplayClassUsage.IsClosure(context, v, out var varType, out _) && varType.Equals(field.Type)).OnlyOrDefault();
                                if (variable != null)
                                {
                                    target = new LdLoc(variable);
                                    HandleArgument(localFunction, 1, 0, target);
                                }
                            }
                        }
                        context.Step($"Replace 'this' with {target}", localFunction);
                        localFunction.AcceptVisitor(new DelegateConstruction.ReplaceDelegateTargetVisitor(target, thisVar));
                    }

                    foreach (var useSite in info.UseSites)
                    {
                        DetermineCaptureAndDeclarationScope(localFunction, useSite);

                        if (function.Method.IsConstructor && localFunction.DeclarationScope == null)
                        {
                            localFunction.DeclarationScope = BlockContainer.FindClosestContainer(useSite);
                        }
                    }

                    if (localFunction.DeclarationScope == null)
                    {
                        localFunction.DeclarationScope = (BlockContainer)function.Body;
                    }

                    ILFunction declaringFunction = GetDeclaringFunction(localFunction);
                    if (declaringFunction != function)
                    {
                        function.LocalFunctions.Remove(localFunction);
                        declaringFunction.LocalFunctions.Add(localFunction);
                    }

                    if (TryValidateSkipCount(info, out int skipCount) && skipCount != localFunction.ReducedMethod.NumberOfCompilerGeneratedTypeParameters)
                    {
                        Debug.Assert(false);
                        function.Warnings.Add($"Could not decode local function '{info.Method}'");
                        if (declaringFunction != function)
                        {
                            declaringFunction.LocalFunctions.Remove(localFunction);
                        }
                        continue;
                    }

                    foreach (var useSite in info.UseSites)
                    {
                        context.Step($"Transform use site at IL_{useSite.StartILOffset:x4}", useSite);
                        if (useSite.OpCode == OpCode.NewObj)
                        {
                            TransformToLocalFunctionReference(localFunction, useSite);
                        }
                        else
                        {
                            TransformToLocalFunctionInvocation(localFunction.ReducedMethod, useSite);
                        }
                    }
                } finally {
                    context.StepEndGroup();
                }
            }
        }