Browse Source

Move CanTransformToExtensionMethodCall to CSharpResolver

pull/3532/head
Siegfried Pammer 5 months ago
parent
commit
d2d9281072
  1. 11
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  2. 28
      ICSharpCode.Decompiler/CSharp/Resolver/CSharpResolver.cs
  3. 11
      ICSharpCode.Decompiler/CSharp/StatementBuilder.cs
  4. 36
      ICSharpCode.Decompiler/CSharp/Transforms/IntroduceExtensionMethods.cs
  5. 13
      ICSharpCode.Decompiler/IL/Transforms/IILTransform.cs
  6. 6
      ICSharpCode.Decompiler/IL/Transforms/NullPropagationTransform.cs
  7. 20
      ICSharpCode.Decompiler/IL/Transforms/TransformCollectionAndObjectInitializers.cs

11
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -83,7 +83,9 @@ namespace ICSharpCode.Decompiler.CSharp @@ -83,7 +83,9 @@ namespace ICSharpCode.Decompiler.CSharp
internal readonly DecompilerSettings settings;
readonly CancellationToken cancellationToken;
public ExpressionBuilder(StatementBuilder statementBuilder, IDecompilerTypeSystem typeSystem, ITypeResolveContext decompilationContext, ILFunction currentFunction, DecompilerSettings settings, CancellationToken cancellationToken)
public ExpressionBuilder(StatementBuilder statementBuilder, IDecompilerTypeSystem typeSystem,
ITypeResolveContext decompilationContext, ILFunction currentFunction, DecompilerSettings settings,
DecompileRun decompileRun, CancellationToken cancellationToken)
{
Debug.Assert(decompilationContext != null);
this.statementBuilder = statementBuilder;
@ -93,7 +95,12 @@ namespace ICSharpCode.Decompiler.CSharp @@ -93,7 +95,12 @@ namespace ICSharpCode.Decompiler.CSharp
this.settings = settings;
this.cancellationToken = cancellationToken;
this.compilation = decompilationContext.Compilation;
this.resolver = new CSharpResolver(new CSharpTypeResolveContext(compilation.MainModule, null, decompilationContext.CurrentTypeDefinition, decompilationContext.CurrentMember));
this.resolver = new CSharpResolver(new CSharpTypeResolveContext(
compilation.MainModule,
decompileRun.UsingScope.Resolve(compilation),
decompilationContext.CurrentTypeDefinition,
decompilationContext.CurrentMember
));
this.astBuilder = new TypeSystemAstBuilder(resolver);
this.astBuilder.AlwaysUseShortTypeNames = true;
this.astBuilder.AddResolveResultAnnotations = true;

28
ICSharpCode.Decompiler/CSharp/Resolver/CSharpResolver.cs

@ -2954,5 +2954,33 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -2954,5 +2954,33 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
new[] { lhs, opResult.Operands[1] });
}
#endregion
#region CanTransformToExtensionMethodCall
public bool CanTransformToExtensionMethodCall(IMethod method,
IReadOnlyList<IType> typeArguments, ResolveResult target, ResolveResult[] arguments, string[] argumentNames)
{
if (target is LambdaResolveResult)
return false;
var rr = ResolveMemberAccess(target, method.Name, typeArguments, NameLookupMode.InvocationTarget) as MethodGroupResolveResult;
if (rr == null)
return false;
var or = rr.PerformOverloadResolution(CurrentTypeResolveContext.Compilation, arguments, argumentNames, allowExtensionMethods: true);
if (or == null || or.IsAmbiguous)
return false;
return method.Equals(or.GetBestCandidateWithSubstitutedTypeArguments())
&& CSharpResolver.IsEligibleExtensionMethod(target.Type, method, useTypeInference: false, out _);
}
public bool CanTransformToExtensionMethodCall(IMethod method, bool ignoreTypeArguments = false, bool ignoreArgumentNames = true)
{
if (method.Parameters.Count == 0)
return false;
var targetType = method.Parameters.Select(p => new ResolveResult(p.Type)).First();
var paramTypes = method.Parameters.Skip(1).Select(p => new ResolveResult(p.Type)).ToArray();
var paramNames = ignoreArgumentNames ? null : method.Parameters.SelectReadOnlyArray(p => p.Name);
var typeArgs = ignoreTypeArguments ? Empty<IType>.Array : method.TypeArguments.ToArray();
return CanTransformToExtensionMethodCall(method, typeArgs, targetType, paramTypes, argumentNames: paramNames);
}
#endregion
}
}

11
ICSharpCode.Decompiler/CSharp/StatementBuilder.cs

@ -24,8 +24,6 @@ using System.Threading; @@ -24,8 +24,6 @@ using System.Threading;
using ICSharpCode.Decompiler.CSharp.Syntax;
using ICSharpCode.Decompiler.CSharp.Syntax.PatternMatching;
using ICSharpCode.Decompiler.CSharp.Transforms;
using ICSharpCode.Decompiler.CSharp.TypeSystem;
using ICSharpCode.Decompiler.IL;
using ICSharpCode.Decompiler.IL.Transforms;
using ICSharpCode.Decompiler.Semantics;
@ -60,6 +58,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -60,6 +58,7 @@ namespace ICSharpCode.Decompiler.CSharp
decompilationContext,
currentFunction,
settings,
decompileRun,
cancellationToken
);
this.currentFunction = currentFunction;
@ -617,12 +616,8 @@ namespace ICSharpCode.Decompiler.CSharp @@ -617,12 +616,8 @@ namespace ICSharpCode.Decompiler.CSharp
if (!m.Success)
return null;
// Validate that the invocation is an extension method invocation.
var context = new CSharpTypeResolveContext(
typeSystem.MainModule,
decompileRun.UsingScope.Resolve(typeSystem)
);
if (!IntroduceExtensionMethods.CanTransformToExtensionMethodCall(context,
(InvocationExpression)resource))
if (!(resource.GetSymbol() is IMethod method
&& exprBuilder.resolver.CanTransformToExtensionMethodCall(method, true)))
{
return null;
}

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

@ -205,41 +205,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -205,41 +205,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
}
pos++;
}
return CanTransformToExtensionMethodCall(resolver, method, typeArguments, target, args, argNames);
}
public static bool CanTransformToExtensionMethodCall(CSharpTypeResolveContext resolveContext,
InvocationExpression invocationExpression)
{
return CanTransformToExtensionMethodCall(new CSharpResolver(resolveContext),
invocationExpression, out _, out _, out _);
}
public static bool CanTransformToExtensionMethodCall(CSharpResolver resolver, IMethod method,
IReadOnlyList<IType> typeArguments, ResolveResult target, ResolveResult[] arguments, string[] argumentNames)
{
if (target is LambdaResolveResult)
return false;
var rr = resolver.ResolveMemberAccess(target, method.Name, typeArguments, NameLookupMode.InvocationTarget) as MethodGroupResolveResult;
if (rr == null)
return false;
var or = rr.PerformOverloadResolution(resolver.CurrentTypeResolveContext.Compilation, arguments, argumentNames, allowExtensionMethods: true);
if (or == null || or.IsAmbiguous)
return false;
return method.Equals(or.GetBestCandidateWithSubstitutedTypeArguments())
&& CSharpResolver.IsEligibleExtensionMethod(target.Type, method, useTypeInference: false, out _);
}
public static bool CanTransformToExtensionMethodCall(IMethod method, CSharpTypeResolveContext resolveContext, bool ignoreTypeArguments = false, bool ignoreArgumentNames = true)
{
if (method.Parameters.Count == 0)
return false;
var targetType = method.Parameters.Select(p => new ResolveResult(p.Type)).First();
var paramTypes = method.Parameters.Skip(1).Select(p => new ResolveResult(p.Type)).ToArray();
var paramNames = ignoreArgumentNames ? null : method.Parameters.SelectReadOnlyArray(p => p.Name);
var typeArgs = ignoreTypeArguments ? Empty<IType>.Array : method.TypeArguments.ToArray();
var resolver = new CSharpResolver(resolveContext);
return CanTransformToExtensionMethodCall(resolver, method, typeArgs, targetType, paramTypes, argumentNames: paramNames);
return resolver.CanTransformToExtensionMethodCall(method, typeArguments, target, args, argNames);
}
}
}

13
ICSharpCode.Decompiler/IL/Transforms/IILTransform.cs

@ -22,9 +22,11 @@ using System; @@ -22,9 +22,11 @@ using System;
using System.Diagnostics;
using System.Threading;
using ICSharpCode.Decompiler.CSharp.Resolver;
using ICSharpCode.Decompiler.CSharp.TypeSystem;
using ICSharpCode.Decompiler.DebugInfo;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.Util;
namespace ICSharpCode.Decompiler.IL.Transforms
{
@ -52,6 +54,17 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -52,6 +54,17 @@ namespace ICSharpCode.Decompiler.IL.Transforms
internal DecompileRun? DecompileRun { get; set; }
internal ResolvedUsingScope? UsingScope => DecompileRun?.UsingScope.Resolve(TypeSystem);
CSharpResolver? csharpResolver;
internal CSharpResolver CSharpResolver {
get {
var resolver = LazyInit.VolatileRead(ref csharpResolver);
if (resolver != null)
return resolver;
return LazyInit.GetOrSet(ref csharpResolver, new CSharpResolver(new CSharpTypeResolveContext(TypeSystem.MainModule, UsingScope)));
}
}
public ILTransformContext(ILFunction function, IDecompilerTypeSystem typeSystem, IDebugInfoProvider? debugInfo, DecompilerSettings? settings = null)
{
this.Function = function ?? throw new ArgumentNullException(nameof(function));

6
ICSharpCode.Decompiler/IL/Transforms/NullPropagationTransform.cs

@ -374,11 +374,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -374,11 +374,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
bool CanTransformToExtensionMethodCall(CallInstruction call, ILTransformContext context)
{
return CSharp.Transforms.IntroduceExtensionMethods.CanTransformToExtensionMethodCall(
call.Method, new CSharp.TypeSystem.CSharpTypeResolveContext(
context.TypeSystem.MainModule, context.UsingScope
)
);
return context.CSharpResolver.CanTransformToExtensionMethodCall(call.Method);
}
}

20
ICSharpCode.Decompiler/IL/Transforms/TransformCollectionAndObjectInitializers.cs

@ -23,7 +23,6 @@ using System.Collections.Generic; @@ -23,7 +23,6 @@ using System.Collections.Generic;
using System.Linq;
using ICSharpCode.Decompiler.CSharp.Resolver;
using ICSharpCode.Decompiler.CSharp.TypeSystem;
using ICSharpCode.Decompiler.Semantics;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.Util;
@ -211,8 +210,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -211,8 +210,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
possibleIndexVariables.Add(stloc.Variable, (stloc.ChildIndex, stloc.Value));
return true;
}
var resolveContext = new CSharpTypeResolveContext(context.TypeSystem.MainModule, context.UsingScope);
(var kind, var newPath, var values, var targetVariable) = AccessPathElement.GetAccessPath(instructions[pos], rootType, context.Settings, resolveContext, possibleIndexVariables);
(var kind, var newPath, var values, var targetVariable) = AccessPathElement.GetAccessPath(instructions[pos], rootType, context.Settings, context.CSharpResolver, possibleIndexVariables);
if (kind == AccessPathKind.Invalid || target != targetVariable)
return false;
// Treat last element separately:
@ -302,7 +300,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -302,7 +300,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
public static (AccessPathKind Kind, List<AccessPathElement> Path, List<ILInstruction>? Values, ILVariable? Target) GetAccessPath(
ILInstruction instruction, IType rootType, DecompilerSettings? settings = null,
CSharpTypeResolveContext? resolveContext = null,
CSharpResolver? resolver = null,
Dictionary<ILVariable, (int Index, ILInstruction Value)>? possibleIndexVariables = null)
{
List<AccessPathElement> path = new List<AccessPathElement>();
@ -319,7 +317,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -319,7 +317,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (!(call is CallVirt || call is Call))
goto default;
method = call.Method;
if (resolveContext != null && !IsMethodApplicable(method, call.Arguments, rootType, resolveContext, settings))
if (resolver != null && !IsMethodApplicable(method, call.Arguments, rootType, resolver, settings))
goto default;
inst = call.Arguments[0];
if (inst is LdObjIfRef ldObjIfRef)
@ -329,7 +327,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -329,7 +327,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (method.IsAccessor)
{
if (method.AccessorOwner is IProperty property &&
!CanBeUsedInInitializer(property, resolveContext, kind))
!CanBeUsedInInitializer(property, resolver, kind))
{
goto default;
}
@ -433,14 +431,14 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -433,14 +431,14 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return (kind, path, values, target);
}
private static bool CanBeUsedInInitializer(IProperty property, CSharpTypeResolveContext? resolveContext, AccessPathKind kind)
private static bool CanBeUsedInInitializer(IProperty property, ITypeResolveContext? resolveContext, AccessPathKind kind)
{
if (property.CanSet && (property.Accessibility == property.Setter.Accessibility || IsAccessorAccessible(property.Setter, resolveContext)))
return true;
return kind != AccessPathKind.Setter;
}
private static bool IsAccessorAccessible(IMethod setter, CSharpTypeResolveContext? resolveContext)
private static bool IsAccessorAccessible(IMethod setter, ITypeResolveContext? resolveContext)
{
if (resolveContext == null)
return true;
@ -448,7 +446,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -448,7 +446,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return lookup.IsAccessible(setter, allowProtectedAccess: setter.DeclaringTypeDefinition == resolveContext.CurrentTypeDefinition);
}
static bool IsMethodApplicable(IMethod method, IReadOnlyList<ILInstruction> arguments, IType rootType, CSharpTypeResolveContext resolveContext, DecompilerSettings? settings)
static bool IsMethodApplicable(IMethod method, IReadOnlyList<ILInstruction> arguments, IType rootType, CSharpResolver resolver, DecompilerSettings? settings)
{
if (method.IsStatic && !method.IsExtensionMethod)
return false;
@ -460,7 +458,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -460,7 +458,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
{
if (settings?.ExtensionMethodsInCollectionInitializers == false)
return false;
if (!CSharp.Transforms.IntroduceExtensionMethods.CanTransformToExtensionMethodCall(method, resolveContext, ignoreTypeArguments: true))
if (!resolver.CanTransformToExtensionMethodCall(method, ignoreTypeArguments: true))
return false;
}
var targetType = GetReturnTypeFromInstruction(arguments[0]) ?? rootType;
@ -476,7 +474,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -476,7 +474,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return true;
// always use unspecialized member, otherwise type inference fails
method = (IMethod)method.MemberDefinition;
new TypeInference(resolveContext.Compilation)
new TypeInference(resolver.Compilation)
.InferTypeArguments(
method.TypeParameters,
// TODO : this is not entirely correct... we need argument type information to resolve Add methods properly

Loading…
Cancel
Save