Skip to content
Open
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
34 changes: 24 additions & 10 deletions ref/Castle.Core-net8.0.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2422,14 +2422,20 @@ public virtual void MethodsInspected() { }
public virtual void NonProxyableMemberNotification(System.Type type, System.Reflection.MemberInfo memberInfo) { }
public virtual bool ShouldInterceptMethod(System.Type type, System.Reflection.MethodInfo methodInfo) { }
}
public class ByRefLikeReference
public class ByRefLikeReference { }
public static class ByRefLikeReferenceUnsafe
{
[System.CLSCompliant(false)]
public ByRefLikeReference(System.Type type, void* ptr) { }
public static unsafe Castle.DynamicProxy.ByRefLikeReference CreateByRefLikeReferenceUntyped(System.Type type, void* ptr, bool valueIsScoped) { }
[System.CLSCompliant(false)]
public unsafe void* GetPtr(System.Type checkType) { }
public static unsafe Castle.DynamicProxy.ReadOnlySpanReference<T> CreateReadOnlySpanReference<T>(System.Type type, void* ptr, bool valueIsScoped) { }
[System.CLSCompliant(false)]
public unsafe void Invalidate(void* checkPtr) { }
public static unsafe Castle.DynamicProxy.SpanReference<T> CreateSpanReference<T>(System.Type type, void* ptr, bool valueIsScoped) { }
[System.CLSCompliant(false)]
public static unsafe void DisposeReference(Castle.DynamicProxy.ByRefLikeReference reference, void* expectedPtr) { }
[System.CLSCompliant(false)]
public static unsafe void* GetRawPtr(Castle.DynamicProxy.ByRefLikeReference reference, System.Type expectedType) { }
public static bool IsReferenceValueScoped(Castle.DynamicProxy.ByRefLikeReference reference) { }
}
public class CustomAttributeInfo : System.IEquatable<Castle.DynamicProxy.CustomAttributeInfo>
{
Expand Down Expand Up @@ -2701,15 +2707,23 @@ public static bool IsProxyType(System.Type type) { }
}
public class ReadOnlySpanReference<T> : Castle.DynamicProxy.ByRefLikeReference
{
[System.CLSCompliant(false)]
public ReadOnlySpanReference(System.Type type, void* ptr) { }
public System.ReadOnlySpan<>& Value { get; }
public System.ReadOnlySpan<T> GetValue() { }
public void SetValue(Castle.DynamicProxy.ReadOnlySpanReference<T>.ValueGetter valueGetter) { }
public void UseValue(Castle.DynamicProxy.ReadOnlySpanReference<T>.ValueConsumer valueConsumer) { }
public TResult UseValue<TResult>(Castle.DynamicProxy.ReadOnlySpanReference<T>.ValueConsumerWithResult<TResult> valueConsumer) { }
public delegate void ValueConsumer<T>([System.Runtime.CompilerServices.ScopedRef] System.ReadOnlySpan<T> value);
public delegate TResult ValueConsumerWithResult<T, TResult>([System.Runtime.CompilerServices.ScopedRef] System.ReadOnlySpan<T> value);
public delegate System.ReadOnlySpan<T> ValueGetter<T>();
}
public class SpanReference<T> : Castle.DynamicProxy.ByRefLikeReference
{
[System.CLSCompliant(false)]
public SpanReference(System.Type type, void* ptr) { }
public System.Span<>& Value { get; }
public System.Span<T> GetValue() { }
public void SetValue(Castle.DynamicProxy.SpanReference<T>.ValueGetter valueGetter) { }
public void UseValue(Castle.DynamicProxy.SpanReference<T>.ValueConsumer valueConsumer) { }
public TResult UseValue<TResult>(Castle.DynamicProxy.SpanReference<T>.ValueConsumerWithResult<TResult> valueConsumer) { }
public delegate void ValueConsumer<T>([System.Runtime.CompilerServices.ScopedRef] System.Span<T> value);
public delegate TResult ValueConsumerWithResult<T, TResult>([System.Runtime.CompilerServices.ScopedRef] System.Span<T> value);
public delegate System.Span<T> ValueGetter<T>();
}
public class StandardInterceptor : Castle.DynamicProxy.IInterceptor
{
Expand Down
39 changes: 22 additions & 17 deletions ref/Castle.Core-net9.0.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2422,21 +2422,34 @@ public virtual void MethodsInspected() { }
public virtual void NonProxyableMemberNotification(System.Type type, System.Reflection.MemberInfo memberInfo) { }
public virtual bool ShouldInterceptMethod(System.Type type, System.Reflection.MethodInfo methodInfo) { }
}
public class ByRefLikeReference
public class ByRefLikeReference { }
public static class ByRefLikeReferenceUnsafe
{
[System.CLSCompliant(false)]
public ByRefLikeReference(System.Type type, void* ptr) { }
public static unsafe Castle.DynamicProxy.ByRefLikeReference<TByRefLike> CreateByRefLikeReference<TByRefLike>(System.Type type, void* ptr, bool valueIsScoped)
where TByRefLike : struct { }
[System.CLSCompliant(false)]
public unsafe void* GetPtr(System.Type checkType) { }
public static unsafe Castle.DynamicProxy.ByRefLikeReference CreateByRefLikeReferenceUntyped(System.Type type, void* ptr, bool valueIsScoped) { }
[System.CLSCompliant(false)]
public unsafe void Invalidate(void* checkPtr) { }
public static unsafe Castle.DynamicProxy.ReadOnlySpanReference<T> CreateReadOnlySpanReference<T>(System.Type type, void* ptr, bool valueIsScoped) { }
[System.CLSCompliant(false)]
public static unsafe Castle.DynamicProxy.SpanReference<T> CreateSpanReference<T>(System.Type type, void* ptr, bool valueIsScoped) { }
[System.CLSCompliant(false)]
public static unsafe void DisposeReference(Castle.DynamicProxy.ByRefLikeReference reference, void* expectedPtr) { }
[System.CLSCompliant(false)]
public static unsafe void* GetRawPtr(Castle.DynamicProxy.ByRefLikeReference reference, System.Type expectedType) { }
public static bool IsReferenceValueScoped(Castle.DynamicProxy.ByRefLikeReference reference) { }
}
public class ByRefLikeReference<TByRefLike> : Castle.DynamicProxy.ByRefLikeReference
where TByRefLike : struct
{
[System.CLSCompliant(false)]
public ByRefLikeReference(System.Type type, void* ptr) { }
public TByRefLike& Value { get; }
public TByRefLike GetValue() { }
public void SetValue(Castle.DynamicProxy.ByRefLikeReference<TByRefLike>.ValueGetter valueGetter) { }
public void UseValue(Castle.DynamicProxy.ByRefLikeReference<TByRefLike>.ValueConsumer valueConsumer) { }
public TResult UseValue<TResult>(Castle.DynamicProxy.ByRefLikeReference<TByRefLike>.ValueConsumerWithResult<TResult> valueConsumer) { }
public delegate void ValueConsumer<TByRefLike>([System.Runtime.CompilerServices.ScopedRef] TByRefLike value);
public delegate TResult ValueConsumerWithResult<TByRefLike, TResult>([System.Runtime.CompilerServices.ScopedRef] TByRefLike value);
public delegate TByRefLike ValueGetter<TByRefLike>();
}
public class CustomAttributeInfo : System.IEquatable<Castle.DynamicProxy.CustomAttributeInfo>
{
Expand Down Expand Up @@ -2716,16 +2729,8 @@ public static bool IsAccessible(System.Reflection.MethodBase method, [System.Dia
public static bool IsProxy(object? instance) { }
public static bool IsProxyType(System.Type type) { }
}
public class ReadOnlySpanReference<T> : Castle.DynamicProxy.ByRefLikeReference<System.ReadOnlySpan<T>>
{
[System.CLSCompliant(false)]
public ReadOnlySpanReference(System.Type type, void* ptr) { }
}
public class SpanReference<T> : Castle.DynamicProxy.ByRefLikeReference<System.Span<T>>
{
[System.CLSCompliant(false)]
public SpanReference(System.Type type, void* ptr) { }
}
public class ReadOnlySpanReference<T> : Castle.DynamicProxy.ByRefLikeReference<System.ReadOnlySpan<T>> { }
public class SpanReference<T> : Castle.DynamicProxy.ByRefLikeReference<System.Span<T>> { }
public class StandardInterceptor : Castle.DynamicProxy.IInterceptor
{
public StandardInterceptor() { }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
namespace Castle.DynamicProxy.Tests.ByRefLikeSupport
{
using System;
using System.Threading.Tasks;
#if NET9_0_OR_GREATER
using System.Runtime.CompilerServices;
#endif
Expand All @@ -40,61 +41,92 @@
Assert.Throws<ArgumentOutOfRangeException>(() =>
{
bool local = default;
_ = new ByRefLikeReference(typeof(bool), &local);
_ = new ByRefLikeReference(typeof(bool), &local, false);
});
}

[Test]
public unsafe void Ctor_succeeds_if_by_ref_like_type()
{
ReadOnlySpan<char> local = default;
_ = new ByRefLikeReference(typeof(ReadOnlySpan<char>), &local);
_ = new ByRefLikeReference(typeof(ReadOnlySpan<char>), &local, false);
}

[Test]
public unsafe void Invalidate_throws_if_address_mismatch()
[TestCase(true)]
[TestCase(false)]
public unsafe void Ctor_preserves_value_is_scoped_value(bool valueIsScoped)
{
ReadOnlySpan<char> local = default;
var reference = new ByRefLikeReference(typeof(ReadOnlySpan<char>), &local);
Assert.Throws<AccessViolationException>(() =>
var result = new ByRefLikeReference(typeof(ReadOnlySpan<char>), &local, valueIsScoped: valueIsScoped);
Assert.AreEqual(valueIsScoped, result.ValueIsScoped);
}

[Test]
public unsafe void Dispose_throws_if_address_mismatch()
{
ReadOnlySpan<char> local = default;
var reference = new ByRefLikeReference(typeof(ReadOnlySpan<char>), &local, false);
Assert.Throws<InvalidOperationException>(() =>
{
ReadOnlySpan<char> otherLocal = default;
reference.Invalidate(&otherLocal);
reference.Dispose(&otherLocal);
});
}

[Test]
public unsafe void Invalidate_succeeds_if_address_match()
public unsafe void Dispose_succeeds_if_address_match()
{
ReadOnlySpan<char> local = default;
var reference = new ByRefLikeReference(typeof(ReadOnlySpan<char>), &local, false);
reference.Dispose(&local);
}

[Test]
public unsafe void Dispose_throws_when_access_from_other_thread()
{
ReadOnlySpan<char> local = default;
var reference = new ByRefLikeReference(typeof(ReadOnlySpan<char>), &local);
reference.Invalidate(&local);
var reference = new ByRefLikeReference(typeof(ReadOnlySpan<char>), &local, false);
var address = reference.GetPtr(typeof(ReadOnlySpan<char>));
var task = Task.Run(() => reference.Dispose(address));
var msg = Assert.Throws<InvalidOperationException>(() => task.GetAwaiter().GetResult()).Message;

Check warning on line 92 in src/Castle.Core.Tests/DynamicProxy.Tests/ByRefLikeSupport/ByRefLikeReferenceTestCase.cs

View workflow job for this annotation

GitHub Actions / Build and test (ubuntu-latest)

Dereference of a possibly null reference.

Check warning on line 92 in src/Castle.Core.Tests/DynamicProxy.Tests/ByRefLikeSupport/ByRefLikeReferenceTestCase.cs

View workflow job for this annotation

GitHub Actions / Build and test (windows-latest)

Dereference of a possibly null reference.
StringAssert.Contains("thread", msg);
}

[Test]
public unsafe void GetPtr_throws_if_type_mismatch()
{
ReadOnlySpan<char> local = default;
var reference = new ByRefLikeReference(typeof(ReadOnlySpan<char>), &local);
Assert.Throws<AccessViolationException>(() => reference.GetPtr(typeof(bool)));
var reference = new ByRefLikeReference(typeof(ReadOnlySpan<char>), &local, false);
Assert.Throws<ArgumentException>(() => reference.GetPtr(typeof(bool)));
}

[Test]
public unsafe void GetPtr_returns_ctor_address_if_type_match()
{
ReadOnlySpan<char> local = default;
var reference = new ByRefLikeReference(typeof(ReadOnlySpan<char>), &local);
var reference = new ByRefLikeReference(typeof(ReadOnlySpan<char>), &local, false);
var ptr = reference.GetPtr(typeof(ReadOnlySpan<char>));
Assert.True(ptr == &local);
}

[Test]
public unsafe void GetPtr_throws_after_Invalidate()
public unsafe void GetPtr_throws_after_Dispose()
{
ReadOnlySpan<char> local = default;
var reference = new ByRefLikeReference(typeof(ReadOnlySpan<char>), &local);
reference.Invalidate(&local);
Assert.Throws<AccessViolationException>(() => reference.GetPtr(typeof(ReadOnlySpan<char>)));
var reference = new ByRefLikeReference(typeof(ReadOnlySpan<char>), &local, false);
reference.Dispose(&local);
Assert.Throws<ObjectDisposedException>(() => reference.GetPtr(typeof(ReadOnlySpan<char>)));
}

[Test]
public unsafe void GetPtr_throws_when_access_from_other_thread()
{
ReadOnlySpan<char> local = default;
var reference = new ByRefLikeReference(typeof(ReadOnlySpan<char>), &local, false);
var task = Task.Run(() => reference.GetPtr(typeof(ReadOnlySpan<char>)));
var msg = Assert.Throws<InvalidOperationException>(() => task.GetAwaiter().GetResult()).Message;

Check warning on line 128 in src/Castle.Core.Tests/DynamicProxy.Tests/ByRefLikeSupport/ByRefLikeReferenceTestCase.cs

View workflow job for this annotation

GitHub Actions / Build and test (ubuntu-latest)

Dereference of a possibly null reference.

Check warning on line 128 in src/Castle.Core.Tests/DynamicProxy.Tests/ByRefLikeSupport/ByRefLikeReferenceTestCase.cs

View workflow job for this annotation

GitHub Actions / Build and test (windows-latest)

Dereference of a possibly null reference.
StringAssert.Contains("thread", msg);
}

#endregion
Expand All @@ -109,35 +141,71 @@
Assert.Throws<ArgumentOutOfRangeException>(() =>
{
ReadOnlySpan<bool> local = default;
_ = new ReadOnlySpanReference<char>(typeof(ReadOnlySpan<bool>), &local);
_ = new ReadOnlySpanReference<char>(typeof(ReadOnlySpan<bool>), &local, false);
});
}

public unsafe void ReadOnlySpanReference_Value_returns_equal_span()
[Test]
[TestCase(true)]
[TestCase(false)]
public unsafe void ReadOnlySpanReference_ctor_preserves_value_is_scoped_value(bool valueIsScoped)
{
ReadOnlySpan<char> local = "foo".AsSpan();
var reference = new ReadOnlySpanReference<char>(typeof(ReadOnlySpan<char>), &local);
Assert.True(reference.Value == "foo".AsSpan());
ReadOnlySpan<char> local = default;
var result = new ReadOnlySpanReference<char>(typeof(ReadOnlySpan<char>), &local, valueIsScoped: valueIsScoped);
Assert.AreEqual(valueIsScoped, result.ValueIsScoped);
}

#if NET9_0_OR_GREATER
[Test]
public unsafe void ReadOnlySpanReference_Value_returns_same_span()
public unsafe void ReadOnlySpanReference_GetValue_returns_equal_span()
{
ReadOnlySpan<char> local = "foo".AsSpan();
var reference = new ReadOnlySpanReference<char>(typeof(ReadOnlySpan<char>), &local);
Assert.True(Unsafe.AreSame(ref reference.Value, ref local));
var reference = new ReadOnlySpanReference<char>(typeof(ReadOnlySpan<char>), &local, false);
Assert.True(reference.GetValue() == "foo".AsSpan());
}

public unsafe void ReadOnlySpanReference_UseValue_returns_equal_span()
{
ReadOnlySpan<char> local = "foo".AsSpan();
var reference = new ReadOnlySpanReference<char>(typeof(ReadOnlySpan<char>), &local, false);
var returnedValue = reference.UseValue((scoped x) => x.ToString());
Assert.True(returnedValue == "foo");
}
#endif

[Test]
public unsafe void ReadOnlySpanReference_Value_can_update_original()
public unsafe void ReadOnlySpanReference_SetValue_can_update_original()
{
ReadOnlySpan<char> local = "foo".AsSpan();
var reference = new ReadOnlySpanReference<char>(typeof(ReadOnlySpan<char>), &local);
reference.Value = "bar".AsSpan();
var reference = new ReadOnlySpanReference<char>(typeof(ReadOnlySpan<char>), &local, false);
reference.SetValue(() => "bar".AsSpan());
Assert.True(local == "bar".AsSpan());
}

[Test]
public unsafe void ReadOnlySpanReference_GetValue_throws_when_access_from_other_thread()
{
ReadOnlySpan<char> local = "foo".AsSpan();
var reference = new ReadOnlySpanReference<char>(typeof(ReadOnlySpan<char>), &local, false);
var task = Task.Run(() => reference.GetValue().ToString());
var msg = Assert.Throws<InvalidOperationException>(() => task.GetAwaiter().GetResult()).Message;

Check warning on line 188 in src/Castle.Core.Tests/DynamicProxy.Tests/ByRefLikeSupport/ByRefLikeReferenceTestCase.cs

View workflow job for this annotation

GitHub Actions / Build and test (windows-latest)

Dereference of a possibly null reference.
StringAssert.Contains("thread", msg);
}

[Test]
public unsafe void ReadOnlySpanReference_GetValue_throws_when_called_for_scoped()
{
ReadOnlySpan<char> local = "foo".AsSpan();
var reference = new ReadOnlySpanReference<char>(typeof(ReadOnlySpan<char>), &local, valueIsScoped: true);
var msg = Assert.Throws<InvalidOperationException>(() => reference.GetValue()).Message;

Check warning on line 197 in src/Castle.Core.Tests/DynamicProxy.Tests/ByRefLikeSupport/ByRefLikeReferenceTestCase.cs

View workflow job for this annotation

GitHub Actions / Build and test (windows-latest)

Dereference of a possibly null reference.
StringAssert.Contains("scoped", msg);
}

[Test]
public unsafe void ReadOnlySpanReference_UseValue_returns_for_scoped()
{
ReadOnlySpan<char> local = "foo".AsSpan();
var reference = new ReadOnlySpanReference<char>(typeof(ReadOnlySpan<char>), &local, valueIsScoped: true);
var returnedValue = reference.UseValue((scoped x) => x.ToString());
Assert.True(returnedValue == "foo");
}

#endregion

Expand Down
Loading