Browse Source

Introduce named arguments only in the statement transform.

Don't use extension method syntax when 'this' parameter of
extension method is named.
pull/1167/head
Daniel Grunwald 7 years ago
parent
commit
21d3881e37
  1. 30
      ICSharpCode.Decompiler/CSharp/Transforms/IntroduceExtensionMethods.cs
  2. 2
      ICSharpCode.Decompiler/IL/Transforms/CachedDelegateInitialization.cs
  3. 2
      ICSharpCode.Decompiler/IL/Transforms/CopyPropagation.cs
  4. 60
      ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs
  5. 2
      ICSharpCode.Decompiler/IL/Transforms/NullCoalescingTransform.cs
  6. 3
      ICSharpCode.Decompiler/IL/Transforms/NullPropagationTransform.cs

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

@ -113,12 +113,28 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -113,12 +113,28 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
}
var firstArgument = invocationExpression.Arguments.First();
if (firstArgument is NamedArgumentExpression)
return;
var target = firstArgument.GetResolveResult();
if (target is ConstantResolveResult crr && crr.ConstantValue == null) {
target = new ConversionResolveResult(method.Parameters[0].Type, crr, Conversion.NullLiteralConversion);
}
var args = invocationExpression.Arguments.Skip(1).Select(a => a.GetResolveResult()).ToArray();
if (!CanTransformToExtensionMethodCall(resolver, method, typeArguments, target, args))
ResolveResult[] args = new ResolveResult[invocationExpression.Arguments.Count - 1];
string[] argNames = null;
int pos = 0;
foreach (var arg in invocationExpression.Arguments.Skip(1)) {
if (arg is NamedArgumentExpression nae) {
if (argNames == null) {
argNames = new string[args.Length];
}
argNames[pos] = nae.Name;
args[pos] = nae.Expression.GetResolveResult();
} else {
args[pos] = arg.GetResolveResult();
}
pos++;
}
if (!CanTransformToExtensionMethodCall(resolver, method, typeArguments, target, args, argNames))
return;
if (firstArgument is NullReferenceExpression)
firstArgument = firstArgument.ReplaceWith(expr => new CastExpression(context.TypeSystemAstBuilder.ConvertType(method.Parameters[0].Type), expr.Detach()));
@ -131,16 +147,16 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -131,16 +147,16 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
}
}
public static bool CanTransformToExtensionMethodCall(CSharpResolver resolver, IMethod method, IReadOnlyList<IType> typeArguments, ResolveResult target, ResolveResult[] arguments)
public static bool CanTransformToExtensionMethodCall(CSharpResolver resolver, IMethod method,
IReadOnlyList<IType> typeArguments, ResolveResult target, ResolveResult[] arguments, string[] argumentNames)
{
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()))
var or = rr.PerformOverloadResolution(resolver.CurrentTypeResolveContext.Compilation, arguments, argumentNames, allowExtensionMethods: true);
if (or == null || or.IsAmbiguous)
return false;
return true;
return method.Equals(or.GetBestCandidateWithSubstitutedTypeArguments());
}
}
}

2
ICSharpCode.Decompiler/IL/Transforms/CachedDelegateInitialization.cs

@ -38,7 +38,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -38,7 +38,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
continue;
}
if (CachedDelegateInitializationWithLocal(inst)) {
ILInlining.InlineOneIfPossible(block, i, true, context);
ILInlining.InlineOneIfPossible(block, i, InliningOptions.Aggressive, context);
continue;
}
if (CachedDelegateInitializationRoslynInStaticWithLocal(inst) || CachedDelegateInitializationRoslynWithLocal(inst)) {

2
ICSharpCode.Decompiler/IL/Transforms/CopyPropagation.cs

@ -125,7 +125,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -125,7 +125,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
expr.ReplaceWith(clone);
}
block.Instructions.RemoveAt(i);
int c = ILInlining.InlineInto(block, i, aggressive: false, context: context);
int c = ILInlining.InlineInto(block, i, InliningOptions.None, context: context);
i -= c + 1;
}
}

60
ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs

@ -23,6 +23,14 @@ using ICSharpCode.Decompiler.TypeSystem; @@ -23,6 +23,14 @@ using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.Decompiler.IL.Transforms
{
[Flags]
public enum InliningOptions
{
None = 0,
Aggressive = 1,
IntroduceNamedArguments = 2,
}
/// <summary>
/// Performs inlining transformations.
/// </summary>
@ -44,7 +52,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -44,7 +52,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms
public void Run(Block block, int pos, StatementTransformContext context)
{
InlineOneIfPossible(block, pos, aggressive: IsCatchWhenBlock(block), context: context);
InliningOptions options = InliningOptions.None;
if (IsCatchWhenBlock(block))
options |= InliningOptions.Aggressive;
if (context.Settings.NamedArguments)
options |= InliningOptions.IntroduceNamedArguments;
InlineOneIfPossible(block, pos, options, context: context);
}
public static bool InlineAllInBlock(ILFunction function, Block block, ILTransformContext context)
@ -58,14 +71,18 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -58,14 +71,18 @@ namespace ICSharpCode.Decompiler.IL.Transforms
bool modified = false;
var instructions = block.Instructions;
for (int i = 0; i < instructions.Count;) {
if (instructions[i] is StLoc inst
&& InlineOneIfPossible(block, i, aggressive: IsCatchWhenBlock(block) || IsInConstructorInitializer(function, inst, ref ctorCallStart), context: context)) {
modified = true;
i = Math.Max(0, i - 1);
// Go back one step
} else {
i++;
if (instructions[i] is StLoc inst) {
InliningOptions options = InliningOptions.None;
if (IsCatchWhenBlock(block) || IsInConstructorInitializer(function, inst, ref ctorCallStart))
options = InliningOptions.Aggressive;
if (InlineOneIfPossible(block, i, options, context)) {
modified = true;
i = Math.Max(0, i - 1);
// Go back one step
continue;
}
}
i++;
}
return modified;
}
@ -100,13 +117,13 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -100,13 +117,13 @@ namespace ICSharpCode.Decompiler.IL.Transforms
/// Inlines instructions before pos into block.Instructions[pos].
/// </summary>
/// <returns>The number of instructions that were inlined.</returns>
public static int InlineInto(Block block, int pos, bool aggressive, ILTransformContext context)
public static int InlineInto(Block block, int pos, InliningOptions options, ILTransformContext context)
{
if (pos >= block.Instructions.Count)
return 0;
int count = 0;
while (--pos >= 0) {
if (InlineOneIfPossible(block, pos, aggressive, context))
if (InlineOneIfPossible(block, pos, options, context))
count++;
else
break;
@ -119,13 +136,13 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -119,13 +136,13 @@ namespace ICSharpCode.Decompiler.IL.Transforms
/// </summary>
public static bool InlineIfPossible(Block block, int pos, ILTransformContext context)
{
return InlineOneIfPossible(block, pos, true, context);
return InlineOneIfPossible(block, pos, InliningOptions.Aggressive, context);
}
/// <summary>
/// Inlines the stloc instruction at block.Instructions[pos] into the next instruction, if possible.
/// </summary>
public static bool InlineOneIfPossible(Block block, int pos, bool aggressive, ILTransformContext context)
public static bool InlineOneIfPossible(Block block, int pos, InliningOptions options, ILTransformContext context)
{
context.CancellationToken.ThrowIfCancellationRequested();
StLoc stloc = block.Instructions[pos] as StLoc;
@ -141,7 +158,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -141,7 +158,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
// but we can't avoid it this easily without breaking lots of tests.
//if (v.Type.IsSmallIntegerType())
// return false; // stloc might perform implicit truncation
return InlineOne(stloc, aggressive, context);
return InlineOne(stloc, options, context);
}
/// <summary>
@ -150,12 +167,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -150,12 +167,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms
/// Note that this method does not check whether 'v' has only one use;
/// the caller is expected to validate whether inlining 'v' has any effects on other uses of 'v'.
/// </summary>
public static bool InlineOne(StLoc stloc, bool aggressive, ILTransformContext context)
public static bool InlineOne(StLoc stloc, InliningOptions options, ILTransformContext context)
{
ILVariable v = stloc.Variable;
Block block = (Block)stloc.Parent;
int pos = stloc.ChildIndex;
if (DoInline(v, stloc.Value, block.Instructions.ElementAtOrDefault(pos + 1), aggressive, context)) {
if (DoInline(v, stloc.Value, block.Instructions.ElementAtOrDefault(pos + 1), options, context)) {
// Assign the ranges of the stloc instruction:
stloc.Value.AddILRange(stloc.ILRange);
// Remove the stloc instruction:
@ -188,7 +205,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -188,7 +205,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
/// Note that this method does not check whether 'v' has only one use;
/// the caller is expected to validate whether inlining 'v' has any effects on other uses of 'v'.
/// </summary>
static bool DoInline(ILVariable v, ILInstruction inlinedExpression, ILInstruction next, bool aggressive, ILTransformContext context)
static bool DoInline(ILVariable v, ILInstruction inlinedExpression, ILInstruction next, InliningOptions options, ILTransformContext context)
{
var r = FindLoadInNext(next, v, inlinedExpression, out var loadInst);
if (r == FindResult.Found) {
@ -197,8 +214,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -197,8 +214,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return false;
} else {
Debug.Assert(loadInst.OpCode == OpCode.LdLoc);
if (!aggressive && v.Kind != VariableKind.StackSlot && !NonAggressiveInlineInto(next, loadInst, inlinedExpression, v))
bool aggressive = (options & InliningOptions.Aggressive) != 0;
if (!aggressive && v.Kind != VariableKind.StackSlot
&& !NonAggressiveInlineInto(next, loadInst, inlinedExpression, v)) {
return false;
}
}
context.Step($"Inline variable '{v.Name}'", inlinedExpression);
@ -213,10 +233,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -213,10 +233,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms
loadInst.ReplaceWith(inlinedExpression);
}
return true;
} else if (r == FindResult.NamedArgument && context.Settings.NamedArguments) {
} else if (r == FindResult.NamedArgument && (options & InliningOptions.IntroduceNamedArguments) != 0) {
Debug.Assert(loadInst.OpCode == OpCode.LdLoc);
//if (!aggressive && v.Kind != VariableKind.StackSlot && !NonAggressiveInlineInto(next, loadInst, inlinedExpression, v))
// return false;
context.Step($"Introduce named argument '{v.Name}'", inlinedExpression);
var call = (CallInstruction)loadInst.Parent;
if (!(call.Parent is Block namedArgBlock) || namedArgBlock.Kind != BlockKind.CallWithNamedArgs) {
@ -484,6 +502,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -484,6 +502,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (type.Kind == TypeKind.Delegate || type.IsAnonymousType())
return FindResult.Stop;
}
if (call.Method.Parameters.Any(p => string.IsNullOrEmpty(p.Name)))
return FindResult.Stop; // cannot use named arguments
for (int i = child.ChildIndex; i < call.Arguments.Count; i++) {
if (call.Arguments[i] is LdLoc ldloc && ldloc.Variable == v) {
loadInst = ldloc;

2
ICSharpCode.Decompiler/IL/Transforms/NullCoalescingTransform.cs

@ -62,7 +62,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -62,7 +62,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
context.Step("NullCoalescingTransform (reference types)", stloc);
stloc.Value = new NullCoalescingInstruction(NullCoalescingKind.Ref, stloc.Value, fallbackValue);
block.Instructions.RemoveAt(pos + 1); // remove if instruction
ILInlining.InlineOneIfPossible(block, pos, false, context);
ILInlining.InlineOneIfPossible(block, pos, InliningOptions.None, context);
return true;
}
return false;

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

@ -248,7 +248,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -248,7 +248,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms
var typeArgs = call.Method.TypeArguments.ToArray();
var resolveContext = new CSharp.TypeSystem.CSharpTypeResolveContext(context.TypeSystem.Compilation.MainAssembly, context.UsingScope);
var resolver = new CSharp.Resolver.CSharpResolver(resolveContext);
return CSharp.Transforms.IntroduceExtensionMethods.CanTransformToExtensionMethodCall(resolver, call.Method, typeArgs, targetType, paramTypes);
return CSharp.Transforms.IntroduceExtensionMethods.CanTransformToExtensionMethodCall(
resolver, call.Method, typeArgs, targetType, paramTypes, argumentNames: null);
}
static bool IsGetter(IMethod method)

Loading…
Cancel
Save