diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2f98df6b..8391fe20 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -42,7 +42,7 @@ jobs: with: dotnet-version: | 6.0.x - 7.0.x + 8.0.x - name: Run build script id: build_script run: ./build.ps1 -ci diff --git a/Directory.Build.props b/Directory.Build.props index c471bc63..22ffa8c3 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -28,7 +28,6 @@ $(WarningsNotAsErrors);1591 - 9.0 true enable $(MSBuildThisFileDirectory)src\StrongName.snk @@ -41,7 +40,7 @@ - 4.1.1 + 5.0.0 beta true $(GITHUB_RUN_NUMBER) @@ -53,11 +52,6 @@ $(PackageVersion)+$(RepositoryCommit) - - - - - diff --git a/docs/samples/attributes/Attributes.csproj b/docs/samples/attributes/Attributes.csproj index 2bb53ac1..29ecb192 100644 --- a/docs/samples/attributes/Attributes.csproj +++ b/docs/samples/attributes/Attributes.csproj @@ -2,7 +2,7 @@ Exe - net7.0 + net8.0 diff --git a/docs/samples/custom-attribute/CustomAttribute.csproj b/docs/samples/custom-attribute/CustomAttribute.csproj index 2bb53ac1..29ecb192 100644 --- a/docs/samples/custom-attribute/CustomAttribute.csproj +++ b/docs/samples/custom-attribute/CustomAttribute.csproj @@ -2,7 +2,7 @@ Exe - net7.0 + net8.0 diff --git a/docs/samples/custom-conventions/CustomConvention.csproj b/docs/samples/custom-conventions/CustomConvention.csproj index 2bb53ac1..29ecb192 100644 --- a/docs/samples/custom-conventions/CustomConvention.csproj +++ b/docs/samples/custom-conventions/CustomConvention.csproj @@ -2,7 +2,7 @@ Exe - net7.0 + net8.0 diff --git a/docs/samples/dependency-injection/custom/CustomServices.csproj b/docs/samples/dependency-injection/custom/CustomServices.csproj index 8c569f7c..ab539c35 100644 --- a/docs/samples/dependency-injection/custom/CustomServices.csproj +++ b/docs/samples/dependency-injection/custom/CustomServices.csproj @@ -2,7 +2,7 @@ Exe - net7.0 + net8.0 diff --git a/docs/samples/dependency-injection/generic-host/GenericHostDI.csproj b/docs/samples/dependency-injection/generic-host/GenericHostDI.csproj index d5814b02..c4ed30fb 100644 --- a/docs/samples/dependency-injection/generic-host/GenericHostDI.csproj +++ b/docs/samples/dependency-injection/generic-host/GenericHostDI.csproj @@ -2,7 +2,7 @@ Exe - net7.0 + net8.0 diff --git a/docs/samples/dependency-injection/standard/StandardServices.csproj b/docs/samples/dependency-injection/standard/StandardServices.csproj index 2bb53ac1..29ecb192 100644 --- a/docs/samples/dependency-injection/standard/StandardServices.csproj +++ b/docs/samples/dependency-injection/standard/StandardServices.csproj @@ -2,7 +2,7 @@ Exe - net7.0 + net8.0 diff --git a/docs/samples/generic-host/AttributeApi/AttributeApi.csproj b/docs/samples/generic-host/AttributeApi/AttributeApi.csproj index 413300dc..25158855 100644 --- a/docs/samples/generic-host/AttributeApi/AttributeApi.csproj +++ b/docs/samples/generic-host/AttributeApi/AttributeApi.csproj @@ -2,7 +2,7 @@ Exe - net7.0 + net8.0 diff --git a/docs/samples/generic-host/BuilderApi/BuilderApi.csproj b/docs/samples/generic-host/BuilderApi/BuilderApi.csproj index 413300dc..25158855 100644 --- a/docs/samples/generic-host/BuilderApi/BuilderApi.csproj +++ b/docs/samples/generic-host/BuilderApi/BuilderApi.csproj @@ -2,7 +2,7 @@ Exe - net7.0 + net8.0 diff --git a/docs/samples/helloworld-async-attributes/AsyncAttributes.csproj b/docs/samples/helloworld-async-attributes/AsyncAttributes.csproj index 2bb53ac1..29ecb192 100644 --- a/docs/samples/helloworld-async-attributes/AsyncAttributes.csproj +++ b/docs/samples/helloworld-async-attributes/AsyncAttributes.csproj @@ -2,7 +2,7 @@ Exe - net7.0 + net8.0 diff --git a/docs/samples/interactive-prompts/Prompt.csproj b/docs/samples/interactive-prompts/Prompt.csproj index 2bb53ac1..29ecb192 100644 --- a/docs/samples/interactive-prompts/Prompt.csproj +++ b/docs/samples/interactive-prompts/Prompt.csproj @@ -2,7 +2,7 @@ Exe - net7.0 + net8.0 diff --git a/docs/samples/pager/Pager.csproj b/docs/samples/pager/Pager.csproj index 2bb53ac1..29ecb192 100644 --- a/docs/samples/pager/Pager.csproj +++ b/docs/samples/pager/Pager.csproj @@ -2,7 +2,7 @@ Exe - net7.0 + net8.0 diff --git a/docs/samples/passthru-args/attributes/AttributesPassThru.csproj b/docs/samples/passthru-args/attributes/AttributesPassThru.csproj index 2bb53ac1..29ecb192 100644 --- a/docs/samples/passthru-args/attributes/AttributesPassThru.csproj +++ b/docs/samples/passthru-args/attributes/AttributesPassThru.csproj @@ -2,7 +2,7 @@ Exe - net7.0 + net8.0 diff --git a/docs/samples/passthru-args/builder-api/BuilderApiPassThru.csproj b/docs/samples/passthru-args/builder-api/BuilderApiPassThru.csproj index 2bb53ac1..29ecb192 100644 --- a/docs/samples/passthru-args/builder-api/BuilderApiPassThru.csproj +++ b/docs/samples/passthru-args/builder-api/BuilderApiPassThru.csproj @@ -2,7 +2,7 @@ Exe - net7.0 + net8.0 diff --git a/docs/samples/response-file-parsing/attributes/RspAttributes.csproj b/docs/samples/response-file-parsing/attributes/RspAttributes.csproj index 2bb53ac1..29ecb192 100644 --- a/docs/samples/response-file-parsing/attributes/RspAttributes.csproj +++ b/docs/samples/response-file-parsing/attributes/RspAttributes.csproj @@ -2,7 +2,7 @@ Exe - net7.0 + net8.0 diff --git a/docs/samples/response-file-parsing/builder-api/RspBuilderApi.csproj b/docs/samples/response-file-parsing/builder-api/RspBuilderApi.csproj index 2bb53ac1..29ecb192 100644 --- a/docs/samples/response-file-parsing/builder-api/RspBuilderApi.csproj +++ b/docs/samples/response-file-parsing/builder-api/RspBuilderApi.csproj @@ -2,7 +2,7 @@ Exe - net7.0 + net8.0 diff --git a/docs/samples/subcommands/builder-api/BuilderApiSubcommands.csproj b/docs/samples/subcommands/builder-api/BuilderApiSubcommands.csproj index 2bb53ac1..29ecb192 100644 --- a/docs/samples/subcommands/builder-api/BuilderApiSubcommands.csproj +++ b/docs/samples/subcommands/builder-api/BuilderApiSubcommands.csproj @@ -2,7 +2,7 @@ Exe - net7.0 + net8.0 diff --git a/docs/samples/subcommands/inheritance/InheritanceSubcommands.csproj b/docs/samples/subcommands/inheritance/InheritanceSubcommands.csproj index 2bb53ac1..29ecb192 100644 --- a/docs/samples/subcommands/inheritance/InheritanceSubcommands.csproj +++ b/docs/samples/subcommands/inheritance/InheritanceSubcommands.csproj @@ -2,7 +2,7 @@ Exe - net7.0 + net8.0 diff --git a/docs/samples/subcommands/nested-types/NestedTypeSubcommands.csproj b/docs/samples/subcommands/nested-types/NestedTypeSubcommands.csproj index 2bb53ac1..29ecb192 100644 --- a/docs/samples/subcommands/nested-types/NestedTypeSubcommands.csproj +++ b/docs/samples/subcommands/nested-types/NestedTypeSubcommands.csproj @@ -2,7 +2,7 @@ Exe - net7.0 + net8.0 diff --git a/docs/samples/validation/attributes/Program.cs b/docs/samples/validation/attributes/Program.cs index e90535ff..1eba78eb 100644 --- a/docs/samples/validation/attributes/Program.cs +++ b/docs/samples/validation/attributes/Program.cs @@ -5,6 +5,9 @@ using System.ComponentModel.DataAnnotations; using System.Linq; using McMaster.Extensions.CommandLineUtils; +// This is required since .NET 8 introduced a new type System.ComponentModel.DataAnnotations.AllowedValuesAttribute +// which conflicts with the attribute in this library (added long before .NET 8.) +using AllowedValues = McMaster.Extensions.CommandLineUtils.AllowedValuesAttribute; [MaxSizeOptionRequiresAttachmentValidation()] class AttributeProgram diff --git a/docs/samples/validation/attributes/ValidationAttributes.csproj b/docs/samples/validation/attributes/ValidationAttributes.csproj index 2bb53ac1..29ecb192 100644 --- a/docs/samples/validation/attributes/ValidationAttributes.csproj +++ b/docs/samples/validation/attributes/ValidationAttributes.csproj @@ -2,7 +2,7 @@ Exe - net7.0 + net8.0 diff --git a/docs/samples/validation/builder-api/ValidationBuilderApi.csproj b/docs/samples/validation/builder-api/ValidationBuilderApi.csproj index 2bb53ac1..29ecb192 100644 --- a/docs/samples/validation/builder-api/ValidationBuilderApi.csproj +++ b/docs/samples/validation/builder-api/ValidationBuilderApi.csproj @@ -2,7 +2,7 @@ Exe - net7.0 + net8.0 diff --git a/src/CommandLineUtils/Abstractions/CommandLineContext.cs b/src/CommandLineUtils/Abstractions/CommandLineContext.cs index ecdb6107..20845572 100644 --- a/src/CommandLineUtils/Abstractions/CommandLineContext.cs +++ b/src/CommandLineUtils/Abstractions/CommandLineContext.cs @@ -11,7 +11,7 @@ namespace McMaster.Extensions.CommandLineUtils.Abstractions /// public abstract class CommandLineContext { - private string[] _args = new string[0]; + private string[] _args = Array.Empty(); private string _workDir = Directory.GetCurrentDirectory(); private IConsole _console = PhysicalConsole.Singleton; diff --git a/src/CommandLineUtils/Abstractions/ValueParserProvider.cs b/src/CommandLineUtils/Abstractions/ValueParserProvider.cs index 07ff412a..d7b694df 100644 --- a/src/CommandLineUtils/Abstractions/ValueParserProvider.cs +++ b/src/CommandLineUtils/Abstractions/ValueParserProvider.cs @@ -61,7 +61,11 @@ private static readonly MethodInfo s_getParserGeneric public IValueParser GetParser(Type type) { var method = s_getParserGeneric.MakeGenericMethod(type); +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. +#pragma warning disable CS8603 // Possible null reference return. return (IValueParser)method.Invoke(this, Array.Empty()); +#pragma warning restore CS8603 // Possible null reference return. +#pragma warning restore CS8600 // Converting null literal or possible null value to non-nullable type. } /// @@ -121,8 +125,12 @@ public IValueParser GetParser(Type type) { return null; } +#pragma warning disable CS8602 // Dereference of a possibly null reference. var method = typeof(ValueTupleValueParser).GetMethod(nameof(ValueTupleValueParser.Create)).MakeGenericMethod(type.GenericTypeArguments[1]); +#pragma warning restore CS8602 // Dereference of a possibly null reference. +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. return (IValueParser)method.Invoke(null, new object[] { innerParser }); +#pragma warning restore CS8600 // Converting null literal or possible null value to non-nullable type. } return null; diff --git a/src/CommandLineUtils/Attributes/AllowedValuesAttribute.cs b/src/CommandLineUtils/Attributes/AllowedValuesAttribute.cs index 5bdc527b..998e0123 100644 --- a/src/CommandLineUtils/Attributes/AllowedValuesAttribute.cs +++ b/src/CommandLineUtils/Attributes/AllowedValuesAttribute.cs @@ -40,7 +40,7 @@ public AllowedValuesAttribute(params string[] allowedValues) public AllowedValuesAttribute(StringComparison comparer, params string[] allowedValues) : base(GetDefaultError(allowedValues)) { - _allowedValues = allowedValues ?? new string[0]; + _allowedValues = allowedValues ?? Array.Empty(); Comparer = comparer; } diff --git a/src/CommandLineUtils/Attributes/VersionOptionFromMemberAttribute.cs b/src/CommandLineUtils/Attributes/VersionOptionFromMemberAttribute.cs index e09e53e3..058759df 100644 --- a/src/CommandLineUtils/Attributes/VersionOptionFromMemberAttribute.cs +++ b/src/CommandLineUtils/Attributes/VersionOptionFromMemberAttribute.cs @@ -60,7 +60,11 @@ internal CommandOption Configure(CommandLineApplication app, Type type, Func { +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. +#pragma warning disable CS8603 // Possible null reference return. return (string)methods[0].Invoke(targetInstanceFactory.Invoke(), Array.Empty()); +#pragma warning restore CS8603 // Possible null reference return. +#pragma warning restore CS8600 // Converting null literal or possible null value to non-nullable type. }; } diff --git a/src/CommandLineUtils/CommandArgument{T}.cs b/src/CommandLineUtils/CommandArgument{T}.cs index e3492011..27a8169f 100644 --- a/src/CommandLineUtils/CommandArgument{T}.cs +++ b/src/CommandLineUtils/CommandArgument{T}.cs @@ -38,7 +38,9 @@ public CommandArgument(IValueParser valueParser) /// /// The parsed value. /// +#pragma warning disable CS8603 // Possible null reference return. public T ParsedValue => ParsedValues.FirstOrDefault(); +#pragma warning restore CS8603 // Possible null reference return. /// /// All parsed values; diff --git a/src/CommandLineUtils/CommandLineApplication.cs b/src/CommandLineUtils/CommandLineApplication.cs index a7138445..7fc9a5e3 100644 --- a/src/CommandLineUtils/CommandLineApplication.cs +++ b/src/CommandLineUtils/CommandLineApplication.cs @@ -877,13 +877,17 @@ void cancelHandler(object o, ConsoleCancelEventArgs e) try { +#pragma warning disable CS8622 // Nullability of reference types in type of parameter doesn't match the target delegate (possibly because of nullability attributes). _context.Console.CancelKeyPress += cancelHandler; +#pragma warning restore CS8622 // Nullability of reference types in type of parameter doesn't match the target delegate (possibly because of nullability attributes). return await command._handler(handlerCancellationTokenSource.Token); } finally { +#pragma warning disable CS8622 // Nullability of reference types in type of parameter doesn't match the target delegate (possibly because of nullability attributes). _context.Console.CancelKeyPress -= cancelHandler; +#pragma warning restore CS8622 // Nullability of reference types in type of parameter doesn't match the target delegate (possibly because of nullability attributes). } } @@ -1146,7 +1150,9 @@ public virtual void Dispose() internal IServiceProvider? AdditionalServices { get; set; } +#pragma warning disable CS8603 // Possible null reference return. object IServiceProvider.GetService(Type serviceType) => _services.Value.GetService(serviceType); +#pragma warning restore CS8603 // Possible null reference return. private sealed class ServiceProvider : IServiceProvider { diff --git a/src/CommandLineUtils/CommandLineApplicationExtensions.cs b/src/CommandLineUtils/CommandLineApplicationExtensions.cs index e369e47b..d2960232 100644 --- a/src/CommandLineUtils/CommandLineApplicationExtensions.cs +++ b/src/CommandLineUtils/CommandLineApplicationExtensions.cs @@ -176,9 +176,11 @@ public static CommandOption VersionOptionFromAssemblyAttributes(this CommandLine var infoVersion = assembly ?.GetCustomAttribute() ?.InformationalVersion; +#pragma warning disable CS8602 // Dereference of a possibly null reference. return string.IsNullOrWhiteSpace(infoVersion) ? assembly?.GetName().Version.ToString() : infoVersion; +#pragma warning restore CS8602 // Dereference of a possibly null reference. } } } diff --git a/src/CommandLineUtils/CommandOption{T}.cs b/src/CommandLineUtils/CommandOption{T}.cs index b15ec78d..db549d17 100644 --- a/src/CommandLineUtils/CommandOption{T}.cs +++ b/src/CommandLineUtils/CommandOption{T}.cs @@ -39,7 +39,9 @@ public CommandOption(IValueParser valueParser, string template, CommandOption /// /// The parsed value. /// +#pragma warning disable CS8603 // Possible null reference return. public T ParsedValue => ParsedValues.FirstOrDefault(); +#pragma warning restore CS8603 // Possible null reference return. /// /// All parsed values; diff --git a/src/CommandLineUtils/Conventions/ArgumentAttributeConvention.cs b/src/CommandLineUtils/Conventions/ArgumentAttributeConvention.cs index 2545e2d4..5b7949a9 100644 --- a/src/CommandLineUtils/Conventions/ArgumentAttributeConvention.cs +++ b/src/CommandLineUtils/Conventions/ArgumentAttributeConvention.cs @@ -151,6 +151,7 @@ private void AddArgument(PropertyInfo prop, if (r.SelectedCommand is IModelAccessor cmd) { var model = cmd.GetModel(); +#pragma warning disable CS8602 // Dereference of a possibly null reference. if (prop.DeclaringType.IsAssignableFrom(model.GetType())) { if (argument.Values.Count == 0) @@ -175,6 +176,7 @@ private void AddArgument(PropertyInfo prop, convention.Application.ValueParsers.ParseCulture)); } } +#pragma warning restore CS8602 // Dereference of a possibly null reference. } }); } diff --git a/src/CommandLineUtils/Conventions/ConstructorInjectionConvention.cs b/src/CommandLineUtils/Conventions/ConstructorInjectionConvention.cs index 7a0d613b..406de96f 100644 --- a/src/CommandLineUtils/Conventions/ConstructorInjectionConvention.cs +++ b/src/CommandLineUtils/Conventions/ConstructorInjectionConvention.cs @@ -94,9 +94,11 @@ private void ApplyImpl(ConventionContext context) goto nextCtor; } +#pragma warning disable CS8604 // Possible null reference argument. return () => throw new InvalidOperationException( Strings.NoParameterTypeRegistered(ctorCandidate.DeclaringType, paramType)); +#pragma warning restore CS8604 // Possible null reference argument. } args[i] = service; diff --git a/src/CommandLineUtils/Conventions/ExecuteMethodConvention.cs b/src/CommandLineUtils/Conventions/ExecuteMethodConvention.cs index f682bd89..b469ad41 100644 --- a/src/CommandLineUtils/Conventions/ExecuteMethodConvention.cs +++ b/src/CommandLineUtils/Conventions/ExecuteMethodConvention.cs @@ -79,17 +79,23 @@ private async Task InvokeAsync(MethodInfo method, object instance, object?[ { try { +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. var result = (Task)method.Invoke(instance, arguments); +#pragma warning restore CS8600 // Converting null literal or possible null value to non-nullable type. if (result is Task intResult) { return await intResult; } +#pragma warning disable CS8602 // Dereference of a possibly null reference. await result; +#pragma warning restore CS8602 // Dereference of a possibly null reference. } catch (TargetInvocationException e) { +#pragma warning disable CS8604 // Possible null reference argument. ExceptionDispatchInfo.Capture(e.InnerException).Throw(); +#pragma warning restore CS8604 // Possible null reference argument. } return 0; @@ -102,12 +108,16 @@ private int Invoke(MethodInfo method, object instance, object?[] arguments) var result = method.Invoke(instance, arguments); if (method.ReturnType == typeof(int)) { +#pragma warning disable CS8605 // Unboxing a possibly null value. return (int)result; +#pragma warning restore CS8605 // Unboxing a possibly null value. } } catch (TargetInvocationException e) { +#pragma warning disable CS8604 // Possible null reference argument. ExceptionDispatchInfo.Capture(e.InnerException).Throw(); +#pragma warning restore CS8604 // Possible null reference argument. } return 0; diff --git a/src/CommandLineUtils/Conventions/ValidateMethodConvention.cs b/src/CommandLineUtils/Conventions/ValidateMethodConvention.cs index 924982bc..bddc1856 100644 --- a/src/CommandLineUtils/Conventions/ValidateMethodConvention.cs +++ b/src/CommandLineUtils/Conventions/ValidateMethodConvention.cs @@ -59,7 +59,11 @@ public void Apply(ConventionContext context) } } +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. +#pragma warning disable CS8603 // Possible null reference return. return (ValidationResult)method.Invoke(modelAccessor.GetModel(), arguments); +#pragma warning restore CS8603 // Possible null reference return. +#pragma warning restore CS8600 // Converting null literal or possible null value to non-nullable type. }); } } diff --git a/src/CommandLineUtils/Conventions/ValidationErrorMethodConvention.cs b/src/CommandLineUtils/Conventions/ValidationErrorMethodConvention.cs index 7104c789..db7021aa 100644 --- a/src/CommandLineUtils/Conventions/ValidationErrorMethodConvention.cs +++ b/src/CommandLineUtils/Conventions/ValidationErrorMethodConvention.cs @@ -34,7 +34,9 @@ public virtual void Apply(ConventionContext context) var result = method.Invoke(modelAccessor.GetModel(), arguments); if (method.ReturnType == typeof(int)) { +#pragma warning disable CS8605 // Unboxing a possibly null value. return (int)result; +#pragma warning restore CS8605 // Unboxing a possibly null value. } return CommandLineApplication.ValidationErrorExitCode; diff --git a/src/CommandLineUtils/IO/Pager.cs b/src/CommandLineUtils/IO/Pager.cs index 8384f0a1..31559ec4 100644 --- a/src/CommandLineUtils/IO/Pager.cs +++ b/src/CommandLineUtils/IO/Pager.cs @@ -42,15 +42,7 @@ public Pager(IConsole console) throw new ArgumentNullException(nameof(console)); } -#if NET46_OR_GREATER - // if .NET Framework, assume we're on Windows unless it's running on Mono. - _enabled = Type.GetType("Mono.Runtime") != null; -#elif NETSTANDARD2_0_OR_GREATER _enabled = !RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && !console.IsOutputRedirected; -#else -#error Update target frameworks -#endif - _less = new Lazy(CreateWriter); _fallbackWriter = console.Out; } diff --git a/src/CommandLineUtils/Internal/CollectionParserProvider.cs b/src/CommandLineUtils/Internal/CollectionParserProvider.cs index 350dea2d..3f336221 100644 --- a/src/CommandLineUtils/Internal/CollectionParserProvider.cs +++ b/src/CommandLineUtils/Internal/CollectionParserProvider.cs @@ -20,7 +20,9 @@ private CollectionParserProvider() if (type.IsArray) { var elementType = type.GetElementType(); +#pragma warning disable CS8604 // Possible null reference argument. var elementParser = valueParsers.GetParser(elementType); +#pragma warning restore CS8604 // Possible null reference argument. return new ArrayParser(elementType, elementParser, valueParsers.ParseCulture); } diff --git a/src/CommandLineUtils/Internal/ReflectionHelper.cs b/src/CommandLineUtils/Internal/ReflectionHelper.cs index 3a3b7f04..07b6daec 100644 --- a/src/CommandLineUtils/Internal/ReflectionHelper.cs +++ b/src/CommandLineUtils/Internal/ReflectionHelper.cs @@ -25,7 +25,9 @@ public static SetPropertyDelegate GetPropertySetter(PropertyInfo prop) } else { +#pragma warning disable CS8602 // Dereference of a possibly null reference. var backingField = prop.DeclaringType.GetField($"<{prop.Name}>k__BackingField", DeclaredOnlyLookup); +#pragma warning restore CS8602 // Dereference of a possibly null reference. if (backingField == null) { throw new InvalidOperationException( @@ -41,30 +43,40 @@ public static GetPropertyDelegate GetPropertyGetter(PropertyInfo prop) var getter = prop.GetGetMethod(nonPublic: true); if (getter != null) { - return obj => getter.Invoke(obj, new object[] { }); +#pragma warning disable CS8603 // Possible null reference return. + return obj => getter.Invoke(obj, Array.Empty()); +#pragma warning restore CS8603 // Possible null reference return. } else { +#pragma warning disable CS8602 // Dereference of a possibly null reference. var backingField = prop.DeclaringType.GetField($"<{prop.Name}>k__BackingField", DeclaredOnlyLookup); +#pragma warning restore CS8602 // Dereference of a possibly null reference. if (backingField == null) { throw new InvalidOperationException( $"Could not find a way to get {prop.DeclaringType.FullName}.{prop.Name}. Try adding a getter."); } +#pragma warning disable CS8603 // Possible null reference return. return obj => backingField.GetValue(obj); +#pragma warning restore CS8603 // Possible null reference return. } } public static MethodInfo[] GetPropertyOrMethod(Type type, string name) { var members = GetAllMembers(type).ToList(); +#pragma warning disable CS8602 // Dereference of a possibly null reference. +#pragma warning disable CS8619 // Nullability of reference types in value doesn't match target type. return members .OfType() .Where(m => m.Name == name) .Concat(members.OfType().Where(m => m.Name == name).Select(p => p.GetMethod)) .Where(m => m.ReturnType == typeof(string) && m.GetParameters().Length == 0) .ToArray(); +#pragma warning restore CS8619 // Nullability of reference types in value doesn't match target type. +#pragma warning restore CS8602 // Dereference of a possibly null reference. } public static PropertyInfo[] GetProperties(Type type) @@ -156,7 +168,9 @@ private static IEnumerable GetAllMembers(Type type) yield return member; } +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. type = type.BaseType; +#pragma warning restore CS8600 // Converting null literal or possible null value to non-nullable type. } } } diff --git a/src/CommandLineUtils/Internal/ValueParsers/HashSetParser.cs b/src/CommandLineUtils/Internal/ValueParsers/HashSetParser.cs index fb84cd23..9951b054 100644 --- a/src/CommandLineUtils/Internal/ValueParsers/HashSetParser.cs +++ b/src/CommandLineUtils/Internal/ValueParsers/HashSetParser.cs @@ -15,11 +15,15 @@ internal class HashSetParser : ICollectionParser private readonly MethodInfo _addMethod; private readonly CultureInfo _parserCulture; +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. public HashSetParser(Type elementType, IValueParser elementParser, CultureInfo parserCulture) +#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. { _elementParser = elementParser; _listType = typeof(HashSet<>).MakeGenericType(elementType); +#pragma warning disable CS8601 // Possible null reference assignment. _addMethod = _listType.GetRuntimeMethod("Add", new[] { elementType }); +#pragma warning restore CS8601 // Possible null reference assignment. _parserCulture = parserCulture; } @@ -30,7 +34,9 @@ public object Parse(string? argName, IReadOnlyList values) { _addMethod.Invoke(set, new[] { _elementParser.Parse(argName, t, _parserCulture) }); } +#pragma warning disable CS8603 // Possible null reference return. return set; +#pragma warning restore CS8603 // Possible null reference return. } } } diff --git a/src/CommandLineUtils/Internal/ValueParsers/ListParser.cs b/src/CommandLineUtils/Internal/ValueParsers/ListParser.cs index 33b0cfd1..d7ceaf8b 100644 --- a/src/CommandLineUtils/Internal/ValueParsers/ListParser.cs +++ b/src/CommandLineUtils/Internal/ValueParsers/ListParser.cs @@ -24,12 +24,18 @@ public ListParser(Type elementType, IValueParser elementParser, CultureInfo pars public object Parse(string? argName, IReadOnlyList values) { +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. var list = (IList)Activator.CreateInstance(_listType, new object[] { values.Count }); +#pragma warning restore CS8600 // Converting null literal or possible null value to non-nullable type. foreach (var t in values) { +#pragma warning disable CS8602 // Dereference of a possibly null reference. list.Add(_elementParser.Parse(argName, t, _parserCulture)); +#pragma warning restore CS8602 // Dereference of a possibly null reference. } +#pragma warning disable CS8603 // Possible null reference return. return list; +#pragma warning restore CS8603 // Possible null reference return. } } } diff --git a/src/CommandLineUtils/Internal/ValueParsers/StockValueParsers.cs b/src/CommandLineUtils/Internal/ValueParsers/StockValueParsers.cs index 8361d632..13d4b12a 100644 --- a/src/CommandLineUtils/Internal/ValueParsers/StockValueParsers.cs +++ b/src/CommandLineUtils/Internal/ValueParsers/StockValueParsers.cs @@ -40,7 +40,9 @@ internal static class StockValueParsers public static readonly IValueParser String = ValueParser.Create((_, value, __) => value); public static readonly IValueParser Uri = ValueParser.Create( +#pragma warning disable CS8604 // Possible null reference argument. (_, value, culture) => new Uri(value, UriKind.RelativeOrAbsolute)); +#pragma warning restore CS8604 // Possible null reference argument. private static FormatException InvalidValueException(string? argName, string specifics) => new($"Invalid value specified for {argName}. {specifics}"); diff --git a/src/CommandLineUtils/Internal/ValueParsers/TypeDescriptorValueParserFactory.cs b/src/CommandLineUtils/Internal/ValueParsers/TypeDescriptorValueParserFactory.cs index 46ead25f..930b1339 100644 --- a/src/CommandLineUtils/Internal/ValueParsers/TypeDescriptorValueParserFactory.cs +++ b/src/CommandLineUtils/Internal/ValueParsers/TypeDescriptorValueParserFactory.cs @@ -45,7 +45,13 @@ public T Parse(string? argName, string? value, CultureInfo culture) try { culture ??= CultureInfo.InvariantCulture; +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. +#pragma warning disable CS8603 // Possible null reference return. +#pragma warning disable CS8604 // Possible null reference argument. return (T)TypeConverter.ConvertFromString(null, culture, value); +#pragma warning restore CS8604 // Possible null reference argument. +#pragma warning restore CS8603 // Possible null reference return. +#pragma warning restore CS8600 // Converting null literal or possible null value to non-nullable type. } catch (ArgumentException e) { diff --git a/src/CommandLineUtils/McMaster.Extensions.CommandLineUtils.csproj b/src/CommandLineUtils/McMaster.Extensions.CommandLineUtils.csproj index 6e86abd6..d3f8037a 100644 --- a/src/CommandLineUtils/McMaster.Extensions.CommandLineUtils.csproj +++ b/src/CommandLineUtils/McMaster.Extensions.CommandLineUtils.csproj @@ -1,8 +1,7 @@  - netstandard2.1;netstandard2.0;net46 - annotations + net6.0 true true Command-line parsing API. @@ -22,16 +21,6 @@ McMaster.Extensions.CommandLineUtils.ArgumentEscaper README.md - - - - - - - - - - diff --git a/src/CommandLineUtils/Properties/Strings.cs b/src/CommandLineUtils/Properties/Strings.cs index 70f5d871..3d58d6ac 100644 --- a/src/CommandLineUtils/Properties/Strings.cs +++ b/src/CommandLineUtils/Properties/Strings.cs @@ -40,31 +40,31 @@ public static string InvalidOnValidateReturnType(Type modelType) public static string CannotDetermineOptionType(PropertyInfo member) => $"Could not automatically determine the {nameof(CommandOptionType)} for type {member.PropertyType.FullName}. " + - $"Set the {nameof(OptionAttribute.OptionType)} on the {nameof(OptionAttribute)} declaration for {member.DeclaringType.FullName}.{member.Name}."; + $"Set the {nameof(OptionAttribute.OptionType)} on the {nameof(OptionAttribute)} declaration for {member.DeclaringType?.FullName}.{member.Name}."; public static string OptionNameIsAmbiguous(string optionName, PropertyInfo first, PropertyInfo second) - => $"Ambiguous option name. Both {first.DeclaringType.FullName}.{first.Name} and {second.DeclaringType.FullName}.{second.Name} produce a CommandOption with the name '{optionName}'."; + => $"Ambiguous option name. Both {first.DeclaringType?.FullName}.{first.Name} and {second.DeclaringType?.FullName}.{second.Name} produce a CommandOption with the name '{optionName}'."; public static string DuplicateSubcommandName(string commandName) => $"The subcommand name '{commandName}' has already been been specified. Subcommand names must be unique."; public static string BothOptionAndArgumentAttributesCannotBeSpecified(PropertyInfo prop) - => $"Cannot specify both {nameof(OptionAttribute)} and {nameof(ArgumentAttribute)} on property {prop.DeclaringType.Name}.{prop.Name}."; + => $"Cannot specify both {nameof(OptionAttribute)} and {nameof(ArgumentAttribute)} on property {prop.DeclaringType?.Name}.{prop.Name}."; public static string BothOptionAndHelpOptionAttributesCannotBeSpecified(PropertyInfo prop) - => $"Cannot specify both {nameof(OptionAttribute)} and {nameof(HelpOptionAttribute)} on property {prop.DeclaringType.Name}.{prop.Name}."; + => $"Cannot specify both {nameof(OptionAttribute)} and {nameof(HelpOptionAttribute)} on property {prop.DeclaringType?.Name}.{prop.Name}."; public static string BothOptionAndVersionOptionAttributesCannotBeSpecified(PropertyInfo prop) - => $"Cannot specify both {nameof(OptionAttribute)} and {nameof(VersionOptionAttribute)} on property {prop.DeclaringType.Name}.{prop.Name}."; + => $"Cannot specify both {nameof(OptionAttribute)} and {nameof(VersionOptionAttribute)} on property {prop.DeclaringType?.Name}.{prop.Name}."; internal static string UnsupportedParameterTypeOnMethod(string methodName, ParameterInfo methodParam) => $"Unsupported type on {methodName} '{methodParam.ParameterType.FullName}' on parameter {methodParam.Name}."; public static string BothHelpOptionAndVersionOptionAttributesCannotBeSpecified(PropertyInfo prop) - => $"Cannot specify both {nameof(HelpOptionAttribute)} and {nameof(VersionOptionAttribute)} on property {prop.DeclaringType.Name}.{prop.Name}."; + => $"Cannot specify both {nameof(HelpOptionAttribute)} and {nameof(VersionOptionAttribute)} on property {prop.DeclaringType?.Name}.{prop.Name}."; public static string DuplicateArgumentPosition(int order, PropertyInfo first, PropertyInfo second) - => $"Duplicate value for argument order. Both {first.DeclaringType.FullName}.{first.Name} and {second.DeclaringType.FullName}.{second.Name} have set Order = {order}."; + => $"Duplicate value for argument order. Both {first.DeclaringType?.FullName}.{first.Name} and {second.DeclaringType?.FullName}.{second.Name} have set Order = {order}."; public static string OnlyLastArgumentCanAllowMultipleValues(string? lastArgName) => $"The last argument '{lastArgName}' accepts multiple values. No more argument can be added."; @@ -73,7 +73,7 @@ public static string CannotDetermineParserType(Type type) => $"Could not automatically determine how to convert string values into {type.FullName}."; public static string CannotDetermineParserType(PropertyInfo prop) - => $"Could not automatically determine how to convert string values into {prop.PropertyType.FullName} on property {prop.DeclaringType.Name}.{prop.Name}."; + => $"Could not automatically determine how to convert string values into {prop.PropertyType.FullName} on property {prop.DeclaringType?.Name}.{prop.Name}."; public const string HelpOptionOnTypeAndProperty = "Multiple HelpOptionAttributes found. HelpOptionAttribute should only be used one per type, either on one property or on the type."; diff --git a/src/CommandLineUtils/Utilities/DotNetExe.cs b/src/CommandLineUtils/Utilities/DotNetExe.cs index 2e1f8e8f..e7424021 100644 --- a/src/CommandLineUtils/Utilities/DotNetExe.cs +++ b/src/CommandLineUtils/Utilities/DotNetExe.cs @@ -43,9 +43,6 @@ public static string FullPathOrDefault() private static string? TryFindDotNetExePath() { var fileName = FileName; -#if NET46_OR_GREATER - fileName += ".exe"; -#elif NETSTANDARD2_0_OR_GREATER if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { fileName += ".exe"; @@ -57,9 +54,7 @@ public static string FullPathOrDefault() { return mainModule.FileName; } -#else -#error Update target frameworks -#endif + // DOTNET_ROOT specifies the location of the .NET runtimes, if they are not installed in the default location. var dotnetRoot = Environment.GetEnvironmentVariable("DOTNET_ROOT"); diff --git a/src/CommandLineUtils/Utilities/Prompt.cs b/src/CommandLineUtils/Utilities/Prompt.cs index 0e100691..d7c90d2e 100644 --- a/src/CommandLineUtils/Utilities/Prompt.cs +++ b/src/CommandLineUtils/Utilities/Prompt.cs @@ -79,7 +79,7 @@ public static bool GetYesNo(string prompt, bool defaultAnswer, ConsoleColor? pro Write(prompt, promptColor, promptBgColor); Console.Write(' '); - string resp; + string? resp; using (ShowCursor()) { resp = Console.ReadLine(); @@ -284,7 +284,9 @@ public CursorState() { try { +#pragma warning disable CA1416 // Validate platform compatibility _original = Console.CursorVisible; +#pragma warning restore CA1416 // Validate platform compatibility } catch { diff --git a/src/CommandLineUtils/Validation/ValidationExtensions.cs b/src/CommandLineUtils/Validation/ValidationExtensions.cs index 0df19e2b..4dbdadaa 100644 --- a/src/CommandLineUtils/Validation/ValidationExtensions.cs +++ b/src/CommandLineUtils/Validation/ValidationExtensions.cs @@ -455,12 +455,18 @@ private static IValidationBuilder Satisfies(this IValidationBuilder builder, Val private static T GetValidationAttr(string? errorMessage, object[]? ctorArgs = null) where T : ValidationAttribute { - var attribute = (T)Activator.CreateInstance(typeof(T), ctorArgs ?? new object[0]); +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. + var attribute = (T)Activator.CreateInstance(typeof(T), ctorArgs ?? Array.Empty()); +#pragma warning restore CS8600 // Converting null literal or possible null value to non-nullable type. if (errorMessage != null) { +#pragma warning disable CS8602 // Dereference of a possibly null reference. attribute.ErrorMessage = errorMessage; +#pragma warning restore CS8602 // Dereference of a possibly null reference. } +#pragma warning disable CS8603 // Possible null reference return. return attribute; +#pragma warning restore CS8603 // Possible null reference return. } private static T AddErrorMessage(T attribute, string? errorMessage) diff --git a/src/Directory.Build.targets b/src/Directory.Build.targets index 5f7f297f..ea33f241 100644 --- a/src/Directory.Build.targets +++ b/src/Directory.Build.targets @@ -1,7 +1,7 @@ - + diff --git a/src/Hosting.CommandLine/McMaster.Extensions.Hosting.CommandLine.csproj b/src/Hosting.CommandLine/McMaster.Extensions.Hosting.CommandLine.csproj index 166399bc..af94d444 100644 --- a/src/Hosting.CommandLine/McMaster.Extensions.Hosting.CommandLine.csproj +++ b/src/Hosting.CommandLine/McMaster.Extensions.Hosting.CommandLine.csproj @@ -1,7 +1,7 @@ - netstandard2.1;netstandard2.0 + net6.0 true true Provides command-line parsing API integration with the generic host API (Microsoft.Extensions.Hosting). diff --git a/test/CommandLineUtils.Tests/FilePathExistsAttributeTests.cs b/test/CommandLineUtils.Tests/FilePathExistsAttributeTests.cs index c561c38c..63fd189c 100644 --- a/test/CommandLineUtils.Tests/FilePathExistsAttributeTests.cs +++ b/test/CommandLineUtils.Tests/FilePathExistsAttributeTests.cs @@ -179,7 +179,7 @@ private class OptionalFileChecks { [DirectoryExists] [Option] - public string[] Dir { get; } = new string[0]; + public string[] Dir { get; } = Array.Empty(); [FileExists] [Option] diff --git a/test/CommandLineUtils.Tests/McMaster.Extensions.CommandLineUtils.Tests.csproj b/test/CommandLineUtils.Tests/McMaster.Extensions.CommandLineUtils.Tests.csproj index a04e46db..1ab1af5f 100644 --- a/test/CommandLineUtils.Tests/McMaster.Extensions.CommandLineUtils.Tests.csproj +++ b/test/CommandLineUtils.Tests/McMaster.Extensions.CommandLineUtils.Tests.csproj @@ -1,8 +1,7 @@  - net8.0;net7.0;net6.0 - $(TargetFrameworks);net472 + net8.0;net6.0 annotations @@ -11,10 +10,6 @@ - - - - diff --git a/test/CommandLineUtils.Tests/OptionAttributeTests.cs b/test/CommandLineUtils.Tests/OptionAttributeTests.cs index f15def5b..cb1da1c5 100644 --- a/test/CommandLineUtils.Tests/OptionAttributeTests.cs +++ b/test/CommandLineUtils.Tests/OptionAttributeTests.cs @@ -153,7 +153,7 @@ private class OptionHasDefaultValues public (bool hasValue, string value) Arg4 { get; } = (false, "Yellow"); [Option("-a5")] - public string[] Arg5 { get; } = new string[0]; + public string[] Arg5 { get; } = Array.Empty(); } [Fact] @@ -206,7 +206,7 @@ private class AppWithMultiValueStringOption string[] Opt1 { get; } [Option("-o2")] - string[] Opt2 { get; } = new string[0]; + string[] Opt2 { get; } = Array.Empty(); } [Fact] diff --git a/test/Hosting.CommandLine.Tests/McMaster.Extensions.Hosting.CommandLine.Tests.csproj b/test/Hosting.CommandLine.Tests/McMaster.Extensions.Hosting.CommandLine.Tests.csproj index 8760e52a..5e19f487 100644 --- a/test/Hosting.CommandLine.Tests/McMaster.Extensions.Hosting.CommandLine.Tests.csproj +++ b/test/Hosting.CommandLine.Tests/McMaster.Extensions.Hosting.CommandLine.Tests.csproj @@ -1,18 +1,13 @@  - net8.0;net7.0;net6.0 - $(TargetFrameworks);net472 + net8.0;net6.0 - - - -