diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/LocalFunctions.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/LocalFunctions.cs index 806e9a57f..03c37273a 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/LocalFunctions.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/LocalFunctions.cs @@ -148,6 +148,23 @@ namespace LocalFunctions } } + private void Name() + { + + } + + private void LocalFunctionHidingMethod() + { + Action action = this.Name; + Name(); + action(); + + void Name() + { + + } + } + public void NamedArgument() { Use(Get(1), Get(2), Get(3)); diff --git a/ICSharpCode.Decompiler/CSharp/CallBuilder.cs b/ICSharpCode.Decompiler/CSharp/CallBuilder.cs index 510930f1e..fc50633d5 100644 --- a/ICSharpCode.Decompiler/CSharp/CallBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/CallBuilder.cs @@ -1227,69 +1227,67 @@ namespace ICSharpCode.Decompiler.CSharp CallOpCode = inst.OpCode }; ResolveResult result = null; - string methodName; + string methodName = method.Name; if (method.IsLocalFunction) { requireTarget = false; var localFunction = expressionBuilder.ResolveLocalFunction(method); result = ToMethodGroup(method, localFunction); target = default; + targetType = default; methodName = localFunction.Name; - } else { - methodName = method.Name; - if (method.IsExtensionMethod && invokeMethod != null && method.Parameters.Count - 1 == invokeMethod.Parameters.Count) { - targetType = method.Parameters[0].Type; - if (targetType.Kind == TypeKind.ByReference && thisArg is Box thisArgBox) { - targetType = ((ByReferenceType)targetType).ElementType; - thisArg = thisArgBox.Argument; - } - target = expressionBuilder.Translate(thisArg, targetType); - requireTarget = true; - } else { - targetType = method.DeclaringType; - if (targetType.IsReferenceType == false && thisArg is Box thisArgBox) { - // Normal struct instance method calls (which TranslateTarget is meant for) expect a 'ref T', - // but delegate construction uses a 'box T'. - if (thisArgBox.Argument is LdObj ldobj) { - thisArg = ldobj.Target; - } else { - thisArg = new AddressOf(thisArgBox.Argument); - } - } - target = expressionBuilder.TranslateTarget(thisArg, - nonVirtualInvocation: func.OpCode == OpCode.LdFtn, - memberStatic: method.IsStatic, - memberDeclaringType: method.DeclaringType); - requireTarget = expressionBuilder.HidesVariableWithName(method.Name) - || (method.IsStatic ? !expressionBuilder.IsCurrentOrContainingType(method.DeclaringTypeDefinition) : !(target.Expression is ThisReferenceExpression)); + } else if (method.IsExtensionMethod && invokeMethod != null && method.Parameters.Count - 1 == invokeMethod.Parameters.Count) { + targetType = method.Parameters[0].Type; + if (targetType.Kind == TypeKind.ByReference && thisArg is Box thisArgBox) { + targetType = ((ByReferenceType)targetType).ElementType; + thisArg = thisArgBox.Argument; } - var or = new OverloadResolution(resolver.Compilation, method.Parameters.SelectReadOnlyArray(p => new TypeResolveResult(p.Type))); - if (!requireTarget) { - result = resolver.ResolveSimpleName(method.Name, method.TypeArguments, isInvocationTarget: false); - if (result is MethodGroupResolveResult mgrr) { - or.AddMethodLists(mgrr.MethodsGroupedByDeclaringType.ToArray()); - requireTarget = (or.BestCandidateErrors != OverloadResolutionErrors.None || !IsAppropriateCallTarget(expectedTargetDetails, method, or.BestCandidate)); + target = expressionBuilder.Translate(thisArg, targetType); + requireTarget = true; + } else { + targetType = method.DeclaringType; + if (targetType.IsReferenceType == false && thisArg is Box thisArgBox) { + // Normal struct instance method calls (which TranslateTarget is meant for) expect a 'ref T', + // but delegate construction uses a 'box T'. + if (thisArgBox.Argument is LdObj ldobj) { + thisArg = ldobj.Target; } else { - requireTarget = true; + thisArg = new AddressOf(thisArgBox.Argument); } } - MemberLookup lookup = null; - bool needsCast = false; - if (requireTarget) { - lookup = new MemberLookup(resolver.CurrentTypeDefinition, resolver.CurrentTypeDefinition.ParentModule); - var rr = lookup.Lookup(target.ResolveResult, method.Name, method.TypeArguments, false); - needsCast = true; - result = rr; - if (rr is MethodGroupResolveResult mgrr) { - or.AddMethodLists(mgrr.MethodsGroupedByDeclaringType.ToArray()); - needsCast = (or.BestCandidateErrors != OverloadResolutionErrors.None || !IsAppropriateCallTarget(expectedTargetDetails, method, or.BestCandidate)); - } + target = expressionBuilder.TranslateTarget(thisArg, + nonVirtualInvocation: func.OpCode == OpCode.LdFtn, + memberStatic: method.IsStatic, + memberDeclaringType: method.DeclaringType); + requireTarget = expressionBuilder.HidesVariableWithName(method.Name) + || (method.IsStatic ? !expressionBuilder.IsCurrentOrContainingType(method.DeclaringTypeDefinition) : !(target.Expression is ThisReferenceExpression)); + } + var or = new OverloadResolution(resolver.Compilation, method.Parameters.SelectReadOnlyArray(p => new TypeResolveResult(p.Type))); + if (!method.IsLocalFunction && !requireTarget) { + result = resolver.ResolveSimpleName(method.Name, method.TypeArguments, isInvocationTarget: false); + if (result is MethodGroupResolveResult mgrr) { + or.AddMethodLists(mgrr.MethodsGroupedByDeclaringType.ToArray()); + requireTarget = (or.BestCandidateErrors != OverloadResolutionErrors.None || !IsAppropriateCallTarget(expectedTargetDetails, method, or.BestCandidate)); + } else { + requireTarget = true; } - if (needsCast) { - Debug.Assert(requireTarget); - target = target.ConvertTo(targetType, expressionBuilder); - result = lookup.Lookup(target.ResolveResult, method.Name, method.TypeArguments, false); + } + MemberLookup lookup = null; + bool needsCast = false; + if (requireTarget) { + lookup = new MemberLookup(resolver.CurrentTypeDefinition, resolver.CurrentTypeDefinition.ParentModule); + var rr = lookup.Lookup(target.ResolveResult, method.Name, method.TypeArguments, false); + needsCast = true; + result = rr; + if (rr is MethodGroupResolveResult mgrr) { + or.AddMethodLists(mgrr.MethodsGroupedByDeclaringType.ToArray()); + needsCast = (or.BestCandidateErrors != OverloadResolutionErrors.None || !IsAppropriateCallTarget(expectedTargetDetails, method, or.BestCandidate)); } } + if (needsCast) { + Debug.Assert(requireTarget); + target = target.ConvertTo(targetType, expressionBuilder); + result = lookup.Lookup(target.ResolveResult, method.Name, method.TypeArguments, false); + } Expression targetExpression; if (requireTarget) { var mre = new MemberReferenceExpression(target, methodName); diff --git a/ICSharpCode.Decompiler/CSharp/Resolver/CSharpInvocationResolveResult.cs b/ICSharpCode.Decompiler/CSharp/Resolver/CSharpInvocationResolveResult.cs index 784c6b9e5..2b71dfc82 100644 --- a/ICSharpCode.Decompiler/CSharp/Resolver/CSharpInvocationResolveResult.cs +++ b/ICSharpCode.Decompiler/CSharp/Resolver/CSharpInvocationResolveResult.cs @@ -47,11 +47,6 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver /// public readonly bool IsExpandedForm; - /// - /// Gets whether this invocation is calling a local function. - /// - public readonly bool IsLocalFunctionInvocation; - readonly IReadOnlyList argumentToParameterMap; public CSharpInvocationResolveResult( diff --git a/ICSharpCode.Decompiler/CSharp/Transforms/IntroduceExtensionMethods.cs b/ICSharpCode.Decompiler/CSharp/Transforms/IntroduceExtensionMethods.cs index e3bd8d7fc..3b11cd87f 100644 --- a/ICSharpCode.Decompiler/CSharp/Transforms/IntroduceExtensionMethods.cs +++ b/ICSharpCode.Decompiler/CSharp/Transforms/IntroduceExtensionMethods.cs @@ -154,7 +154,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms var newResolveResult = new CSharpInvocationResolveResult( irr.TargetResult, irr.Member, irr.Arguments, irr.OverloadResolutionErrors, isExtensionMethodInvocation: true, irr.IsExpandedForm, irr.IsDelegateInvocation, - irr.IsLocalFunctionInvocation, irr.GetArgumentToParameterMap(), irr.InitializerStatements); + irr.GetArgumentToParameterMap(), irr.InitializerStatements); invocationExpression.AddAnnotation(newResolveResult); } }