Skip to content

Commit

Permalink
Introducing some nullable ref type support on public APIs (#6757)
Browse files Browse the repository at this point in the history
* Started marking a few types as non-nullable

* Replace guard with more modern one

* A few more nullables

* More nullables

* Adjust guard method

* Approval test to show public types without nullable annotations

---------

Co-authored-by: David Boike <david.boike@gmail.com>
  • Loading branch information
danielmarbach and DavidBoike committed Jun 12, 2023
1 parent b8212c1 commit 11c8799
Show file tree
Hide file tree
Showing 195 changed files with 1,130 additions and 695 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public AcceptanceTestingTransport(bool enableNativeDelayedDelivery = true, bool

public override async Task<TransportInfrastructure> Initialize(HostSettings hostSettings, ReceiveSettings[] receivers, string[] sendingAddresses, CancellationToken cancellationToken = default)
{
Guard.AgainstNull(nameof(hostSettings), hostSettings);
Guard.ThrowIfNull(hostSettings);

var infrastructure = new AcceptanceTestingTransportInfrastructure(hostSettings, this, receivers);
infrastructure.ConfigureDispatcher();
Expand Down Expand Up @@ -72,7 +72,7 @@ public string StorageLocation
get => storageLocation;
set
{
Guard.AgainstNull(nameof(StorageLocation), value);
Guard.ThrowIfNull(value);
PathChecker.ThrowForBadPath(value, nameof(StorageLocation));
storageLocation = value;
}
Expand Down
10 changes: 5 additions & 5 deletions src/NServiceBus.AcceptanceTesting/Support/RunSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public class RunSettings : IEnumerable<KeyValuePair<string, object>>
}
set
{
Guard.AgainstNull(nameof(value), value);
Guard.ThrowIfNull(value);
Set("TestExecutionTimeout", value);
}
}
Expand Down Expand Up @@ -49,7 +49,7 @@ public T Get<T>()
/// <returns>The type instance.</returns>
public T Get<T>(string key)
{
Guard.AgainstNullAndEmpty(nameof(key), key);
Guard.ThrowIfNullOrEmpty(key);

if (!TryGet(key, out T result))
{
Expand Down Expand Up @@ -112,7 +112,7 @@ public void Remove<T>()
/// <param name="key">The key of the value being removed.</param>
public void Remove(string key)
{
Guard.AgainstNullAndEmpty(nameof(key), key);
Guard.ThrowIfNullOrEmpty(key);
stash.TryRemove(key, out _);
}

Expand All @@ -121,7 +121,7 @@ public void Remove(string key)
/// </summary>
public void Set<T>(string key, T t)
{
Guard.AgainstNullAndEmpty(nameof(key), key);
Guard.ThrowIfNullOrEmpty(key);
stash[key] = t;
}

Expand All @@ -134,7 +134,7 @@ public void Set<T>(string key, T t)
/// <returns><code>true</code> if found, otherwise <code>false</code>.</returns>
public bool TryGet<T>(string key, out T result)
{
Guard.AgainstNullAndEmpty(nameof(key), key);
Guard.ThrowIfNullOrEmpty(key);
if (stash.TryGetValue(key, out var value))
{
result = (T)value;
Expand Down
87 changes: 87 additions & 0 deletions src/NServiceBus.Core.Tests/API/NullableAnnotations.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#if NET6_0_OR_GREATER
namespace NServiceBus.Core.Tests.API
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using NServiceBus.Core.Tests.API.Infra;
using NUnit.Framework;
using Particular.Approvals;



[TestFixture]
public class NullableAnnotations
{
// Only available with net6.0+, implementation for net472 not worth it
NullabilityInfoContext nullContext = new NullabilityInfoContext();

[Test]
public void ApproveNullableTypes()
{
var b = new StringBuilder()
.AppendLine("The following types do not have annotations for nullable reference types.")
.AppendLine("Changes that make this list longer should not be approved.")
.AppendLine("-----");

var context = new NullabilityInfoContext();

foreach (var type in NServiceBusAssembly.Types.Where(t => t.IsPublic).OrderBy(t => t.FullName))
{
if (HasNonAnnotatedMember(type))
{
b.AppendLine(type.FullName);
}
}

Console.WriteLine(b.ToString());
Approver.Verify(b.ToString());

}

bool HasNonAnnotatedMember(Type type)
{
var allInfo = AllMemberNullabilityInfoFor(type);
var noNullInfoFor = allInfo.Where(info => info.WriteState is NullabilityState.Unknown || info.ReadState == NullabilityState.Unknown);
return noNullInfoFor.Any();
}

IEnumerable<NullabilityInfo> AllMemberNullabilityInfoFor(Type type)
{
foreach (var member in type.GetMembers())
{
if (member is PropertyInfo prop)
{
yield return nullContext.Create(prop);
}
else if (member is FieldInfo field)
{
yield return nullContext.Create(field);
}
else if (member is EventInfo evt)
{
yield return nullContext.Create(evt);
}
else if (member is MethodBase method)
{
var parameters = method.GetParameters();
foreach (var parameter in parameters)
{
yield return nullContext.Create(parameter);
}
}
else if (member.MemberType == MemberTypes.NestedType)
{
continue;
}
else
{
throw new Exception($"Unhandled MemberType: {member.MemberType}");
}
}
}
}
}
#endif
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ namespace NServiceBus
public class AssemblyScannerConfiguration
{
public AssemblyScannerConfiguration() { }
public string AdditionalAssemblyScanningPath { get; set; }
public string? AdditionalAssemblyScanningPath { get; set; }
public bool ScanAppDomainAssemblies { get; set; }
public bool ScanAssembliesInNestedDirectories { get; set; }
public bool ScanFileSystemAssemblies { get; set; }
Expand All @@ -29,7 +29,7 @@ namespace NServiceBus
public static class AuditConfigReader
{
public static bool TryGetAuditMessageExpiration(this NServiceBus.Settings.IReadOnlySettings settings, out System.TimeSpan auditMessageExpiration) { }
public static bool TryGetAuditQueueAddress(this NServiceBus.Settings.IReadOnlySettings settings, out string address) { }
public static bool TryGetAuditQueueAddress(this NServiceBus.Settings.IReadOnlySettings settings, [System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out string? address) { }
}
public static class AuditContextExtensions
{
Expand Down Expand Up @@ -1029,7 +1029,7 @@ namespace NServiceBus
public NServiceBus.IContainSagaData Entity { get; set; }
protected abstract void ConfigureHowToFindSaga(NServiceBus.IConfigureHowToFindSagaWithMessage sagaMessageFindingConfiguration);
protected void MarkAsComplete() { }
protected System.Threading.Tasks.Task ReplyToOriginator(NServiceBus.IMessageHandlerContext context, object message, System.Collections.Generic.IReadOnlyDictionary<string, string> outgoingHeaders = null) { }
protected System.Threading.Tasks.Task ReplyToOriginator(NServiceBus.IMessageHandlerContext context, object message, System.Collections.Generic.IReadOnlyDictionary<string, string>? outgoingHeaders = null) { }
protected System.Threading.Tasks.Task RequestTimeout<TTimeoutMessageType>(NServiceBus.IMessageHandlerContext context, System.DateTimeOffset at)
where TTimeoutMessageType : new() { }
protected System.Threading.Tasks.Task RequestTimeout<TTimeoutMessageType>(NServiceBus.IMessageHandlerContext context, System.TimeSpan within)
Expand Down Expand Up @@ -1839,22 +1839,22 @@ namespace NServiceBus.MessageMutator
}
public class MutateOutgoingMessageContext : NServiceBus.ICancellableContext
{
public MutateOutgoingMessageContext(object outgoingMessage, System.Collections.Generic.Dictionary<string, string> outgoingHeaders, object incomingMessage, System.Collections.Generic.IReadOnlyDictionary<string, string> incomingHeaders, System.Threading.CancellationToken cancellationToken = default) { }
public MutateOutgoingMessageContext(object outgoingMessage, System.Collections.Generic.Dictionary<string, string> outgoingHeaders, object? incomingMessage, System.Collections.Generic.IReadOnlyDictionary<string, string>? incomingHeaders, System.Threading.CancellationToken cancellationToken = default) { }
public System.Threading.CancellationToken CancellationToken { get; }
public System.Collections.Generic.Dictionary<string, string> OutgoingHeaders { get; }
public object OutgoingMessage { get; set; }
public bool TryGetIncomingHeaders(out System.Collections.Generic.IReadOnlyDictionary<string, string> incomingHeaders) { }
public bool TryGetIncomingMessage(out object incomingMessage) { }
public bool TryGetIncomingHeaders([System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out System.Collections.Generic.IReadOnlyDictionary<string, string>? incomingHeaders) { }
public bool TryGetIncomingMessage([System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out object? incomingMessage) { }
}
public class MutateOutgoingTransportMessageContext : NServiceBus.ICancellableContext
{
public MutateOutgoingTransportMessageContext(System.ReadOnlyMemory<byte> outgoingBody, object outgoingMessage, System.Collections.Generic.Dictionary<string, string> outgoingHeaders, object incomingMessage, System.Collections.Generic.IReadOnlyDictionary<string, string> incomingHeaders, System.Threading.CancellationToken cancellationToken = default) { }
public MutateOutgoingTransportMessageContext(System.ReadOnlyMemory<byte> outgoingBody, object outgoingMessage, System.Collections.Generic.Dictionary<string, string> outgoingHeaders, object? incomingMessage, System.Collections.Generic.IReadOnlyDictionary<string, string>? incomingHeaders, System.Threading.CancellationToken cancellationToken = default) { }
public System.Threading.CancellationToken CancellationToken { get; }
public System.ReadOnlyMemory<byte> OutgoingBody { get; set; }
public System.Collections.Generic.Dictionary<string, string> OutgoingHeaders { get; }
public object OutgoingMessage { get; }
public bool TryGetIncomingHeaders(out System.Collections.Generic.IReadOnlyDictionary<string, string> incomingHeaders) { }
public bool TryGetIncomingMessage(out object incomingMessage) { }
public bool TryGetIncomingHeaders([System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out System.Collections.Generic.IReadOnlyDictionary<string, string>? incomingHeaders) { }
public bool TryGetIncomingMessage([System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out object? incomingMessage) { }
}
public static class MutatorRegistrationExtensions
{
Expand Down Expand Up @@ -2427,7 +2427,7 @@ namespace NServiceBus.Sagas
public interface ISagaFinder<TSagaData, TMessage> : NServiceBus.Sagas.IFinder
where TSagaData : NServiceBus.IContainSagaData
{
System.Threading.Tasks.Task<TSagaData> FindBy(TMessage message, NServiceBus.Persistence.ISynchronizedStorageSession storageSession, NServiceBus.Extensibility.IReadOnlyContextBag context, System.Threading.CancellationToken cancellationToken = default);
System.Threading.Tasks.Task<TSagaData?> FindBy(TMessage message, NServiceBus.Persistence.ISynchronizedStorageSession storageSession, NServiceBus.Extensibility.IReadOnlyContextBag context, System.Threading.CancellationToken cancellationToken = default);
}
public interface ISagaIdGenerator
{
Expand Down

0 comments on commit 11c8799

Please sign in to comment.