Browse Source

Clean up CallBuilder.HandleDelegateConstruction

pull/1586/head
Siegfried Pammer 6 years ago
parent
commit
763ea38644
  1. 17
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/LocalFunctions.cs
  2. 98
      ICSharpCode.Decompiler/CSharp/CallBuilder.cs
  3. 5
      ICSharpCode.Decompiler/CSharp/Resolver/CSharpInvocationResolveResult.cs
  4. 2
      ICSharpCode.Decompiler/CSharp/Transforms/IntroduceExtensionMethods.cs

17
ICSharpCode.Decompiler.Tests/TestCases/Pretty/LocalFunctions.cs

@ -148,6 +148,23 @@ namespace LocalFunctions @@ -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));

98
ICSharpCode.Decompiler/CSharp/CallBuilder.cs

@ -1227,69 +1227,67 @@ namespace ICSharpCode.Decompiler.CSharp @@ -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);

5
ICSharpCode.Decompiler/CSharp/Resolver/CSharpInvocationResolveResult.cs

@ -47,11 +47,6 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -47,11 +47,6 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
/// </summary>
public readonly bool IsExpandedForm;
/// <summary>
/// Gets whether this invocation is calling a local function.
/// </summary>
public readonly bool IsLocalFunctionInvocation;
readonly IReadOnlyList<int> argumentToParameterMap;
public CSharpInvocationResolveResult(

2
ICSharpCode.Decompiler/CSharp/Transforms/IntroduceExtensionMethods.cs

@ -154,7 +154,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -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);
}
}

Loading…
Cancel
Save