| 
						
						
							
								
							
						
						
					 | 
					 | 
					@ -40,6 +40,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						{ | 
					 | 
					 | 
					 | 
						{ | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							ILTransformContext context; | 
					 | 
					 | 
					 | 
							ILTransformContext context; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
							struct LocalFunctionInfo | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
							{ | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
								public List<CallInstruction> UseSites; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
								public ILFunction Definition; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
							} | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							/// <summary>
 | 
					 | 
					 | 
					 | 
							/// <summary>
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							/// The transform works like this:
 | 
					 | 
					 | 
					 | 
							/// The transform works like this:
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							/// 
 | 
					 | 
					 | 
					 | 
							/// 
 | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					 | 
					@ -51,67 +57,103 @@ namespace ICSharpCode.Decompiler.IL.Transforms | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							/// After all use-sites are collected we construct the ILAst of the local function and add it to the parent function.
 | 
					 | 
					 | 
					 | 
							/// 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>.
 | 
					 | 
					 | 
					 | 
							/// 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.
 | 
					 | 
					 | 
					 | 
							/// In a next step we handle all nested local functions.
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							/// After all local functions are transformed, we move all local functions that do not capture any variables to the top-level function.
 | 
					 | 
					 | 
					 | 
							/// After all local functions are transformed, we move all local functions that capture any variables to their respective declaration scope.
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							/// </summary>
 | 
					 | 
					 | 
					 | 
							/// </summary>
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							public void Run(ILFunction function, ILTransformContext context) | 
					 | 
					 | 
					 | 
							public void Run(ILFunction function, ILTransformContext context) | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							{ | 
					 | 
					 | 
					 | 
							{ | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								if (!context.Settings.LocalFunctions) | 
					 | 
					 | 
					 | 
								if (!context.Settings.LocalFunctions) | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									return; | 
					 | 
					 | 
					 | 
									return; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								this.context = context; | 
					 | 
					 | 
					 | 
								this.context = context; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								var localFunctions = new Dictionary<IMethod, List<CallInstruction>>(); | 
					 | 
					 | 
					 | 
								var localFunctions = new Dictionary<MethodDefinitionHandle, LocalFunctionInfo>(); | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								var cancellationToken = context.CancellationToken; | 
					 | 
					 | 
					 | 
								var cancellationToken = context.CancellationToken; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								// Find use-sites
 | 
					 | 
					 | 
					 | 
								// Find all local functions declared inside this method, including nested local functions or local functions declared in lambdas.
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								foreach (var inst in function.Descendants) { | 
					 | 
					 | 
					 | 
								FindUseSites(function, context, localFunctions); | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
								foreach (var (method, info) in localFunctions) { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									cancellationToken.ThrowIfCancellationRequested(); | 
					 | 
					 | 
					 | 
									cancellationToken.ThrowIfCancellationRequested(); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									if (inst is CallInstruction call && IsLocalFunctionMethod(call.Method) && !call.Method.IsLocalFunction) { | 
					 | 
					 | 
					 | 
									var firstUseSite = info.UseSites[0]; | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
										if (!localFunctions.TryGetValue(call.Method, out var info)) { | 
					 | 
					 | 
					 | 
									context.StepStartGroup($"Transform " + info.Definition.Name, info.Definition); | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
											info = new List<CallInstruction>() { call }; | 
					 | 
					 | 
					 | 
									try { | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
											localFunctions.Add(call.Method, info); | 
					 | 
					 | 
					 | 
										var localFunction = info.Definition; | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
										} else { | 
					 | 
					 | 
					 | 
										if (!localFunction.Method.IsStatic) { | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
											info.Add(call); | 
					 | 
					 | 
					 | 
											var target = firstUseSite.Arguments[0]; | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
											context.Step($"Replace 'this' with {target}", localFunction); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
											var thisVar = localFunction.Variables.SingleOrDefault(VariableKindExtensions.IsThis); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
											localFunction.AcceptVisitor(new DelegateConstruction.ReplaceDelegateTargetVisitor(target, thisVar)); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
										} | 
					 | 
					 | 
					 | 
										} | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									} else if (inst is LdFtn ldftn && !ldftn.Method.IsLocalFunction && ldftn.Parent is NewObj newObj && IsLocalFunctionMethod(ldftn.Method) && DelegateConstruction.IsDelegateConstruction(newObj)) { | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
										context.StepStartGroup($"LocalFunctionDecompiler {ldftn.StartILOffset}", ldftn); | 
					 | 
					 | 
					 | 
										foreach (var useSite in info.UseSites) { | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
										if (!localFunctions.TryGetValue(ldftn.Method, out var info)) { | 
					 | 
					 | 
					 | 
											context.Step("Transform use site at " + useSite.StartILOffset, useSite); | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
											info = new List<CallInstruction>() { newObj }; | 
					 | 
					 | 
					 | 
											if (useSite.OpCode == OpCode.NewObj) { | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
											localFunctions.Add(ldftn.Method, info); | 
					 | 
					 | 
					 | 
												TransformToLocalFunctionReference(localFunction, useSite); | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
											} else { | 
					 | 
					 | 
					 | 
											} else { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
											info.Add(newObj); | 
					 | 
					 | 
					 | 
												DetermineCaptureAndDeclarationScope(localFunction, useSite); | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
										} | 
					 | 
					 | 
					 | 
												TransformToLocalFunctionInvocation(localFunction.ReducedMethod, useSite); | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
										context.StepEndGroup(); | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
											} | 
					 | 
					 | 
					 | 
											} | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
										} | 
					 | 
					 | 
					 | 
										} | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								foreach (var (method, useSites) in localFunctions) { | 
					 | 
					 | 
					 | 
										if (localFunction.DeclarationScope == null) { | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									context.StepStartGroup($"LocalFunctionDecompiler {useSites[0].StartILOffset}", useSites[0]); | 
					 | 
					 | 
					 | 
											localFunction.DeclarationScope = (BlockContainer)function.Body; | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									try { | 
					 | 
					 | 
					 | 
										} else if (localFunction.DeclarationScope != function.Body && localFunction.DeclarationScope.Parent is ILFunction declaringFunction) { | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
										TransformLocalFunction(function, method, useSites); | 
					 | 
					 | 
					 | 
											function.LocalFunctions.Remove(localFunction); | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
											declaringFunction.LocalFunctions.Add(localFunction); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
										} | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									} finally { | 
					 | 
					 | 
					 | 
									} finally { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
										context.StepEndGroup(); | 
					 | 
					 | 
					 | 
										context.StepEndGroup(); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									} | 
					 | 
					 | 
					 | 
									} | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								} | 
					 | 
					 | 
					 | 
								} | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
							} | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								foreach (var f in function.LocalFunctions) { | 
					 | 
					 | 
					 | 
							void FindUseSites(ILFunction function, ILTransformContext context, Dictionary<MethodDefinitionHandle, LocalFunctionInfo> localFunctions) | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									// handle nested functions
 | 
					 | 
					 | 
					 | 
							{ | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									var nestedContext = new ILTransformContext(context, f); | 
					 | 
					 | 
					 | 
								foreach (var inst in function.Body.Descendants) { | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									nestedContext.StepStartGroup("LocalFunctionDecompiler (nested functions)", f); | 
					 | 
					 | 
					 | 
									context.CancellationToken.ThrowIfCancellationRequested(); | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									new LocalFunctionDecompiler().Run(f, nestedContext); | 
					 | 
					 | 
					 | 
									if (inst is CallInstruction call && !call.Method.IsLocalFunction && IsLocalFunctionMethod(call.Method, context)) { | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									nestedContext.StepEndGroup(); | 
					 | 
					 | 
					 | 
										HandleUseSite(call.Method, call); | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
									} else if (inst is LdFtn ldftn && !ldftn.Method.IsLocalFunction && ldftn.Parent is NewObj newObj && IsLocalFunctionMethod(ldftn.Method, context) && DelegateConstruction.IsDelegateConstruction(newObj)) { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
										HandleUseSite(ldftn.Method, newObj); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
									} | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								} | 
					 | 
					 | 
					 | 
								} | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								if (function.Kind == ILFunctionKind.TopLevelFunction) { | 
					 | 
					 | 
					 | 
								void HandleUseSite(IMethod targetMethod, CallInstruction inst) | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									var movableFunctions = TreeTraversal.PostOrder(function, f => f.LocalFunctions) | 
					 | 
					 | 
					 | 
								{ | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
										.Where(f => f.Kind == ILFunctionKind.LocalFunction && f.DeclarationScope == null) | 
					 | 
					 | 
					 | 
									if (!localFunctions.TryGetValue((MethodDefinitionHandle)targetMethod.MetadataToken, out var info)) { | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
										.ToArray(); | 
					 | 
					 | 
					 | 
										context.StepStartGroup($"Read local function '{targetMethod.Name}'", inst); | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									foreach (var f in movableFunctions) { | 
					 | 
					 | 
					 | 
										info = new LocalFunctionInfo() { | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
										var parent = (ILFunction)f.Parent; | 
					 | 
					 | 
					 | 
											UseSites = new List<CallInstruction>() { inst }, | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
										f.DeclarationScope = (BlockContainer)function.Body; | 
					 | 
					 | 
					 | 
											Definition = ReadLocalFunctionDefinition(context.Function, targetMethod) | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
										parent.LocalFunctions.Remove(f); | 
					 | 
					 | 
					 | 
										}; | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
										function.LocalFunctions.Add(f); | 
					 | 
					 | 
					 | 
										localFunctions.Add((MethodDefinitionHandle)targetMethod.MetadataToken, info); | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
										FindUseSites(info.Definition, context, localFunctions); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
										context.StepEndGroup(); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
									} else { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
										info.UseSites.Add(inst); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									} | 
					 | 
					 | 
					 | 
									} | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								} | 
					 | 
					 | 
					 | 
								} | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							} | 
					 | 
					 | 
					 | 
							} | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
							ILFunction ReadLocalFunctionDefinition(ILFunction rootFunction, IMethod targetMethod) | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
							{ | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
								var methodDefinition = context.PEFile.Metadata.GetMethodDefinition((MethodDefinitionHandle)targetMethod.MetadataToken); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
								if (!methodDefinition.HasBody()) | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
									return null; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
								var genericContext = DelegateConstruction.GenericContextFromTypeArguments(targetMethod.Substitution); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
								if (genericContext == null) | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
									return null; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
								var ilReader = context.CreateILReader(); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
								var body = context.PEFile.Reader.GetMethodBody(methodDefinition.RelativeVirtualAddress); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
								var function = ilReader.ReadIL((MethodDefinitionHandle)targetMethod.MetadataToken, body, genericContext.Value, ILFunctionKind.LocalFunction, context.CancellationToken); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
								// Embed the local function into the parent function's ILAst, so that "Show steps" can show
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
								// how the local function body is being transformed.
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
								rootFunction.LocalFunctions.Add(function); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
								function.DeclarationScope = (BlockContainer)rootFunction.Body; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
								function.CheckInvariant(ILPhase.Normal); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
								var nestedContext = new ILTransformContext(context, function); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
								function.RunTransforms(CSharpDecompiler.GetILTransforms().TakeWhile(t => !(t is LocalFunctionDecompiler)), nestedContext); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
								function.DeclarationScope = null; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
								function.ReducedMethod = ReduceToLocalFunction(targetMethod); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
								return function; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
							} | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							static T FindCommonAncestorInstruction<T>(ILInstruction a, ILInstruction b) | 
					 | 
					 | 
					 | 
							static T FindCommonAncestorInstruction<T>(ILInstruction a, ILInstruction b) | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								where T : ILInstruction | 
					 | 
					 | 
					 | 
								where T : ILInstruction | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							{ | 
					 | 
					 | 
					 | 
							{ | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					 | 
					@ -137,71 +179,13 @@ namespace ICSharpCode.Decompiler.IL.Transforms | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							internal static ILInstruction GetStatement(ILInstruction inst) | 
					 | 
					 | 
					 | 
							internal static ILInstruction GetStatement(ILInstruction inst) | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							{ | 
					 | 
					 | 
					 | 
							{ | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								while (inst.Parent != null) { | 
					 | 
					 | 
					 | 
								while (inst.Parent != null) { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									if (inst.Parent is Block) | 
					 | 
					 | 
					 | 
									if (inst.Parent is Block b && b.Kind == BlockKind.ControlFlow) | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
										return inst; | 
					 | 
					 | 
					 | 
										return inst; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									inst = inst.Parent; | 
					 | 
					 | 
					 | 
									inst = inst.Parent; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								} | 
					 | 
					 | 
					 | 
								} | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								return inst; | 
					 | 
					 | 
					 | 
								return inst; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							} | 
					 | 
					 | 
					 | 
							} | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							private ILFunction TransformLocalFunction(ILFunction parentFunction, IMethod targetMethod, List<CallInstruction> useSites) | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							{ | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								var methodDefinition = context.PEFile.Metadata.GetMethodDefinition((MethodDefinitionHandle)targetMethod.MetadataToken); | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								if (!methodDefinition.HasBody()) | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									return null; | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								var genericContext = DelegateConstruction.GenericContextFromTypeArguments(targetMethod.Substitution); | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								if (genericContext == null) | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									return null; | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								var function = parentFunction.Ancestors.OfType<ILFunction>().SelectMany(f => f.LocalFunctions).FirstOrDefault(f => f.Method == targetMethod); | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								if (function == null) { | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									var ilReader = context.CreateILReader(); | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									var body = context.PEFile.Reader.GetMethodBody(methodDefinition.RelativeVirtualAddress); | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									function = ilReader.ReadIL((MethodDefinitionHandle)targetMethod.MetadataToken, body, genericContext.Value, ILFunctionKind.LocalFunction, context.CancellationToken); | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									// Embed the local function into the parent function's ILAst, so that "Show steps" can show
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									// how the local function body is being transformed.
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									parentFunction.LocalFunctions.Add(function); | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									function.DeclarationScope = (BlockContainer)parentFunction.Body; | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									function.CheckInvariant(ILPhase.Normal); | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									var nestedContext = new ILTransformContext(context, function); | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									function.RunTransforms(CSharpDecompiler.GetILTransforms().TakeWhile(t => !(t is LocalFunctionDecompiler)), nestedContext); | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									if (IsNonLocalTarget(targetMethod, useSites, out var target)) { | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
										Debug.Assert(target != null); | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
										nestedContext.Step("LocalFunctionDecompiler (ReplaceDelegateTargetVisitor)", function); | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
										var thisVar = function.Variables.SingleOrDefault(v => v.Index == -1 && v.Kind == VariableKind.Parameter); | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
										function.AcceptVisitor(new DelegateConstruction.ReplaceDelegateTargetVisitor(target, thisVar)); | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									} | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									function.DeclarationScope = null; | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									function.ReducedMethod = ReduceToLocalFunction(targetMethod); | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									foreach (var innerUseSite in function.Descendants.OfType<CallInstruction>()) { | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
										if (innerUseSite.Method != function.Method) | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
											continue; | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
										if (innerUseSite.OpCode == OpCode.NewObj) { | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
											TransformToLocalFunctionReference(function, innerUseSite); | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
										} else { | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
											TransformToLocalFunctionInvocation(function.ReducedMethod, innerUseSite); | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
										} | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									} | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								} | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								foreach (var useSite in useSites) { | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									if (useSite.OpCode == OpCode.NewObj) { | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
										TransformToLocalFunctionReference(function, useSite); | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									} else { | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
										DetermineCaptureAndDeclarationScope(function, useSite); | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
										TransformToLocalFunctionInvocation(function.ReducedMethod, useSite); | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									} | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								} | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								if (function.DeclarationScope != null | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									&& parentFunction.LocalFunctions.Contains(function) | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									&& function.DeclarationScope.Parent is ILFunction betterParentFunction) { | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									parentFunction.LocalFunctions.Remove(function); | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									betterParentFunction.LocalFunctions.Add(function); | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								} | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								return function; | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							} | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							LocalFunctionMethod ReduceToLocalFunction(IMethod method) | 
					 | 
					 | 
					 | 
							LocalFunctionMethod ReduceToLocalFunction(IMethod method) | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							{ | 
					 | 
					 | 
					 | 
							{ | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								int parametersToRemove = 0; | 
					 | 
					 | 
					 | 
								int parametersToRemove = 0; | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
					 | 
					@ -272,47 +256,28 @@ namespace ICSharpCode.Decompiler.IL.Transforms | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								} | 
					 | 
					 | 
					 | 
								} | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							} | 
					 | 
					 | 
					 | 
							} | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							bool IsNonLocalTarget(IMethod targetMethod, List<CallInstruction> useSites, out ILInstruction target) | 
					 | 
					 | 
					 | 
							internal static bool IsLocalFunctionReference(NewObj inst, ILTransformContext context) | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							{ | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								target = null; | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								if (targetMethod.IsStatic) | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									return false; | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								ValidateUseSites(useSites); | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								target = useSites.Select(call => call.Arguments.First()).First(); | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								return !target.MatchLdThis(); | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							} | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							[Conditional("DEBUG")] | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							static void ValidateUseSites(List<CallInstruction> useSites) | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							{ | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								ILInstruction targetInstruction = null; | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								foreach (var site in useSites) { | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									if (targetInstruction == null) | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
										targetInstruction = site.Arguments.First(); | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									else | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
										Debug.Assert(targetInstruction.Match(site.Arguments[0]).Success); | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								} | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							} | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							internal static bool IsLocalFunctionReference(NewObj inst) | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							{ | 
					 | 
					 | 
					 | 
							{ | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								if (inst == null || inst.Arguments.Count != 2 || inst.Method.DeclaringType.Kind != TypeKind.Delegate) | 
					 | 
					 | 
					 | 
								if (inst == null || inst.Arguments.Count != 2 || inst.Method.DeclaringType.Kind != TypeKind.Delegate) | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									return false; | 
					 | 
					 | 
					 | 
									return false; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								var opCode = inst.Arguments[1].OpCode; | 
					 | 
					 | 
					 | 
								var opCode = inst.Arguments[1].OpCode; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								return (opCode == OpCode.LdFtn || opCode == OpCode.LdVirtFtn) | 
					 | 
					 | 
					 | 
								return (opCode == OpCode.LdFtn || opCode == OpCode.LdVirtFtn) | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									&& IsLocalFunctionMethod(((IInstructionWithMethodOperand)inst.Arguments[1]).Method); | 
					 | 
					 | 
					 | 
									&& IsLocalFunctionMethod(((IInstructionWithMethodOperand)inst.Arguments[1]).Method, context); | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							} | 
					 | 
					 | 
					 | 
							} | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							public static bool IsLocalFunctionMethod(IMethod method) | 
					 | 
					 | 
					 | 
							public static bool IsLocalFunctionMethod(IMethod method, ILTransformContext context) | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							{ | 
					 | 
					 | 
					 | 
							{ | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								if (method.MetadataToken.IsNil) | 
					 | 
					 | 
					 | 
								if (method.MetadataToken.IsNil) | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									return false; | 
					 | 
					 | 
					 | 
									return false; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								return IsLocalFunctionMethod(method.ParentModule.PEFile, (MethodDefinitionHandle)method.MetadataToken); | 
					 | 
					 | 
					 | 
								return IsLocalFunctionMethod(method.ParentModule.PEFile, (MethodDefinitionHandle)method.MetadataToken, context); | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							} | 
					 | 
					 | 
					 | 
							} | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							public static bool IsLocalFunctionMethod(PEFile module, MethodDefinitionHandle methodHandle) | 
					 | 
					 | 
					 | 
							public static bool IsLocalFunctionMethod(PEFile module, MethodDefinitionHandle methodHandle, ILTransformContext context = null) | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							{ | 
					 | 
					 | 
					 | 
							{ | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
								if (context != null && context.PEFile != module) | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
									return false; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								var metadata = module.Metadata; | 
					 | 
					 | 
					 | 
								var metadata = module.Metadata; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								var method = metadata.GetMethodDefinition(methodHandle); | 
					 | 
					 | 
					 | 
								var method = metadata.GetMethodDefinition(methodHandle); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								var declaringType = method.GetDeclaringType(); | 
					 | 
					 | 
					 | 
								var declaringType = method.GetDeclaringType(); | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					 | 
					@ -326,12 +291,15 @@ namespace ICSharpCode.Decompiler.IL.Transforms | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								return true; | 
					 | 
					 | 
					 | 
								return true; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							} | 
					 | 
					 | 
					 | 
							} | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							public static bool IsLocalFunctionDisplayClass(PEFile module, TypeDefinitionHandle typeHandle) | 
					 | 
					 | 
					 | 
							public static bool IsLocalFunctionDisplayClass(PEFile module, TypeDefinitionHandle typeHandle, ILTransformContext context = null) | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							{ | 
					 | 
					 | 
					 | 
							{ | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
								if (context != null && context.PEFile != module) | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
									return false; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								var metadata = module.Metadata; | 
					 | 
					 | 
					 | 
								var metadata = module.Metadata; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								var type = metadata.GetTypeDefinition(typeHandle); | 
					 | 
					 | 
					 | 
								var type = metadata.GetTypeDefinition(typeHandle); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								if ((type.Attributes & TypeAttributes.NestedPrivate) == 0) | 
					 | 
					 | 
					 | 
								if ((type.Attributes & TypeAttributes.VisibilityMask) != TypeAttributes.NestedPrivate) | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									return false; | 
					 | 
					 | 
					 | 
									return false; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								if (!type.HasGeneratedName(metadata)) | 
					 | 
					 | 
					 | 
								if (!type.HasGeneratedName(metadata)) | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									return false; | 
					 | 
					 | 
					 | 
									return false; | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					 | 
					@ -340,7 +308,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								var declaringType = metadata.GetTypeDefinition(declaringTypeHandle); | 
					 | 
					 | 
					 | 
								var declaringType = metadata.GetTypeDefinition(declaringTypeHandle); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								foreach (var method in declaringType.GetMethods()) { | 
					 | 
					 | 
					 | 
								foreach (var method in declaringType.GetMethods()) { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									if (!IsLocalFunctionMethod(module, method)) | 
					 | 
					 | 
					 | 
									if (!IsLocalFunctionMethod(module, method, context)) | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
										continue; | 
					 | 
					 | 
					 | 
										continue; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									var md = metadata.GetMethodDefinition(method); | 
					 | 
					 | 
					 | 
									var md = metadata.GetMethodDefinition(method); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									if (md.DecodeSignature(new FindTypeDecoder(typeHandle), default).ParameterTypes.Any()) | 
					 | 
					 | 
					 | 
									if (md.DecodeSignature(new FindTypeDecoder(typeHandle), default).ParameterTypes.Any()) | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
						
					 | 
					 | 
					
  |