Browse Source

Improve decompilation of delegate references of extension methods.

pull/2679/head
Siegfried Pammer 3 years ago
parent
commit
6a27959cbc
  1. 2
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/DelegateConstruction.cs
  2. 92
      ICSharpCode.Decompiler/CSharp/CallBuilder.cs
  3. 2
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

2
ICSharpCode.Decompiler.Tests/TestCases/Pretty/DelegateConstruction.cs

@ -496,7 +496,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
public static void ExtensionDelegateReference(IEnumerable<int> ints) public static void ExtensionDelegateReference(IEnumerable<int> ints)
{ {
Use2((Func<Func<int, int>, IEnumerable<int>>)ints.Select<int, int>); Use2(ints.Select<int, int>);
} }
#if CS70 #if CS70

92
ICSharpCode.Decompiler/CSharp/CallBuilder.cs

@ -1612,29 +1612,40 @@ namespace ICSharpCode.Decompiler.CSharp
thisArg = thisArgBox.Argument; thisArg = thisArgBox.Argument;
} }
TranslatedExpression target = expressionBuilder.Translate(thisArg, targetType); TranslatedExpression target = expressionBuilder.Translate(thisArg, targetType);
var currentTarget = target;
bool targetCasted = false; bool targetCasted = false;
bool addTypeArguments = false; bool addTypeArguments = false;
// Initial inputs for IsUnambiguousMethodReference: // Initial inputs for IsUnambiguousMethodReference:
ResolveResult targetResolveResult = target.ResolveResult; ResolveResult targetResolveResult = target.ResolveResult;
IReadOnlyList<IType> typeArguments = EmptyList<IType>.Instance; IReadOnlyList<IType> typeArguments = EmptyList<IType>.Instance;
if (thisArg.MatchLdNull())
{
targetCasted = true;
currentTarget = currentTarget.ConvertTo(targetType, expressionBuilder);
targetResolveResult = currentTarget.ResolveResult;
}
// Find somewhat minimal solution: // Find somewhat minimal solution:
ResolveResult result; ResolveResult result;
targetCasted = true; while (!IsUnambiguousMethodReference(expectedTargetDetails, method, targetResolveResult, typeArguments, true, out result))
target = target.ConvertTo(targetType, expressionBuilder); {
targetResolveResult = target.ResolveResult; if (!targetCasted)
addTypeArguments = true; {
typeArguments = method.TypeArguments; // try casting target
result = new MethodGroupResolveResult( targetCasted = true;
targetResolveResult, method.Name, currentTarget = currentTarget.ConvertTo(targetType, expressionBuilder);
new[] { targetResolveResult = currentTarget.ResolveResult;
new MethodListWithDeclaringType( continue;
null, }
new[] { method } if (!addTypeArguments)
) {
}, // try adding type arguments
typeArguments addTypeArguments = true;
); typeArguments = method.TypeArguments;
return (target, addTypeArguments, method.Name, result); continue;
}
break;
}
return (currentTarget, addTypeArguments, method.Name, result);
} }
else else
{ {
@ -1672,7 +1683,7 @@ namespace ICSharpCode.Decompiler.CSharp
IReadOnlyList<IType> typeArguments = EmptyList<IType>.Instance; IReadOnlyList<IType> typeArguments = EmptyList<IType>.Instance;
// Find somewhat minimal solution: // Find somewhat minimal solution:
ResolveResult result; ResolveResult result;
while (!IsUnambiguousMethodReference(expectedTargetDetails, method, targetResolveResult, typeArguments, out result)) while (!IsUnambiguousMethodReference(expectedTargetDetails, method, targetResolveResult, typeArguments, false, out result))
{ {
if (!addTypeArguments) if (!addTypeArguments)
{ {
@ -1717,30 +1728,47 @@ namespace ICSharpCode.Decompiler.CSharp
return oce; return oce;
} }
bool IsUnambiguousMethodReference(ExpectedTargetDetails expectedTargetDetails, IMethod method, ResolveResult target, IReadOnlyList<IType> typeArguments, out ResolveResult result) bool IsUnambiguousMethodReference(ExpectedTargetDetails expectedTargetDetails, IMethod method, ResolveResult target, IReadOnlyList<IType> typeArguments, bool isExtensionMethodReference, out ResolveResult result)
{ {
Log.WriteLine("IsUnambiguousMethodReference: Performing overload resolution for " + method); Log.WriteLine("IsUnambiguousMethodReference: Performing overload resolution for " + method);
var lookup = new MemberLookup(resolver.CurrentTypeDefinition, resolver.CurrentTypeDefinition.ParentModule); var lookup = new MemberLookup(resolver.CurrentTypeDefinition, resolver.CurrentTypeDefinition.ParentModule);
var or = new OverloadResolution(resolver.Compilation, OverloadResolution or;
arguments: method.Parameters.SelectReadOnlyArray(p => new TypeResolveResult(p.Type)), // there are no arguments, use parameter types
argumentNames: null, // argument names are not possible if (isExtensionMethodReference)
typeArguments.ToArray(),
conversions: expressionBuilder.resolver.conversions
);
if (target == null)
{ {
result = resolver.ResolveSimpleName(method.Name, typeArguments, isInvocationTarget: false); var resolver = this.resolver.WithCurrentUsingScope(this.expressionBuilder.statementBuilder.decompileRun.UsingScope.Resolve(this.resolver.Compilation));
if (!(result is MethodGroupResolveResult mgrr)) result = resolver.ResolveMemberAccess(target, method.Name, typeArguments, NameLookupMode.InvocationTarget) as MethodGroupResolveResult;
if (result == null)
return false;
or = ((MethodGroupResolveResult)result).PerformOverloadResolution(resolver.CurrentTypeResolveContext.Compilation,
method.Parameters.SelectReadOnlyArray(p => new TypeResolveResult(p.Type)),
argumentNames: null, allowExtensionMethods: true);
if (or == null || or.IsAmbiguous)
return false; return false;
or.AddMethodLists(mgrr.MethodsGroupedByDeclaringType.ToArray());
} }
else else
{ {
result = lookup.Lookup(target, method.Name, typeArguments, isInvocation: false); or = new OverloadResolution(resolver.Compilation,
if (!(result is MethodGroupResolveResult mgrr)) arguments: method.Parameters.SelectReadOnlyArray(p => new TypeResolveResult(p.Type)), // there are no arguments, use parameter types
return false; argumentNames: null, // argument names are not possible
or.AddMethodLists(mgrr.MethodsGroupedByDeclaringType.ToArray()); typeArguments.ToArray(),
conversions: expressionBuilder.resolver.conversions
);
if (target == null)
{
result = resolver.ResolveSimpleName(method.Name, typeArguments, isInvocationTarget: false);
if (!(result is MethodGroupResolveResult mgrr))
return false;
or.AddMethodLists(mgrr.MethodsGroupedByDeclaringType.ToArray());
}
else
{
result = lookup.Lookup(target, method.Name, typeArguments, isInvocation: false);
if (!(result is MethodGroupResolveResult mgrr))
return false;
or.AddMethodLists(mgrr.MethodsGroupedByDeclaringType.ToArray());
}
} }
var foundMethod = or.GetBestCandidateWithSubstitutedTypeArguments(); var foundMethod = or.GetBestCandidateWithSubstitutedTypeArguments();

2
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -71,7 +71,7 @@ namespace ICSharpCode.Decompiler.CSharp
/// </remarks> /// </remarks>
sealed class ExpressionBuilder : ILVisitor<TranslationContext, TranslatedExpression> sealed class ExpressionBuilder : ILVisitor<TranslationContext, TranslatedExpression>
{ {
readonly StatementBuilder statementBuilder; internal readonly StatementBuilder statementBuilder;
readonly IDecompilerTypeSystem typeSystem; readonly IDecompilerTypeSystem typeSystem;
internal readonly ITypeResolveContext decompilationContext; internal readonly ITypeResolveContext decompilationContext;
internal readonly ILFunction currentFunction; internal readonly ILFunction currentFunction;

Loading…
Cancel
Save