diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/NamedArguments.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/NamedArguments.cs
index f6bc4d7eb..499baef34 100644
--- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/NamedArguments.cs
+++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/NamedArguments.cs
@@ -20,6 +20,18 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
public class NamedArguments
{
+ private class ClassWithNamedArgCtor
+ {
+ internal ClassWithNamedArgCtor(bool arg1 = false, bool arg2 = false)
+ {
+ }
+
+ internal ClassWithNamedArgCtor()
+ : this(arg2: Get(1) != 1, arg1: Get(2) == 2)
+ {
+ }
+ }
+
public void Use(int a, int b, int c)
{
}
diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/NamedArguments.il b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/NamedArguments.il
index ae6d2e2a7..b0ace0e0a 100644
--- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/NamedArguments.il
+++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/NamedArguments.il
@@ -32,6 +32,54 @@
.class public auto ansi beforefieldinit ICSharpCode.Decompiler.Tests.TestCases.Pretty.NamedArguments
extends [mscorlib]System.Object
{
+ .class auto ansi nested private beforefieldinit ClassWithNamedArgCtor
+ extends [mscorlib]System.Object
+ {
+ .method assembly hidebysig specialname rtspecialname
+ instance void .ctor([opt] bool arg1,
+ [opt] bool arg2) cil managed
+ {
+ .param [1] = bool(false)
+ .param [2] = bool(false)
+ // Code size 10 (0xa)
+ .maxstack 8
+ IL_0000: ldarg.0
+ IL_0001: call instance void [mscorlib]System.Object::.ctor()
+ IL_0006: nop
+ IL_0007: nop
+ IL_0008: nop
+ IL_0009: ret
+ } // end of method ClassWithNamedArgCtor::.ctor
+
+ .method assembly hidebysig specialname rtspecialname
+ instance void .ctor() cil managed
+ {
+ // Code size 33 (0x21)
+ .maxstack 3
+ .locals init (bool V_0)
+ IL_0000: ldarg.0
+ IL_0001: ldc.i4.1
+ IL_0002: call int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.NamedArguments::Get(int32)
+ IL_0007: ldc.i4.1
+ IL_0008: ceq
+ IL_000a: ldc.i4.0
+ IL_000b: ceq
+ IL_000d: stloc.0
+ IL_000e: ldc.i4.2
+ IL_000f: call int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.NamedArguments::Get(int32)
+ IL_0014: ldc.i4.2
+ IL_0015: ceq
+ IL_0017: ldloc.0
+ IL_0018: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.NamedArguments/ClassWithNamedArgCtor::.ctor(bool,
+ bool)
+ IL_001d: nop
+ IL_001e: nop
+ IL_001f: nop
+ IL_0020: ret
+ } // end of method ClassWithNamedArgCtor::.ctor
+
+ } // end of class ClassWithNamedArgCtor
+
.method public hidebysig instance void
Use(int32 a,
int32 b,
diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/NamedArguments.opt.il b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/NamedArguments.opt.il
index efb47ca67..8aea36a8a 100644
--- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/NamedArguments.opt.il
+++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/NamedArguments.opt.il
@@ -32,6 +32,48 @@
.class public auto ansi beforefieldinit ICSharpCode.Decompiler.Tests.TestCases.Pretty.NamedArguments
extends [mscorlib]System.Object
{
+ .class auto ansi nested private beforefieldinit ClassWithNamedArgCtor
+ extends [mscorlib]System.Object
+ {
+ .method assembly hidebysig specialname rtspecialname
+ instance void .ctor([opt] bool arg1,
+ [opt] bool arg2) cil managed
+ {
+ .param [1] = bool(false)
+ .param [2] = bool(false)
+ // Code size 7 (0x7)
+ .maxstack 8
+ IL_0000: ldarg.0
+ IL_0001: call instance void [mscorlib]System.Object::.ctor()
+ IL_0006: ret
+ } // end of method ClassWithNamedArgCtor::.ctor
+
+ .method assembly hidebysig specialname rtspecialname
+ instance void .ctor() cil managed
+ {
+ // Code size 30 (0x1e)
+ .maxstack 3
+ .locals init (bool V_0)
+ IL_0000: ldarg.0
+ IL_0001: ldc.i4.1
+ IL_0002: call int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.NamedArguments::Get(int32)
+ IL_0007: ldc.i4.1
+ IL_0008: ceq
+ IL_000a: ldc.i4.0
+ IL_000b: ceq
+ IL_000d: stloc.0
+ IL_000e: ldc.i4.2
+ IL_000f: call int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.NamedArguments::Get(int32)
+ IL_0014: ldc.i4.2
+ IL_0015: ceq
+ IL_0017: ldloc.0
+ IL_0018: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.NamedArguments/ClassWithNamedArgCtor::.ctor(bool,
+ bool)
+ IL_001d: ret
+ } // end of method ClassWithNamedArgCtor::.ctor
+
+ } // end of class ClassWithNamedArgCtor
+
.method public hidebysig instance void
Use(int32 a,
int32 b,
diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/NamedArguments.opt.roslyn.il b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/NamedArguments.opt.roslyn.il
index 86b33e26d..fa62bac33 100644
--- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/NamedArguments.opt.roslyn.il
+++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/NamedArguments.opt.roslyn.il
@@ -36,6 +36,48 @@
.class public auto ansi beforefieldinit ICSharpCode.Decompiler.Tests.TestCases.Pretty.NamedArguments
extends [mscorlib]System.Object
{
+ .class auto ansi nested private beforefieldinit ClassWithNamedArgCtor
+ extends [mscorlib]System.Object
+ {
+ .method assembly hidebysig specialname rtspecialname
+ instance void .ctor([opt] bool arg1,
+ [opt] bool arg2) cil managed
+ {
+ .param [1] = bool(false)
+ .param [2] = bool(false)
+ // Code size 7 (0x7)
+ .maxstack 8
+ IL_0000: ldarg.0
+ IL_0001: call instance void [mscorlib]System.Object::.ctor()
+ IL_0006: ret
+ } // end of method ClassWithNamedArgCtor::.ctor
+
+ .method assembly hidebysig specialname rtspecialname
+ instance void .ctor() cil managed
+ {
+ // Code size 30 (0x1e)
+ .maxstack 3
+ .locals init (bool V_0)
+ IL_0000: ldarg.0
+ IL_0001: ldc.i4.1
+ IL_0002: call int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.NamedArguments::Get(int32)
+ IL_0007: ldc.i4.1
+ IL_0008: ceq
+ IL_000a: ldc.i4.0
+ IL_000b: ceq
+ IL_000d: stloc.0
+ IL_000e: ldc.i4.2
+ IL_000f: call int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.NamedArguments::Get(int32)
+ IL_0014: ldc.i4.2
+ IL_0015: ceq
+ IL_0017: ldloc.0
+ IL_0018: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.NamedArguments/ClassWithNamedArgCtor::.ctor(bool,
+ bool)
+ IL_001d: ret
+ } // end of method ClassWithNamedArgCtor::.ctor
+
+ } // end of class ClassWithNamedArgCtor
+
.method public hidebysig instance void
Use(int32 a,
int32 b,
diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/NamedArguments.roslyn.il b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/NamedArguments.roslyn.il
index 0b3206cd4..466082996 100644
--- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/NamedArguments.roslyn.il
+++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/NamedArguments.roslyn.il
@@ -36,6 +36,52 @@
.class public auto ansi beforefieldinit ICSharpCode.Decompiler.Tests.TestCases.Pretty.NamedArguments
extends [mscorlib]System.Object
{
+ .class auto ansi nested private beforefieldinit ClassWithNamedArgCtor
+ extends [mscorlib]System.Object
+ {
+ .method assembly hidebysig specialname rtspecialname
+ instance void .ctor([opt] bool arg1,
+ [opt] bool arg2) cil managed
+ {
+ .param [1] = bool(false)
+ .param [2] = bool(false)
+ // Code size 9 (0x9)
+ .maxstack 8
+ IL_0000: ldarg.0
+ IL_0001: call instance void [mscorlib]System.Object::.ctor()
+ IL_0006: nop
+ IL_0007: nop
+ IL_0008: ret
+ } // end of method ClassWithNamedArgCtor::.ctor
+
+ .method assembly hidebysig specialname rtspecialname
+ instance void .ctor() cil managed
+ {
+ // Code size 32 (0x20)
+ .maxstack 3
+ .locals init (bool V_0)
+ IL_0000: ldarg.0
+ IL_0001: ldc.i4.1
+ IL_0002: call int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.NamedArguments::Get(int32)
+ IL_0007: ldc.i4.1
+ IL_0008: ceq
+ IL_000a: ldc.i4.0
+ IL_000b: ceq
+ IL_000d: stloc.0
+ IL_000e: ldc.i4.2
+ IL_000f: call int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.NamedArguments::Get(int32)
+ IL_0014: ldc.i4.2
+ IL_0015: ceq
+ IL_0017: ldloc.0
+ IL_0018: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.NamedArguments/ClassWithNamedArgCtor::.ctor(bool,
+ bool)
+ IL_001d: nop
+ IL_001e: nop
+ IL_001f: ret
+ } // end of method ClassWithNamedArgCtor::.ctor
+
+ } // end of class ClassWithNamedArgCtor
+
.method public hidebysig instance void
Use(int32 a,
int32 b,
diff --git a/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs b/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
index 3667696c2..c84fd041b 100644
--- a/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
+++ b/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
@@ -133,7 +133,8 @@ namespace ICSharpCode.Decompiler.CSharp
new NullPropagationStatementTransform(),
new TransformArrayInitializers(),
new TransformCollectionAndObjectInitializers(),
- new TransformExpressionTrees()
+ new TransformExpressionTrees(),
+ new NamedArgumentTransform()
),
}
},
diff --git a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
index cacda3343..eef45e352 100644
--- a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
+++ b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
@@ -297,6 +297,7 @@
+
diff --git a/ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs b/ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs
index 2c1feee87..8dc6aa802 100644
--- a/ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs
+++ b/ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs
@@ -51,13 +51,16 @@ namespace ICSharpCode.Decompiler.IL.Transforms
}
public void Run(Block block, int pos, StatementTransformContext context)
+ {
+ InlineOneIfPossible(block, pos, OptionsForBlock(block), context: context);
+ }
+
+ internal static InliningOptions OptionsForBlock(Block block)
{
InliningOptions options = InliningOptions.None;
if (IsCatchWhenBlock(block))
options |= InliningOptions.Aggressive;
- if (context.Settings.NamedArguments)
- options |= InliningOptions.IntroduceNamedArguments;
- InlineOneIfPossible(block, pos, options, context: context);
+ return options;
}
public static bool InlineAllInBlock(ILFunction function, Block block, ILTransformContext context)
@@ -234,31 +237,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms
}
return true;
} else if (r == FindResult.NamedArgument && (options & InliningOptions.IntroduceNamedArguments) != 0) {
- Debug.Assert(loadInst.OpCode == OpCode.LdLoc);
- StLoc originalStore = (StLoc)inlinedExpression.Parent;
- if ((options & InliningOptions.Aggressive) == 0 && originalStore.ILStackWasEmpty)
- 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) {
- // create namedArgBlock:
- namedArgBlock = new Block(BlockKind.CallWithNamedArgs);
- call.ReplaceWith(namedArgBlock);
- namedArgBlock.FinalInstruction = call;
- if (call.IsInstanceCall) {
- IType thisVarType = call.Method.DeclaringType;
- if (CallInstruction.ExpectedTypeForThisPointer(thisVarType) == StackType.Ref) {
- thisVarType = new ByReferenceType(thisVarType);
- }
- var function = call.Ancestors.OfType().First();
- var thisArgVar = function.RegisterVariable(VariableKind.NamedArgument, thisVarType, "this_arg");
- namedArgBlock.Instructions.Add(new StLoc(thisArgVar, call.Arguments[0]));
- call.Arguments[0] = new LdLoc(thisArgVar);
- }
- }
- v.Kind = VariableKind.NamedArgument;
- namedArgBlock.Instructions.Insert(call.IsInstanceCall ? 1 : 0, originalStore);
- return true;
+ return NamedArgumentTransform.DoInline(v, (StLoc)inlinedExpression.Parent, (LdLoc)loadInst,
+ options, context);
}
return false;
}
@@ -400,7 +380,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return FindLoadInNext(expr, v, expressionBeingMoved, out _) == FindResult.Found;
}
- enum FindResult
+ internal enum FindResult
{
///
/// Found a load; inlining is possible.
@@ -427,7 +407,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
/// Finds the position to inline to.
///
/// true = found; false = cannot continue search; null = not found
- static FindResult FindLoadInNext(ILInstruction expr, ILVariable v, ILInstruction expressionBeingMoved, out ILInstruction loadInst)
+ internal static FindResult FindLoadInNext(ILInstruction expr, ILVariable v, ILInstruction expressionBeingMoved, out ILInstruction loadInst)
{
loadInst = null;
if (expr == null)
@@ -449,7 +429,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
// If FindLoadInNext() returns null, we still can't continue searching
// because we can't inline over the remainder of the block.
case BlockKind.CallWithNamedArgs:
- return CanExtendNamedArgument(block, v, expressionBeingMoved, out loadInst);
+ return NamedArgumentTransform.CanExtendNamedArgument(block, v, expressionBeingMoved, out loadInst);
default:
return FindResult.Stop;
}
@@ -472,7 +452,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
FindResult r = FindLoadInNext(child, v, expressionBeingMoved, out loadInst);
if (r != FindResult.Continue) {
if (r == FindResult.Stop && expr is CallInstruction call)
- return CanIntroduceNamedArgument(call, child, v, out loadInst);
+ return NamedArgumentTransform.CanIntroduceNamedArgument(call, child, v, out loadInst);
return r;
}
}
@@ -490,67 +470,6 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return findResult;
}
- private static FindResult CanIntroduceNamedArgument(CallInstruction call, ILInstruction child, ILVariable v, out ILInstruction loadInst)
- {
- loadInst = null;
- Debug.Assert(child.Parent == call);
- if (call.IsInstanceCall && child.ChildIndex == 0)
- return FindResult.Stop; // cannot use named arg to move expressionBeingMoved before this pointer
- if (call.Method.IsOperator || call.Method.IsAccessor)
- return FindResult.Stop; // cannot use named arg for operators or accessors
- if (call.Method is VarArgInstanceMethod)
- return FindResult.Stop; // CallBuilder doesn't support named args when using varargs
- if (call.Method.IsConstructor) {
- IType type = call.Method.DeclaringType;
- 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;
- return FindResult.NamedArgument;
- }
- }
- return FindResult.Stop;
- }
-
- private static FindResult CanExtendNamedArgument(Block block, ILVariable v, ILInstruction expressionBeingMoved, out ILInstruction loadInst)
- {
- Debug.Assert(block.Kind == BlockKind.CallWithNamedArgs);
- var firstArg = ((StLoc)block.Instructions[0]).Value;
- var r = FindLoadInNext(firstArg, v, expressionBeingMoved, out loadInst);
- if (r == FindResult.Found || r == FindResult.NamedArgument) {
- return r; // OK, inline into first instruction of block
- }
- var call = (CallInstruction)block.FinalInstruction;
- if (call.IsInstanceCall) {
- // For instance calls, block.Instructions[0] is the argument
- // for the 'this' pointer. We can only insert at position 1.
- if (r == FindResult.Stop) {
- // error: can't move expressionBeingMoved after block.Instructions[0]
- return FindResult.Stop;
- }
- // Because we always ensure block.Instructions[0] is the 'this' argument,
- // it's possible that the place we actually need to inline into
- // is within block.Instructions[1]:
- if (block.Instructions.Count > 1) {
- r = FindLoadInNext(block.Instructions[1], v, expressionBeingMoved, out loadInst);
- if (r == FindResult.Found || r == FindResult.NamedArgument) {
- return r; // OK, inline into block.Instructions[1]
- }
- }
- }
- foreach (var arg in call.Arguments) {
- if (arg.MatchLdLoc(v)) {
- loadInst = arg;
- return FindResult.NamedArgument;
- }
- }
- return FindResult.Stop;
- }
-
///
/// Determines whether it is safe to move 'expressionBeingMoved' past 'expr'
///
diff --git a/ICSharpCode.Decompiler/IL/Transforms/NamedArgumentTransform.cs b/ICSharpCode.Decompiler/IL/Transforms/NamedArgumentTransform.cs
new file mode 100644
index 000000000..a9627c68b
--- /dev/null
+++ b/ICSharpCode.Decompiler/IL/Transforms/NamedArgumentTransform.cs
@@ -0,0 +1,111 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Text;
+using ICSharpCode.Decompiler.TypeSystem;
+
+namespace ICSharpCode.Decompiler.IL.Transforms
+{
+ using FindResult = ILInlining.FindResult;
+
+ class NamedArgumentTransform : IStatementTransform
+ {
+ public static FindResult CanIntroduceNamedArgument(CallInstruction call, ILInstruction child, ILVariable v, out ILInstruction loadInst)
+ {
+ loadInst = null;
+ Debug.Assert(child.Parent == call);
+ if (call.IsInstanceCall && child.ChildIndex == 0)
+ return FindResult.Stop; // cannot use named arg to move expressionBeingMoved before this pointer
+ if (call.Method.IsOperator || call.Method.IsAccessor)
+ return FindResult.Stop; // cannot use named arg for operators or accessors
+ if (call.Method is VarArgInstanceMethod)
+ return FindResult.Stop; // CallBuilder doesn't support named args when using varargs
+ if (call.Method.IsConstructor) {
+ IType type = call.Method.DeclaringType;
+ 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;
+ return FindResult.NamedArgument;
+ }
+ }
+ return FindResult.Stop;
+ }
+
+ internal static FindResult CanExtendNamedArgument(Block block, ILVariable v, ILInstruction expressionBeingMoved, out ILInstruction loadInst)
+ {
+ Debug.Assert(block.Kind == BlockKind.CallWithNamedArgs);
+ var firstArg = ((StLoc)block.Instructions[0]).Value;
+ var r = ILInlining.FindLoadInNext(firstArg, v, expressionBeingMoved, out loadInst);
+ if (r == FindResult.Found || r == FindResult.NamedArgument) {
+ return r; // OK, inline into first instruction of block
+ }
+ var call = (CallInstruction)block.FinalInstruction;
+ if (call.IsInstanceCall) {
+ // For instance calls, block.Instructions[0] is the argument
+ // for the 'this' pointer. We can only insert at position 1.
+ if (r == FindResult.Stop) {
+ // error: can't move expressionBeingMoved after block.Instructions[0]
+ return FindResult.Stop;
+ }
+ // Because we always ensure block.Instructions[0] is the 'this' argument,
+ // it's possible that the place we actually need to inline into
+ // is within block.Instructions[1]:
+ if (block.Instructions.Count > 1) {
+ r = ILInlining.FindLoadInNext(block.Instructions[1], v, expressionBeingMoved, out loadInst);
+ if (r == FindResult.Found || r == FindResult.NamedArgument) {
+ return r; // OK, inline into block.Instructions[1]
+ }
+ }
+ }
+ foreach (var arg in call.Arguments) {
+ if (arg.MatchLdLoc(v)) {
+ loadInst = arg;
+ return FindResult.NamedArgument;
+ }
+ }
+ return FindResult.Stop;
+ }
+
+ internal static bool DoInline(ILVariable v, StLoc originalStore, LdLoc loadInst, InliningOptions options, ILTransformContext context)
+ {
+ if ((options & InliningOptions.Aggressive) == 0 && originalStore.ILStackWasEmpty)
+ return false;
+ context.Step($"Introduce named argument '{v.Name}'", originalStore);
+ var call = (CallInstruction)loadInst.Parent;
+ if (!(call.Parent is Block namedArgBlock) || namedArgBlock.Kind != BlockKind.CallWithNamedArgs) {
+ // create namedArgBlock:
+ namedArgBlock = new Block(BlockKind.CallWithNamedArgs);
+ call.ReplaceWith(namedArgBlock);
+ namedArgBlock.FinalInstruction = call;
+ if (call.IsInstanceCall) {
+ IType thisVarType = call.Method.DeclaringType;
+ if (CallInstruction.ExpectedTypeForThisPointer(thisVarType) == StackType.Ref) {
+ thisVarType = new ByReferenceType(thisVarType);
+ }
+ var function = call.Ancestors.OfType().First();
+ var thisArgVar = function.RegisterVariable(VariableKind.NamedArgument, thisVarType, "this_arg");
+ namedArgBlock.Instructions.Add(new StLoc(thisArgVar, call.Arguments[0]));
+ call.Arguments[0] = new LdLoc(thisArgVar);
+ }
+ }
+ v.Kind = VariableKind.NamedArgument;
+ namedArgBlock.Instructions.Insert(call.IsInstanceCall ? 1 : 0, originalStore);
+ return true;
+ }
+
+ public void Run(Block block, int pos, StatementTransformContext context)
+ {
+ if (!context.Settings.NamedArguments)
+ return;
+ var options = ILInlining.OptionsForBlock(block);
+ options |= InliningOptions.IntroduceNamedArguments;
+ ILInlining.InlineOneIfPossible(block, pos, options, context: context);
+ }
+ }
+}