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. 60
      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

60
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;
while (!IsUnambiguousMethodReference(expectedTargetDetails, method, targetResolveResult, typeArguments, true, out result))
{
if (!targetCasted)
{
// try casting target
targetCasted = true; targetCasted = true;
target = target.ConvertTo(targetType, expressionBuilder); currentTarget = currentTarget.ConvertTo(targetType, expressionBuilder);
targetResolveResult = target.ResolveResult; targetResolveResult = currentTarget.ResolveResult;
continue;
}
if (!addTypeArguments)
{
// try adding type arguments
addTypeArguments = true; addTypeArguments = true;
typeArguments = method.TypeArguments; typeArguments = method.TypeArguments;
result = new MethodGroupResolveResult( continue;
targetResolveResult, method.Name, }
new[] { break;
new MethodListWithDeclaringType( }
null, return (currentTarget, addTypeArguments, method.Name, result);
new[] { method }
)
},
typeArguments
);
return (target, 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,12 +1728,28 @@ 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;
if (isExtensionMethodReference)
{
var resolver = this.resolver.WithCurrentUsingScope(this.expressionBuilder.statementBuilder.decompileRun.UsingScope.Resolve(this.resolver.Compilation));
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;
}
else
{
or = new OverloadResolution(resolver.Compilation,
arguments: method.Parameters.SelectReadOnlyArray(p => new TypeResolveResult(p.Type)), // there are no arguments, use parameter types arguments: method.Parameters.SelectReadOnlyArray(p => new TypeResolveResult(p.Type)), // there are no arguments, use parameter types
argumentNames: null, // argument names are not possible argumentNames: null, // argument names are not possible
typeArguments.ToArray(), typeArguments.ToArray(),
@ -1742,6 +1769,7 @@ namespace ICSharpCode.Decompiler.CSharp
return false; return false;
or.AddMethodLists(mgrr.MethodsGroupedByDeclaringType.ToArray()); or.AddMethodLists(mgrr.MethodsGroupedByDeclaringType.ToArray());
} }
}
var foundMethod = or.GetBestCandidateWithSubstitutedTypeArguments(); var foundMethod = or.GetBestCandidateWithSubstitutedTypeArguments();
if (!IsAppropriateCallTarget(expectedTargetDetails, method, foundMethod)) if (!IsAppropriateCallTarget(expectedTargetDetails, method, foundMethod))

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