diff --git a/Directory.Build.props b/Directory.Build.props index 34da8f49..1bfa061d 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -32,7 +32,7 @@ $(WarningsNotAsErrors);1591 9.0 true - annotations + enable $(MSBuildThisFileDirectory)src\StrongName.snk true diff --git a/src/CommandLineUtils/Attributes/AllowedValuesAttribute.cs b/src/CommandLineUtils/Attributes/AllowedValuesAttribute.cs index 3312c1ce..5bdc527b 100644 --- a/src/CommandLineUtils/Attributes/AllowedValuesAttribute.cs +++ b/src/CommandLineUtils/Attributes/AllowedValuesAttribute.cs @@ -66,14 +66,14 @@ or StringComparison.InvariantCultureIgnoreCase } /// - protected override ValidationResult IsValid(object value, ValidationContext validationContext) + protected override ValidationResult? IsValid(object? value, ValidationContext validationContext) { if (value is string str && _allowedValues.Any(t => str.Equals(t, Comparer))) { return ValidationResult.Success; } - return new ValidationResult(FormatErrorMessage(value as string)); + return new ValidationResult(FormatErrorMessage(value?.ToString() ?? string.Empty)); } } } diff --git a/src/CommandLineUtils/Attributes/FilePathExistsAttributeBase.cs b/src/CommandLineUtils/Attributes/FilePathExistsAttributeBase.cs index 90bfbb0e..891a7ecc 100644 --- a/src/CommandLineUtils/Attributes/FilePathExistsAttributeBase.cs +++ b/src/CommandLineUtils/Attributes/FilePathExistsAttributeBase.cs @@ -27,11 +27,11 @@ internal FilePathExistsAttributeBase(FilePathType filePathType) } /// - protected override ValidationResult IsValid(object value, ValidationContext validationContext) + protected override ValidationResult? IsValid(object? value, ValidationContext validationContext) { if (value is not string path || path.Length == 0 || path.IndexOfAny(Path.GetInvalidPathChars()) >= 0) { - return new ValidationResult(FormatErrorMessage(value as string)); + return new ValidationResult(FormatErrorMessage(value?.ToString() ?? string.Empty)); } if (!Path.IsPathRooted(path) @@ -50,7 +50,7 @@ protected override ValidationResult IsValid(object value, ValidationContext vali return ValidationResult.Success; } - return new ValidationResult(FormatErrorMessage(value as string)); + return new ValidationResult(FormatErrorMessage(value?.ToString() ?? string.Empty)); } private static string GetDefaultErrorMessage(FilePathType filePathType) diff --git a/src/CommandLineUtils/Attributes/FilePathNotExistsAttributeBase.cs b/src/CommandLineUtils/Attributes/FilePathNotExistsAttributeBase.cs index 0b1a1e78..535637ab 100644 --- a/src/CommandLineUtils/Attributes/FilePathNotExistsAttributeBase.cs +++ b/src/CommandLineUtils/Attributes/FilePathNotExistsAttributeBase.cs @@ -27,11 +27,11 @@ internal FilePathNotExistsAttributeBase(FilePathType filePathType) } /// - protected override ValidationResult IsValid(object value, ValidationContext validationContext) + protected override ValidationResult? IsValid(object? value, ValidationContext validationContext) { if (value is not string path || path.Length == 0 || path.IndexOfAny(Path.GetInvalidPathChars()) >= 0) { - return new ValidationResult(FormatErrorMessage(value as string)); + return new ValidationResult(FormatErrorMessage(value?.ToString() ?? string.Empty)); } if (!Path.IsPathRooted(path) @@ -55,7 +55,7 @@ protected override ValidationResult IsValid(object value, ValidationContext vali return ValidationResult.Success; } - return new ValidationResult(FormatErrorMessage(value as string)); + return new ValidationResult(FormatErrorMessage(value?.ToString() ?? string.Empty)); } private static string GetDefaultErrorMessage(FilePathType filePathType) diff --git a/src/CommandLineUtils/Attributes/LegalFilePathAttribute.cs b/src/CommandLineUtils/Attributes/LegalFilePathAttribute.cs index 2fc79fd0..45df3ec5 100644 --- a/src/CommandLineUtils/Attributes/LegalFilePathAttribute.cs +++ b/src/CommandLineUtils/Attributes/LegalFilePathAttribute.cs @@ -23,7 +23,7 @@ public LegalFilePathAttribute() } /// - protected override ValidationResult IsValid(object value, ValidationContext validationContext) + protected override ValidationResult? IsValid(object? value, ValidationContext validationContext) { if (value is string path) { @@ -37,7 +37,7 @@ protected override ValidationResult IsValid(object value, ValidationContext vali } } - return new ValidationResult(FormatErrorMessage(value as string)); + return new ValidationResult(FormatErrorMessage(value?.ToString() ?? string.Empty)); } } } diff --git a/src/CommandLineUtils/CommandArgument.cs b/src/CommandLineUtils/CommandArgument.cs index e0330b38..f9c183bf 100644 --- a/src/CommandLineUtils/CommandArgument.cs +++ b/src/CommandLineUtils/CommandArgument.cs @@ -78,7 +78,7 @@ public IReadOnlyList Values /// /// Defines the underlying type of the argument for the help-text-generator /// - internal Type UnderlyingType { get; set; } + internal Type? UnderlyingType { get; set; } /// /// Try to add a value to this argument. diff --git a/src/CommandLineUtils/CommandArgument{T}.cs b/src/CommandLineUtils/CommandArgument{T}.cs index 2bdf7d41..e3492011 100644 --- a/src/CommandLineUtils/CommandArgument{T}.cs +++ b/src/CommandLineUtils/CommandArgument{T}.cs @@ -52,9 +52,9 @@ public IReadOnlyList ParsedValues ((IInternalCommandParamOfT)this).Parse(CultureInfo.CurrentCulture); } - if (_parsedValues.Count == 0 && _hasDefaultValue) + if (_parsedValues.Count == 0 && _hasDefaultValue && DefaultValue != null) { - return new[] { DefaultValue }; + return new T[] { DefaultValue }; } return _parsedValues; @@ -85,7 +85,7 @@ void IInternalCommandParamOfT.Parse(CultureInfo culture) } } - void SetBaseDefaultValue(T value) + void SetBaseDefaultValue(T? value) { if (!ReflectionHelper.IsSpecialValueTupleType(typeof(T), out _)) { diff --git a/src/CommandLineUtils/CommandLineApplication.Validation.cs b/src/CommandLineUtils/CommandLineApplication.Validation.cs index a46091b3..a77a5b29 100644 --- a/src/CommandLineUtils/CommandLineApplication.Validation.cs +++ b/src/CommandLineUtils/CommandLineApplication.Validation.cs @@ -32,7 +32,7 @@ public Func ValidationErrorHandler /// Validates arguments and options. /// /// The first validation result that is not if there is an error. - public ValidationResult GetValidationResult() + public ValidationResult? GetValidationResult() { if (Parent != null) { diff --git a/src/CommandLineUtils/CommandLineApplication.cs b/src/CommandLineUtils/CommandLineApplication.cs index e5774009..7987e8a0 100644 --- a/src/CommandLineUtils/CommandLineApplication.cs +++ b/src/CommandLineUtils/CommandLineApplication.cs @@ -863,7 +863,7 @@ public async Task ExecuteAsync(string[] args, CancellationToken cancellatio } var validationResult = command.GetValidationResult(); - if (validationResult != ValidationResult.Success) + if (validationResult != null) { return command.ValidationErrorHandler(validationResult); } diff --git a/src/CommandLineUtils/CommandLineApplication{T}.cs b/src/CommandLineUtils/CommandLineApplication{T}.cs index 26e4dbc6..6ea6ab53 100644 --- a/src/CommandLineUtils/CommandLineApplication{T}.cs +++ b/src/CommandLineUtils/CommandLineApplication{T}.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Diagnostics.CodeAnalysis; using McMaster.Extensions.CommandLineUtils.Abstractions; using McMaster.Extensions.CommandLineUtils.Conventions; using McMaster.Extensions.CommandLineUtils.HelpText; @@ -15,6 +16,7 @@ namespace McMaster.Extensions.CommandLineUtils public class CommandLineApplication : CommandLineApplication, IModelAccessor where TModel : class { + [AllowNull] // this is initialized in common method called in all constructors private Lazy _lazy; private Func _modelFactory = DefaultModelFactory; diff --git a/src/CommandLineUtils/CommandOption.cs b/src/CommandLineUtils/CommandOption.cs index ae6a5fb9..f8d7ddee 100644 --- a/src/CommandLineUtils/CommandOption.cs +++ b/src/CommandLineUtils/CommandOption.cs @@ -137,7 +137,7 @@ public IReadOnlyList Values /// /// Defines the underlying type of the option for the help-text-generator /// - internal Type UnderlyingType { get; set; } + internal Type? UnderlyingType { get; set; } /// /// A collection of validators that execute before invoking . diff --git a/src/CommandLineUtils/CommandOption{T}.cs b/src/CommandLineUtils/CommandOption{T}.cs index 84d18a36..b15ec78d 100644 --- a/src/CommandLineUtils/CommandOption{T}.cs +++ b/src/CommandLineUtils/CommandOption{T}.cs @@ -53,7 +53,7 @@ public IReadOnlyList ParsedValues ((IInternalCommandParamOfT)this).Parse(CultureInfo.CurrentCulture); } - if (_parsedValues.Count == 0 && _hasDefaultValue) + if (_parsedValues.Count == 0 && _hasDefaultValue && DefaultValue != null) { return new[] { DefaultValue }; } @@ -86,7 +86,7 @@ void IInternalCommandParamOfT.Parse(CultureInfo culture) } } - private void SetBaseDefaultValue(T value) + private void SetBaseDefaultValue(T? value) { if (!ReflectionHelper.IsSpecialValueTupleType(typeof(T), out _)) { diff --git a/src/CommandLineUtils/Conventions/ExecuteMethodConvention.cs b/src/CommandLineUtils/Conventions/ExecuteMethodConvention.cs index 473b15c9..f682bd89 100644 --- a/src/CommandLineUtils/Conventions/ExecuteMethodConvention.cs +++ b/src/CommandLineUtils/Conventions/ExecuteMethodConvention.cs @@ -35,8 +35,8 @@ private async Task OnExecute(ConventionContext context, CancellationToken c MethodInfo? asyncMethod; try { - method = context.ModelType.GetMethod("OnExecute", binding); - asyncMethod = context.ModelType.GetMethod("OnExecuteAsync", binding); + method = context.ModelType?.GetMethod("OnExecute", binding); + asyncMethod = context.ModelType?.GetMethod("OnExecuteAsync", binding); } catch (AmbiguousMatchException ex) { @@ -75,7 +75,7 @@ private async Task OnExecute(ConventionContext context, CancellationToken c throw new InvalidOperationException(Strings.InvalidOnExecuteReturnType(method.Name)); } - private async Task InvokeAsync(MethodInfo method, object instance, object[] arguments) + private async Task InvokeAsync(MethodInfo method, object instance, object?[] arguments) { try { @@ -95,7 +95,7 @@ private async Task InvokeAsync(MethodInfo method, object instance, object[] return 0; } - private int Invoke(MethodInfo method, object instance, object[] arguments) + private int Invoke(MethodInfo method, object instance, object?[] arguments) { try { diff --git a/src/CommandLineUtils/Conventions/SubcommandAttributeConvention.cs b/src/CommandLineUtils/Conventions/SubcommandAttributeConvention.cs index 637127f0..6997b2a0 100644 --- a/src/CommandLineUtils/Conventions/SubcommandAttributeConvention.cs +++ b/src/CommandLineUtils/Conventions/SubcommandAttributeConvention.cs @@ -67,7 +67,7 @@ private static readonly MethodInfo s_addSubcommandMethod private void AddSubcommandImpl(ConventionContext context) where TSubCommand : class { - context.Application.Command(null, null); + context.Application.Command(null!, null!); // Hmm, should probably rethink this... } } } diff --git a/src/CommandLineUtils/HelpText/DefaultHelpTextGenerator.cs b/src/CommandLineUtils/HelpText/DefaultHelpTextGenerator.cs index fe5a57ea..1875d3d9 100644 --- a/src/CommandLineUtils/HelpText/DefaultHelpTextGenerator.cs +++ b/src/CommandLineUtils/HelpText/DefaultHelpTextGenerator.cs @@ -409,7 +409,7 @@ protected virtual string Format(CommandOption option) } } - private string[] ExtractNamesFromEnum(Type type) + private string[] ExtractNamesFromEnum(Type? type) { if (type == null) { diff --git a/src/CommandLineUtils/Internal/CommandLineProcessor.cs b/src/CommandLineUtils/Internal/CommandLineProcessor.cs index 5ab7d709..5a515784 100644 --- a/src/CommandLineUtils/Internal/CommandLineProcessor.cs +++ b/src/CommandLineUtils/Internal/CommandLineProcessor.cs @@ -335,7 +335,10 @@ private bool ProcessUnexpectedArg(string argTypeName, string? argValue = null) case UnrecognizedArgumentHandling.CollectAndContinue: var arg = _enumerator.Current; - _currentCommand._remainingArguments.Add(arg.Raw); + if (arg != null) + { + _currentCommand._remainingArguments.Add(arg.Raw); + } return true; case UnrecognizedArgumentHandling.StopParsingAndCollect: diff --git a/src/CommandLineUtils/Internal/ReflectionHelper.cs b/src/CommandLineUtils/Internal/ReflectionHelper.cs index e22c795d..3a3b7f04 100644 --- a/src/CommandLineUtils/Internal/ReflectionHelper.cs +++ b/src/CommandLineUtils/Internal/ReflectionHelper.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Reflection; using System.Threading; @@ -78,10 +79,10 @@ public static MemberInfo[] GetMembers(Type type) return GetAllMembers(type).ToArray(); } - public static object[] BindParameters(MethodInfo method, CommandLineApplication command, CancellationToken cancellationToken) + public static object?[] BindParameters(MethodInfo method, CommandLineApplication command, CancellationToken cancellationToken) { var methodParams = method.GetParameters(); - var arguments = new object[methodParams.Length]; + var arguments = new object?[methodParams.Length]; for (var i = 0; i < methodParams.Length; i++) { @@ -117,7 +118,7 @@ public static object[] BindParameters(MethodInfo method, CommandLineApplication return arguments; } - public static bool IsNullableType(Type type, out Type? wrappedType) + public static bool IsNullableType(Type type, [NotNullWhen(true)] out Type? wrappedType) { var result = type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>); wrappedType = result ? type.GetGenericArguments().First() : null; @@ -125,7 +126,7 @@ public static bool IsNullableType(Type type, out Type? wrappedType) return result; } - public static bool IsSpecialValueTupleType(Type type, out Type? wrappedType) + public static bool IsSpecialValueTupleType(Type type, [NotNullWhen(true)] out Type? wrappedType) { var result = type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ValueTuple<,>) && @@ -135,7 +136,7 @@ public static bool IsSpecialValueTupleType(Type type, out Type? wrappedType) return result; } - public static bool IsSpecialTupleType(Type type, out Type? wrappedType) + public static bool IsSpecialTupleType(Type type, [NotNullWhen(true)] out Type? wrappedType) { var result = type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Tuple<,>) && diff --git a/src/CommandLineUtils/Internal/ValueParsers/TypeDescriptorValueParserFactory.cs b/src/CommandLineUtils/Internal/ValueParsers/TypeDescriptorValueParserFactory.cs index 34f617ff..46ead25f 100644 --- a/src/CommandLineUtils/Internal/ValueParsers/TypeDescriptorValueParserFactory.cs +++ b/src/CommandLineUtils/Internal/ValueParsers/TypeDescriptorValueParserFactory.cs @@ -3,6 +3,7 @@ using System; using System.ComponentModel; +using System.Diagnostics.CodeAnalysis; using System.Globalization; namespace McMaster.Extensions.CommandLineUtils.Abstractions @@ -13,7 +14,7 @@ namespace McMaster.Extensions.CommandLineUtils.Abstractions /// internal class TypeDescriptorValueParserFactory { - public bool TryGetParser(out IValueParser parser) + public bool TryGetParser([NotNullWhen(true)] out IValueParser? parser) { var targetType = typeof(T); var converter = TypeDescriptor.GetConverter(targetType); @@ -39,7 +40,7 @@ public TypeConverterValueParser(Type targetType, TypeConverter typeConverter) private TypeConverter TypeConverter { get; } - public T Parse(string argName, string value, CultureInfo culture) + public T Parse(string? argName, string? value, CultureInfo culture) { try { @@ -52,7 +53,7 @@ public T Parse(string argName, string value, CultureInfo culture) } } - object IValueParser.Parse(string argName, string value, CultureInfo culture) + object? IValueParser.Parse(string? argName, string? value, CultureInfo culture) => Parse(argName, value, culture); } } diff --git a/src/CommandLineUtils/Properties/NullabilityHelpers.cs b/src/CommandLineUtils/Properties/NullabilityHelpers.cs new file mode 100644 index 00000000..7056bc25 --- /dev/null +++ b/src/CommandLineUtils/Properties/NullabilityHelpers.cs @@ -0,0 +1,21 @@ +// Copyright (c) Nate McMaster. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +// Files here are for simplify annotations of nullable code and are not functional in .NET Standard 2.0 +#if NETSTANDARD2_0 || NET45 +namespace System.Diagnostics.CodeAnalysis +{ + // https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.codeanalysis.notnullwhenattribute? + [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] + internal sealed class NotNullWhenAttribute : Attribute + { + public NotNullWhenAttribute(bool returnValue) + { + } + } + + // https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.codeanalysis.allownullattribute + [System.AttributeUsage(System.AttributeTargets.Field | System.AttributeTargets.Parameter | System.AttributeTargets.Property, Inherited=false)] + internal sealed class AllowNullAttribute : Attribute { } +} +#endif diff --git a/src/CommandLineUtils/PublicAPI.Shipped.txt b/src/CommandLineUtils/PublicAPI.Shipped.txt index 1476d1c4..b72b2bdf 100644 --- a/src/CommandLineUtils/PublicAPI.Shipped.txt +++ b/src/CommandLineUtils/PublicAPI.Shipped.txt @@ -127,7 +127,7 @@ McMaster.Extensions.CommandLineUtils.CommandLineApplication.ExtendedHelpText.set McMaster.Extensions.CommandLineUtils.CommandLineApplication.FullName.get -> string? McMaster.Extensions.CommandLineUtils.CommandLineApplication.FullName.set -> void McMaster.Extensions.CommandLineUtils.CommandLineApplication.GetOptions() -> System.Collections.Generic.IEnumerable! -McMaster.Extensions.CommandLineUtils.CommandLineApplication.GetValidationResult() -> System.ComponentModel.DataAnnotations.ValidationResult! +McMaster.Extensions.CommandLineUtils.CommandLineApplication.GetValidationResult() -> System.ComponentModel.DataAnnotations.ValidationResult? McMaster.Extensions.CommandLineUtils.CommandLineApplication.HelpOption(string! template, bool inherited) -> McMaster.Extensions.CommandLineUtils.CommandOption! McMaster.Extensions.CommandLineUtils.CommandLineApplication.HelpOption(string! template) -> McMaster.Extensions.CommandLineUtils.CommandOption! McMaster.Extensions.CommandLineUtils.CommandLineApplication.HelpTextGenerator.get -> McMaster.Extensions.CommandLineUtils.HelpText.IHelpTextGenerator! @@ -435,9 +435,9 @@ McMaster.Extensions.CommandLineUtils.ValidateMethodConvention.Apply(McMaster.Ext McMaster.Extensions.CommandLineUtils.ValidateMethodConvention.ValidateMethodConvention() -> void McMaster.Extensions.CommandLineUtils.Validation.AttributeValidator McMaster.Extensions.CommandLineUtils.Validation.AttributeValidator.AttributeValidator(System.ComponentModel.DataAnnotations.ValidationAttribute! attribute) -> void -McMaster.Extensions.CommandLineUtils.Validation.AttributeValidator.GetValidationResult(McMaster.Extensions.CommandLineUtils.CommandArgument! argument, System.ComponentModel.DataAnnotations.ValidationContext! context) -> System.ComponentModel.DataAnnotations.ValidationResult! -McMaster.Extensions.CommandLineUtils.Validation.AttributeValidator.GetValidationResult(McMaster.Extensions.CommandLineUtils.CommandLineApplication! command, System.ComponentModel.DataAnnotations.ValidationContext! context) -> System.ComponentModel.DataAnnotations.ValidationResult! -McMaster.Extensions.CommandLineUtils.Validation.AttributeValidator.GetValidationResult(McMaster.Extensions.CommandLineUtils.CommandOption! option, System.ComponentModel.DataAnnotations.ValidationContext! context) -> System.ComponentModel.DataAnnotations.ValidationResult! +McMaster.Extensions.CommandLineUtils.Validation.AttributeValidator.GetValidationResult(McMaster.Extensions.CommandLineUtils.CommandArgument! argument, System.ComponentModel.DataAnnotations.ValidationContext! context) -> System.ComponentModel.DataAnnotations.ValidationResult? +McMaster.Extensions.CommandLineUtils.Validation.AttributeValidator.GetValidationResult(McMaster.Extensions.CommandLineUtils.CommandLineApplication! command, System.ComponentModel.DataAnnotations.ValidationContext! context) -> System.ComponentModel.DataAnnotations.ValidationResult? +McMaster.Extensions.CommandLineUtils.Validation.AttributeValidator.GetValidationResult(McMaster.Extensions.CommandLineUtils.CommandOption! option, System.ComponentModel.DataAnnotations.ValidationContext! context) -> System.ComponentModel.DataAnnotations.ValidationResult? McMaster.Extensions.CommandLineUtils.Validation.DelegateValidator McMaster.Extensions.CommandLineUtils.Validation.DelegateValidator.DelegateValidator(System.Func! validator) -> void McMaster.Extensions.CommandLineUtils.Validation.FilePathExistsAttributeBase @@ -446,14 +446,14 @@ McMaster.Extensions.CommandLineUtils.Validation.IArgumentValidationBuilder McMaster.Extensions.CommandLineUtils.Validation.IArgumentValidationBuilder.Use(McMaster.Extensions.CommandLineUtils.Validation.IArgumentValidator! validator) -> void McMaster.Extensions.CommandLineUtils.Validation.IArgumentValidationBuilder McMaster.Extensions.CommandLineUtils.Validation.IArgumentValidator -McMaster.Extensions.CommandLineUtils.Validation.IArgumentValidator.GetValidationResult(McMaster.Extensions.CommandLineUtils.CommandArgument! argument, System.ComponentModel.DataAnnotations.ValidationContext! context) -> System.ComponentModel.DataAnnotations.ValidationResult! +McMaster.Extensions.CommandLineUtils.Validation.IArgumentValidator.GetValidationResult(McMaster.Extensions.CommandLineUtils.CommandArgument! argument, System.ComponentModel.DataAnnotations.ValidationContext! context) -> System.ComponentModel.DataAnnotations.ValidationResult? McMaster.Extensions.CommandLineUtils.Validation.ICommandValidator -McMaster.Extensions.CommandLineUtils.Validation.ICommandValidator.GetValidationResult(McMaster.Extensions.CommandLineUtils.CommandLineApplication! command, System.ComponentModel.DataAnnotations.ValidationContext! context) -> System.ComponentModel.DataAnnotations.ValidationResult! +McMaster.Extensions.CommandLineUtils.Validation.ICommandValidator.GetValidationResult(McMaster.Extensions.CommandLineUtils.CommandLineApplication! command, System.ComponentModel.DataAnnotations.ValidationContext! context) -> System.ComponentModel.DataAnnotations.ValidationResult? McMaster.Extensions.CommandLineUtils.Validation.IOptionValidationBuilder McMaster.Extensions.CommandLineUtils.Validation.IOptionValidationBuilder.Use(McMaster.Extensions.CommandLineUtils.Validation.IOptionValidator! validator) -> void McMaster.Extensions.CommandLineUtils.Validation.IOptionValidationBuilder McMaster.Extensions.CommandLineUtils.Validation.IOptionValidator -McMaster.Extensions.CommandLineUtils.Validation.IOptionValidator.GetValidationResult(McMaster.Extensions.CommandLineUtils.CommandOption! option, System.ComponentModel.DataAnnotations.ValidationContext! context) -> System.ComponentModel.DataAnnotations.ValidationResult! +McMaster.Extensions.CommandLineUtils.Validation.IOptionValidator.GetValidationResult(McMaster.Extensions.CommandLineUtils.CommandOption! option, System.ComponentModel.DataAnnotations.ValidationContext! context) -> System.ComponentModel.DataAnnotations.ValidationResult? McMaster.Extensions.CommandLineUtils.Validation.IValidationBuilder McMaster.Extensions.CommandLineUtils.Validation.IValidationBuilder.Use(McMaster.Extensions.CommandLineUtils.Validation.IValidator! validator) -> void McMaster.Extensions.CommandLineUtils.Validation.IValidationBuilder diff --git a/src/CommandLineUtils/Validation/AttributeValidator.cs b/src/CommandLineUtils/Validation/AttributeValidator.cs index 565b6ab9..5816553a 100644 --- a/src/CommandLineUtils/Validation/AttributeValidator.cs +++ b/src/CommandLineUtils/Validation/AttributeValidator.cs @@ -30,7 +30,7 @@ public AttributeValidator(ValidationAttribute attribute) /// /// /// - public ValidationResult GetValidationResult(CommandOption option, ValidationContext context) + public ValidationResult? GetValidationResult(CommandOption option, ValidationContext context) { if (ValidationAttribute is RequiredAttribute && option.OptionType == CommandOptionType.NoValue) { @@ -49,10 +49,10 @@ public ValidationResult GetValidationResult(CommandOption option, ValidationCont /// /// /// - public ValidationResult GetValidationResult(CommandArgument argument, ValidationContext context) + public ValidationResult? GetValidationResult(CommandArgument argument, ValidationContext context) => GetValidationResult(argument.Values, context); - private ValidationResult GetValidationResult(IReadOnlyList? values, ValidationContext context) + private ValidationResult? GetValidationResult(IReadOnlyList? values, ValidationContext context) { if (values == null) { @@ -79,7 +79,7 @@ private ValidationResult GetValidationResult(IReadOnlyList? values, Val /// Checks whether the command is valid using any associated validation attributes. /// The command line application to validate /// The context under which validation should be performed - public ValidationResult GetValidationResult(CommandLineApplication command, ValidationContext context) + public ValidationResult? GetValidationResult(CommandLineApplication command, ValidationContext context) { var model = (command as IModelAccessor)?.GetModel(); return model != null diff --git a/src/CommandLineUtils/Validation/IArgumentValidator.cs b/src/CommandLineUtils/Validation/IArgumentValidator.cs index 15f71aa1..ed50fc24 100644 --- a/src/CommandLineUtils/Validation/IArgumentValidator.cs +++ b/src/CommandLineUtils/Validation/IArgumentValidator.cs @@ -16,6 +16,6 @@ public interface IArgumentValidator /// The argument. /// The validation context. /// The validation result. Returns if the values pass validation. - ValidationResult GetValidationResult(CommandArgument argument, ValidationContext context); + ValidationResult? GetValidationResult(CommandArgument argument, ValidationContext context); } } diff --git a/src/CommandLineUtils/Validation/ICommandValidator.cs b/src/CommandLineUtils/Validation/ICommandValidator.cs index f14eb70c..1c9962dd 100644 --- a/src/CommandLineUtils/Validation/ICommandValidator.cs +++ b/src/CommandLineUtils/Validation/ICommandValidator.cs @@ -16,6 +16,6 @@ public interface ICommandValidator /// The command. /// The validation context. /// The validation result. Returns if the values pass validation. - ValidationResult GetValidationResult(CommandLineApplication command, ValidationContext context); + ValidationResult? GetValidationResult(CommandLineApplication command, ValidationContext context); } } diff --git a/src/CommandLineUtils/Validation/IOptionValidator.cs b/src/CommandLineUtils/Validation/IOptionValidator.cs index e298beba..086bde12 100644 --- a/src/CommandLineUtils/Validation/IOptionValidator.cs +++ b/src/CommandLineUtils/Validation/IOptionValidator.cs @@ -16,6 +16,6 @@ public interface IOptionValidator /// The option. /// The validation context. /// The validation result. Returns if the values pass validation. - ValidationResult GetValidationResult(CommandOption option, ValidationContext context); + ValidationResult? GetValidationResult(CommandOption option, ValidationContext context); } } diff --git a/src/Hosting.CommandLine/HostBuilderExtensions.cs b/src/Hosting.CommandLine/HostBuilderExtensions.cs index be8f4902..b27d2614 100644 --- a/src/Hosting.CommandLine/HostBuilderExtensions.cs +++ b/src/Hosting.CommandLine/HostBuilderExtensions.cs @@ -35,7 +35,7 @@ public static async Task RunCommandLineApplicationAsync( CancellationToken cancellationToken = default) where TApp : class { - return await RunCommandLineApplicationAsync(hostBuilder, args, null, cancellationToken); + return await RunCommandLineApplicationAsync(hostBuilder, args, _ => { }, cancellationToken); } /// diff --git a/test/CommandLineUtils.Tests/CustomValidationAttributeTest.cs b/test/CommandLineUtils.Tests/CustomValidationAttributeTest.cs index cc00e855..f6284cde 100644 --- a/test/CommandLineUtils.Tests/CustomValidationAttributeTest.cs +++ b/test/CommandLineUtils.Tests/CustomValidationAttributeTest.cs @@ -59,7 +59,7 @@ public RedOrBlueAttribute() { } - protected override ValidationResult IsValid(object value, ValidationContext context) + protected override ValidationResult? IsValid(object? value, ValidationContext context) { if (value == null || (value is string str && str != "red" && str != "blue")) { diff --git a/test/CommandLineUtils.Tests/McMaster.Extensions.CommandLineUtils.Tests.csproj b/test/CommandLineUtils.Tests/McMaster.Extensions.CommandLineUtils.Tests.csproj index 0a495e9f..698fd2e5 100644 --- a/test/CommandLineUtils.Tests/McMaster.Extensions.CommandLineUtils.Tests.csproj +++ b/test/CommandLineUtils.Tests/McMaster.Extensions.CommandLineUtils.Tests.csproj @@ -3,6 +3,8 @@ net5.0;netcoreapp3.1;netcoreapp2.1 $(TargetFrameworks);net472 + + annotations diff --git a/test/CommandLineUtils.Tests/ValidationTests.cs b/test/CommandLineUtils.Tests/ValidationTests.cs index b3953cb8..83f233cb 100644 --- a/test/CommandLineUtils.Tests/ValidationTests.cs +++ b/test/CommandLineUtils.Tests/ValidationTests.cs @@ -149,7 +149,8 @@ public void RequiredOption_ErrorMessage(string template, string valueName) var app = new CommandLineApplication(); app.Option(template, string.Empty, CommandOptionType.SingleValue).IsRequired(); var validation = app.GetValidationResult(); - Assert.Equal(expected, validation.ErrorMessage); + Assert.NotNull(validation); + Assert.Equal(expected, validation!.ErrorMessage); } [Fact] @@ -160,7 +161,8 @@ public void RequiredArgument_ErrorMessage() var app = new CommandLineApplication(); app.Argument("Arg", string.Empty).IsRequired(); var validation = app.GetValidationResult(); - Assert.Equal(expected, validation.ErrorMessage); + Assert.NotNull(validation); + Assert.Equal(expected, validation!.ErrorMessage); } [Subcommand(typeof(ValidationErrorSubcommand))] diff --git a/test/Hosting.CommandLine.Tests/CustomValueParserTests.cs b/test/Hosting.CommandLine.Tests/CustomValueParserTests.cs index 54a66bd1..5ef3583f 100644 --- a/test/Hosting.CommandLine.Tests/CustomValueParserTests.cs +++ b/test/Hosting.CommandLine.Tests/CustomValueParserTests.cs @@ -64,15 +64,17 @@ public async Task ItParsesUsingCustomParserFromAttribute() class CustomType { - public string Value { get; set; } + public string? Value { get; set; } } - class CustomValueParser : IValueParser + class CustomValueParser : IValueParser { public Type TargetType => typeof(CustomType); - public CustomType Parse(string? argName, string? value, CultureInfo culture) + public CustomType? Parse(string? argName, string? value, CultureInfo culture) { + if (value == null) + return null; return JsonSerializer.Deserialize(value); } @@ -86,7 +88,7 @@ public CustomType Parse(string? argName, string? value, CultureInfo culture) class CustomOptionTypeCommand { [Option("--custom-type", CommandOptionType.SingleValue)] - public CustomType Option { get; set; } + public CustomType? Option { get; set; } private int OnExecute() { @@ -126,7 +128,7 @@ public void Apply(ConventionContext context) class CustomOptionTypeCommandWithAttribute { [Option("--custom-type", CommandOptionType.SingleValue)] - public CustomType Option { get; set; } + public CustomType? Option { get; set; } private int OnExecute() { diff --git a/test/Hosting.CommandLine.Tests/HostBuilderExtensionsAttributeAPITests.cs b/test/Hosting.CommandLine.Tests/HostBuilderExtensionsAttributeAPITests.cs index 9f862204..0e9581b1 100644 --- a/test/Hosting.CommandLine.Tests/HostBuilderExtensionsAttributeAPITests.cs +++ b/test/Hosting.CommandLine.Tests/HostBuilderExtensionsAttributeAPITests.cs @@ -69,7 +69,7 @@ public async Task TestConventionInjection() [Fact] public async Task TestConfigureCommandLineApplication() { - CommandLineApplication commandLineApp = default; + CommandLineApplication? commandLineApp = null; await new HostBuilder() .RunCommandLineApplicationAsync( Array.Empty(), @@ -80,7 +80,7 @@ public async Task TestConfigureCommandLineApplication() [Fact] public async Task TestUseCommandLineApplication() { - CommandLineApplication commandLineApp = default; + CommandLineApplication? commandLineApp = null; var hostBuilder = new HostBuilder(); hostBuilder.UseCommandLineApplication(Array.Empty(), app => commandLineApp = app); var host = hostBuilder.Build(); diff --git a/test/Hosting.CommandLine.Tests/HostBuilderExtensionsBuilderAPITests.cs b/test/Hosting.CommandLine.Tests/HostBuilderExtensionsBuilderAPITests.cs index 64ae05e5..5856da8f 100644 --- a/test/Hosting.CommandLine.Tests/HostBuilderExtensionsBuilderAPITests.cs +++ b/test/Hosting.CommandLine.Tests/HostBuilderExtensionsBuilderAPITests.cs @@ -57,7 +57,7 @@ public async Task TestConventionInjection() c.Application.UnrecognizedArgumentHandling = UnrecognizedArgumentHandling.StopParsingAndCollect) .Verifiable(); var args = new[] { "Capture", "some", "test", "arguments" }; - string[] remainingArgs = null; + string[]? remainingArgs = null; await new HostBuilder() .ConfigureServices(collection => collection .AddSingleton(new TestConsole(_output)) @@ -96,7 +96,7 @@ public async Task ItRethrowsThrownExceptions() [Fact] public async Task TestUsingServiceProvider() { - IHostEnvironment env = null; + IHostEnvironment? env = null; await new HostBuilder() .ConfigureServices(collection => collection.AddSingleton(new TestConsole(_output))) @@ -111,8 +111,8 @@ public async Task TestUsingServiceProvider() [Fact] public async Task TestCommandLineContextFromNonDIContexts() { - CommandLineContext configureServicesContext = null; - CommandLineContext configureAppContext = null; + CommandLineContext? configureServicesContext = null; + CommandLineContext? configureAppContext = null; await new HostBuilder() .ConfigureServices((context, collection) => {