Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
319 changes: 317 additions & 2 deletions ICSharpCode.Decompiler.Tests/TestCases/Pretty/RefFields.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,45 @@

namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
internal struct Buffer
{
private int value;

[UnscopedRef]
public ref int GetRef()
{
return ref value;
}
}

internal ref struct Holder
{
public Span<int> Inner;

public void Set(Span<int> inner)
{
Inner = inner;
}

public readonly void ReadonlyUse(Span<int> inner)
{
_ = inner.Length;
}
}

internal static class HolderExtensions
{
public static void SetExtension(this ref Holder holder, Span<int> inner)
{
holder.Inner = inner;
}

public static void ReadonlyExtension(this in Holder holder, Span<int> inner)
{
_ = inner.Length;
}
}

internal class LifetimeTests
{
private static int staticField;
Expand Down Expand Up @@ -35,15 +74,277 @@ public void OutSpan(out Span<int> span)
span = default(Span<int>);
}

public Span<int> CaptureOut([UnscopedRef] out int value)
{
value = 0;
return new Span<int>(ref value);
}

public Span<int> NoCaptureOut(out int value)
{
value = 0;
return default(Span<int>);
}

public Span<int> Identity(Span<int> span)
{
return span;
}

public void Calls()
{
int value = 0;
Span<int> span = CreateWithoutCapture(ref value);
//span = CreateAndCapture(ref value); -- would need scoped local, not yet implemented
scoped Span<int> span = CreateWithoutCapture(ref value);
span = CreateAndCapture(ref value);
span = ScopedRefSpan(ref span);
span = ScopedSpan(span);
OutSpan(out span);
}

public int ReassignScopedRefToLocal(bool b, ref int x)
{
int num = 42;
scoped ref int reference = ref x;
if (b)
{
reference = ref num;
}
return reference;
}

public int ReassignScopedSpanFromOut(bool b)
{
int value = 0;
scoped Span<int> span = default(Span<int>);
if (b)
{
span = CaptureOut(out value);
}
return span[0] + value;
}

public int ImplicitScopedOutDoesNotCapture()
{
Span<int> span = default(Span<int>);
span = NoCaptureOut(out var value);
Console.WriteLine(span.Length);
return span.Length + value;
}

public int ReassignScopedSpanFromReceiver(bool b)
{
UnscopedRefStruct unscopedRefStruct = default(UnscopedRefStruct);
scoped Span<int> span = default(Span<int>);
if (b)
{
span = unscopedRefStruct.AsSpan();
}
return span[0];
}

public int ReassignScopedSpanFromRefParameter(bool b, ref int value)
{
scoped Span<int> span = default(Span<int>);
if (b)
{
span = CreateAndCapture(ref value);
}
return span[0];
}

public int ReassignScopedSpanFromStackAlloc(bool b)
{
scoped Span<int> span = default(Span<int>);
if (b)
{
span = stackalloc int[1];
}
return span[0];
}

public int ReassignScopedSpanFromScopedValue(bool b, scoped Span<int> value)
{
scoped Span<int> span = default(Span<int>);
if (b)
{
span = value;
}
return span[0];
}

public int ReassignScopedSpanFromNestedCall(bool b)
{
int value = 0;
scoped Span<int> span = default(Span<int>);
if (b)
{
span = Identity(CreateAndCapture(ref value));
}
return span[0];
}

public int ReassignScopedSpanFromLocalCopy(bool b)
{
Span<int> span = stackalloc int[1];
scoped Span<int> span2 = default(Span<int>);
if (b)
{
span2 = span;
}
return span2[0];
}

public int ReassignScopedSpanFromScopedRefValue(bool b)
{
Span<int> span = stackalloc int[1];
scoped Span<int> span2 = default(Span<int>);
if (b)
{
span2 = ScopedRefSpan(ref span);
}
return span2[0];
}

public int NarrowInitializerDoesNotNeedScoped(bool b)
{
int num = 1;
int num2 = 2;
ref int reference = ref num;
if (b)
{
reference = ref num2;
}
return reference;
}

public int NarrowThenWideDoesNotNeedScoped(bool b, ref int value)
{
int num = 1;
ref int reference = ref num;
if (b)
{
reference = ref value;
}
return reference;
}

public int ClassParameterReceiverDoesNotNarrow(SpanProvider provider, bool b)
{
Span<int> span = default(Span<int>);
if (b)
{
span = provider.GetBuffer();
}
return span.Length;
}

public int ClassLocalReceiverDoesNotNarrow(bool b)
{
SpanProvider spanProvider = new SpanProvider();
Span<int> span = default(Span<int>);
if (b)
{
span = spanProvider.GetBuffer();
}
return span.Length;
}

public ref int PlainStructReceiverDoesNotForceScoped(bool b, ref Buffer buffer, ref int other)
{
ref int result = ref buffer.GetRef();
if (b)
{
result = ref other;
}
return ref result;
}

public int FieldStoreRequiresScoped()
{
scoped Holder holder = default(Holder);
Span<int> inner = stackalloc int[4];
holder.Inner = inner;
return holder.Inner.Length;
}

public int ReceiverCallRequiresScoped()
{
scoped Holder holder = default(Holder);
Span<int> inner = stackalloc int[4];
holder.Set(inner);
return holder.Inner.Length;
}

public int ExtensionReceiverCallRequiresScoped()
{
scoped Holder holder = default(Holder);
Span<int> inner = stackalloc int[4];
holder.SetExtension(inner);
return holder.Inner.Length;
}

public Holder ReadonlyReceiverDoesNotRequireScoped(bool b)
{
Holder result = default(Holder);
if (b)
{
Span<int> inner = stackalloc int[4];
result.ReadonlyUse(inner);
}
return result;
}

public Holder ReadonlyExtensionReceiverDoesNotRequireScoped(bool b)
{
Holder holder = default(Holder);
if (b)
{
Span<int> inner = stackalloc int[4];
holder.ReadonlyExtension(inner);
}
return holder;
}

public ReadOnlyHolder ReadonlyRefStructReceiverDoesNotRequireScoped(bool b, Span<int> wide)
{
ReadOnlyHolder result = new ReadOnlyHolder(wide);
if (b)
{
Span<int> other = stackalloc int[1];
result.Compare(other);
}
return result;
}

public int TryInitThenReassign(bool condition, Span<int> wide)
{
scoped Span<int> span;
try
{
span = stackalloc int[4];
}
finally
{
Console.WriteLine("cleanup");
}
if (condition)
{
span = wide;
}
return span[0];
}

}

internal readonly ref struct ReadOnlyHolder(Span<int> inner)
{
private readonly Span<int> inner = inner;

public void Compare(Span<int> other)
{
_ = inner.Length;
_ = other.Length;
}
}

internal ref struct RefFields
Expand Down Expand Up @@ -86,6 +387,14 @@ public RefFields(ref int v)
}
}

internal sealed class SpanProvider
{
public Span<int> GetBuffer()
{
return default(Span<int>);
}
}

internal ref struct UnscopedRefStruct
{
private int val;
Expand All @@ -98,5 +407,11 @@ public ref int ByRefAccess()
{
return ref val;
}

[UnscopedRef]
public Span<int> AsSpan()
{
return new Span<int>(ref val);
}
}
}
Loading
Loading