diff --git a/src/BenchmarkDotNet/Characteristics/Characteristic.cs b/src/BenchmarkDotNet/Characteristics/Characteristic.cs index d6e5815b4e..30c90a502f 100644 --- a/src/BenchmarkDotNet/Characteristics/Characteristic.cs +++ b/src/BenchmarkDotNet/Characteristics/Characteristic.cs @@ -2,6 +2,8 @@ using System.Diagnostics.CodeAnalysis; using static BenchmarkDotNet.Characteristics.CharacteristicHelper; +#nullable enable + namespace BenchmarkDotNet.Characteristics { public abstract class Characteristic @@ -24,7 +26,7 @@ public abstract class Characteristic null, fallbackValue, false); - public static Characteristic Create(string memberName, Func resolver, T fallbackValue, bool ignoreOnApply) + public static Characteristic Create(string memberName, Func resolver, T fallbackValue, bool ignoreOnApply) where TOwner : CharacteristicObject => new Characteristic( memberName, @@ -52,7 +54,7 @@ protected Characteristic( string id, [DynamicallyAccessedMembers(CharacteristicObject.CharacteristicMemberTypes)] Type characteristicType, Type declaringType, - object fallbackValue, + object? fallbackValue, bool ignoreOnApply, bool dontShowInSummary = false) { @@ -84,7 +86,7 @@ protected Characteristic( public Type DeclaringType { get; } - private object FallbackValue { get; } + private object? FallbackValue { get; } public object? this[CharacteristicObject obj] { @@ -94,7 +96,7 @@ public object? this[CharacteristicObject obj] public bool HasChildCharacteristics => IsCharacteristicObjectSubclass(CharacteristicType); - internal virtual object ResolveValueCore(CharacteristicObject obj, object currentValue) => + internal virtual object? ResolveValueCore(CharacteristicObject obj, object currentValue) => ReferenceEquals(currentValue, EmptyValue) ? FallbackValue : currentValue; public override string ToString() => Id; diff --git a/src/BenchmarkDotNet/Characteristics/CharacteristicHelper.cs b/src/BenchmarkDotNet/Characteristics/CharacteristicHelper.cs index 176a72874f..d5830dd397 100644 --- a/src/BenchmarkDotNet/Characteristics/CharacteristicHelper.cs +++ b/src/BenchmarkDotNet/Characteristics/CharacteristicHelper.cs @@ -6,6 +6,8 @@ using System.Reflection; using JetBrains.Annotations; +#nullable enable + namespace BenchmarkDotNet.Characteristics { public static class CharacteristicHelper @@ -17,7 +19,7 @@ internal static bool IsCharacteristicObjectSubclass(Type type) => private static bool IsCharacteristicSubclass(Type type) => type.GetTypeInfo().IsSubclassOf(typeof(Characteristic)); - private static Characteristic AssertHasValue(MemberInfo member, Characteristic value) + private static Characteristic AssertHasValue(MemberInfo member, Characteristic? value) { if (member?.DeclaringType == null) throw new NullReferenceException($"{nameof(member.DeclaringType)}"); @@ -54,12 +56,12 @@ private static IReadOnlyList GetThisTypeCharacteristicsCore( var fieldValues = characteristicObjectType.GetTypeInfo() .GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy | BindingFlags.Static) .Where(f => IsCharacteristicSubclass(f.FieldType)) - .Select(f => AssertHasValue(f, (Characteristic)f.GetValue(null))); + .Select(f => AssertHasValue(f, (Characteristic?)f.GetValue(null))); var propertyValues = characteristicObjectType.GetTypeInfo() .GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy | BindingFlags.Static) .Where(p => p.GetMethod != null && IsCharacteristicSubclass(p.PropertyType)) - .Select(p => AssertHasValue(p, (Characteristic)p.GetValue(null))); + .Select(p => AssertHasValue(p, (Characteristic?)p.GetValue(null))); // DONTTOUCH: DO NOT change the order of characteristic as it may break logic of some operations. return fieldValues diff --git a/src/BenchmarkDotNet/Characteristics/CharacteristicObject.cs b/src/BenchmarkDotNet/Characteristics/CharacteristicObject.cs index 6cb4a983c3..d4254178ec 100644 --- a/src/BenchmarkDotNet/Characteristics/CharacteristicObject.cs +++ b/src/BenchmarkDotNet/Characteristics/CharacteristicObject.cs @@ -5,6 +5,8 @@ using System.Reflection; using JetBrains.Annotations; +#nullable enable + namespace BenchmarkDotNet.Characteristics { // TODO: better naming. @@ -17,15 +19,15 @@ public abstract class CharacteristicObject DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties | DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields; - protected static string ResolveId(CharacteristicObject obj, string actual) + protected static string ResolveId(CharacteristicObject obj, string? actual) { if (!string.IsNullOrEmpty(actual) && actual != IdCharacteristic.FallbackValue) - return actual; + return actual!; string result = CharacteristicSetPresenter.Display.ToPresentation(obj); if (result.Length == 0) - result = IdCharacteristic.FallbackValue; + result = IdCharacteristic.FallbackValue!; return result; } @@ -44,7 +46,7 @@ protected CharacteristicObject() sharedValues = new Dictionary(); } - protected CharacteristicObject(string? id) : this() + protected CharacteristicObject(string id) : this() { if (!string.IsNullOrEmpty(id)) { @@ -79,7 +81,7 @@ private void AssertIsNonFrozenRoot() AssertIsRoot(); } - private static void AssertIsAssignable(Characteristic characteristic, object value) + private static void AssertIsAssignable(Characteristic characteristic, object? value) { if (ReferenceEquals(value, Characteristic.EmptyValue) || ReferenceEquals(value, null)) { @@ -140,12 +142,12 @@ public bool HasValue(Characteristic characteristic) return false; } - internal T GetValue<[DynamicallyAccessedMembers(CharacteristicMemberTypes)] T>(Characteristic characteristic) + internal T? GetValue<[DynamicallyAccessedMembers(CharacteristicMemberTypes)] T>(Characteristic characteristic) { - return (T)GetValue((Characteristic)characteristic); + return (T?)GetValue((Characteristic)characteristic); } - internal object GetValue(Characteristic characteristic) + internal object? GetValue(Characteristic characteristic) { if (!sharedValues.TryGetValue(characteristic, out var result)) result = Characteristic.EmptyValue; @@ -153,40 +155,40 @@ internal object GetValue(Characteristic characteristic) return ResolveCore(characteristic, result); } - private object ResolveCore(Characteristic characteristic, object result) + private object? ResolveCore(Characteristic characteristic, object result) { return characteristic.ResolveValueCore(this, result); } #endregion #region Resolve - public T ResolveValue<[DynamicallyAccessedMembers(CharacteristicMemberTypes)] T>(Characteristic characteristic, IResolver resolver) + public T? ResolveValue<[DynamicallyAccessedMembers(CharacteristicMemberTypes)] T>(Characteristic characteristic, IResolver resolver) { return resolver.Resolve(this, characteristic); } - public T ResolveValue<[DynamicallyAccessedMembers(CharacteristicMemberTypes)] T>(Characteristic characteristic, IResolver resolver, T defaultValue) + public T? ResolveValue<[DynamicallyAccessedMembers(CharacteristicMemberTypes)] T>(Characteristic characteristic, IResolver resolver, T defaultValue) { return resolver.Resolve(this, characteristic, defaultValue); } - public object ResolveValue(Characteristic characteristic, IResolver resolver) + public object? ResolveValue(Characteristic characteristic, IResolver resolver) { return resolver.Resolve(this, characteristic); } - public object ResolveValue(Characteristic characteristic, IResolver resolver, object defaultValue) + public object? ResolveValue(Characteristic characteristic, IResolver resolver, object defaultValue) { return resolver.Resolve(this, characteristic, defaultValue); } - public T ResolveValue<[DynamicallyAccessedMembers(CharacteristicObject.CharacteristicMemberTypes)] T>(Characteristic characteristic, T defaultValue) + public T? ResolveValue<[DynamicallyAccessedMembers(CharacteristicObject.CharacteristicMemberTypes)] T>(Characteristic characteristic, T defaultValue) { - return HasValue(characteristic) ? GetValue(characteristic) : (T)characteristic.ResolveValueCore(this, defaultValue); + return HasValue(characteristic) ? GetValue(characteristic) : (T?)characteristic.ResolveValueCore(this, defaultValue!); } [PublicAPI] - public object ResolveValue(Characteristic characteristic, object defaultValue) + public object? ResolveValue(Characteristic characteristic, object defaultValue) { return HasValue(characteristic) ? GetValue(characteristic) : characteristic.ResolveValueCore(this, defaultValue); } @@ -203,7 +205,7 @@ public object ResolveValue(Characteristic characteristic, object defaultValue) SetValue((Characteristic)characteristic, value); } - internal void SetValue(Characteristic characteristic, object value) + internal void SetValue(Characteristic characteristic, object? value) { AssertNotFrozen(); @@ -211,8 +213,8 @@ internal void SetValue(Characteristic characteristic, object value) { AssertIsAssignable(characteristic, value); - var oldObjectValue = (CharacteristicObject)GetValue(characteristic); - var newObjectValue = (CharacteristicObject)ResolveCore(characteristic, value); + var oldObjectValue = (CharacteristicObject?)GetValue(characteristic); + var newObjectValue = (CharacteristicObject?)ResolveCore(characteristic, value!); if (!ReferenceEquals(oldObjectValue, newObjectValue)) { @@ -226,7 +228,7 @@ internal void SetValue(Characteristic characteristic, object value) } } - private void SetValueCore(Characteristic characteristic, object value) + private void SetValueCore(Characteristic characteristic, object? value) { AssertIsAssignable(characteristic, value); @@ -243,7 +245,7 @@ private void SetValueCore(Characteristic characteristic, object value) $"The current node {this} has value for {characteristic} already.", nameof(characteristic)); - var characteristicObject = (CharacteristicObject)ResolveCore(characteristic, value); + var characteristicObject = (CharacteristicObject)ResolveCore(characteristic, value!)!; characteristicObject.SetOwnerCore(OwnerOrSelf); sharedValues[characteristic] = characteristicObject; @@ -321,7 +323,7 @@ private void SetValueOnAttach(Characteristic characteristic, object value) if (characteristic.HasChildCharacteristics) { // DONTTOUCH: workaround on case there were no parent characteristic. - var characteristicObject = (CharacteristicObject)GetValue(characteristic); + var characteristicObject = (CharacteristicObject?)GetValue(characteristic); characteristicObject?.DetachFromOwner(characteristic); } @@ -358,13 +360,13 @@ private CharacteristicObject ApplyCore( { if (!HasValue(characteristic)) { - var characteristicObject = (CharacteristicObject)ResolveCore(characteristic, value); + var characteristicObject = (CharacteristicObject?)ResolveCore(characteristic, value); if (characteristicObject != null) { value = Activator.CreateInstance(characteristicObject.GetType()); } - SetValueCore(characteristic, value); + SetValueCore(characteristic, value!); } } else @@ -399,20 +401,20 @@ protected CharacteristicObject UnfreezeCopyCore() { AssertIsRoot(); - var newRoot = (CharacteristicObject)Activator.CreateInstance(GetType()); + var newRoot = (CharacteristicObject)Activator.CreateInstance(GetType())!; newRoot.ApplyCore(this); // Preserve the IdCharacteristic of the original object if (this.HasValue(IdCharacteristic)) { - newRoot.SetValue(IdCharacteristic, this.GetValue(IdCharacteristic)); + newRoot.SetValue(IdCharacteristic, this.GetValue(IdCharacteristic)!); } return newRoot; } #endregion - public string Id => IdCharacteristic[this]; + public string Id => IdCharacteristic[this]!; public override string ToString() => Id; } diff --git a/src/BenchmarkDotNet/Characteristics/CharacteristicObject`1.cs b/src/BenchmarkDotNet/Characteristics/CharacteristicObject`1.cs index e69167dc7b..a5959e1b62 100644 --- a/src/BenchmarkDotNet/Characteristics/CharacteristicObject`1.cs +++ b/src/BenchmarkDotNet/Characteristics/CharacteristicObject`1.cs @@ -8,7 +8,7 @@ public abstract class CharacteristicObject : CharacteristicObject { protected CharacteristicObject() { } - protected CharacteristicObject(string? id) : base(id) { } + protected CharacteristicObject(string id) : base(id) { } public new T Apply(CharacteristicObject other) => (T)ApplyCore(other); diff --git a/src/BenchmarkDotNet/Characteristics/CharacteristicPresenter.cs b/src/BenchmarkDotNet/Characteristics/CharacteristicPresenter.cs index 4e90742b73..b013ac6597 100644 --- a/src/BenchmarkDotNet/Characteristics/CharacteristicPresenter.cs +++ b/src/BenchmarkDotNet/Characteristics/CharacteristicPresenter.cs @@ -5,6 +5,8 @@ using BenchmarkDotNet.Helpers; using BenchmarkDotNet.Jobs; +#nullable enable + namespace BenchmarkDotNet.Characteristics { public abstract class CharacteristicPresenter @@ -16,7 +18,7 @@ public abstract class CharacteristicPresenter public abstract string ToPresentation(CharacteristicObject obj, Characteristic characteristic); - public abstract string ToPresentation(object characteristicValue, Characteristic characteristic); + public abstract string ToPresentation(object? characteristicValue, Characteristic characteristic); private class DefaultCharacteristicPresenter : CharacteristicPresenter { @@ -26,11 +28,11 @@ public override string ToPresentation(CharacteristicObject obj, Characteristic c return job.ResolvedId; return obj.HasValue(characteristic) - ? ToPresentation(characteristic[obj], characteristic) + ? ToPresentation(characteristic[obj]!, characteristic) : "Default"; } - public override string ToPresentation(object value, Characteristic characteristic) + public override string ToPresentation(object? value, Characteristic characteristic) { if (!(value is string) && value is IEnumerable collection) return ToPresentation(collection); @@ -64,7 +66,7 @@ private static string ToPresentation(IEnumerable collection) return buffer.ToString(); } - private static string ToPresentation(object value) + private static string ToPresentation(object? value) => (value as IFormattable)?.ToString(null, DefaultCultureInfo.Instance) ?? value?.ToString() ?? ""; @@ -77,11 +79,11 @@ private class SourceCodeCharacteristicPresenter : CharacteristicPresenter public override string ToPresentation(CharacteristicObject obj, Characteristic characteristic) => ToPresentation(characteristic[obj], characteristic); - public override string ToPresentation(object characteristicValue, Characteristic characteristic) + public override string ToPresentation(object? characteristicValue, Characteristic characteristic) { // TODO: DO NOT hardcode Characteristic suffix string id = characteristic.Id; - string type = characteristic.DeclaringType.FullName; + string type = characteristic.DeclaringType.FullName!; string value = SourceCodeHelper.ToSourceCode(characteristicValue); return $"{type}.{id}Characteristic[job] = {value}"; } @@ -94,7 +96,7 @@ public override string ToPresentation(CharacteristicObject obj, Characteristic c ? ToPresentation(characteristic[obj], characteristic) : "Default"; - public override string ToPresentation(object characteristicValue, Characteristic characteristic) + public override string ToPresentation(object? characteristicValue, Characteristic characteristic) => FolderNameHelper.ToFolderName(characteristicValue); } } diff --git a/src/BenchmarkDotNet/Characteristics/Characteristic`1.cs b/src/BenchmarkDotNet/Characteristics/Characteristic`1.cs index a5bc131817..d28bf643c8 100644 --- a/src/BenchmarkDotNet/Characteristics/Characteristic`1.cs +++ b/src/BenchmarkDotNet/Characteristics/Characteristic`1.cs @@ -1,6 +1,8 @@ using System; using System.Diagnostics.CodeAnalysis; +#nullable enable + namespace BenchmarkDotNet.Characteristics { public class Characteristic<[DynamicallyAccessedMembers(CharacteristicObject.CharacteristicMemberTypes)] T> : Characteristic @@ -8,8 +10,8 @@ public class Characteristic<[DynamicallyAccessedMembers(CharacteristicObject.Cha internal Characteristic( string id, Type declaringType, - Func? resolver, - T fallbackValue, + Func? resolver, + T? fallbackValue, bool ignoreOnApply, bool dontShowInSummary = false) : base(id, typeof(T), declaringType, fallbackValue, ignoreOnApply, dontShowInSummary) @@ -18,22 +20,22 @@ internal Characteristic( FallbackValue = fallbackValue; } - private Func? Resolver { get; } + private Func? Resolver { get; } - public T FallbackValue { get; } + public T? FallbackValue { get; } - public new T this[CharacteristicObject obj] + public new T? this[CharacteristicObject obj] { get { return obj.GetValue(this); } set { obj.SetValue(this, value); } } - internal override object ResolveValueCore(CharacteristicObject obj, object currentValue) + internal override object? ResolveValueCore(CharacteristicObject obj, object currentValue) { if (Resolver == null) - return (T)base.ResolveValueCore(obj, currentValue); + return (T?)base.ResolveValueCore(obj, currentValue); - return Resolver(obj, (T)base.ResolveValueCore(obj, currentValue)); + return Resolver(obj, (T?)base.ResolveValueCore(obj, currentValue)); } } } \ No newline at end of file diff --git a/src/BenchmarkDotNet/Characteristics/CompositeResolver.cs b/src/BenchmarkDotNet/Characteristics/CompositeResolver.cs index 7eda67c19f..d61602edb7 100644 --- a/src/BenchmarkDotNet/Characteristics/CompositeResolver.cs +++ b/src/BenchmarkDotNet/Characteristics/CompositeResolver.cs @@ -2,6 +2,8 @@ using System.Diagnostics.CodeAnalysis; using System.Linq; +#nullable enable + namespace BenchmarkDotNet.Characteristics { public class CompositeResolver : IResolver @@ -15,7 +17,7 @@ public CompositeResolver(params IResolver[] resolvers) public bool CanResolve(Characteristic characteristic) => resolvers.Any(r => r.CanResolve(characteristic)); - public object Resolve(CharacteristicObject obj, Characteristic characteristic) + public object? Resolve(CharacteristicObject obj, Characteristic characteristic) { if (obj.HasValue(characteristic)) return characteristic[obj]; @@ -26,7 +28,7 @@ public object Resolve(CharacteristicObject obj, Characteristic characteristic) throw new InvalidOperationException($"There is no default resolver for {characteristic.FullId}"); } - public T Resolve<[DynamicallyAccessedMembers(CharacteristicObject.CharacteristicMemberTypes)] T>(CharacteristicObject obj, Characteristic characteristic) + public T? Resolve<[DynamicallyAccessedMembers(CharacteristicObject.CharacteristicMemberTypes)] T>(CharacteristicObject obj, Characteristic characteristic) { if (obj.HasValue(characteristic)) return characteristic[obj]; @@ -37,7 +39,7 @@ public object Resolve(CharacteristicObject obj, Characteristic characteristic) throw new InvalidOperationException($"There is no default resolver for {characteristic.FullId}"); } - public object Resolve(CharacteristicObject obj, Characteristic characteristic, object defaultValue) + public object? Resolve(CharacteristicObject obj, Characteristic characteristic, object defaultValue) { if (obj.HasValue(characteristic)) return characteristic[obj]; @@ -48,7 +50,7 @@ public object Resolve(CharacteristicObject obj, Characteristic characteristic, o return defaultValue; } - public T Resolve<[DynamicallyAccessedMembers(CharacteristicObject.CharacteristicMemberTypes)] T>(CharacteristicObject obj, Characteristic characteristic, T defaultValue) + public T? Resolve<[DynamicallyAccessedMembers(CharacteristicObject.CharacteristicMemberTypes)] T>(CharacteristicObject obj, Characteristic characteristic, T defaultValue) { if (obj.HasValue(characteristic)) return characteristic[obj]; diff --git a/src/BenchmarkDotNet/Characteristics/IResolver.cs b/src/BenchmarkDotNet/Characteristics/IResolver.cs index 9a20036d02..b4c6afb548 100644 --- a/src/BenchmarkDotNet/Characteristics/IResolver.cs +++ b/src/BenchmarkDotNet/Characteristics/IResolver.cs @@ -1,5 +1,7 @@ using System.Diagnostics.CodeAnalysis; +#nullable enable + namespace BenchmarkDotNet.Characteristics { /// @@ -9,12 +11,12 @@ public interface IResolver { bool CanResolve(Characteristic characteristic); - object Resolve(CharacteristicObject obj, Characteristic characteristic); + object? Resolve(CharacteristicObject obj, Characteristic characteristic); - T Resolve<[DynamicallyAccessedMembers(CharacteristicObject.CharacteristicMemberTypes)] T>(CharacteristicObject obj, Characteristic characteristic); + T? Resolve<[DynamicallyAccessedMembers(CharacteristicObject.CharacteristicMemberTypes)] T>(CharacteristicObject obj, Characteristic characteristic); - object Resolve(CharacteristicObject obj, Characteristic characteristic, object defaultValue); + object? Resolve(CharacteristicObject obj, Characteristic characteristic, object defaultValue); - T Resolve<[DynamicallyAccessedMembers(CharacteristicObject.CharacteristicMemberTypes)] T>(CharacteristicObject obj, Characteristic characteristic, T defaultValue); + T? Resolve<[DynamicallyAccessedMembers(CharacteristicObject.CharacteristicMemberTypes)] T>(CharacteristicObject obj, Characteristic characteristic, T defaultValue); } } \ No newline at end of file diff --git a/src/BenchmarkDotNet/Characteristics/Resolver.cs b/src/BenchmarkDotNet/Characteristics/Resolver.cs index b5d8c6128b..8580e48b66 100644 --- a/src/BenchmarkDotNet/Characteristics/Resolver.cs +++ b/src/BenchmarkDotNet/Characteristics/Resolver.cs @@ -2,21 +2,23 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; +#nullable enable + namespace BenchmarkDotNet.Characteristics { public class Resolver : IResolver { - private readonly Dictionary> resolvers = new Dictionary>(); + private readonly Dictionary> resolvers = new Dictionary>(); - protected void Register<[DynamicallyAccessedMembers(CharacteristicObject.CharacteristicMemberTypes)] T>(Characteristic characteristic, Func resolver) => + protected void Register<[DynamicallyAccessedMembers(CharacteristicObject.CharacteristicMemberTypes)] T>(Characteristic characteristic, Func resolver) => resolvers[characteristic] = obj => resolver(); - protected void Register<[DynamicallyAccessedMembers(CharacteristicObject.CharacteristicMemberTypes)] T>(Characteristic characteristic, Func resolver) => + protected void Register<[DynamicallyAccessedMembers(CharacteristicObject.CharacteristicMemberTypes)] T>(Characteristic characteristic, Func resolver) => resolvers[characteristic] = obj => resolver(obj); public bool CanResolve(Characteristic characteristic) => resolvers.ContainsKey(characteristic); - public object Resolve(CharacteristicObject obj, Characteristic characteristic) + public object? Resolve(CharacteristicObject obj, Characteristic characteristic) { if (obj.HasValue(characteristic)) return characteristic[obj]; @@ -26,17 +28,17 @@ public object Resolve(CharacteristicObject obj, Characteristic characteristic) throw new InvalidOperationException($"There is no default resolver for {characteristic.FullId}"); } - public T Resolve<[DynamicallyAccessedMembers(CharacteristicObject.CharacteristicMemberTypes)] T>(CharacteristicObject obj, Characteristic characteristic) + public T? Resolve<[DynamicallyAccessedMembers(CharacteristicObject.CharacteristicMemberTypes)] T>(CharacteristicObject obj, Characteristic characteristic) { if (obj.HasValue(characteristic)) return characteristic[obj]; if (resolvers.TryGetValue(characteristic, out var resolver)) - return (T)resolver(obj); + return (T?)resolver(obj); throw new InvalidOperationException($"There is no default resolver for {characteristic.FullId}"); } - public object Resolve(CharacteristicObject obj, Characteristic characteristic, object defaultValue) + public object? Resolve(CharacteristicObject obj, Characteristic characteristic, object defaultValue) { if (obj.HasValue(characteristic)) return characteristic[obj]; @@ -47,13 +49,13 @@ public object Resolve(CharacteristicObject obj, Characteristic characteristic, o return defaultValue; } - public T Resolve<[DynamicallyAccessedMembers(CharacteristicObject.CharacteristicMemberTypes)] T>(CharacteristicObject obj, Characteristic characteristic, T defaultValue) + public T? Resolve<[DynamicallyAccessedMembers(CharacteristicObject.CharacteristicMemberTypes)] T>(CharacteristicObject obj, Characteristic characteristic, T defaultValue) { if (obj.HasValue(characteristic)) return characteristic[obj]; if (resolvers.TryGetValue(characteristic, out var resolver)) - return (T)resolver(obj); + return (T?)resolver(obj); return defaultValue; } diff --git a/src/BenchmarkDotNet/Diagnosers/ThreadingDiagnoser.cs b/src/BenchmarkDotNet/Diagnosers/ThreadingDiagnoser.cs index 40bd3f482b..419c8e3c4e 100644 --- a/src/BenchmarkDotNet/Diagnosers/ThreadingDiagnoser.cs +++ b/src/BenchmarkDotNet/Diagnosers/ThreadingDiagnoser.cs @@ -47,7 +47,7 @@ public IEnumerable Validate(ValidationParameters validationPara { var runtime = benchmark.Job.ResolveValue(EnvironmentMode.RuntimeCharacteristic, EnvironmentResolver.Instance); - if (runtime.RuntimeMoniker < RuntimeMoniker.NetCoreApp30) + if (runtime != null && runtime.RuntimeMoniker < RuntimeMoniker.NetCoreApp30) { yield return new ValidationError(true, $"{nameof(ThreadingDiagnoser)} supports only .NET Core 3.0+", benchmark); } diff --git a/src/BenchmarkDotNet/Extensions/ProcessExtensions.cs b/src/BenchmarkDotNet/Extensions/ProcessExtensions.cs index d52ea8b2fe..a17617a37b 100644 --- a/src/BenchmarkDotNet/Extensions/ProcessExtensions.cs +++ b/src/BenchmarkDotNet/Extensions/ProcessExtensions.cs @@ -160,7 +160,7 @@ internal static void SetEnvironmentVariables(this ProcessStartInfo start, Benchm if (!benchmarkCase.Job.HasValue(EnvironmentMode.EnvironmentVariablesCharacteristic)) return; - foreach (var environmentVariable in benchmarkCase.Job.Environment.EnvironmentVariables) + foreach (var environmentVariable in benchmarkCase.Job.Environment.EnvironmentVariables ?? []) start.EnvironmentVariables[environmentVariable.Key] = environmentVariable.Value; } diff --git a/src/BenchmarkDotNet/Helpers/FolderNameHelper.cs b/src/BenchmarkDotNet/Helpers/FolderNameHelper.cs index 01bb71dd36..4625f9c03d 100644 --- a/src/BenchmarkDotNet/Helpers/FolderNameHelper.cs +++ b/src/BenchmarkDotNet/Helpers/FolderNameHelper.cs @@ -10,9 +10,11 @@ namespace BenchmarkDotNet.Helpers { public static class FolderNameHelper { - public static string ToFolderName(object value) + public static string ToFolderName(object? value) { switch (value) { + case null: + return "null"; case bool b: return b.ToLowerCase(); case string s: diff --git a/src/BenchmarkDotNet/Helpers/SourceCodeHelper.cs b/src/BenchmarkDotNet/Helpers/SourceCodeHelper.cs index 524878b2c1..511b9a87df 100644 --- a/src/BenchmarkDotNet/Helpers/SourceCodeHelper.cs +++ b/src/BenchmarkDotNet/Helpers/SourceCodeHelper.cs @@ -7,11 +7,13 @@ using Perfolizer.Horology; using SimpleJson.Reflection; +#nullable enable + namespace BenchmarkDotNet.Helpers { public static class SourceCodeHelper { - public static string ToSourceCode(object value) + public static string ToSourceCode(object? value) { switch (value) { case null: @@ -42,7 +44,7 @@ public static string ToSourceCode(object value) { elementsSourceCode[i] = ToSourceCode(array.GetValue(i)); } - return $"new {array.GetType().GetElementType().GetCorrectCSharpTypeName()}[] {{ {string.Join(", ", elementsSourceCode)} }}"; + return $"new {array.GetType().GetElementType()!.GetCorrectCSharpTypeName()}[] {{ {string.Join(", ", elementsSourceCode)} }}"; } } if (ReflectionUtils.GetTypeInfo(value.GetType()).IsEnum) @@ -61,7 +63,7 @@ public static string ToSourceCode(object value) return formattable.ToString(null, CultureInfo.InvariantCulture); } - return value.ToString(); + return value.ToString()!; } public static bool IsCompilationTimeConstant(object value) diff --git a/src/BenchmarkDotNet/Jobs/Argument.cs b/src/BenchmarkDotNet/Jobs/Argument.cs index c86c83906a..15c08e4caf 100644 --- a/src/BenchmarkDotNet/Jobs/Argument.cs +++ b/src/BenchmarkDotNet/Jobs/Argument.cs @@ -1,6 +1,8 @@ using System; using JetBrains.Annotations; +#nullable enable + namespace BenchmarkDotNet.Jobs { public abstract class Argument: IEquatable @@ -15,14 +17,14 @@ protected Argument(string value) // CharacteristicPresenters call ToString(), this is why we need this override public override string ToString() => TextRepresentation; - public bool Equals(Argument other) + public bool Equals(Argument? other) { if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(this, other)) return true; return TextRepresentation == other.TextRepresentation; } - public override bool Equals(object obj) => Equals(obj as Argument); + public override bool Equals(object? obj) => Equals(obj as Argument); public override int GetHashCode() => HashCode.Combine(TextRepresentation); } diff --git a/src/BenchmarkDotNet/Jobs/EnvironmentMode.cs b/src/BenchmarkDotNet/Jobs/EnvironmentMode.cs index 0d5113db48..7cefe5d9fb 100644 --- a/src/BenchmarkDotNet/Jobs/EnvironmentMode.cs +++ b/src/BenchmarkDotNet/Jobs/EnvironmentMode.cs @@ -7,6 +7,8 @@ using BenchmarkDotNet.Portability; using JetBrains.Annotations; +#nullable enable + namespace BenchmarkDotNet.Jobs { public sealed class EnvironmentMode : JobMode @@ -29,7 +31,7 @@ public sealed class EnvironmentMode : JobMode public static readonly EnvironmentMode RyuJitX86 = new EnvironmentMode(nameof(RyuJitX86), Jit.RyuJit, Platform.X86).Freeze(); [PublicAPI] - public EnvironmentMode() : this(id: null) { } + public EnvironmentMode() : this(id: "") { } [PublicAPI] public EnvironmentMode(Runtime runtime) : this(runtime.ToString()) => Runtime = runtime; @@ -42,7 +44,10 @@ public EnvironmentMode(string id, Jit jit, Platform platform) : this(id) } [PublicAPI] - public EnvironmentMode(string id) : base(id) => GcCharacteristic[this] = new GcMode(); + public EnvironmentMode(string id) : base(id) + { + GcCharacteristic[this] = new GcMode(); + } /// /// Platform (x86 or x64) @@ -84,9 +89,9 @@ public IntPtr Affinity /// /// GcMode /// - public GcMode Gc => GcCharacteristic[this]; + public GcMode Gc => GcCharacteristic[this]!; - public IReadOnlyList EnvironmentVariables + public IReadOnlyList? EnvironmentVariables { get => EnvironmentVariablesCharacteristic[this]; set => EnvironmentVariablesCharacteristic[this] = value; @@ -137,7 +142,12 @@ public void SetEnvironmentVariable(EnvironmentVariable variable) EnvironmentVariables = newVariables; } - internal Runtime GetRuntime() => HasValue(RuntimeCharacteristic) ? Runtime : RuntimeInformation.GetCurrentRuntime(); + internal Runtime GetRuntime() + { + return HasValue(RuntimeCharacteristic) && Runtime != null + ? Runtime + : RuntimeInformation.GetCurrentRuntime(); + } internal BdnEnvironment ToPerfonar() => new() { diff --git a/src/BenchmarkDotNet/Jobs/EnvironmentVariable.cs b/src/BenchmarkDotNet/Jobs/EnvironmentVariable.cs index fab2ba3c99..985ef07bc5 100644 --- a/src/BenchmarkDotNet/Jobs/EnvironmentVariable.cs +++ b/src/BenchmarkDotNet/Jobs/EnvironmentVariable.cs @@ -1,5 +1,7 @@ using System; +#nullable enable + namespace BenchmarkDotNet.Jobs { public class EnvironmentVariable : IEquatable @@ -17,9 +19,12 @@ public EnvironmentVariable(string key, string value) // CharacteristicPresenters call ToString(), this is why we need this override public override string ToString() => $"{Key}={Value}"; - public bool Equals(EnvironmentVariable other) => string.Equals(Key, other.Key) && string.Equals(Value, other.Value); + public bool Equals(EnvironmentVariable? other) + { + return string.Equals(Key, other?.Key) && string.Equals(Value, other?.Value); + } - public override bool Equals(object obj) + public override bool Equals(object? obj) { if (ReferenceEquals(null, obj)) return false; diff --git a/src/BenchmarkDotNet/Jobs/GcMode.cs b/src/BenchmarkDotNet/Jobs/GcMode.cs index 79664e8c0c..e836f43cc3 100644 --- a/src/BenchmarkDotNet/Jobs/GcMode.cs +++ b/src/BenchmarkDotNet/Jobs/GcMode.cs @@ -2,6 +2,8 @@ using System.Diagnostics.CodeAnalysis; using BenchmarkDotNet.Characteristics; +#nullable enable + namespace BenchmarkDotNet.Jobs { [SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] @@ -112,7 +114,7 @@ public int HeapCount set { HeapCountCharacteristic[this] = value; } } - public bool Equals(GcMode other) + public bool Equals(GcMode? other) => other != null && other.AllowVeryLargeObjects == AllowVeryLargeObjects && other.Concurrent == Concurrent diff --git a/src/BenchmarkDotNet/Jobs/InfrastructureMode.cs b/src/BenchmarkDotNet/Jobs/InfrastructureMode.cs index 277627d2e9..58f779b1ef 100644 --- a/src/BenchmarkDotNet/Jobs/InfrastructureMode.cs +++ b/src/BenchmarkDotNet/Jobs/InfrastructureMode.cs @@ -8,6 +8,8 @@ using BenchmarkDotNet.Toolchains.InProcess.Emit; using Perfolizer.Horology; +#nullable enable + namespace BenchmarkDotNet.Jobs { [SuppressMessage("ReSharper", "UnusedMember.Global")] @@ -35,13 +37,13 @@ private InfrastructureMode(IToolchain toolchain) Toolchain = toolchain; } - public IToolchain Toolchain + public IToolchain? Toolchain { get { return ToolchainCharacteristic[this]; } set { ToolchainCharacteristic[this] = value; } } - public IClock Clock + public IClock? Clock { get { return ClockCharacteristic[this]; } set { ClockCharacteristic[this] = value; } @@ -51,19 +53,19 @@ public IClock Clock /// this type will be used in the auto-generated program to create engine in separate process /// it must have parameterless constructor /// - public IEngineFactory EngineFactory + public IEngineFactory? EngineFactory { get { return EngineFactoryCharacteristic[this]; } set { EngineFactoryCharacteristic[this] = value; } } - public string BuildConfiguration + public string? BuildConfiguration { get => BuildConfigurationCharacteristic[this]; set => BuildConfigurationCharacteristic[this] = value; } - public IReadOnlyList Arguments + public IReadOnlyList? Arguments { get => ArgumentsCharacteristic[this]; set => ArgumentsCharacteristic[this] = value; @@ -71,13 +73,13 @@ public IReadOnlyList Arguments [EditorBrowsable(EditorBrowsableState.Never)] [Obsolete("This will soon be removed")] - public IReadOnlyCollection NuGetReferences + public IReadOnlyCollection? NuGetReferences { get => NuGetReferencesCharacteristic[this]; set => NuGetReferencesCharacteristic[this] = value; } - public bool TryGetToolchain(out IToolchain toolchain) + public bool TryGetToolchain([NotNullWhen(true)]out IToolchain? toolchain) { toolchain = HasValue(ToolchainCharacteristic) ? Toolchain : default; return toolchain != default; diff --git a/src/BenchmarkDotNet/Jobs/Job.cs b/src/BenchmarkDotNet/Jobs/Job.cs index 0985b5e578..091ab7c3d7 100644 --- a/src/BenchmarkDotNet/Jobs/Job.cs +++ b/src/BenchmarkDotNet/Jobs/Job.cs @@ -30,9 +30,9 @@ public sealed class Job : JobMode public static readonly Job InProcess = new Job(nameof(InProcess), InfrastructureMode.InProcess); public static readonly Job InProcessDontLogOutput = new Job(nameof(InProcessDontLogOutput), InfrastructureMode.InProcessDontLogOutput); - public Job() : this((string?)null) { } + public Job() : this("") { } - public Job(string? id) : base(id) + public Job(string id) : base(id) { EnvironmentCharacteristic[this] = new EnvironmentMode(); RunCharacteristic[this] = new RunMode(); @@ -41,29 +41,29 @@ public Job(string? id) : base(id) MetaCharacteristic[this] = new MetaMode(); } - public Job(CharacteristicObject other) : this((string?)null, other) + public Job(CharacteristicObject other) : this("", other) { } - public Job(params CharacteristicObject[] others) : this(null, others) + public Job(params CharacteristicObject[] others) : this("", others) { } - public Job(string? id, CharacteristicObject other) : this(id) + public Job(string id, CharacteristicObject other) : this(id) { Apply(other); } - public Job(string? id, params CharacteristicObject[] others) : this(id) + public Job(string id, params CharacteristicObject[] others) : this(id) { Apply(others); } - public EnvironmentMode Environment => EnvironmentCharacteristic[this]; - public RunMode Run => RunCharacteristic[this]; - public InfrastructureMode Infrastructure => InfrastructureCharacteristic[this]; - public AccuracyMode Accuracy => AccuracyCharacteristic[this]; - public MetaMode Meta => MetaCharacteristic[this]; + public EnvironmentMode Environment => EnvironmentCharacteristic[this]!; + public RunMode Run => RunCharacteristic[this]!; + public InfrastructureMode Infrastructure => InfrastructureCharacteristic[this]!; + public AccuracyMode Accuracy => AccuracyCharacteristic[this]!; + public MetaMode Meta => MetaCharacteristic[this]!; public string ResolvedId => HasValue(IdCharacteristic) ? Id : JobIdGenerator.GenerateRandomId(this); public string FolderInfo => ResolvedId; @@ -72,7 +72,7 @@ public string DisplayInfo { get { - string props = ResolveId(this, null); + string props = ResolveId(this, ""); return props == IdCharacteristic.FallbackValue ? ResolvedId : ResolvedId + $"({props})"; diff --git a/src/BenchmarkDotNet/Jobs/JobComparer.cs b/src/BenchmarkDotNet/Jobs/JobComparer.cs index ac1539ce7c..e39aa3e450 100644 --- a/src/BenchmarkDotNet/Jobs/JobComparer.cs +++ b/src/BenchmarkDotNet/Jobs/JobComparer.cs @@ -3,6 +3,8 @@ using System; using System.Collections.Generic; +#nullable enable + namespace BenchmarkDotNet.Jobs { internal class JobComparer : IComparer, IEqualityComparer @@ -19,7 +21,7 @@ public JobComparer(JobOrderPolicy jobOrderPolicy = JobOrderPolicy.Default) : new NumericStringComparer(); // TODO: Use `StringComparer.Create(CultureInfo.InvariantCulture, CompareOptions.NumericOrdering)` for .NET10 or greater. } - public int Compare(Job x, Job y) + public int Compare(Job? x, Job? y) { if (ReferenceEquals(x, y)) return 0; @@ -60,7 +62,7 @@ public int Compare(Job x, Job y) return 0; } - public bool Equals(Job x, Job y) => Compare(x, y) == 0; + public bool Equals(Job? x, Job? y) => Compare(x, y) == 0; public int GetHashCode(Job obj) => obj.Id.GetHashCode(); diff --git a/src/BenchmarkDotNet/Jobs/JobExtensions.cs b/src/BenchmarkDotNet/Jobs/JobExtensions.cs index 0424528ad4..b901c2a724 100644 --- a/src/BenchmarkDotNet/Jobs/JobExtensions.cs +++ b/src/BenchmarkDotNet/Jobs/JobExtensions.cs @@ -12,6 +12,8 @@ using Perfolizer.Horology; using Perfolizer.Mathematics.OutlierDetection; +#nullable enable + namespace BenchmarkDotNet.Jobs { public static class JobExtensions @@ -345,7 +347,7 @@ public static Job WithNuGet(this Job job, string packageName, string? packageVer job.WithCore(j => j.Infrastructure.NuGetReferences = new NuGetReferenceList(j.Infrastructure.NuGetReferences ?? Array.Empty()) { - new NuGetReference(packageName, packageVersion, source, prerelease) + new NuGetReference(packageName, packageVersion ?? "", source, prerelease) }); /// diff --git a/src/BenchmarkDotNet/Jobs/JobMode`1.cs b/src/BenchmarkDotNet/Jobs/JobMode`1.cs index 61a51a8bd8..4dfa8ebe21 100644 --- a/src/BenchmarkDotNet/Jobs/JobMode`1.cs +++ b/src/BenchmarkDotNet/Jobs/JobMode`1.cs @@ -1,6 +1,8 @@ using BenchmarkDotNet.Characteristics; using JetBrains.Annotations; +#nullable enable + namespace BenchmarkDotNet.Jobs { public abstract class JobMode : CharacteristicObject where T : JobMode, new() @@ -9,8 +11,8 @@ namespace BenchmarkDotNet.Jobs protected JobMode() { } - protected JobMode(string? id) : base(id) { } + protected JobMode(string id) : base(id) { } - [PublicAPI] public Job Job => OwnerOrSelf as Job; + [PublicAPI] public Job Job => (Job)OwnerOrSelf; } } \ No newline at end of file diff --git a/src/BenchmarkDotNet/Jobs/NugetReference.cs b/src/BenchmarkDotNet/Jobs/NugetReference.cs index 89dc4c3734..3d7eea3eea 100644 --- a/src/BenchmarkDotNet/Jobs/NugetReference.cs +++ b/src/BenchmarkDotNet/Jobs/NugetReference.cs @@ -2,6 +2,8 @@ using System.ComponentModel; using System.Text.RegularExpressions; +#nullable enable + namespace BenchmarkDotNet.Jobs { [EditorBrowsable(EditorBrowsableState.Never)] @@ -26,9 +28,9 @@ public NuGetReference(string packageName, string packageVersion, Uri? source = n public string PackageName { get; } public string PackageVersion { get; } public bool Prerelease { get; } - public Uri PackageSource { get; } + public Uri? PackageSource { get; } - public override bool Equals(object obj) + public override bool Equals(object? obj) { return Equals(obj as NuGetReference); } @@ -38,7 +40,7 @@ public override bool Equals(object obj) /// /// /// - public bool Equals(NuGetReference other) + public bool Equals(NuGetReference? other) { return other != null && PackageName == other.PackageName && diff --git a/src/BenchmarkDotNet/Jobs/RunMode.cs b/src/BenchmarkDotNet/Jobs/RunMode.cs index 3e1e56c22f..fe3e144823 100644 --- a/src/BenchmarkDotNet/Jobs/RunMode.cs +++ b/src/BenchmarkDotNet/Jobs/RunMode.cs @@ -6,6 +6,8 @@ using BenchmarkDotNet.Models; using Perfolizer.Horology; +#nullable enable + namespace BenchmarkDotNet.Jobs { [SuppressMessage("ReSharper", "UnusedMember.Global")] @@ -64,7 +66,7 @@ public sealed class RunMode : JobMode }.Freeze(); - public RunMode() : this(null) { } + public RunMode() : this("") { } private RunMode(string id) : base(id) { } diff --git a/src/BenchmarkDotNet/Toolchains/ToolchainExtensions.cs b/src/BenchmarkDotNet/Toolchains/ToolchainExtensions.cs index 8b18bd290d..e8382c45c7 100644 --- a/src/BenchmarkDotNet/Toolchains/ToolchainExtensions.cs +++ b/src/BenchmarkDotNet/Toolchains/ToolchainExtensions.cs @@ -34,7 +34,7 @@ internal static IToolchain GetToolchain(this Job job) => job.Infrastructure.TryGetToolchain(out var toolchain) ? toolchain : GetToolchain( - job.ResolveValue(EnvironmentMode.RuntimeCharacteristic, EnvironmentResolver.Instance), + job.ResolveValue(EnvironmentMode.RuntimeCharacteristic, EnvironmentResolver.Instance)!, null, job.HasDynamicBuildCharacteristic(), job.Environment.HasValue(EnvironmentMode.RuntimeCharacteristic)