Add the unlanded remainder of the coverage-audit fixtures

The coverage audit's green tests landed on master as per-topic commits;
this collects what remains from the exploration branch: failing Pretty
cases documenting decompiler gaps (stackalloc initializers, attribute
params, local-function optional/params parameters, async-foreach tuple
element names, for-loop comma lists, char increment operators, string
reference equality, nested await handlers, async-stream cancellation
with await in finally, expression-tree member/list bindings, and
friends) plus small green additions that never landed. Some cases are
red by design; run before harvesting to see which gaps still exist.

Assisted-by: Claude:claude-fable-5:Claude Code
This commit is contained in:
Siegfried Pammer
2026-07-29 07:19:40 +02:00
parent d7bbf17e2e
commit d676b3b010
21 changed files with 309 additions and 0 deletions
@@ -616,6 +616,32 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
return $"val={await t,5:x} end";
}
#endif
public static async Task<int> MultiAwaitInExpression(Task<int> a, Task<int> b, Task<int> c)
{
return await a + await b * await c - await a;
}
#if CS60
public static async Task NestedAwaitHandlers(Task t)
{
try
{
await t;
}
catch (Exception ex)
{
try
{
await Task.Delay(ex.Message.Length);
}
finally
{
await Task.Yield();
}
}
}
#endif
}
public struct AsyncInStruct
@@ -61,5 +61,15 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
}
return sum;
}
public async Task<int> SumNamedTupleElements(IAsyncEnumerable<(int A, string B)> items)
{
int sum = 0;
await foreach (var item in items)
{
sum += item.A + item.B.Length;
}
return sum;
}
}
}
@@ -114,6 +114,36 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
yield return 'a';
yield return AsyncStreamColor.Green;
}
public static async IAsyncEnumerable<int> CancellationAndAwaitInFinally([EnumeratorCancellation] CancellationToken cancellationToken)
{
int handle = await OpenAsync(cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
try
{
yield return handle;
await WorkAsync(cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
}
finally
{
await CloseAsync(handle, cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
}
}
private static async Task<int> OpenAsync(CancellationToken ct)
{
await Task.Yield();
return 1;
}
private static async Task WorkAsync(CancellationToken ct)
{
await Task.Yield();
}
private static async Task CloseAsync(int h, CancellationToken ct)
{
await Task.Yield();
}
}
public interface IAsyncStreamEntry
@@ -128,6 +128,17 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
return UsePointer(ptr);
}
public unsafe string SimpleStackAllocEnum()
{
DayOfWeek* ptr = stackalloc DayOfWeek[3] {
DayOfWeek.Monday,
DayOfWeek.Tuesday,
DayOfWeek.Friday
};
Console.WriteLine(*ptr);
return UsePointer((byte*)ptr);
}
public unsafe string SimpleStackAllocChar()
{
char* ptr = stackalloc char[4] { '1', '2', '3', '4' };
@@ -373,6 +384,18 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
Console.WriteLine((stackalloc byte[3])[1]);
}
public unsafe int PointerStackAllocSingleUse()
{
int* ptr = stackalloc int[4];
return *ptr;
}
public unsafe int PointerStackAllocInitializerSingleUse()
{
int* ptr = stackalloc int[3] { 7, 8, 9 };
return *ptr;
}
public string UseSpan(Span<int> span)
{
throw new NotImplementedException();
@@ -1,6 +1,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
@@ -14,6 +15,21 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
}
public class WithStructEnumerator
{
}
[StructLayout(LayoutKind.Sequential, Size = 1)]
public struct StructEnumerator
{
public int Current => 0;
public bool MoveNext()
{
return false;
}
}
public void Test(NonGeneric c)
{
foreach (object item in c)
@@ -29,6 +45,14 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
Console.WriteLine(item);
}
}
public void Test(WithStructEnumerator c)
{
foreach (int item in c)
{
Console.WriteLine(item);
}
}
#if !NET40
public async void TestAsync(Generic<int> c)
{
@@ -50,6 +74,10 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
throw null;
}
public static CS9_ExtensionGetEnumerator.StructEnumerator GetEnumerator(this CS9_ExtensionGetEnumerator.WithStructEnumerator c)
{
return default(CS9_ExtensionGetEnumerator.StructEnumerator);
}
#if !NET40
public static IAsyncEnumerator<T> GetAsyncEnumerator<T>(this CS9_ExtensionGetEnumerator.Generic<T> c)
{
@@ -130,5 +130,12 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
}
}
}
public int HashCodeAccumulator(int type, string text)
{
int num = 1688038063;
num = num * -1521134295 + type.GetHashCode();
return num * -1521134295 + text.GetHashCode();
}
}
}
@@ -411,6 +411,16 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
return a == 'A';
}
public void Char_Local_Add(char c)
{
c++;
Console.WriteLine(c++);
Console.WriteLine(++c);
c--;
Console.WriteLine(c--);
Console.WriteLine(--c);
}
public void Int32_Local_Add(int i)
{
i++;
@@ -40,6 +40,13 @@ namespace CustomAttributes
{
}
}
[AttributeUsage(AttributeTargets.All)]
public class ParamsArrayAttribute : Attribute
{
public ParamsArrayAttribute(params int[] values)
{
}
}
#if CS110
[AttributeUsage(AttributeTargets.All, AllowMultiple = true)]
public class GenericAttribute<T> : Attribute
@@ -178,5 +185,13 @@ namespace CustomAttributes
{
}
#endif
[ParamsArray(1, 2, 3)]
public static void UseParamsAttributeExpanded()
{
}
[ParamsArray]
public static void UseParamsAttributeEmpty()
{
}
}
}
@@ -2,6 +2,9 @@ using System;
#if CS120
using System.Collections.Generic;
#endif
#if !NET40
using System.Threading.Tasks;
#endif
namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
@@ -207,6 +207,13 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
}
}
internal class TypeWithNestedMembers
{
public SimpleType Nested = new SimpleType();
public List<int> List = new List<int>();
}
internal class SimpleTypeWithMultipleCtors
{
public SimpleTypeWithMultipleCtors()
@@ -955,6 +962,16 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
ToCode(null, (int a) => (short)a);
}
}
public void MemberAndListBindings()
{
ToCode(null, () => new TypeWithNestedMembers {
Nested = {
Field = 2
},
List = { 1, 2 }
});
}
}
internal static class Extensions
@@ -697,6 +697,20 @@ namespace LocalFunctions
}
}
public static int LocalFunctionWithOptionalAndParams()
{
return Local(5) + Local(2, 3, 4);
#if CS80
static int Local(int x = 5, params int[] rest)
#else
int Local(int x = 5, params int[] rest)
#endif
{
return x + rest.Length;
}
}
public void WriteCapturedParameter(int i)
{
ParamWrite();
@@ -1084,5 +1084,15 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
throw new NotImplementedException();
}
}
public static int ForWithCommaLists(int n)
{
int num = 0;
for (int i = 0, j = n; i < j; i++, j--)
{
num += i * j;
}
return num;
}
}
}
@@ -326,5 +326,10 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
return x?.ToString();
#endif
}
private bool TwoChainsInShortCircuitAnd(MyClass a, MyClass b)
{
return a?.Field?.IntVal > 0 && b?.Property?.Text?.Length == 3;
}
}
}
@@ -27,6 +27,8 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
public delegate int D(int p = 10);
public delegate int ParamsDelegate(params int[] xs);
public enum MyEnum
{
A,
@@ -329,6 +331,12 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
d();
d(42);
}
#endif
#if CS130
public static ParamsDelegate LambdaWithParamsArray()
{
return (params int[] xs) => xs.Length;
}
#endif
}
}
@@ -33,6 +33,20 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
public object Obj { get; set; }
}
#if CS80
public struct DeconstructablePoint
{
public int X;
public int Y;
public void Deconstruct(out int x, out int y)
{
x = X;
y = Y;
}
}
#endif
public void SimpleTypePattern(object x)
{
if (x is string value)
@@ -333,6 +347,18 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
}
#if CS80
public void PositionalPattern(object obj)
{
if (obj is DeconstructablePoint(0, var y))
{
Console.WriteLine(y);
}
else
{
Console.WriteLine("no match");
}
}
public void RecursivePattern_Type(object x)
{
if (x is X { Obj: string obj })
@@ -45,6 +45,13 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
public string S = "abc";
}
public record FieldBeforeProperty(int ID, string Text)
{
public int Field;
public int Property { get; set; }
}
public record Interface(int B) : IRecord;
public interface IRecord
@@ -44,6 +44,28 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
span = ScopedSpan(span);
OutSpan(out span);
}
public int ScopedRefLocal(bool b, ref int x)
{
int num = 42;
scoped ref int reference = ref x;
if (b)
{
reference = ref num;
}
return reference;
}
public int ScopedRefStructLocal(bool b)
{
int value = 7;
scoped Span<int> span = CreateWithoutCapture(ref value);
if (b)
{
span = CreateAndCapture(ref value);
}
return span[0];
}
}
internal ref struct RefFields
@@ -354,6 +354,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
M2<RefLocalsAndReturns>(this);
}
public static void ConditionalRefInAssignmentTarget(bool b, int[] x, int[] y)
{
(b ? ref x[0] : ref y[0]) = 5;
}
#if CS120
public ref readonly int M(in int x)
{
@@ -544,6 +544,24 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
}
}
public static string SwitchOverStringWithEmptyCase(string text)
{
Console.WriteLine("SwitchOverStringWithEmptyCase: " + text);
switch (text)
{
case "":
return "empty";
case " ":
return "space";
case null:
return "null";
case "First case":
return "Text1";
default:
return "Default";
}
}
public static string SwitchOverString1(string text)
{
Console.WriteLine("SwitchOverString1: " + text);
@@ -1744,6 +1762,16 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
return "Default";
}
}
public static bool IsPatternOverReadOnlySpanChar(ReadOnlySpan<char> text)
{
return text is "hello";
}
public static bool OrPatternOverReadOnlySpanChar(ReadOnlySpan<char> text)
{
return text is "hello" or "hi";
}
#endif
#if ROSLYN
@@ -200,5 +200,10 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
}
public static int TernaryThrow(bool cond)
{
return cond ? 1 : throw new InvalidOperationException();
}
}
}
@@ -344,5 +344,15 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
return (int)a == 0;
}
public static bool ReferenceEqualityStrings(string a, string b)
{
return (object)a == (object)b;
}
public static bool ReferenceInequalityStrings(string a, string b)
{
return (object)a != (object)b;
}
}
}