Browse Source

Fix #1080: Invalid null propagation decompilation with ambiguous extension method call

pull/1087/head
Siegfried Pammer 7 years ago
parent
commit
8da26dc315
  1. 19
      ICSharpCode.Decompiler/CSharp/Transforms/IntroduceExtensionMethods.cs
  2. 35
      ICSharpCode.Decompiler/IL/Transforms/NullPropagationTransform.cs

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

@ -22,6 +22,7 @@ using System.Linq; @@ -22,6 +22,7 @@ using System.Linq;
using ICSharpCode.Decompiler.CSharp.Resolver;
using ICSharpCode.Decompiler.CSharp.Syntax;
using ICSharpCode.Decompiler.CSharp.TypeSystem;
using ICSharpCode.Decompiler.Semantics;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.Util;
@ -100,16 +101,24 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -100,16 +101,24 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
var firstArgument = invocationExpression.Arguments.First();
var target = firstArgument.GetResolveResult();
var args = invocationExpression.Arguments.Skip(1).Select(a => a.GetResolveResult()).ToArray();
var rr = resolver.ResolveMemberAccess(target, method.Name, typeArguments, NameLookupMode.InvocationTarget) as MethodGroupResolveResult;
if (rr == null)
return;
var or = rr.PerformOverloadResolution(resolver.CurrentTypeResolveContext.Compilation, args, allowExtensionMethods: true);
if (or == null || or.IsAmbiguous || !method.Equals(or.GetBestCandidateWithSubstitutedTypeArguments()))
if (!CanTransformToExtensionMethodCall(resolver, method, typeArguments, target, args))
return;
if (firstArgument is NullReferenceExpression)
firstArgument = firstArgument.ReplaceWith(expr => new CastExpression(context.TypeSystemAstBuilder.ConvertType(method.Parameters[0].Type), expr.Detach()));
else
mre.Target = firstArgument.Detach();
}
public static bool CanTransformToExtensionMethodCall(CSharpResolver resolver, IMethod method, IReadOnlyList<IType> typeArguments, ResolveResult target, ResolveResult[] arguments)
{
var rr = resolver.ResolveMemberAccess(target, method.Name, typeArguments, NameLookupMode.InvocationTarget) as MethodGroupResolveResult;
if (rr == null)
return false;
// TODO : add support for argument names as soon as named arguments are implemented in the decompiler.
var or = rr.PerformOverloadResolution(resolver.CurrentTypeResolveContext.Compilation, arguments, allowExtensionMethods: true);
if (or == null || or.IsAmbiguous || !method.Equals(or.GetBestCandidateWithSubstitutedTypeArguments()))
return false;
return true;
}
}
}

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

@ -18,8 +18,12 @@ @@ -18,8 +18,12 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using System.Text;
using ICSharpCode.Decompiler.CSharp.Syntax;
using ICSharpCode.Decompiler.Semantics;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.Util;
@ -193,7 +197,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -193,7 +197,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (call.Arguments.Count == 0) {
return false;
}
if (call.Method.IsStatic && !call.Method.IsExtensionMethod) {
if (call.Method.IsStatic && (!call.Method.IsExtensionMethod || !CanTransformToExtensionMethodCall(call))) {
return false; // only instance or extension methods can be called with ?. syntax
}
if (call.Method.IsAccessor && !IsGetter(call.Method)) {
@ -235,6 +239,35 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -235,6 +239,35 @@ namespace ICSharpCode.Decompiler.IL.Transforms
}
}
bool CanTransformToExtensionMethodCall(CallInstruction call)
{
if (call.Method.Parameters.Count == 0) return false;
var targetType = call.Method.Parameters.Select(p => new ResolveResult(p.Type)).First();
var paramTypes = call.Method.Parameters.Skip(1).Select(p => new ResolveResult(p.Type)).ToArray();
var paramNames = call.Method.Parameters.SelectArray(p => p.Name);
var typeArgs = call.Method.TypeArguments.ToArray();
var usingScope = CreateUsingScope(context.RequiredNamespacesSuperset).Resolve(context.TypeSystem.Compilation);
var resolveContext = new CSharp.TypeSystem.CSharpTypeResolveContext(context.TypeSystem.Compilation.MainAssembly, usingScope);
var resolver = new CSharp.Resolver.CSharpResolver(resolveContext);
return CSharp.Transforms.IntroduceExtensionMethods.CanTransformToExtensionMethodCall(resolver, call.Method, typeArgs, targetType, paramTypes);
}
CSharp.TypeSystem.UsingScope CreateUsingScope(IImmutableSet<string> requiredNamespacesSuperset)
{
var usingScope = new CSharp.TypeSystem.UsingScope();
foreach (var ns in requiredNamespacesSuperset) {
string[] parts = ns.Split('.');
AstType nsType = new SimpleType(parts[0]);
for (int i = 1; i < parts.Length; i++) {
nsType = new MemberType { Target = nsType, MemberName = parts[i] };
}
var reference = nsType.ToTypeReference(CSharp.Resolver.NameLookupMode.TypeInUsingDeclaration) as CSharp.TypeSystem.TypeOrNamespaceReference;
if (reference != null)
usingScope.Usings.Add(reference);
}
return usingScope;
}
static bool IsGetter(IMethod method)
{
return method.AccessorOwner is IProperty p && p.Getter == method;

Loading…
Cancel
Save