Browse Source

Merge acdd0042a6 into 96acef1fef

pull/4133/merge
Michał "DualFroz" Fox 17 hours ago committed by GitHub
parent
commit
5039f250ee
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 6
      ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs
  2. 29
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Issue3965.cs
  3. 19
      ICSharpCode.Decompiler/IL/Transforms/CachedDelegateInitialization.cs

6
ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs

@ -926,6 +926,12 @@ namespace ICSharpCode.Decompiler.Tests @@ -926,6 +926,12 @@ namespace ICSharpCode.Decompiler.Tests
await RunForLibrary(cscOptions: cscOptions);
}
[Test]
public async Task Issue3965([ValueSource(nameof(roslyn4OrNewerOptions))] CompilerOptions cscOptions)
{
await RunForLibrary(cscOptions: cscOptions);
}
[Test]
public async Task AssemblyCustomAttributes([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions)
{

29
ICSharpCode.Decompiler.Tests/TestCases/Pretty/Issue3965.cs

@ -0,0 +1,29 @@ @@ -0,0 +1,29 @@
using System;
namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
internal class Issue3965
{
private static void M(int x)
{
}
private static void Use(Action<int> action)
{
}
public static void DiscardedMethodGroupConversion()
{
#if EXPECTED_OUTPUT
new Action<int>(M);
#else
_ = (Action<int>)M;
#endif
}
public static void UsedMethodGroupConversion()
{
Use(M);
}
}
}

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

@ -37,7 +37,6 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -37,7 +37,6 @@ namespace ICSharpCode.Decompiler.IL.Transforms
{
if (CachedDelegateInitializationWithField(inst))
{
block.Instructions.RemoveAt(i);
context.IndexOfFirstAlreadyTransformedInstruction = block.Instructions.Count;
continue;
}
@ -95,13 +94,25 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -95,13 +94,25 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (!DelegateConstruction.MatchDelegateConstruction(value.UnwrapConv(ConversionKind.Invalid) as NewObj, out _, out _, out _, true))
return false;
var nextInstruction = inst.Parent.Children.ElementAtOrDefault(inst.ChildIndex + 1);
if (nextInstruction == null)
return false;
var usages = nextInstruction.Descendants.Where(i => i.MatchLdsFld(field)).ToArray();
var usages = nextInstruction?.Descendants.Where(i => i.MatchLdsFld(field)).ToArray() ?? [];
if (usages.Length == 0)
{
// A discarded method-group conversion ("_ = (Action)M;") caches the
// delegate without ever reading the cache back. Keep the conversion,
// which still allocates, and drop the caching around it -- but only
// once the rest of the method is known not to read the field either.
if (context.Function.Descendants.Any(i => i != left && i.MatchLdsFld(field)))
return false;
context.Step("CachedDelegateInitializationWithField (unused)", inst);
inst.ReplaceWith(value);
context.EndStep(value);
return true;
}
if (usages.Length != 1)
return false;
context.Step("CachedDelegateInitializationWithField", inst);
usages[0].ReplaceWith(value);
((Block)inst.Parent).Instructions.RemoveAt(inst.ChildIndex);
context.EndStep(value);
return true;
}

Loading…
Cancel
Save