diff --git a/src/System.CommandLine.Tests/ArgumentTests.cs b/src/System.CommandLine.Tests/ArgumentTests.cs index 50a57a5254..10e2483805 100644 --- a/src/System.CommandLine.Tests/ArgumentTests.cs +++ b/src/System.CommandLine.Tests/ArgumentTests.cs @@ -56,6 +56,26 @@ public void When_there_is_no_default_value_then_GetDefaultValue_throws() .Be("Argument \"the-arg\" does not have a default value"); } + [Fact] + public void When_argument_type_is_set_to_null_then_it_throws() + { + var argument = new Argument(); + + argument.Invoking(a => a.ArgumentType = null) + .Should() + .Throw(); + } + + [Fact] + public void By_default_the_argument_type_is_void() + { + var argument = new Argument(); + + argument.ArgumentType + .Should() + .Be(typeof(void)); + } + public class CustomParsing { [Fact] diff --git a/src/System.CommandLine/Argument.cs b/src/System.CommandLine/Argument.cs index 3e1a16ca4d..1f41bdac78 100644 --- a/src/System.CommandLine/Argument.cs +++ b/src/System.CommandLine/Argument.cs @@ -11,33 +11,34 @@ namespace System.CommandLine { public class Argument : Symbol, IArgument { - private Func _defaultValueFactory; + private Func? _defaultValueFactory; private readonly List _suggestions = new List(); private readonly List _suggestionSources = new List(); - private IArgumentArity _arity; - private TryConvertArgument _convertArguments; + private IArgumentArity? _arity; + private TryConvertArgument? _convertArguments; + private Type _argumentType = typeof(void); public Argument() { } - public Argument(string name) + public Argument(string? name) { if (!string.IsNullOrWhiteSpace(name)) { - Name = name; + Name = name!; } } - internal HashSet AllowedValues { get; private set; } + internal HashSet? AllowedValues { get; private set; } public IArgumentArity Arity { get { - if (_arity == null) + if (_arity is null) { - if (ArgumentType != null) + if (ArgumentType != typeof(void)) { return ArgumentArity.Default(ArgumentType, this, Parents.FirstOrDefault()); } @@ -52,19 +53,19 @@ public IArgumentArity Arity set => _arity = value; } - internal TryConvertArgument ConvertArguments + internal TryConvertArgument? ConvertArguments { get { if (_convertArguments == null && - ArgumentType != null) + ArgumentType != typeof(void)) { if (ArgumentType.CanBeBoundFromScalarValue()) { if (Arity.MaximumNumberOfValues == 1 && ArgumentType == typeof(bool)) { - _convertArguments = (ArgumentResult symbol, out object value) => + _convertArguments = (ArgumentResult symbol, out object? value) => { value = ArgumentConverter.ConvertObject( this, @@ -108,18 +109,22 @@ bool DefaultConvert(SymbolResult symbol, out object value) set => _convertArguments = value; } - public Type ArgumentType { get; set; } + public Type ArgumentType + { + get => _argumentType; + set => _argumentType = value ?? throw new ArgumentNullException(nameof(value)); + } internal List> Validators { get; } = new List>(); public void AddValidator(ValidateSymbol validator) => Validators.Add(validator); - public object GetDefaultValue() + public object? GetDefaultValue() { return GetDefaultValue(new ArgumentResult(this, null)); } - internal object GetDefaultValue(ArgumentResult argumentResult) + internal object? GetDefaultValue(ArgumentResult argumentResult) { if (_defaultValueFactory is null) { @@ -134,9 +139,9 @@ public void SetDefaultValue(object value) SetDefaultValueFactory(() => value); } - public void SetDefaultValueFactory(Func getDefaultValue) + public void SetDefaultValueFactory(Func getDefaultValue) { - if (getDefaultValue == null) + if (getDefaultValue is null) { throw new ArgumentNullException(nameof(getDefaultValue)); } @@ -144,7 +149,7 @@ public void SetDefaultValueFactory(Func getDefaultValue) SetDefaultValueFactory(_ => getDefaultValue()); } - public void SetDefaultValueFactory(Func getDefaultValue) + public void SetDefaultValueFactory(Func getDefaultValue) { _defaultValueFactory = getDefaultValue ?? throw new ArgumentNullException(nameof(getDefaultValue)); } @@ -155,7 +160,7 @@ public void SetDefaultValueFactory(Func getDefaultValue) public void AddSuggestions(IReadOnlyCollection suggestions) { - if (suggestions == null) + if (suggestions is null) { throw new ArgumentNullException(nameof(suggestions)); } @@ -165,7 +170,7 @@ public void AddSuggestions(IReadOnlyCollection suggestions) public void AddSuggestionSource(ISuggestionSource suggest) { - if (suggest == null) + if (suggest is null) { throw new ArgumentNullException(nameof(suggest)); } @@ -175,7 +180,7 @@ public void AddSuggestionSource(ISuggestionSource suggest) public void AddSuggestionSource(Suggest suggest) { - if (suggest == null) + if (suggest is null) { throw new ArgumentNullException(nameof(suggest)); } @@ -185,7 +190,7 @@ public void AddSuggestionSource(Suggest suggest) internal void AddAllowedValues(IEnumerable values) { - if (AllowedValues == null) + if (AllowedValues is null) { AllowedValues = new HashSet(); } @@ -193,7 +198,7 @@ internal void AddAllowedValues(IEnumerable values) AllowedValues.UnionWith(values); } - public override IEnumerable GetSuggestions(string textToMatch = null) + public override IEnumerable GetSuggestions(string? textToMatch = null) { var fixedSuggestions = _suggestions; diff --git a/src/System.CommandLine/ArgumentArity.cs b/src/System.CommandLine/ArgumentArity.cs index dabe31b706..4aa7b70d24 100644 --- a/src/System.CommandLine/ArgumentArity.cs +++ b/src/System.CommandLine/ArgumentArity.cs @@ -29,15 +29,15 @@ public ArgumentArity(int minimumNumberOfValues, int maximumNumberOfValues) public int MaximumNumberOfValues { get; set; } - internal static FailedArgumentConversionArityResult Validate( - SymbolResult symbolResult, + internal static FailedArgumentConversionArityResult? Validate( + SymbolResult? symbolResult, IArgument argument, int minimumNumberOfValues, int maximumNumberOfValues) { var argumentResult = symbolResult switch { - CommandResult commandResult => commandResult.Root.FindResultFor(argument), + CommandResult commandResult => commandResult.Root?.FindResultFor(argument), OptionResult optionResult => optionResult.Children.ResultFor(argument), _ => symbolResult }; @@ -46,7 +46,7 @@ internal static FailedArgumentConversionArityResult Validate( if (tokenCount < minimumNumberOfValues) { - if (symbolResult.UseDefaultValueFor(argument)) + if (symbolResult!.UseDefaultValueFor(argument)) { return null; } @@ -60,7 +60,7 @@ internal static FailedArgumentConversionArityResult Validate( { return new TooManyArgumentsConversionResult( argument, - symbolResult.ValidationMessages.ExpectsOneArgument(symbolResult)); + symbolResult!.ValidationMessages.ExpectsOneArgument(symbolResult)); } return null; @@ -98,6 +98,11 @@ internal static IArgumentArity Default(Type type, Argument argument, ISymbol par return ZeroOrOne; } + if (type == typeof(void)) + { + return Zero; + } + return ExactlyOne; } } diff --git a/src/System.CommandLine/Argument{T}.cs b/src/System.CommandLine/Argument{T}.cs index 365c28e012..8895886961 100644 --- a/src/System.CommandLine/Argument{T}.cs +++ b/src/System.CommandLine/Argument{T}.cs @@ -14,7 +14,7 @@ public Argument() : base(null) public Argument( string name, - string description = null) : base(name) + string? description = null) : base(name) { ArgumentType = typeof(T); Description = description; @@ -23,9 +23,9 @@ public Argument( public Argument( string name, Func getDefaultValue, - string description = null) : this(name) + string? description = null) : this(name) { - if (getDefaultValue == null) + if (getDefaultValue is null) { throw new ArgumentNullException(nameof(getDefaultValue)); } @@ -37,7 +37,7 @@ public Argument( public Argument(Func getDefaultValue) : this() { - if (getDefaultValue == null) + if (getDefaultValue is null) { throw new ArgumentNullException(nameof(getDefaultValue)); } @@ -46,16 +46,16 @@ public Argument(Func getDefaultValue) : this() } public Argument( - string name, - ParseArgument parse, + string? name, + ParseArgument parse, bool isDefault = false) : this() { if (!string.IsNullOrWhiteSpace(name)) { - Name = name; + Name = name!; } - if (parse == null) + if (parse is null) { throw new ArgumentNullException(nameof(parse)); } @@ -65,7 +65,7 @@ public Argument( SetDefaultValueFactory(argumentResult => parse(argumentResult)); } - ConvertArguments = (ArgumentResult argumentResult, out object value) => + ConvertArguments = (ArgumentResult argumentResult, out object? value) => { var result = parse(argumentResult); @@ -76,7 +76,7 @@ public Argument( } else { - value = default(T); + value = default(T)!; return false; } }; diff --git a/src/System.CommandLine/Binding/ArgumentConversionResult.cs b/src/System.CommandLine/Binding/ArgumentConversionResult.cs index b8779979cb..4567968136 100644 --- a/src/System.CommandLine/Binding/ArgumentConversionResult.cs +++ b/src/System.CommandLine/Binding/ArgumentConversionResult.cs @@ -12,11 +12,11 @@ private protected ArgumentConversionResult(IArgument argument) public IArgument Argument { get; } - internal string ErrorMessage { get; set; } + internal string? ErrorMessage { get; set; } internal static FailedArgumentConversionResult Failure(IArgument argument, string error) => new FailedArgumentConversionResult(argument, error); - public static SuccessfulArgumentConversionResult Success(IArgument argument, object value) => new SuccessfulArgumentConversionResult(argument, value); + public static SuccessfulArgumentConversionResult Success(IArgument argument, object? value) => new SuccessfulArgumentConversionResult(argument, value); internal static NoArgumentConversionResult None(IArgument argument) => new NoArgumentConversionResult(argument); } diff --git a/src/System.CommandLine/Binding/ArgumentConverter.cs b/src/System.CommandLine/Binding/ArgumentConverter.cs index 001faca571..80ce7b08fb 100644 --- a/src/System.CommandLine/Binding/ArgumentConverter.cs +++ b/src/System.CommandLine/Binding/ArgumentConverter.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.CommandLine.Parsing; using System.ComponentModel; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Reflection; @@ -36,7 +37,7 @@ internal static class ArgumentConverter internal static ArgumentConversionResult ConvertObject( IArgument argument, Type type, - object value) + object? value) { switch (value) { @@ -59,7 +60,7 @@ internal static ArgumentConversionResult ConvertObject( private static ArgumentConversionResult ConvertString( IArgument argument, - Type type, + Type? type, string value) { type ??= typeof(string); @@ -89,9 +90,9 @@ private static ArgumentConversionResult ConvertString( } if (type.TryFindConstructorWithSingleParameterOfType( - typeof(string), out (ConstructorInfo ctor, ParameterDescriptor parameterDescriptor) tuple)) + typeof(string), out ConstructorInfo? ctor)) { - var instance = tuple.ctor.Invoke(new object[] + var instance = ctor.Invoke(new object[] { value }); @@ -107,12 +108,12 @@ public static ArgumentConversionResult ConvertStrings( Type type, IReadOnlyCollection arguments) { - if (type == null) + if (type is null) { throw new ArgumentNullException(nameof(type)); } - if (arguments == null) + if (arguments is null) { throw new ArgumentNullException(nameof(arguments)); } @@ -139,7 +140,7 @@ public static ArgumentConversionResult ConvertStrings( return Success(argument, value); } - private static Type GetItemTypeIfEnumerable(Type type) + private static Type? GetItemTypeIfEnumerable(Type type) { if (type.IsArray) { @@ -153,7 +154,7 @@ private static Type GetItemTypeIfEnumerable(Type type) .GetInterfaces() .FirstOrDefault(IsEnumerable); - if (enumerableInterface == null) + if (enumerableInterface is null) { return null; } @@ -183,7 +184,7 @@ private static bool HasStringTypeConverter(this Type type) private static FailedArgumentConversionResult Failure( IArgument argument, - Type type, + Type type, string value) { return new FailedArgumentTypeConversionResult(argument, type, value); @@ -208,7 +209,7 @@ public static bool CanBeBoundFromScalarValue(this Type type) return true; } - if (TryFindConstructorWithSingleParameterOfType(type, typeof(string), out _) ) + if (TryFindConstructorWithSingleParameterOfType(type, typeof(string), out _)) { return true; } @@ -224,7 +225,7 @@ public static bool CanBeBoundFromScalarValue(this Type type) private static bool TryFindConstructorWithSingleParameterOfType( this Type type, Type parameterType, - out (ConstructorInfo ctor, ParameterDescriptor parameterDescriptor) info) + [NotNullWhen(true)] out ConstructorInfo? ctor) { var (x, y) = type.GetConstructors() .Select(c => (ctor: c, parameters: c.GetParameters())) @@ -234,12 +235,12 @@ private static bool TryFindConstructorWithSingleParameterOfType( if (x != null) { - info = (x, new ParameterDescriptor(y[0], new ConstructorDescriptor(x, ModelDescriptor.FromType(type)))); + ctor = x; return true; } else { - info = (null, null); + ctor = null; return false; } } @@ -249,7 +250,7 @@ internal static ArgumentConversionResult ConvertIfNeeded( SymbolResult symbolResult, Type type) { - if (conversionResult == null) + if (conversionResult is null) { throw new ArgumentNullException(nameof(conversionResult)); } @@ -281,21 +282,22 @@ internal static ArgumentConversionResult ConvertIfNeeded( } } - internal static object GetValueOrDefault(this ArgumentConversionResult result) => - result.GetValueOrDefault(); + internal static object? GetValueOrDefault(this ArgumentConversionResult result) => + result.GetValueOrDefault(); + [return: MaybeNull] internal static T GetValueOrDefault(this ArgumentConversionResult result) { switch (result) { case SuccessfulArgumentConversionResult successful: - return (T)successful.Value; + return (T)successful.Value!; case FailedArgumentConversionResult failed: throw new InvalidOperationException(failed.ErrorMessage); case NoArgumentConversionResult _: - return default; + return default!; default: - return default; + return default!; } } } diff --git a/src/System.CommandLine/Binding/Binder.cs b/src/System.CommandLine/Binding/Binder.cs index 807afc9342..ea7b90de6d 100644 --- a/src/System.CommandLine/Binding/Binder.cs +++ b/src/System.CommandLine/Binding/Binder.cs @@ -23,7 +23,7 @@ internal static bool IsNullable(this Type t) t.GetGenericTypeDefinition() == typeof(Nullable<>); } - public static object GetDefaultValueForType(this Type type) + public static object? GetDefaultValueForType(this Type type) { return type.IsValueType ? Activator.CreateInstance(type) : null; } diff --git a/src/System.CommandLine/Binding/BindingContext.cs b/src/System.CommandLine/Binding/BindingContext.cs index b942ba6a47..7104958df4 100644 --- a/src/System.CommandLine/Binding/BindingContext.cs +++ b/src/System.CommandLine/Binding/BindingContext.cs @@ -6,6 +6,7 @@ using System.CommandLine.Invocation; using System.CommandLine.IO; using System.CommandLine.Parsing; +using System.Diagnostics.CodeAnalysis; using System.Linq; #nullable enable @@ -69,7 +70,7 @@ public void AddService(Type serviceType, Func factory) public void AddService(Func factory) { - if (factory == null) + if (factory is null) { throw new ArgumentNullException(nameof(factory)); } @@ -79,7 +80,7 @@ public void AddService(Func factory) internal bool TryGetValueSource( IValueDescriptor valueDescriptor, - out IValueSource? valueSource) + [MaybeNullWhen(false)] out IValueSource valueSource) { if (ServiceProvider.AvailableServiceTypes.Contains(valueDescriptor.ValueType)) { @@ -87,7 +88,7 @@ internal bool TryGetValueSource( return true; } - valueSource = default; + valueSource = default!; return false; } @@ -98,7 +99,7 @@ internal bool TryBindToScalarValue( { if (valueSource.TryGetValue(valueDescriptor, this, out var value)) { - if (value == null || valueDescriptor.ValueType.IsInstanceOfType(value)) + if (value is null || valueDescriptor.ValueType.IsInstanceOfType(value)) { boundValue = new BoundValue(value, valueDescriptor, valueSource); return true; diff --git a/src/System.CommandLine/Binding/BoundValue.cs b/src/System.CommandLine/Binding/BoundValue.cs index aeec2a4b8b..608771a72e 100644 --- a/src/System.CommandLine/Binding/BoundValue.cs +++ b/src/System.CommandLine/Binding/BoundValue.cs @@ -6,7 +6,7 @@ namespace System.CommandLine.Binding public class BoundValue { internal BoundValue( - object value, + object? value, IValueDescriptor valueDescriptor, IValueSource valueSource) { @@ -25,7 +25,7 @@ internal BoundValue( public IValueSource ValueSource { get; } - public object Value { get; } + public object? Value { get; } public override string ToString() => $"{ValueDescriptor}: {Value}"; diff --git a/src/System.CommandLine/Binding/ConstructorDescriptor.cs b/src/System.CommandLine/Binding/ConstructorDescriptor.cs index 3405aad1e5..7bd09c6fdd 100644 --- a/src/System.CommandLine/Binding/ConstructorDescriptor.cs +++ b/src/System.CommandLine/Binding/ConstructorDescriptor.cs @@ -9,7 +9,7 @@ namespace System.CommandLine.Binding { public class ConstructorDescriptor : IMethodDescriptor { - private List _parameterDescriptors; + private List? _parameterDescriptors; private readonly ConstructorInfo _constructorInfo; @@ -24,11 +24,10 @@ internal ConstructorDescriptor( public ModelDescriptor Parent { get; } public IReadOnlyList ParameterDescriptors => - _parameterDescriptors - ?? - (_parameterDescriptors = _constructorInfo.GetParameters().Select(p => new ParameterDescriptor(p, this)).ToList()); + _parameterDescriptors ??= + _constructorInfo.GetParameters().Select(p => new ParameterDescriptor(p, this)).ToList(); - internal object Invoke(IReadOnlyCollection parameters) + internal object Invoke(IReadOnlyCollection parameters) { return _constructorInfo.Invoke(parameters.ToArray()); } diff --git a/src/System.CommandLine/Binding/DelegateHandlerDescriptor.cs b/src/System.CommandLine/Binding/DelegateHandlerDescriptor.cs index a77347dbd5..9e5f418910 100644 --- a/src/System.CommandLine/Binding/DelegateHandlerDescriptor.cs +++ b/src/System.CommandLine/Binding/DelegateHandlerDescriptor.cs @@ -23,7 +23,7 @@ public override ICommandHandler GetCommandHandler() ParameterDescriptors); } - public override ModelDescriptor Parent => null; + public override ModelDescriptor? Parent => null; protected override IEnumerable InitializeParameterDescriptors() { diff --git a/src/System.CommandLine/Binding/DelegateValueSource.cs b/src/System.CommandLine/Binding/DelegateValueSource.cs index 133eb0bca6..d641b72ef1 100644 --- a/src/System.CommandLine/Binding/DelegateValueSource.cs +++ b/src/System.CommandLine/Binding/DelegateValueSource.cs @@ -5,14 +5,14 @@ namespace System.CommandLine.Binding { internal class DelegateValueSource : IValueSource { - private readonly Func _getValue; + private readonly Func _getValue; - public DelegateValueSource(Func getValue) + public DelegateValueSource(Func getValue) { _getValue = getValue; } - public bool TryGetValue(IValueDescriptor valueDescriptor, BindingContext bindingContext, out object boundValue) + public bool TryGetValue(IValueDescriptor valueDescriptor, BindingContext? bindingContext, out object? boundValue) { boundValue = _getValue(bindingContext); diff --git a/src/System.CommandLine/Binding/ExpressionExtensions.cs b/src/System.CommandLine/Binding/ExpressionExtensions.cs index ff5684a734..d98fd81366 100644 --- a/src/System.CommandLine/Binding/ExpressionExtensions.cs +++ b/src/System.CommandLine/Binding/ExpressionExtensions.cs @@ -7,30 +7,26 @@ internal static class ExpressionExtensions { internal static (Type memberType, string memberName) MemberTypeAndName(this Expression> expression) { - if (expression == null) + if (expression is null) { throw new ArgumentNullException(nameof(expression)); } if (expression.Body is MemberExpression memberExpression) { - return TypeAndName(); + return TypeAndName(memberExpression); } // when the return type of the expression is a value type, it contains a call to Convert, resulting in boxing, so we get a UnaryExpression instead - if (expression.Body is UnaryExpression unaryExpression) + if (expression.Body is UnaryExpression unaryExpression && + unaryExpression.Operand is MemberExpression operandMemberExpression) { - memberExpression = unaryExpression.Operand as MemberExpression; - - if (memberExpression != null) - { - return TypeAndName(); - } + return TypeAndName(operandMemberExpression); } throw new ArgumentException($"Expression {expression} does not specify a member."); - (Type memberType, string memberName) TypeAndName() + static (Type memberType, string memberName) TypeAndName(MemberExpression memberExpression) { return (memberExpression.Member.ReturnType(), memberExpression.Member.Name); } diff --git a/src/System.CommandLine/Binding/HandlerDescriptor.cs b/src/System.CommandLine/Binding/HandlerDescriptor.cs index ba51a5ffc6..4628e28e75 100644 --- a/src/System.CommandLine/Binding/HandlerDescriptor.cs +++ b/src/System.CommandLine/Binding/HandlerDescriptor.cs @@ -10,11 +10,11 @@ namespace System.CommandLine.Binding { public abstract class HandlerDescriptor : IMethodDescriptor { - private List _parameterDescriptors; + private List? _parameterDescriptors; public abstract ICommandHandler GetCommandHandler(); - public abstract ModelDescriptor Parent { get; } + public abstract ModelDescriptor? Parent { get; } public IReadOnlyList ParameterDescriptors => _parameterDescriptors ??= new List(InitializeParameterDescriptors()); @@ -24,7 +24,7 @@ public abstract class HandlerDescriptor : IMethodDescriptor public override string ToString() => $"{Parent} ({string.Join(", ", ParameterDescriptors)})"; - public static HandlerDescriptor FromMethodInfo(MethodInfo methodInfo, object target = null) => + public static HandlerDescriptor FromMethodInfo(MethodInfo methodInfo, object? target = null) => new MethodInfoHandlerDescriptor(methodInfo, target); public static HandlerDescriptor FromDelegate(Delegate @delegate) => diff --git a/src/System.CommandLine/Binding/IMethodDescriptor.cs b/src/System.CommandLine/Binding/IMethodDescriptor.cs index 86090b7de3..0bcdf34702 100644 --- a/src/System.CommandLine/Binding/IMethodDescriptor.cs +++ b/src/System.CommandLine/Binding/IMethodDescriptor.cs @@ -7,7 +7,7 @@ namespace System.CommandLine.Binding { public interface IMethodDescriptor { - ModelDescriptor Parent { get; } + ModelDescriptor? Parent { get; } IReadOnlyList ParameterDescriptors { get; } } diff --git a/src/System.CommandLine/Binding/IValueDescriptor.cs b/src/System.CommandLine/Binding/IValueDescriptor.cs index a54d4deb4e..786c7e2337 100644 --- a/src/System.CommandLine/Binding/IValueDescriptor.cs +++ b/src/System.CommandLine/Binding/IValueDescriptor.cs @@ -5,12 +5,12 @@ namespace System.CommandLine.Binding { public interface IValueDescriptor { - string ValueName { get; } + string? ValueName { get; } Type ValueType { get; } bool HasDefaultValue { get; } - object GetDefaultValue(); + object? GetDefaultValue(); } } diff --git a/src/System.CommandLine/Binding/IValueSource.cs b/src/System.CommandLine/Binding/IValueSource.cs index 1567f39bf3..e07409c046 100644 --- a/src/System.CommandLine/Binding/IValueSource.cs +++ b/src/System.CommandLine/Binding/IValueSource.cs @@ -7,7 +7,7 @@ public interface IValueSource { bool TryGetValue( IValueDescriptor valueDescriptor, - BindingContext bindingContext, - out object boundValue); + BindingContext? bindingContext, + out object? boundValue); } } diff --git a/src/System.CommandLine/Binding/MethodInfoHandlerDescriptor.cs b/src/System.CommandLine/Binding/MethodInfoHandlerDescriptor.cs index 1ab64c80da..e048abb5ad 100644 --- a/src/System.CommandLine/Binding/MethodInfoHandlerDescriptor.cs +++ b/src/System.CommandLine/Binding/MethodInfoHandlerDescriptor.cs @@ -11,11 +11,11 @@ namespace System.CommandLine.Binding internal class MethodInfoHandlerDescriptor : HandlerDescriptor { private readonly MethodInfo _handlerMethodInfo; - private readonly object _invocationTarget; + private readonly object? _invocationTarget; public MethodInfoHandlerDescriptor( MethodInfo handlerMethodInfo, - object target = null) + object? target = null) { _handlerMethodInfo = handlerMethodInfo ?? throw new ArgumentNullException(nameof(handlerMethodInfo)); @@ -24,7 +24,7 @@ public MethodInfoHandlerDescriptor( public override ICommandHandler GetCommandHandler() { - if (_invocationTarget == null) + if (_invocationTarget is null) { return new ModelBindingCommandHandler( _handlerMethodInfo, diff --git a/src/System.CommandLine/Binding/ModelBinder.cs b/src/System.CommandLine/Binding/ModelBinder.cs index 1f08a224f2..0979e8c574 100644 --- a/src/System.CommandLine/Binding/ModelBinder.cs +++ b/src/System.CommandLine/Binding/ModelBinder.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Reflection; @@ -11,7 +12,7 @@ public class ModelBinder { public ModelBinder(Type modelType) : this(new AnonymousValueDescriptor(modelType)) { - if (modelType == null) + if (modelType is null) { throw new ArgumentNullException(nameof(modelType)); } @@ -102,7 +103,7 @@ public void BindMemberFromValue(PropertyInfo property, new SpecificSymbolValueSource(valueDescriptor); } - public object CreateInstance(BindingContext context) + public object? CreateInstance(BindingContext context) { var values = GetValues( // No binding sources, as were are attempting to bind a value @@ -128,7 +129,7 @@ public object CreateInstance(BindingContext context) private bool TryDefaultConstructorAndPropertiesStrategy( BindingContext context, - out object instance) + [NotNullWhen(true)] out object? instance) { var constructorDescriptors = ModelDescriptor @@ -148,7 +149,7 @@ private bool TryDefaultConstructorAndPropertiesStrategy( continue; } - // Found invocable constructor, invoke and return + // Found invokable constructor, invoke and return var values = boundConstructorArguments.Select(v => v.Value).ToArray(); try @@ -187,7 +188,7 @@ public void UpdateInstance(T instance, BindingContext bindingContext) } private IReadOnlyList GetValues( - IDictionary bindingSources, + IDictionary? bindingSources, BindingContext bindingContext, IReadOnlyList valueDescriptors, bool includeMissingValues) @@ -200,7 +201,7 @@ private IReadOnlyList GetValues( var valueSource = GetValueSource(bindingSources, bindingContext, valueDescriptor); - BoundValue boundValue; + BoundValue? boundValue; if (valueSource is null) { // If there is no source to bind from, no value can be bound. @@ -214,7 +215,7 @@ private IReadOnlyList GetValues( boundValue = BoundValue.DefaultForValueDescriptor(valueDescriptor); } - if (boundValue == null) + if (boundValue is null) { if (includeMissingValues) { @@ -239,13 +240,13 @@ private IReadOnlyList GetValues( return values; } - private IValueSource GetValueSource( - IDictionary bindingSources, + private IValueSource? GetValueSource( + IDictionary? bindingSources, BindingContext bindingContext, IValueDescriptor valueDescriptor) { if (!(bindingSources is null) && - bindingSources.TryGetValue(valueDescriptor, out var valueSource)) + bindingSources.TryGetValue(valueDescriptor, out IValueSource? valueSource)) { return valueSource; } @@ -269,7 +270,7 @@ public override string ToString() => $"{ModelDescriptor.ModelType.Name}"; private bool ShouldPassNullToConstructor(ModelDescriptor modelDescriptor, - ConstructorDescriptor ctor = null) + ConstructorDescriptor? ctor = null) { if (!(ctor is null)) { @@ -288,11 +289,11 @@ public AnonymousValueDescriptor(Type modelType) ValueType = modelType; } - public string ValueName => null; + public string? ValueName => null; public bool HasDefaultValue => false; - public object GetDefaultValue() => null; + public object? GetDefaultValue() => null; public override string ToString() => $"{ValueType}"; } diff --git a/src/System.CommandLine/Binding/ModelBinder{T}.cs b/src/System.CommandLine/Binding/ModelBinder{T}.cs index 9f61f03c00..04f86eb712 100644 --- a/src/System.CommandLine/Binding/ModelBinder{T}.cs +++ b/src/System.CommandLine/Binding/ModelBinder{T}.cs @@ -24,7 +24,7 @@ public void BindMemberFromValue( public void BindMemberFromValue( Expression> property, - Func getValue) + Func getValue) { var (propertyType, propertyName) = property.MemberTypeAndName(); var propertyDescriptor = FindModelPropertyDescriptor( diff --git a/src/System.CommandLine/Binding/ModelDescriptor.cs b/src/System.CommandLine/Binding/ModelDescriptor.cs index 66838c9d73..9759498026 100644 --- a/src/System.CommandLine/Binding/ModelDescriptor.cs +++ b/src/System.CommandLine/Binding/ModelDescriptor.cs @@ -17,8 +17,8 @@ public class ModelDescriptor private static readonly ConcurrentDictionary _modelDescriptors = new ConcurrentDictionary(); - private List _propertyDescriptors; - private List _constructorDescriptors; + private List? _propertyDescriptors; + private List? _constructorDescriptors; protected ModelDescriptor(Type modelType) { diff --git a/src/System.CommandLine/Binding/ParameterDescriptor.cs b/src/System.CommandLine/Binding/ParameterDescriptor.cs index 9df99aeaac..29b3729380 100644 --- a/src/System.CommandLine/Binding/ParameterDescriptor.cs +++ b/src/System.CommandLine/Binding/ParameterDescriptor.cs @@ -30,7 +30,7 @@ public bool AllowsNull { get { - if (_allowsNull == null) + if (_allowsNull is null) { if (_parameterInfo.ParameterType.IsNullable()) { @@ -38,7 +38,7 @@ public bool AllowsNull } if (_parameterInfo.HasDefaultValue && - _parameterInfo.DefaultValue == null) + _parameterInfo.DefaultValue is null) { _allowsNull = true; } @@ -48,7 +48,7 @@ public bool AllowsNull } } - public object GetDefaultValue() => + public object? GetDefaultValue() => _parameterInfo.DefaultValue is DBNull ? ValueType.GetDefaultValueForType() : _parameterInfo.DefaultValue; diff --git a/src/System.CommandLine/Binding/ParseResultMatchingValueSource.cs b/src/System.CommandLine/Binding/ParseResultMatchingValueSource.cs index 88f05d47fa..e4b963213e 100644 --- a/src/System.CommandLine/Binding/ParseResultMatchingValueSource.cs +++ b/src/System.CommandLine/Binding/ParseResultMatchingValueSource.cs @@ -9,12 +9,12 @@ internal class ParseResultMatchingValueSource : IValueSource { public bool TryGetValue( IValueDescriptor valueDescriptor, - BindingContext bindingContext, - out object boundValue) + BindingContext? bindingContext, + out object? boundValue) { if (!string.IsNullOrEmpty(valueDescriptor.ValueName)) { - var commandResult = bindingContext.ParseResult.CommandResult; + CommandResult? commandResult = bindingContext?.ParseResult.CommandResult; while (commandResult != null) { diff --git a/src/System.CommandLine/Binding/PropertyDescriptor.cs b/src/System.CommandLine/Binding/PropertyDescriptor.cs index 6e9124b1ee..19600067f9 100644 --- a/src/System.CommandLine/Binding/PropertyDescriptor.cs +++ b/src/System.CommandLine/Binding/PropertyDescriptor.cs @@ -13,7 +13,7 @@ internal PropertyDescriptor( PropertyInfo propertyInfo, ModelDescriptor parent) { - Parent = parent; + Parent = parent ?? throw new ArgumentNullException(nameof(parent)); _propertyInfo = propertyInfo; } @@ -21,17 +21,15 @@ internal PropertyDescriptor( public ModelDescriptor Parent { get; } - internal string Path => Parent != null - ? Parent + "." + ValueName - : ValueName; + internal string Path => Parent + "." + ValueName; public Type ValueType => _propertyInfo.PropertyType; public bool HasDefaultValue => false; - public object GetDefaultValue() => ValueType.GetDefaultValueForType(); + public object? GetDefaultValue() => ValueType.GetDefaultValueForType(); - public void SetValue(object instance, object value) + public void SetValue(object? instance, object? value) { _propertyInfo.SetValue(instance, value); } diff --git a/src/System.CommandLine/Binding/ServiceProviderValueSource.cs b/src/System.CommandLine/Binding/ServiceProviderValueSource.cs index fc2f034a91..6c4e80010e 100644 --- a/src/System.CommandLine/Binding/ServiceProviderValueSource.cs +++ b/src/System.CommandLine/Binding/ServiceProviderValueSource.cs @@ -7,10 +7,10 @@ internal class ServiceProviderValueSource : IValueSource { public bool TryGetValue( IValueDescriptor valueDescriptor, - BindingContext bindingContext, - out object boundValue) + BindingContext? bindingContext, + out object? boundValue) { - boundValue = bindingContext.ServiceProvider.GetService(valueDescriptor.ValueType); + boundValue = bindingContext?.ServiceProvider.GetService(valueDescriptor.ValueType); return true; } } diff --git a/src/System.CommandLine/Binding/SpecificSymbolValueSource.cs b/src/System.CommandLine/Binding/SpecificSymbolValueSource.cs index 00c2bf7215..abaaa10115 100644 --- a/src/System.CommandLine/Binding/SpecificSymbolValueSource.cs +++ b/src/System.CommandLine/Binding/SpecificSymbolValueSource.cs @@ -16,14 +16,14 @@ public SpecificSymbolValueSource(IValueDescriptor valueDescriptor) public IValueDescriptor ValueDescriptor { get; } public bool TryGetValue(IValueDescriptor valueDescriptor, - BindingContext bindingContext, - out object boundValue) + BindingContext? bindingContext, + out object? boundValue) { var specificDescriptor = ValueDescriptor; switch (specificDescriptor) { case IOption option: - var optionResult = bindingContext.ParseResult.FindResultFor(option); + var optionResult = bindingContext?.ParseResult.FindResultFor(option); if (!(optionResult is null)) { boundValue = optionResult.GetValueOrDefault(); @@ -31,8 +31,8 @@ public bool TryGetValue(IValueDescriptor valueDescriptor, } break; case IArgument argument: - var argumentResult = bindingContext.ParseResult.FindResultFor(argument); - if (!(argument is null)) + var argumentResult = bindingContext?.ParseResult.FindResultFor(argument); + if (!(argumentResult is null)) { boundValue = argumentResult.GetValueOrDefault(); return true; diff --git a/src/System.CommandLine/Binding/SuccessfulArgumentConversionResult.cs b/src/System.CommandLine/Binding/SuccessfulArgumentConversionResult.cs index 80b9d88d47..cfb5336b05 100644 --- a/src/System.CommandLine/Binding/SuccessfulArgumentConversionResult.cs +++ b/src/System.CommandLine/Binding/SuccessfulArgumentConversionResult.cs @@ -5,11 +5,11 @@ namespace System.CommandLine.Binding { internal class SuccessfulArgumentConversionResult : ArgumentConversionResult { - internal SuccessfulArgumentConversionResult(IArgument argument, object value) : base(argument) + internal SuccessfulArgumentConversionResult(IArgument argument, object? value) : base(argument) { Value = value; } - public object Value { get; } + public object? Value { get; } } } diff --git a/src/System.CommandLine/Binding/TryConvertArgument.cs b/src/System.CommandLine/Binding/TryConvertArgument.cs index 72b63a0387..44d777e939 100644 --- a/src/System.CommandLine/Binding/TryConvertArgument.cs +++ b/src/System.CommandLine/Binding/TryConvertArgument.cs @@ -7,5 +7,5 @@ namespace System.CommandLine.Binding { internal delegate bool TryConvertArgument( ArgumentResult argumentResult, - out object value); + out object? value); } \ No newline at end of file diff --git a/src/System.CommandLine/Binding/TypeDefaultValueSource.cs b/src/System.CommandLine/Binding/TypeDefaultValueSource.cs index bca1ed0140..f200cff6f8 100644 --- a/src/System.CommandLine/Binding/TypeDefaultValueSource.cs +++ b/src/System.CommandLine/Binding/TypeDefaultValueSource.cs @@ -5,7 +5,7 @@ namespace System.CommandLine.Binding { internal class TypeDefaultValueSource : IValueSource { - public static IValueSource Instance = new TypeDefaultValueSource(); + public static readonly IValueSource Instance = new TypeDefaultValueSource(); private TypeDefaultValueSource() { @@ -13,8 +13,8 @@ private TypeDefaultValueSource() public bool TryGetValue( IValueDescriptor valueDescriptor, - BindingContext bindingContext, - out object boundValue) + BindingContext? bindingContext, + out object? boundValue) { boundValue = valueDescriptor.ValueType.GetDefaultValueForType(); return true; diff --git a/src/System.CommandLine/Binding/ValueDescriptorDefaultValueSource.cs b/src/System.CommandLine/Binding/ValueDescriptorDefaultValueSource.cs index 684d2b293c..ce72ebd6c0 100644 --- a/src/System.CommandLine/Binding/ValueDescriptorDefaultValueSource.cs +++ b/src/System.CommandLine/Binding/ValueDescriptorDefaultValueSource.cs @@ -5,13 +5,13 @@ namespace System.CommandLine.Binding { internal class ValueDescriptorDefaultValueSource : IValueSource { - public static IValueSource Instance = new ValueDescriptorDefaultValueSource(); + public static readonly IValueSource Instance = new ValueDescriptorDefaultValueSource(); private ValueDescriptorDefaultValueSource() { } - public bool TryGetValue(IValueDescriptor valueDescriptor, BindingContext bindingContext, out object boundValue) + public bool TryGetValue(IValueDescriptor valueDescriptor, BindingContext? bindingContext, out object? boundValue) { boundValue = valueDescriptor.GetDefaultValue(); return true; diff --git a/src/System.CommandLine/Builder/CommandLineBuilder.cs b/src/System.CommandLine/Builder/CommandLineBuilder.cs index 7781888244..4b8f39fd96 100644 --- a/src/System.CommandLine/Builder/CommandLineBuilder.cs +++ b/src/System.CommandLine/Builder/CommandLineBuilder.cs @@ -14,7 +14,7 @@ public class CommandLineBuilder : CommandBuilder { private readonly List<(InvocationMiddleware middleware, int order)> _middlewareList = new List<(InvocationMiddleware middleware, int order)>(); - public CommandLineBuilder(Command rootCommand = null) + public CommandLineBuilder(Command? rootCommand = null) : base(rootCommand ?? new RootCommand()) { } @@ -25,11 +25,11 @@ public CommandLineBuilder(Command rootCommand = null) public ResponseFileHandling ResponseFileHandling { get; set; } - internal Func HelpBuilderFactory { get; set; } + internal Func? HelpBuilderFactory { get; set; } - internal Option HelpOption { get; set; } + internal Option? HelpOption { get; set; } - internal ValidationMessages ValidationMessages { get; set; } + internal ValidationMessages? ValidationMessages { get; set; } public Parser Build() { @@ -42,7 +42,7 @@ public Parser Build() enableDirectives: EnableDirectives, validationMessages: ValidationMessages, responseFileHandling: ResponseFileHandling, - middlewarePipeline: _middlewareList?.OrderBy(m => m.order) + middlewarePipeline: _middlewareList.OrderBy(m => m.order) .Select(m => m.middleware) .ToArray(), helpBuilderFactory: HelpBuilderFactory)); diff --git a/src/System.CommandLine/Builder/CommandLineBuilderExtensions.cs b/src/System.CommandLine/Builder/CommandLineBuilderExtensions.cs index 8611502fdf..c5e14bff0e 100644 --- a/src/System.CommandLine/Builder/CommandLineBuilderExtensions.cs +++ b/src/System.CommandLine/Builder/CommandLineBuilderExtensions.cs @@ -24,7 +24,7 @@ public static class CommandLineBuilderExtensions new Lazy(() => { var assembly = Assembly.GetEntryAssembly() ?? Assembly.GetExecutingAssembly(); var assemblyVersionAttribute = assembly.GetCustomAttribute(); - if (assemblyVersionAttribute == null) + if (assemblyVersionAttribute is null) { return assembly.GetName().Version.ToString(); } @@ -79,14 +79,14 @@ public static CommandLineBuilder CancelOnProcessTermination(this CommandLineBuil builder.AddMiddleware(async (context, next) => { bool cancellationHandlingAdded = false; - ManualResetEventSlim blockProcessExit = null; - ConsoleCancelEventHandler consoleHandler = null; - EventHandler processExitHandler = null; + ManualResetEventSlim? blockProcessExit = null; + ConsoleCancelEventHandler? consoleHandler = null; + EventHandler? processExitHandler = null; context.CancellationHandlingAdded += (CancellationTokenSource cts) => { - cancellationHandlingAdded = true; blockProcessExit = new ManualResetEventSlim(initialState: false); + cancellationHandlingAdded = true; consoleHandler = (_, args) => { cts.Cancel(); @@ -119,7 +119,7 @@ public static CommandLineBuilder CancelOnProcessTermination(this CommandLineBuil { Console.CancelKeyPress -= consoleHandler; AppDomain.CurrentDomain.ProcessExit -= processExitHandler; - blockProcessExit.Set(); + blockProcessExit!.Set(); } } }, MiddlewareOrderInternal.Startup); @@ -245,7 +245,7 @@ public static CommandLineBuilder UseDefaults(this CommandLineBuilder builder) public static CommandLineBuilder UseExceptionHandler( this CommandLineBuilder builder, - Action onException = null) + Action? onException = null) { builder.AddMiddleware(async (context, next) => { @@ -284,7 +284,7 @@ internal static CommandLineBuilder UseHelp( this CommandLineBuilder builder, Option helpOption) { - if (builder.HelpOption == null) + if (builder.HelpOption is null) { builder.HelpOption = helpOption; builder.Command.TryAddGlobalOption(helpOption); @@ -304,7 +304,7 @@ internal static CommandLineBuilder UseHelp( public static TBuilder UseHelpBuilder(this TBuilder builder, Func getHelpBuilder) where TBuilder : CommandLineBuilder { - if (builder == null) + if (builder is null) { throw new ArgumentNullException(nameof(builder)); } diff --git a/src/System.CommandLine/Collections/AliasedSet.cs b/src/System.CommandLine/Collections/AliasedSet.cs index 5b1863e9d1..099d6805cc 100644 --- a/src/System.CommandLine/Collections/AliasedSet.cs +++ b/src/System.CommandLine/Collections/AliasedSet.cs @@ -3,7 +3,6 @@ using System.Collections; using System.Collections.Generic; -using System.Linq; namespace System.CommandLine.Collections { @@ -12,9 +11,9 @@ public abstract class AliasedSet : IReadOnlyCollection { protected IList Items { get; } = new List(); - public T this[string alias] => GetByAlias(alias); + public T? this[string alias] => GetByAlias(alias); - public T GetByAlias(string alias) + public T? GetByAlias(string alias) { for (var i = 0; i < Items.Count; i++) { diff --git a/src/System.CommandLine/Collections/ISymbolSet.cs b/src/System.CommandLine/Collections/ISymbolSet.cs index 00d8d53373..c115bf2509 100644 --- a/src/System.CommandLine/Collections/ISymbolSet.cs +++ b/src/System.CommandLine/Collections/ISymbolSet.cs @@ -7,6 +7,6 @@ namespace System.CommandLine.Collections { public interface ISymbolSet : IReadOnlyCollection { - ISymbol GetByAlias(string alias); + ISymbol? GetByAlias(string alias); } } diff --git a/src/System.CommandLine/Collections/SymbolSet.cs b/src/System.CommandLine/Collections/SymbolSet.cs index 8e73b5207a..68bafc522c 100644 --- a/src/System.CommandLine/Collections/SymbolSet.cs +++ b/src/System.CommandLine/Collections/SymbolSet.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; namespace System.CommandLine.Collections { @@ -18,7 +19,7 @@ internal override void Add(ISymbol item) internal bool IsAnyAliasInUse( ISymbol item, - out string aliasAlreadyInUse) + [MaybeNullWhen(false)] out string aliasAlreadyInUse) { var itemRawAliases = GetRawAliases(item); @@ -38,7 +39,7 @@ internal bool IsAnyAliasInUse( } } - aliasAlreadyInUse = null; + aliasAlreadyInUse = null!; return false; static IReadOnlyList GetRawAliases(ISymbol symbol) @@ -53,7 +54,7 @@ static IReadOnlyList GetRawAliases(ISymbol symbol) internal void ThrowIfAnyAliasIsInUse(ISymbol item) { - string rawAliasAlreadyInUse; + string? rawAliasAlreadyInUse; switch (item) { diff --git a/src/System.CommandLine/Command.cs b/src/System.CommandLine/Command.cs index 299456f2c8..c381fbe148 100644 --- a/src/System.CommandLine/Command.cs +++ b/src/System.CommandLine/Command.cs @@ -14,7 +14,7 @@ public class Command : Symbol, ICommand, IEnumerable { private readonly SymbolSet _globalOptions = new SymbolSet(); - public Command(string name, string description = null) : base(new[] { name }, description) + public Command(string name, string? description = null) : base(new[] { name }, description) { } @@ -72,7 +72,7 @@ private protected override void AddSymbol(Symbol symbol) public bool TreatUnmatchedTokensAsErrors { get; set; } = true; - public ICommandHandler Handler { get; set; } + public ICommandHandler? Handler { get; set; } public IEnumerator GetEnumerator() => Children.OfType().GetEnumerator(); @@ -82,6 +82,6 @@ private protected override void AddSymbol(Symbol symbol) IEnumerable ICommand.Options => Options; - internal Parser ImplicitParser { get; set; } + internal Parser? ImplicitParser { get; set; } } } diff --git a/src/System.CommandLine/CommandExtensions.cs b/src/System.CommandLine/CommandExtensions.cs index 8d0fb26435..058e0c142f 100644 --- a/src/System.CommandLine/CommandExtensions.cs +++ b/src/System.CommandLine/CommandExtensions.cs @@ -15,7 +15,7 @@ public static class CommandExtensions public static int Invoke( this Command command, string[] args, - IConsole console = null) + IConsole? console = null) { return GetInvocationPipeline(command, args).Invoke(console); } @@ -23,13 +23,13 @@ public static int Invoke( public static int Invoke( this Command command, string commandLine, - IConsole console = null) => + IConsole? console = null) => command.Invoke(CommandLineStringSplitter.Instance.Split(commandLine).ToArray(), console); public static async Task InvokeAsync( this Command command, string[] args, - IConsole console = null) + IConsole? console = null) { return await GetInvocationPipeline(command, args).InvokeAsync(console); } @@ -37,7 +37,7 @@ public static async Task InvokeAsync( public static Task InvokeAsync( this Command command, string commandLine, - IConsole console = null) => + IConsole? console = null) => command.InvokeAsync(CommandLineStringSplitter.Instance.Split(commandLine).ToArray(), console); private static InvocationPipeline GetInvocationPipeline(Command command, string[] args) @@ -60,7 +60,7 @@ public static ParseResult Parse( public static ParseResult Parse( this Command command, string commandLine, - IReadOnlyCollection delimiters = null) => + IReadOnlyCollection? delimiters = null) => new Parser(command).Parse(commandLine); } } diff --git a/src/System.CommandLine/CommandLineConfiguration.cs b/src/System.CommandLine/CommandLineConfiguration.cs index 24150db604..ad186c2593 100644 --- a/src/System.CommandLine/CommandLineConfiguration.cs +++ b/src/System.CommandLine/CommandLineConfiguration.cs @@ -19,15 +19,15 @@ public class CommandLineConfiguration public CommandLineConfiguration( IReadOnlyCollection symbols, - IReadOnlyCollection argumentDelimiters = null, + IReadOnlyCollection? argumentDelimiters = null, bool enablePosixBundling = true, bool enableDirectives = true, - ValidationMessages validationMessages = null, + ValidationMessages? validationMessages = null, ResponseFileHandling responseFileHandling = ResponseFileHandling.ParseArgsAsLineSeparated, - IReadOnlyCollection middlewarePipeline = null, - Func helpBuilderFactory = null) + IReadOnlyCollection? middlewarePipeline = null, + Func? helpBuilderFactory = null) { - if (symbols == null) + if (symbols is null) { throw new ArgumentNullException(nameof(symbols)); } @@ -61,21 +61,22 @@ public CommandLineConfiguration( else { // reuse existing auto-generated root command, if one is present, to prevent repeated mutations - rootCommand = symbols.SelectMany(s => s.Parents) - .OfType() - .FirstOrDefault(); + RootCommand? parentRootCommand = + symbols.SelectMany(s => s.Parents) + .OfType() + .FirstOrDefault(); - if (rootCommand == null) + if (parentRootCommand is null) { - rootCommand = new RootCommand(); + parentRootCommand = new RootCommand(); foreach (var symbol in symbols) { - rootCommand.Add(symbol); + parentRootCommand.Add(symbol); } } - RootCommand = rootCommand; + RootCommand = rootCommand = parentRootCommand; } _symbols.Add(RootCommand); @@ -86,8 +87,8 @@ public CommandLineConfiguration( EnableDirectives = enableDirectives; ValidationMessages = validationMessages ?? ValidationMessages.Instance; ResponseFileHandling = responseFileHandling; - _middlewarePipeline = middlewarePipeline; - _helpBuilderFactory = helpBuilderFactory; + _middlewarePipeline = middlewarePipeline ?? new List(); + _helpBuilderFactory = helpBuilderFactory ?? (context => new HelpBuilder(context.Console)); } private void AddGlobalOptionsToChildren(Command parentCommand) @@ -98,7 +99,7 @@ private void AddGlobalOptionsToChildren(Command parentCommand) { if (child is Command childCommand) { - if (!childCommand.Children.IsAnyAliasInUse(globalOption, out var inUse)) + if (!childCommand.Children.IsAnyAliasInUse(globalOption, out _)) { childCommand.AddOption(globalOption); } @@ -106,9 +107,7 @@ private void AddGlobalOptionsToChildren(Command parentCommand) } } } - - public IReadOnlyCollection Prefixes { get; } - + public ISymbolSet Symbols => _symbols; public IReadOnlyCollection ArgumentDelimiters { get; } @@ -119,11 +118,9 @@ private void AddGlobalOptionsToChildren(Command parentCommand) public ValidationMessages ValidationMessages { get; } - internal Func HelpBuilderFactory => - _helpBuilderFactory ??= context => new HelpBuilder(context.Console); + internal Func HelpBuilderFactory => _helpBuilderFactory; - internal IReadOnlyCollection Middleware => - _middlewarePipeline ??= new List(); + internal IReadOnlyCollection Middleware => _middlewarePipeline; public ICommand RootCommand { get; } diff --git a/src/System.CommandLine/DirectiveCollection.cs b/src/System.CommandLine/DirectiveCollection.cs index 8a9b7cf8fc..188ca7a9cd 100644 --- a/src/System.CommandLine/DirectiveCollection.cs +++ b/src/System.CommandLine/DirectiveCollection.cs @@ -3,6 +3,7 @@ using System.Collections; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; namespace System.CommandLine @@ -11,22 +12,18 @@ internal class DirectiveCollection : IDirectiveCollection { private readonly Dictionary> _directives = new Dictionary>(); - public void Add(string name, string value) + public void Add(string name, string? value) { - if (_directives.TryGetValue(name, out var values)) + if (!_directives.TryGetValue(name, out var values)) { - values.Add(value); - } - else - { - var list = new List(); + values = new List(); - if (value != null) - { - list.Add(value); - } + _directives.Add(name, values); + } - _directives.Add(name, list); + if (value != null) + { + values.Add(value); } } @@ -35,7 +32,7 @@ public bool Contains(string name) return _directives.ContainsKey(name); } - public bool TryGetValues(string name, out IEnumerable values) + public bool TryGetValues(string name, [NotNullWhen(true)] out IEnumerable? values) { if (_directives.TryGetValue(name, out var v)) { diff --git a/src/System.CommandLine/EnumerableExtensions.cs b/src/System.CommandLine/EnumerableExtensions.cs index daf92c2752..6259fabdd9 100644 --- a/src/System.CommandLine/EnumerableExtensions.cs +++ b/src/System.CommandLine/EnumerableExtensions.cs @@ -33,10 +33,12 @@ internal static IEnumerable FlattenBreadthFirst( } internal static IEnumerable RecurseWhileNotNull( - this T source, - Func next) + this T? source, + Func next) where T : class { + if (source is null) yield break; + yield return source; while ((source = next(source)) != null) diff --git a/src/System.CommandLine/Help/HelpBuilder.cs b/src/System.CommandLine/Help/HelpBuilder.cs index dbe647a744..56c2eae515 100644 --- a/src/System.CommandLine/Help/HelpBuilder.cs +++ b/src/System.CommandLine/Help/HelpBuilder.cs @@ -57,7 +57,7 @@ public HelpBuilder( /// public virtual void Write(ICommand command) { - if (command == null) + if (command is null) { throw new ArgumentNullException(nameof(command)); } @@ -161,9 +161,9 @@ private void AppendText(string text, int? offset = null) /// /// Heading text content to write to the console /// - private void AppendHeading(string heading) + private void AppendHeading(string? heading) { - if (heading == null) + if (heading is null) { throw new ArgumentNullException(nameof(heading)); } @@ -178,7 +178,7 @@ private void AppendHeading(string heading) /// private void AppendDescription(string description) { - if (description == null) + if (description is null) { throw new ArgumentNullException(nameof(description)); } @@ -205,7 +205,7 @@ private void AppendDescription(string description) /// protected void AppendHelpItem(HelpItem helpItem, int maxInvocationWidth) { - if (helpItem == null) + if (helpItem is null) { throw new ArgumentNullException(nameof(helpItem)); } @@ -562,9 +562,9 @@ protected virtual void AddAdditionalArguments(ICommand command) HelpSection.Write(this, AdditionalArguments.Title, AdditionalArguments.Description); } - private bool ShouldDisplayArgumentHelp(ICommand command) + private bool ShouldDisplayArgumentHelp(ICommand? command) { - if (command == null) + if (command is null) { return false; } @@ -586,7 +586,7 @@ private int GetConsoleWindowWidth() protected class HelpItem { - public HelpItem(string invocation, string description = null) + public HelpItem(string invocation, string? description = null) { Invocation = invocation; Description = description ?? ""; @@ -609,7 +609,7 @@ private static class HelpSection public static void Write( HelpBuilder builder, string title, - string description = null) + string? description = null) { if (!ShouldWrite(description, null)) { @@ -626,9 +626,9 @@ public static void Write( public static void Write( HelpBuilder builder, string title, - IReadOnlyCollection usageItems = null, - Func> formatter = null, - string description = null) + IReadOnlyCollection? usageItems = null, + Func>? formatter = null, + string? description = null) { if (!ShouldWrite(description, usageItems)) { @@ -643,7 +643,7 @@ public static void Write( builder.AppendBlankLine(); } - private static bool ShouldWrite(string description, IReadOnlyCollection usageItems) + private static bool ShouldWrite(string? description, IReadOnlyCollection? usageItems) { if (!string.IsNullOrWhiteSpace(description)) { @@ -653,7 +653,7 @@ private static bool ShouldWrite(string description, IReadOnlyCollection return usageItems?.Any() == true; } - private static void AppendHeading(HelpBuilder builder, string title = null) + private static void AppendHeading(HelpBuilder builder, string? title = null) { if (string.IsNullOrWhiteSpace(title)) { @@ -663,20 +663,20 @@ private static void AppendHeading(HelpBuilder builder, string title = null) builder.AppendHeading(title); } - private static void AddDescription(HelpBuilder builder, string description = null) + private static void AddDescription(HelpBuilder builder, string? description = null) { if (string.IsNullOrWhiteSpace(description)) { return; } - builder.AppendDescription(description); + builder.AppendDescription(description!); } private static void AddInvocation( HelpBuilder builder, - IReadOnlyCollection symbols, - Func> formatter) + IReadOnlyCollection? symbols, + Func>? formatter) { var helpItems = symbols .SelectMany(formatter) diff --git a/src/System.CommandLine/IDirectiveCollection.cs b/src/System.CommandLine/IDirectiveCollection.cs index 26117c5426..75393dd17b 100644 --- a/src/System.CommandLine/IDirectiveCollection.cs +++ b/src/System.CommandLine/IDirectiveCollection.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; namespace System.CommandLine { @@ -9,6 +10,6 @@ public interface IDirectiveCollection : IEnumerable values); + bool TryGetValues(string name, [NotNullWhen(true)] out IEnumerable? values); } } diff --git a/src/System.CommandLine/IO/StandardStreamWriter.cs b/src/System.CommandLine/IO/StandardStreamWriter.cs index fcb88015a2..655e7398f1 100644 --- a/src/System.CommandLine/IO/StandardStreamWriter.cs +++ b/src/System.CommandLine/IO/StandardStreamWriter.cs @@ -9,7 +9,7 @@ public static class StandardStreamWriter { public static IStandardStreamWriter Create(TextWriter writer) { - if (writer == null) + if (writer is null) { throw new ArgumentNullException(nameof(writer)); } @@ -19,7 +19,7 @@ public static IStandardStreamWriter Create(TextWriter writer) public static void WriteLine(this IStandardStreamWriter writer) { - if (writer == null) + if (writer is null) { throw new ArgumentNullException(nameof(writer)); } @@ -29,7 +29,7 @@ public static void WriteLine(this IStandardStreamWriter writer) public static void WriteLine(this IStandardStreamWriter writer, string value) { - if (writer == null) + if (writer is null) { throw new ArgumentNullException(nameof(writer)); } diff --git a/src/System.CommandLine/ISymbol.cs b/src/System.CommandLine/ISymbol.cs index fc5b7a035c..8a7e2bfbb0 100644 --- a/src/System.CommandLine/ISymbol.cs +++ b/src/System.CommandLine/ISymbol.cs @@ -11,7 +11,7 @@ public interface ISymbol : ISuggestionSource { string Name { get; } - string Description { get; } + string? Description { get; } IReadOnlyList Aliases { get; } diff --git a/src/System.CommandLine/Invocation/CommandHandler.cs b/src/System.CommandLine/Invocation/CommandHandler.cs index 691c4e12a1..0e73396791 100644 --- a/src/System.CommandLine/Invocation/CommandHandler.cs +++ b/src/System.CommandLine/Invocation/CommandHandler.cs @@ -12,7 +12,7 @@ public static class CommandHandler public static ICommandHandler Create(Delegate @delegate) => HandlerDescriptor.FromDelegate(@delegate).GetCommandHandler(); - public static ICommandHandler Create(MethodInfo method, object target = null) => + public static ICommandHandler Create(MethodInfo method, object? target = null) => HandlerDescriptor.FromMethodInfo(method, target).GetCommandHandler(); public static ICommandHandler Create(Action action) => diff --git a/src/System.CommandLine/Invocation/InvocationContext.cs b/src/System.CommandLine/Invocation/InvocationContext.cs index a23eb39de4..5803e1f963 100644 --- a/src/System.CommandLine/Invocation/InvocationContext.cs +++ b/src/System.CommandLine/Invocation/InvocationContext.cs @@ -9,14 +9,14 @@ namespace System.CommandLine.Invocation { public sealed class InvocationContext : IDisposable { - private CancellationTokenSource _cts; - private Action _cancellationHandlingAddedEvent; + private CancellationTokenSource? _cts; + private Action? _cancellationHandlingAddedEvent; public BindingContext BindingContext { get; } public InvocationContext( ParseResult parseResult, - IConsole console = null) + IConsole? console = null) { BindingContext = new BindingContext(parseResult, console); BindingContext.ServiceProvider.AddService(_ => GetCancellationToken()); @@ -35,7 +35,7 @@ public ParseResult ParseResult public int ResultCode { get; set; } - public IInvocationResult InvocationResult { get; set; } + public IInvocationResult? InvocationResult { get; set; } internal event Action CancellationHandlingAdded { @@ -57,7 +57,7 @@ internal event Action CancellationHandlingAdded /// Token used by the caller to implement cancellation handling. public CancellationToken GetCancellationToken() { - if (_cts == null) + if (_cts is null) { _cts = new CancellationTokenSource(); _cancellationHandlingAddedEvent?.Invoke(_cts); diff --git a/src/System.CommandLine/Invocation/InvocationPipeline.cs b/src/System.CommandLine/Invocation/InvocationPipeline.cs index a8124593a8..dd8d8d4a51 100644 --- a/src/System.CommandLine/Invocation/InvocationPipeline.cs +++ b/src/System.CommandLine/Invocation/InvocationPipeline.cs @@ -17,7 +17,7 @@ public InvocationPipeline(ParseResult parseResult) this.parseResult = parseResult ?? throw new ArgumentNullException(nameof(parseResult)); } - public async Task InvokeAsync(IConsole console = null) + public async Task InvokeAsync(IConsole? console = null) { var context = new InvocationContext(parseResult, console); @@ -28,7 +28,7 @@ public async Task InvokeAsync(IConsole console = null) return GetResultCode(context); } - public int Invoke(IConsole console = null) + public int Invoke(IConsole? console = null) { var context = new InvocationContext(parseResult, console); diff --git a/src/System.CommandLine/Invocation/ModelBindingCommandHandler.cs b/src/System.CommandLine/Invocation/ModelBindingCommandHandler.cs index ac8542746b..b037b26243 100644 --- a/src/System.CommandLine/Invocation/ModelBindingCommandHandler.cs +++ b/src/System.CommandLine/Invocation/ModelBindingCommandHandler.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.CommandLine.Binding; +using System.Diagnostics; using System.Linq; using System.Reflection; using System.Threading.Tasks; @@ -11,39 +12,39 @@ namespace System.CommandLine.Invocation { internal class ModelBindingCommandHandler : ICommandHandler { - private readonly Delegate _handlerDelegate; - private readonly object _invocationTarget; - private readonly ModelBinder _invocationTargetBinder; - private readonly MethodInfo _handlerMethodInfo; + private readonly Delegate? _handlerDelegate; + private readonly object? _invocationTarget; + private readonly ModelBinder? _invocationTargetBinder; + private readonly MethodInfo? _handlerMethodInfo; private readonly IReadOnlyList _parameterDescriptors; public ModelBindingCommandHandler( MethodInfo handlerMethodInfo, IReadOnlyList parameterDescriptors) { - _handlerMethodInfo = handlerMethodInfo; + _handlerMethodInfo = handlerMethodInfo ?? throw new ArgumentNullException(nameof(handlerMethodInfo)); _invocationTargetBinder = _handlerMethodInfo.IsStatic ? null : new ModelBinder(_handlerMethodInfo.DeclaringType); - _parameterDescriptors = parameterDescriptors; + _parameterDescriptors = parameterDescriptors ?? throw new ArgumentNullException(nameof(parameterDescriptors)); } public ModelBindingCommandHandler( MethodInfo handlerMethodInfo, IReadOnlyList parameterDescriptors, - object invocationTarget) + object? invocationTarget) { _invocationTarget = invocationTarget; - _handlerMethodInfo = handlerMethodInfo; - _parameterDescriptors = parameterDescriptors; + _handlerMethodInfo = handlerMethodInfo ?? throw new ArgumentNullException(nameof(handlerMethodInfo)); + _parameterDescriptors = parameterDescriptors ?? throw new ArgumentNullException(nameof(parameterDescriptors)); } public ModelBindingCommandHandler( Delegate handlerDelegate, IReadOnlyList parameterDescriptors) { - _handlerDelegate = handlerDelegate; - _parameterDescriptors = parameterDescriptors; + _handlerDelegate = handlerDelegate ?? throw new ArgumentNullException(nameof(handlerDelegate)); + _parameterDescriptors = parameterDescriptors ?? throw new ArgumentNullException(nameof(parameterDescriptors)); } public async Task InvokeAsync(InvocationContext context) @@ -63,9 +64,9 @@ public async Task InvokeAsync(InvocationContext context) _invocationTargetBinder?.CreateInstance(bindingContext); object result; - if (_handlerDelegate == null) + if (_handlerDelegate is null) { - result = _handlerMethodInfo.Invoke( + result = _handlerMethodInfo!.Invoke( invocationTarget, invocationArguments); } diff --git a/src/System.CommandLine/Invocation/Process.cs b/src/System.CommandLine/Invocation/Process.cs index 87cd1e87f9..023fa1218e 100644 --- a/src/System.CommandLine/Invocation/Process.cs +++ b/src/System.CommandLine/Invocation/Process.cs @@ -11,9 +11,9 @@ public static class Process public static async Task ExecuteAsync( string command, string args, - string workingDir = null, - Action stdOut = null, - Action stdErr = null, + string? workingDir = null, + Action? stdOut = null, + Action? stdErr = null, params (string key, string value)[] environmentVariables) { var process = StartProcess(command, @@ -39,9 +39,9 @@ await Task.Run(() => public static Diagnostics.Process StartProcess( string command, string args, - string workingDir = null, - Action stdOut = null, - Action stdErr = null, + string? workingDir = null, + Action? stdOut = null, + Action? stdErr = null, params (string key, string value)[] environmentVariables) { args = args ?? ""; diff --git a/src/System.CommandLine/Invocation/TypoCorrection.cs b/src/System.CommandLine/Invocation/TypoCorrection.cs index d38aa82fa3..47545d836a 100644 --- a/src/System.CommandLine/Invocation/TypoCorrection.cs +++ b/src/System.CommandLine/Invocation/TypoCorrection.cs @@ -57,7 +57,7 @@ private IEnumerable GetPossibleTokens(ISymbol targetSymbol, string token .TakeWhile(tuple => { var (_, distance) = tuple; - if (bestDistance == null) + if (bestDistance is null) { bestDistance = distance; } @@ -78,12 +78,12 @@ private static int GetStartsWithDistance(string first, string second) private static int GetDistance(string first, string second) { // Validate parameters - if (first == null) + if (first is null) { throw new ArgumentNullException(nameof(first)); } - if (second == null) + if (second is null) { throw new ArgumentNullException(nameof(second)); } diff --git a/src/System.CommandLine/Option.cs b/src/System.CommandLine/Option.cs index 4cd0fce9e1..75a6910208 100644 --- a/src/System.CommandLine/Option.cs +++ b/src/System.CommandLine/Option.cs @@ -10,7 +10,7 @@ namespace System.CommandLine { public class Option : Symbol, IOption { - public Option(string alias, string description = null) + public Option(string alias, string? description = null) : base(new[] { alias @@ -18,7 +18,7 @@ public Option(string alias, string description = null) { } - public Option(string[] aliases, string description = null) : base(aliases, description) + public Option(string[] aliases, string? description = null) : base(aliases, description) { } @@ -52,6 +52,6 @@ public virtual Argument Argument bool IValueDescriptor.HasDefaultValue => Argument.HasDefaultValue; - object IValueDescriptor.GetDefaultValue() => Argument.GetDefaultValue(); + object? IValueDescriptor.GetDefaultValue() => Argument.GetDefaultValue(); } } diff --git a/src/System.CommandLine/Option{T}.cs b/src/System.CommandLine/Option{T}.cs index 69e81fad2c..208d9a2ec5 100644 --- a/src/System.CommandLine/Option{T}.cs +++ b/src/System.CommandLine/Option{T}.cs @@ -9,14 +9,14 @@ public class Option : Option { public Option( string alias, - string description = null) : base(alias, description) + string? description = null) : base(alias, description) { Argument = new Argument(); } public Option( string[] aliases, - string description = null) : base(aliases, description) + string? description = null) : base(aliases, description) { Argument = new Argument(); } @@ -25,7 +25,7 @@ public Option( string alias, ParseArgument parseArgument, bool isDefault = false, - string description = null) : base(alias, description) + string? description = null) : base(alias, description) { if (parseArgument is null) { @@ -39,7 +39,7 @@ public Option( string[] aliases, ParseArgument parseArgument, bool isDefault = false, - string description = null) : base(aliases, description) + string? description = null) : base(aliases, description) { if (parseArgument is null) { @@ -52,7 +52,7 @@ public Option( public Option( string alias, Func getDefaultValue, - string description = null) : base(alias, description) + string? description = null) : base(alias, description) { if (getDefaultValue is null) { @@ -65,7 +65,7 @@ public Option( public Option( string[] aliases, Func getDefaultValue, - string description = null) : base(aliases, description) + string? description = null) : base(aliases, description) { if (getDefaultValue is null) { diff --git a/src/System.CommandLine/Parsing/ArgumentResult.cs b/src/System.CommandLine/Parsing/ArgumentResult.cs index b5fa1da6c7..770c23864b 100644 --- a/src/System.CommandLine/Parsing/ArgumentResult.cs +++ b/src/System.CommandLine/Parsing/ArgumentResult.cs @@ -8,11 +8,11 @@ namespace System.CommandLine.Parsing { public class ArgumentResult : SymbolResult { - private ArgumentConversionResult _conversionResult; + private ArgumentConversionResult? _conversionResult; internal ArgumentResult( IArgument argument, - SymbolResult parent) : base(argument, parent) + SymbolResult? parent) : base(argument, parent) { Argument = argument; } @@ -24,11 +24,11 @@ internal ArgumentConversionResult GetArgumentConversionResult() => public override string ToString() => $"{GetType().Name} {Argument.Name}: {string.Join(" ", Tokens.Select(t => $"<{t.Value}>"))}"; - internal ParseError CustomError(Argument argument) + internal ParseError? CustomError(Argument argument) { if (!string.IsNullOrEmpty(ErrorMessage)) { - return new ParseError(ErrorMessage, this); + return new ParseError(ErrorMessage!, this); } for (var i = 0; i < argument.Validators.Count; i++) @@ -38,7 +38,7 @@ internal ParseError CustomError(Argument argument) if (!string.IsNullOrWhiteSpace(errorMessage)) { - return new ParseError(errorMessage, this); + return new ParseError(errorMessage!, this); } } @@ -61,7 +61,7 @@ internal virtual ArgumentConversionResult Convert( if (argument is Argument arg) { - if (parentResult.UseDefaultValueFor(argument)) + if (parentResult!.UseDefaultValueFor(argument)) { var argumentResult = new ArgumentResult(arg, Parent); @@ -77,7 +77,7 @@ internal virtual ArgumentConversionResult Convert( { return ArgumentConversionResult.Failure( argument, - argumentResult.ErrorMessage); + argumentResult.ErrorMessage!); } } diff --git a/src/System.CommandLine/Parsing/ArgumentResultExtensions.cs b/src/System.CommandLine/Parsing/ArgumentResultExtensions.cs index cce0888477..9a35cff0f8 100644 --- a/src/System.CommandLine/Parsing/ArgumentResultExtensions.cs +++ b/src/System.CommandLine/Parsing/ArgumentResultExtensions.cs @@ -2,14 +2,16 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System.CommandLine.Binding; +using System.Diagnostics.CodeAnalysis; namespace System.CommandLine.Parsing { public static class ArgumentResultExtensions { - public static object GetValueOrDefault(this ArgumentResult argumentResult) => - argumentResult.GetValueOrDefault(); + public static object? GetValueOrDefault(this ArgumentResult argumentResult) => + argumentResult.GetValueOrDefault(); + [return: MaybeNull] public static T GetValueOrDefault(this ArgumentResult argumentResult) => argumentResult.GetArgumentConversionResult() .ConvertIfNeeded(argumentResult, typeof(T)) diff --git a/src/System.CommandLine/Parsing/CommandLineStringSplitter.cs b/src/System.CommandLine/Parsing/CommandLineStringSplitter.cs index 11facd4ca7..ccb91230f5 100644 --- a/src/System.CommandLine/Parsing/CommandLineStringSplitter.cs +++ b/src/System.CommandLine/Parsing/CommandLineStringSplitter.cs @@ -95,7 +95,7 @@ public IEnumerable Split(string commandLine) string CurrentToken() { - if (skipQuoteAtIndex == null) + if (skipQuoteAtIndex is null) { return memory.Slice( startTokenIndex, diff --git a/src/System.CommandLine/Parsing/CommandNode.cs b/src/System.CommandLine/Parsing/CommandNode.cs index be08998823..6d54a068c3 100644 --- a/src/System.CommandLine/Parsing/CommandNode.cs +++ b/src/System.CommandLine/Parsing/CommandNode.cs @@ -8,7 +8,7 @@ internal class CommandNode : NonterminalSyntaxNode public CommandNode( Token token, ICommand command, - CommandNode parent) : base(token, parent) + CommandNode? parent) : base(token, parent) { if (token.Type != TokenType.Command) { diff --git a/src/System.CommandLine/Parsing/CommandResult.cs b/src/System.CommandLine/Parsing/CommandResult.cs index 1afe397872..f62791012f 100644 --- a/src/System.CommandLine/Parsing/CommandResult.cs +++ b/src/System.CommandLine/Parsing/CommandResult.cs @@ -3,18 +3,19 @@ using System.Collections.Generic; using System.CommandLine.Binding; +using System.Diagnostics.CodeAnalysis; using System.Linq; namespace System.CommandLine.Parsing { public class CommandResult : SymbolResult { - private ArgumentConversionResultSet _results; + private ArgumentConversionResultSet? _results; internal CommandResult( ICommand command, Token token, - CommandResult parent = null) : + CommandResult? parent = null) : base(command ?? throw new ArgumentNullException(nameof(command)), parent) { @@ -25,9 +26,9 @@ internal CommandResult( public ICommand Command { get; } - public OptionResult this[string alias] => OptionResult(alias); + public OptionResult? this[string alias] => OptionResult(alias); - public OptionResult OptionResult(string alias) + public OptionResult? OptionResult(string alias) { return Children[alias] as OptionResult; } @@ -35,18 +36,21 @@ public OptionResult OptionResult(string alias) public Token Token { get; } - internal virtual RootCommandResult Root => (Parent as CommandResult)?.Root; + internal virtual RootCommandResult? Root => (Parent as CommandResult)?.Root; internal bool TryGetValueForArgument( IValueDescriptor valueDescriptor, - out object value) + out object? value) { - foreach (var argument in Command.Arguments) + if (valueDescriptor.ValueName is string valueName) { - if (valueDescriptor.ValueName.IsMatch(argument.Name)) + foreach (var argument in Command.Arguments) { - value = ArgumentConversionResults[argument.Name].GetValueOrDefault(); - return true; + if (valueName.IsMatch(argument.Name)) + { + value = ArgumentConversionResults[argument.Name]?.GetValueOrDefault(); + return true; + } } } @@ -54,7 +58,7 @@ internal bool TryGetValueForArgument( return false; } - public object ValueForOption(string alias) + public object? ValueForOption(string alias) { if (Children[alias] is OptionResult optionResult) { @@ -64,9 +68,10 @@ public object ValueForOption(string alias) } } - return ValueForOption(alias); + return ValueForOption(alias); } + [return: MaybeNull] public T ValueForOption(string alias) { if (string.IsNullOrWhiteSpace(alias)) @@ -80,7 +85,7 @@ public T ValueForOption(string alias) } else { - return default; + return default!; } } @@ -88,7 +93,7 @@ internal ArgumentConversionResultSet ArgumentConversionResults { get { - if (_results == null) + if (_results is null) { var results = Children .OfType() diff --git a/src/System.CommandLine/Parsing/CommandResultExtensions.cs b/src/System.CommandLine/Parsing/CommandResultExtensions.cs index 8933f9a4dd..4a69bb414e 100644 --- a/src/System.CommandLine/Parsing/CommandResultExtensions.cs +++ b/src/System.CommandLine/Parsing/CommandResultExtensions.cs @@ -1,19 +1,21 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System.CommandLine.Binding; +using System.Diagnostics.CodeAnalysis; using System.Linq; namespace System.CommandLine.Parsing { public static class CommandResultExtensions { - public static object GetArgumentValueOrDefault( + public static object? GetArgumentValueOrDefault( this CommandResult commandResult, string argumentName) { - return commandResult.GetArgumentValueOrDefault(argumentName); + return commandResult.GetArgumentValueOrDefault(argumentName); } + [return: MaybeNull] public static T GetArgumentValueOrDefault( this CommandResult commandResult, string argumentName) @@ -28,14 +30,14 @@ public static T GetArgumentValueOrDefault( internal static bool TryGetValueForOption( this CommandResult commandResult, IValueDescriptor valueDescriptor, - out object value) + out object? value) { var children = commandResult .Children - .Where(o => valueDescriptor.ValueName.IsMatch(o.Symbol)) + .Where(o => valueDescriptor.ValueName?.IsMatch(o.Symbol) == true) .ToArray(); - SymbolResult symbolResult = null; + SymbolResult? symbolResult = null; if (children.Length > 1) { diff --git a/src/System.CommandLine/Parsing/DirectiveNode.cs b/src/System.CommandLine/Parsing/DirectiveNode.cs index e1ea843810..a0010085ed 100644 --- a/src/System.CommandLine/Parsing/DirectiveNode.cs +++ b/src/System.CommandLine/Parsing/DirectiveNode.cs @@ -9,7 +9,7 @@ public DirectiveNode( Token token, RootCommandNode parent, string name, - string value) : base(token, parent) + string? value) : base(token, parent) { if (token.Type != TokenType.Directive) { @@ -22,6 +22,6 @@ public DirectiveNode( public string Name { get; } - public string Value { get; } + public string? Value { get; } } } diff --git a/src/System.CommandLine/Parsing/ImplicitToken.cs b/src/System.CommandLine/Parsing/ImplicitToken.cs index 612c33baca..e5acf2b8e4 100644 --- a/src/System.CommandLine/Parsing/ImplicitToken.cs +++ b/src/System.CommandLine/Parsing/ImplicitToken.cs @@ -5,11 +5,11 @@ namespace System.CommandLine.Parsing { internal class ImplicitToken : Token { - public ImplicitToken(object value, TokenType type) : base(value?.ToString(), type) + public ImplicitToken(object? value, TokenType type) : base(value?.ToString(), type) { ActualValue = value; } - public object ActualValue { get; } + public object? ActualValue { get; } } } diff --git a/src/System.CommandLine/Parsing/NonterminalSyntaxNode.cs b/src/System.CommandLine/Parsing/NonterminalSyntaxNode.cs index 77b54f7fc5..c3ae50e281 100644 --- a/src/System.CommandLine/Parsing/NonterminalSyntaxNode.cs +++ b/src/System.CommandLine/Parsing/NonterminalSyntaxNode.cs @@ -9,7 +9,7 @@ internal abstract class NonterminalSyntaxNode : SyntaxNode { private readonly List _children = new List(); - protected NonterminalSyntaxNode(Token token, SyntaxNode parent) : base(token, parent) + protected NonterminalSyntaxNode(Token token, SyntaxNode? parent) : base(token, parent) { } diff --git a/src/System.CommandLine/Parsing/OptionResult.cs b/src/System.CommandLine/Parsing/OptionResult.cs index 8facef4d4f..28207c6229 100644 --- a/src/System.CommandLine/Parsing/OptionResult.cs +++ b/src/System.CommandLine/Parsing/OptionResult.cs @@ -8,12 +8,12 @@ namespace System.CommandLine.Parsing { public class OptionResult : SymbolResult { - private ArgumentConversionResult _argumentConversionResult; + private ArgumentConversionResult? _argumentConversionResult; internal OptionResult( IOption option, - Token token = null, - CommandResult parent = null) : + Token? token = null, + CommandResult? parent = null) : base(option ?? throw new ArgumentNullException(nameof(option)), parent) { @@ -25,7 +25,7 @@ internal OptionResult( public bool IsImplicit => Token is ImplicitToken || Token is null; - public Token Token { get; } + public Token? Token { get; } private protected override int RemainingArgumentCapacity { @@ -46,7 +46,7 @@ internal ArgumentConversionResult ArgumentConversionResult { get { - if (_argumentConversionResult == null) + if (_argumentConversionResult is null) { var results = Children .OfType() diff --git a/src/System.CommandLine/Parsing/OptionResultExtensions.cs b/src/System.CommandLine/Parsing/OptionResultExtensions.cs index 38f0474912..443639125e 100644 --- a/src/System.CommandLine/Parsing/OptionResultExtensions.cs +++ b/src/System.CommandLine/Parsing/OptionResultExtensions.cs @@ -2,7 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System.CommandLine.Binding; -using System.Linq; +using System.Diagnostics.CodeAnalysis; namespace System.CommandLine.Parsing { @@ -12,7 +12,7 @@ internal static ArgumentConversionResult ConvertIfNeeded( this OptionResult optionResult, Type type) { - if (optionResult == null) + if (optionResult is null) { throw new ArgumentNullException(nameof(optionResult)); } @@ -21,11 +21,12 @@ internal static ArgumentConversionResult ConvertIfNeeded( .ConvertIfNeeded(optionResult, type); } - public static object GetValueOrDefault(this OptionResult optionResult) + public static object? GetValueOrDefault(this OptionResult optionResult) { - return optionResult.GetValueOrDefault(); + return optionResult.GetValueOrDefault(); } + [return: MaybeNull] public static T GetValueOrDefault(this OptionResult optionResult) { return optionResult.ConvertIfNeeded(typeof(T)) diff --git a/src/System.CommandLine/Parsing/ParseError.cs b/src/System.CommandLine/Parsing/ParseError.cs index 3351aa268d..1c0a96e7f8 100644 --- a/src/System.CommandLine/Parsing/ParseError.cs +++ b/src/System.CommandLine/Parsing/ParseError.cs @@ -7,7 +7,7 @@ public class ParseError { internal ParseError( string message, - SymbolResult symbolResult = null) + SymbolResult? symbolResult = null) { if (string.IsNullOrWhiteSpace(message)) { @@ -20,7 +20,7 @@ internal ParseError( public string Message { get; } - public SymbolResult SymbolResult { get; } + public SymbolResult? SymbolResult { get; } public override string ToString() => Message; } diff --git a/src/System.CommandLine/Parsing/ParseOperation.cs b/src/System.CommandLine/Parsing/ParseOperation.cs index 04eebeb3c2..4d2aa44031 100644 --- a/src/System.CommandLine/Parsing/ParseOperation.cs +++ b/src/System.CommandLine/Parsing/ParseOperation.cs @@ -26,7 +26,7 @@ public ParseOperation( public List Errors { get; } = new List(); - public RootCommandNode RootCommandNode { get; private set; } + public RootCommandNode? RootCommandNode { get; private set; } public List UnmatchedTokens { get; } = new List(); @@ -84,7 +84,7 @@ private RootCommandNode ParseRootCommand() return rootCommandNode; } - private CommandNode ParseSubcommand(CommandNode parentNode) + private CommandNode? ParseSubcommand(CommandNode parentNode) { if (CurrentToken.Type != TokenType.Command) { @@ -95,7 +95,7 @@ private CommandNode ParseSubcommand(CommandNode parentNode) .Children .GetByAlias(CurrentToken.Value) as ICommand; - if (command == null) + if (command is null) { return null; } @@ -119,10 +119,10 @@ private void ParseCommandChildren(CommandNode parent) } var child = ParseSubcommand(parent) ?? - (SyntaxNode)ParseOption(parent) ?? + (SyntaxNode?)ParseOption(parent) ?? ParseCommandArgument(parent); - if (child == null) + if (child is null) { UnmatchedTokens.Add(CurrentToken); Advance(); @@ -134,7 +134,7 @@ private void ParseCommandChildren(CommandNode parent) } } - private CommandArgumentNode ParseCommandArgument(CommandNode commandNode) + private CommandArgumentNode? ParseCommandArgument(CommandNode commandNode) { if (CurrentToken.Type != TokenType.Argument) { @@ -145,7 +145,7 @@ private CommandArgumentNode ParseCommandArgument(CommandNode commandNode) .Arguments .FirstOrDefault(a => !IsFull(a)); - if (argument == null) + if (argument is null) { return null; } @@ -162,14 +162,14 @@ private CommandArgumentNode ParseCommandArgument(CommandNode commandNode) return argumentNode; } - private OptionNode ParseOption(CommandNode parent) + private OptionNode? ParseOption(CommandNode parent) { if (CurrentToken.Type != TokenType.Option) { return null; } - OptionNode optionNode = null; + OptionNode? optionNode = null; if (parent.Command.Children.GetByAlias(CurrentToken.Value) is IOption option) { diff --git a/src/System.CommandLine/Parsing/ParseResult.cs b/src/System.CommandLine/Parsing/ParseResult.cs index 4d7b46603d..e476af5c2f 100644 --- a/src/System.CommandLine/Parsing/ParseResult.cs +++ b/src/System.CommandLine/Parsing/ParseResult.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; namespace System.CommandLine.Parsing @@ -19,8 +20,8 @@ internal ParseResult( TokenizeResult tokenizeResult, IReadOnlyCollection unparsedTokens, IReadOnlyCollection unmatchedTokens, - List errors = null, - string rawInput = null) + List? errors = null, + string? rawInput = null) { Parser = parser; _rootCommandResult = rootCommandResult; @@ -59,16 +60,15 @@ internal ParseResult( public IReadOnlyCollection UnmatchedTokens { get; } - internal string RawInput { get; } + internal string? RawInput { get; } public IReadOnlyCollection UnparsedTokens { get; } - public object ValueForOption( - string alias) => - ValueForOption(alias); + public object? ValueForOption(string alias) => + ValueForOption(alias); - public T ValueForOption( - string alias) + [return: MaybeNull] + public T ValueForOption(string alias) { if (string.IsNullOrWhiteSpace(alias)) { @@ -81,21 +81,21 @@ public T ValueForOption( } else { - return default; + return default!; } } - public SymbolResult this[string alias] => CommandResult.Children[alias]; + public SymbolResult? this[string alias] => CommandResult.Children[alias]; public override string ToString() => $"{nameof(ParseResult)}: {this.Diagram()}"; - public ArgumentResult FindResultFor(IArgument argument) => + public ArgumentResult? FindResultFor(IArgument argument) => _rootCommandResult.FindResultFor(argument); - - public CommandResult FindResultFor(ICommand command) => + + public CommandResult? FindResultFor(ICommand command) => _rootCommandResult.FindResultFor(command); - public OptionResult FindResultFor(IOption option) => + public OptionResult? FindResultFor(IOption option) => _rootCommandResult.FindResultFor(option); } } diff --git a/src/System.CommandLine/Parsing/ParseResultExtensions.cs b/src/System.CommandLine/Parsing/ParseResultExtensions.cs index 92a4af04f3..b7f5301459 100644 --- a/src/System.CommandLine/Parsing/ParseResultExtensions.cs +++ b/src/System.CommandLine/Parsing/ParseResultExtensions.cs @@ -16,22 +16,22 @@ public static class ParseResultExtensions { public static async Task InvokeAsync( this ParseResult parseResult, - IConsole console = null) => + IConsole? console = null) => await new InvocationPipeline(parseResult).InvokeAsync(console); public static int Invoke( this ParseResult parseResult, - IConsole console = null) => + IConsole? console = null) => new InvocationPipeline(parseResult).Invoke(console); public static string TextToMatch( this ParseResult source, int? position = null) { - var lastToken = source.Tokens.LastOrDefault(t => t.Type != TokenType.Directive); + Token? lastToken = source.Tokens.LastOrDefault(t => t.Type != TokenType.Directive); - string textToMatch = null; - var rawInput = source.RawInput; + string? textToMatch = null; + string? rawInput = source.RawInput; if (rawInput != null) { @@ -59,12 +59,12 @@ public static string TextToMatch( if (source.UnmatchedTokens.Any() || lastToken?.Type == TokenType.Argument) { - return textToMatch; + return textToMatch ?? ""; } } else { - var textBeforeCursor = rawInput.Substring(0, position.Value); + var textBeforeCursor = rawInput!.Substring(0, position!.Value); var textAfterCursor = rawInput.Substring(position.Value); @@ -186,7 +186,7 @@ public static bool HasOption( this ParseResult parseResult, IOption option) { - if (parseResult == null) + if (parseResult is null) { throw new ArgumentNullException(nameof(parseResult)); } @@ -198,7 +198,7 @@ public static bool HasOption( this ParseResult parseResult, string alias) { - if (parseResult == null) + if (parseResult is null) { throw new ArgumentNullException(nameof(parseResult)); } @@ -206,7 +206,7 @@ public static bool HasOption( return parseResult.CommandResult.Children.Contains(alias); } - public static IEnumerable GetSuggestions( + public static IEnumerable GetSuggestions( this ParseResult parseResult, int? position = null) { @@ -219,13 +219,13 @@ currentSymbol is ISuggestionSource currentSuggestionSource ? currentSuggestionSource.GetSuggestions(textToMatch) : Array.Empty(); - IEnumerable siblingSuggestions; + IEnumerable siblingSuggestions; var parentSymbol = currentSymbolResult.Parent?.Symbol; - if (parentSymbol == null || + if (parentSymbol is null || !currentSymbolResult.IsArgumentLimitReached) { - siblingSuggestions = Array.Empty(); + siblingSuggestions = Array.Empty(); } else { diff --git a/src/System.CommandLine/Parsing/ParseResultVisitor.cs b/src/System.CommandLine/Parsing/ParseResultVisitor.cs index c51656bfe6..c85d0ef92e 100644 --- a/src/System.CommandLine/Parsing/ParseResultVisitor.cs +++ b/src/System.CommandLine/Parsing/ParseResultVisitor.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.CommandLine.Binding; using System.CommandLine.Help; +using System.Diagnostics; using System.Linq; namespace System.CommandLine.Parsing @@ -12,15 +13,15 @@ internal class ParseResultVisitor : SyntaxVisitor { private readonly Parser _parser; private readonly TokenizeResult _tokenizeResult; - private readonly string _rawInput; + private readonly string? _rawInput; private readonly DirectiveCollection _directives = new DirectiveCollection(); private readonly List _unparsedTokens; private readonly List _unmatchedTokens; private readonly List _errors; - private RootCommandResult _rootCommandResult; - private CommandResult _innermostCommandResult; + private RootCommandResult? _rootCommandResult; + private CommandResult? _innermostCommandResult; public ParseResultVisitor( Parser parser, @@ -28,7 +29,7 @@ public ParseResultVisitor( IReadOnlyCollection unparsedTokens, IReadOnlyCollection unmatchedTokens, IReadOnlyCollection parseErrors, - string rawInput) + string? rawInput) { _parser = parser; _tokenizeResult = tokenizeResult; @@ -68,7 +69,9 @@ protected override void VisitCommandNode(CommandNode commandNode) commandNode.Token, _innermostCommandResult); - _innermostCommandResult + Debug.Assert(_innermostCommandResult != null); + + _innermostCommandResult! .Children .Add(commandResult); @@ -81,11 +84,11 @@ protected override void VisitCommandArgumentNode( var commandResult = _innermostCommandResult; var argumentResult = - commandResult.Children + commandResult!.Children .OfType() .SingleOrDefault(r => r.Symbol == argumentNode.Argument); - if (argumentResult == null) + if (argumentResult is null) { argumentResult = new ArgumentResult( @@ -101,7 +104,7 @@ protected override void VisitCommandArgumentNode( protected override void VisitOptionNode(OptionNode optionNode) { - if (_innermostCommandResult.Children.ResultFor(optionNode.Option) == null) + if (_innermostCommandResult!.Children.ResultFor(optionNode.Option) is null) { var optionResult = new OptionResult( optionNode.Option, @@ -119,14 +122,14 @@ protected override void VisitOptionArgumentNode( { var option = argumentNode.ParentOptionNode.Option; - var optionResult = _innermostCommandResult.Children.ResultFor(option); + var optionResult = _innermostCommandResult!.Children.ResultFor(option); var argument = argumentNode.Argument; var argumentResult = - (ArgumentResult)optionResult.Children.ResultFor(argument); + (ArgumentResult?)optionResult!.Children.ResultFor(argument); - if (argumentResult == null) + if (argumentResult is null) { argumentResult = new ArgumentResult( @@ -157,7 +160,7 @@ protected override void Stop(SyntaxNode node) ValidateCommandResult(); - foreach (var result in _innermostCommandResult.Children.ToArray()) + foreach (var result in _innermostCommandResult!.Children.ToArray()) { switch (result) { @@ -178,7 +181,7 @@ protected override void Stop(SyntaxNode node) private void ValidateCommandResult() { - if (_innermostCommandResult.Command is Command command) + if (_innermostCommandResult!.Command is Command command) { foreach (var validator in command.Validators) { @@ -187,7 +190,7 @@ private void ValidateCommandResult() if (!string.IsNullOrWhiteSpace(errorMessage)) { _errors.Add( - new ParseError(errorMessage, _innermostCommandResult)); + new ParseError(errorMessage!, _innermostCommandResult)); } } } @@ -198,7 +201,7 @@ private void ValidateCommandResult() { if (option is Option o && o.Required && - _rootCommandResult.FindResultFor(o) == null) + _rootCommandResult!.FindResultFor(o) is null) { _errors.Add( new ParseError($"Option '{o.RawAliases.First()}' is required.", @@ -219,14 +222,14 @@ private void ValidateCommandResult() if (arityFailure != null) { _errors.Add( - new ParseError(arityFailure.ErrorMessage, _innermostCommandResult)); + new ParseError(arityFailure.ErrorMessage!, _innermostCommandResult)); } } } private void ValidateCommandHandler() { - if (!(_innermostCommandResult.Command is Command cmd) || + if (!(_innermostCommandResult!.Command is Command cmd) || cmd.Handler != null) { return; @@ -261,7 +264,7 @@ private void ValidateOptionResult(OptionResult optionResult) if (arityFailure != null) { _errors.Add( - new ParseError(arityFailure.ErrorMessage, optionResult)); + new ParseError(arityFailure.ErrorMessage!, optionResult)); } if (optionResult.Option is Option option) @@ -272,7 +275,7 @@ private void ValidateOptionResult(OptionResult optionResult) if (!string.IsNullOrWhiteSpace(message)) { - _errors.Add(new ParseError(message, optionResult)); + _errors.Add(new ParseError(message!, optionResult)); } } } @@ -290,7 +293,7 @@ private void ValidateArgumentResult(ArgumentResult argumentResult) if (argumentResult.Argument is Argument argument) { var parseError = - argumentResult.Parent.UnrecognizedArgumentError(argument) ?? + argumentResult.Parent?.UnrecognizedArgumentError(argument) ?? argumentResult.CustomError(argument); if (parseError != null) @@ -304,23 +307,23 @@ private void ValidateArgumentResult(ArgumentResult argumentResult) { _errors.Add( new ParseError( - failed.ErrorMessage, + failed.ErrorMessage!, argumentResult)); } } private void PopulateDefaultValues() { - var commandResults = _innermostCommandResult + var commandResults = _innermostCommandResult! .RecurseWhileNotNull(c => c.Parent as CommandResult); foreach (var commandResult in commandResults) { foreach (var symbol in commandResult.Command.Children) { - var symbolResult = _rootCommandResult.FindResultFor(symbol); + var symbolResult = _rootCommandResult!.FindResultFor(symbol); - if (symbolResult == null) + if (symbolResult is null) { switch (symbol) { @@ -367,8 +370,8 @@ private void PopulateDefaultValues() public ParseResult Result => new ParseResult( _parser, - _rootCommandResult, - _innermostCommandResult, + _rootCommandResult ?? throw new InvalidOperationException("No root command was found"), + _innermostCommandResult ?? throw new InvalidOperationException("No command was found"), _directives, _tokenizeResult, _unparsedTokens, diff --git a/src/System.CommandLine/Parsing/Parser.cs b/src/System.CommandLine/Parsing/Parser.cs index a007a1baa7..5ef852c39d 100644 --- a/src/System.CommandLine/Parsing/Parser.cs +++ b/src/System.CommandLine/Parsing/Parser.cs @@ -24,7 +24,7 @@ public Parser() : this(new RootCommand()) public ParseResult Parse( IReadOnlyList arguments, - string rawInput = null) + string? rawInput = null) { var tokenizeResult = arguments.Tokenize(Configuration); @@ -42,7 +42,7 @@ public ParseResult Parse( operation.Errors, rawInput); - visitor.Visit(operation.RootCommandNode); + visitor.Visit(operation.RootCommandNode!); return visitor.Result; } diff --git a/src/System.CommandLine/Parsing/ParserExtensions.cs b/src/System.CommandLine/Parsing/ParserExtensions.cs index 864e1509b7..16d018abe0 100644 --- a/src/System.CommandLine/Parsing/ParserExtensions.cs +++ b/src/System.CommandLine/Parsing/ParserExtensions.cs @@ -11,25 +11,25 @@ public static class ParserExtensions public static int Invoke( this Parser parser, string commandLine, - IConsole console = null) => + IConsole? console = null) => parser.Invoke(CommandLineStringSplitter.Instance.Split(commandLine).ToArray(), console); public static int Invoke( this Parser parser, string[] args, - IConsole console = null) => + IConsole? console = null) => parser.Parse(args).Invoke(console); public static Task InvokeAsync( this Parser parser, string commandLine, - IConsole console = null) => + IConsole? console = null) => parser.InvokeAsync(CommandLineStringSplitter.Instance.Split(commandLine).ToArray(), console); public static async Task InvokeAsync( this Parser parser, string[] args, - IConsole console = null) => + IConsole? console = null) => await parser.Parse(args).InvokeAsync(console); public static ParseResult Parse( diff --git a/src/System.CommandLine/Parsing/RootCommandResult.cs b/src/System.CommandLine/Parsing/RootCommandResult.cs index 783e842bf0..fd81cdf3c8 100644 --- a/src/System.CommandLine/Parsing/RootCommandResult.cs +++ b/src/System.CommandLine/Parsing/RootCommandResult.cs @@ -7,9 +7,9 @@ namespace System.CommandLine.Parsing { internal class RootCommandResult : CommandResult { - private Dictionary _allArgumentResults; - private Dictionary _allCommandResults; - private Dictionary _allOptionResults; + private Dictionary? _allArgumentResults; + private Dictionary? _allCommandResults; + private Dictionary? _allOptionResults; public RootCommandResult( ICommand command, @@ -47,34 +47,34 @@ private void EnsureResultMapsAreInitialized() } } - public ArgumentResult FindResultFor(IArgument argument) + public ArgumentResult? FindResultFor(IArgument argument) { EnsureResultMapsAreInitialized(); - _allArgumentResults.TryGetValue(argument, out var result); + _allArgumentResults!.TryGetValue(argument, out var result); return result; } - public CommandResult FindResultFor(ICommand command) + public CommandResult? FindResultFor(ICommand command) { EnsureResultMapsAreInitialized(); - _allCommandResults.TryGetValue(command, out var result); + _allCommandResults!.TryGetValue(command, out var result); return result; } - public OptionResult FindResultFor(IOption option) + public OptionResult? FindResultFor(IOption option) { EnsureResultMapsAreInitialized(); - _allOptionResults.TryGetValue(option, out var result); + _allOptionResults!.TryGetValue(option, out var result); return result; } - public SymbolResult FindResultFor(ISymbol symbol) + public SymbolResult? FindResultFor(ISymbol symbol) { switch (symbol) { @@ -84,26 +84,28 @@ public SymbolResult FindResultFor(ISymbol symbol) return FindResultFor(command); case IOption option: return FindResultFor(option); - default: + default: throw new ArgumentException($"Unsupported symbol type: {symbol.GetType()}"); } } internal void AddToSymbolMap(SymbolResult result) { - switch (result) + EnsureResultMapsAreInitialized(); + + switch (result) { case ArgumentResult argumentResult: - _allArgumentResults.Add(argumentResult.Argument, argumentResult); + _allArgumentResults!.Add(argumentResult.Argument, argumentResult); break; case CommandResult commandResult: - _allCommandResults.Add(commandResult.Command, commandResult); + _allCommandResults!.Add(commandResult.Command, commandResult); break; case OptionResult optionResult: - _allOptionResults.Add(optionResult.Option, optionResult); + _allOptionResults!.Add(optionResult.Option, optionResult); break; - - default: + + default: throw new ArgumentException($"Unsupported {nameof(SymbolResult)} type: {result.GetType()}"); } } diff --git a/src/System.CommandLine/Parsing/StringExtensions.cs b/src/System.CommandLine/Parsing/StringExtensions.cs index 1c454bdd87..ca93ab0602 100644 --- a/src/System.CommandLine/Parsing/StringExtensions.cs +++ b/src/System.CommandLine/Parsing/StringExtensions.cs @@ -16,12 +16,12 @@ public static class StringExtensions internal static bool ContainsCaseInsensitive( this string source, - string value) => + string? value) => source.IndexOfCaseInsensitive(value) >= 0; internal static int IndexOfCaseInsensitive( this string source, - string value) => + string? value) => CultureInfo.InvariantCulture .CompareInfo .IndexOf(source, @@ -41,7 +41,7 @@ internal static string RemovePrefix(this string rawAlias) return rawAlias; } - internal static (string prefix, string alias) SplitPrefix(this string rawAlias) + internal static (string? prefix, string alias) SplitPrefix(this string rawAlias) { foreach (var prefix in _optionPrefixStrings) { @@ -61,7 +61,7 @@ internal static TokenizeResult Tokenize( var tokenList = new List(); var errorList = new List(); - ICommand currentCommand = null; + ICommand? currentCommand = null; var foundEndOfArguments = false; var foundEndOfDirectives = !configuration.EnableDirectives; var argList = NormalizeRootCommand(configuration, args); @@ -113,7 +113,7 @@ internal static TokenizeResult Tokenize( } if (configuration.EnablePosixBundling && - CanBeUnbundled(arg, out var replacement)) + CanBeUnbundled(arg, out IEnumerable? replacement)) { argList.InsertRange(i + 1, replacement); argList.RemoveAt(i); @@ -166,7 +166,7 @@ internal static TokenizeResult Tokenize( symbolSet = configuration.Symbols; } - currentCommand = (ICommand) symbolSet.GetByAlias(arg); + currentCommand = (ICommand) symbolSet.GetByAlias(arg)!; knownTokens = currentCommand.ValidTokens(); knownTokensStrings = new HashSet(knownTokens.Select(t => t.Value)); tokenList.Add(Command(arg)); @@ -176,7 +176,7 @@ internal static TokenizeResult Tokenize( return new TokenizeResult(tokenList, errorList); - bool CanBeUnbundled(string arg, out IReadOnlyList replacement) + bool CanBeUnbundled(string arg, out IEnumerable? replacement) { replacement = null; @@ -194,7 +194,7 @@ bool CanBeUnbundled(string arg, out IReadOnlyList replacement) return prefix == "-" && TryUnbundle(alias, out replacement); - Token TokenForOptionAlias(char c) => + Token? TokenForOptionAlias(char c) => argumentDelimiters.Contains(c) ? null : knownTokens.FirstOrDefault(t => @@ -213,7 +213,7 @@ void AddRestValue(List list, string rest) } } - bool TryUnbundle(string arg, out IReadOnlyList replacement) + bool TryUnbundle(string arg, out IEnumerable? replacement) { if (arg == string.Empty) { @@ -226,7 +226,7 @@ bool TryUnbundle(string arg, out IReadOnlyList replacement) for (var i = 0; i < arg.Length; i++) { var token = TokenForOptionAlias(arg[i]); - if (token == null) + if (token is null) { if (lastTokenHasArgument) { @@ -318,14 +318,14 @@ void ReadResponseFile(string filePath, int i) private static List NormalizeRootCommand( CommandLineConfiguration commandLineConfiguration, - IReadOnlyList args) + IReadOnlyList? args) { - if (args == null) + if (args is null) { args = new List(); } - string potentialRootCommand = null; + string? potentialRootCommand = null; if (args.Count > 0) { @@ -338,7 +338,8 @@ private static List NormalizeRootCommand( // possible exception for illegal characters in path on .NET Framework } - if (commandLineConfiguration.RootCommand.HasRawAlias(potentialRootCommand)) + if (potentialRootCommand != null && + commandLineConfiguration.RootCommand.HasRawAlias(potentialRootCommand)) { return args.ToList(); } @@ -366,7 +367,7 @@ private static List NormalizeRootCommand( bool FirstArgMatchesRootCommand() { - if (potentialRootCommand == null) + if (potentialRootCommand is null) { return false; } @@ -385,7 +386,7 @@ bool FirstArgMatchesRootCommand() } } - private static string GetResponseFileReference(this string arg) => + private static string? GetResponseFileReference(this string arg) => arg.StartsWith("@") && arg.Length > 1 ? arg.Substring(1) : null; @@ -405,7 +406,7 @@ public static string ToKebabCase(this string value) int i = 0; bool addDash = false; - // handles beginning of string, breaks onfirst letter or digit. addDash might be better named "canAddDash" + // handles beginning of string, breaks on first letter or digit. addDash might be better named "canAddDash" for (; i < value.Length; i++) { char ch = value[i]; diff --git a/src/System.CommandLine/Parsing/SymbolResult.cs b/src/System.CommandLine/Parsing/SymbolResult.cs index e11da6ee7d..e316d2390f 100644 --- a/src/System.CommandLine/Parsing/SymbolResult.cs +++ b/src/System.CommandLine/Parsing/SymbolResult.cs @@ -9,23 +9,23 @@ namespace System.CommandLine.Parsing public abstract class SymbolResult { private protected readonly List _tokens = new List(); - private ValidationMessages _validationMessages; + private ValidationMessages? _validationMessages; private readonly Dictionary _defaultArgumentValues = new Dictionary(); private protected SymbolResult( ISymbol symbol, - SymbolResult parent) + SymbolResult? parent) { Symbol = symbol ?? throw new ArgumentNullException(nameof(symbol)); Parent = parent; } - public string ErrorMessage { get; set; } + public string? ErrorMessage { get; set; } public SymbolResultSet Children { get; } = new SymbolResultSet(); - public SymbolResult Parent { get; } + public SymbolResult? Parent { get; } public ISymbol Symbol { get; } @@ -44,9 +44,9 @@ protected internal ValidationMessages ValidationMessages { get { - if (_validationMessages == null) + if (_validationMessages is null) { - if (Parent == null) + if (Parent is null) { _validationMessages = ValidationMessages.Instance; } @@ -89,7 +89,7 @@ when Children.ResultFor(argument)?.Tokens.Count == 0: public override string ToString() => $"{GetType().Name}: {this.Token()}"; - internal ParseError UnrecognizedArgumentError(Argument argument) + internal ParseError? UnrecognizedArgumentError(Argument argument) { if (argument.AllowedValues?.Count > 0 && Tokens.Count > 0) diff --git a/src/System.CommandLine/Parsing/SymbolResultExtensions.cs b/src/System.CommandLine/Parsing/SymbolResultExtensions.cs index 3988bb585e..3c00fe5e37 100644 --- a/src/System.CommandLine/Parsing/SymbolResultExtensions.cs +++ b/src/System.CommandLine/Parsing/SymbolResultExtensions.cs @@ -10,7 +10,7 @@ internal static class SymbolResultExtensions { internal static IEnumerable AllSymbolResults(this SymbolResult symbolResult) { - if (symbolResult == null) + if (symbolResult is null) { throw new ArgumentNullException(nameof(symbolResult)); } diff --git a/src/System.CommandLine/Parsing/SymbolResultSet.cs b/src/System.CommandLine/Parsing/SymbolResultSet.cs index 90d28c0b19..0e9dc3ad2e 100644 --- a/src/System.CommandLine/Parsing/SymbolResultSet.cs +++ b/src/System.CommandLine/Parsing/SymbolResultSet.cs @@ -9,7 +9,7 @@ namespace System.CommandLine.Parsing { public class SymbolResultSet : AliasedSet { - internal SymbolResult ResultFor(ISymbol symbol) => + internal SymbolResult? ResultFor(ISymbol symbol) => Items.SingleOrDefault(i => i.Symbol == symbol); protected override IReadOnlyList GetAliases(SymbolResult item) => diff --git a/src/System.CommandLine/Parsing/SyntaxNode.cs b/src/System.CommandLine/Parsing/SyntaxNode.cs index ef5fd4eb6c..48105dec91 100644 --- a/src/System.CommandLine/Parsing/SyntaxNode.cs +++ b/src/System.CommandLine/Parsing/SyntaxNode.cs @@ -7,13 +7,13 @@ internal abstract class SyntaxNode { protected SyntaxNode( Token token, - SyntaxNode parent) + SyntaxNode? parent) { Token = token; Parent = parent; } - public SyntaxNode Parent { get; } + public SyntaxNode? Parent { get; } public Token Token { get; } diff --git a/src/System.CommandLine/Parsing/Token.cs b/src/System.CommandLine/Parsing/Token.cs index e7f13357f5..407a28ff09 100644 --- a/src/System.CommandLine/Parsing/Token.cs +++ b/src/System.CommandLine/Parsing/Token.cs @@ -7,7 +7,7 @@ namespace System.CommandLine.Parsing { public class Token { - public Token(string value, TokenType type) + public Token(string? value, TokenType type) { Value = value ?? ""; Type = type; diff --git a/src/System.CommandLine/Parsing/ValidateSymbol.cs b/src/System.CommandLine/Parsing/ValidateSymbol.cs index a12b3efb95..e18011ce0f 100644 --- a/src/System.CommandLine/Parsing/ValidateSymbol.cs +++ b/src/System.CommandLine/Parsing/ValidateSymbol.cs @@ -3,6 +3,6 @@ namespace System.CommandLine.Parsing { - public delegate string ValidateSymbol(T symbolResult) + public delegate string? ValidateSymbol(T symbolResult) where T : SymbolResult; } diff --git a/src/System.CommandLine/Platform.cs b/src/System.CommandLine/Platform.cs index 2fd4209ad1..742895eb70 100644 --- a/src/System.CommandLine/Platform.cs +++ b/src/System.CommandLine/Platform.cs @@ -8,7 +8,7 @@ public static bool IsConsoleRedirectionCheckSupported { get { - if (_isConsoleRedirectionCheckSupported == null) + if (_isConsoleRedirectionCheckSupported is null) { try { diff --git a/src/System.CommandLine/Suggestions/AnonymousSuggestionSource.cs b/src/System.CommandLine/Suggestions/AnonymousSuggestionSource.cs index f82b770c90..c564375d11 100644 --- a/src/System.CommandLine/Suggestions/AnonymousSuggestionSource.cs +++ b/src/System.CommandLine/Suggestions/AnonymousSuggestionSource.cs @@ -7,16 +7,16 @@ namespace System.CommandLine.Suggestions { internal class AnonymousSuggestionSource : ISuggestionSource { - private readonly Suggest suggest; + private readonly Suggest _suggest; public AnonymousSuggestionSource(Suggest suggest) { - this.suggest = suggest; + _suggest = suggest ?? throw new ArgumentNullException(nameof(suggest)); } - public IEnumerable GetSuggestions(string textToMatch = null) + public IEnumerable GetSuggestions(string? textToMatch = null) { - return suggest(textToMatch); + return _suggest(textToMatch); } } } diff --git a/src/System.CommandLine/Suggestions/ISuggestionSource.cs b/src/System.CommandLine/Suggestions/ISuggestionSource.cs index ca52aa70f4..1bc37ea66c 100644 --- a/src/System.CommandLine/Suggestions/ISuggestionSource.cs +++ b/src/System.CommandLine/Suggestions/ISuggestionSource.cs @@ -7,6 +7,6 @@ namespace System.CommandLine.Suggestions { public interface ISuggestionSource { - IEnumerable GetSuggestions(string textToMatch = null); + IEnumerable GetSuggestions(string? textToMatch = null); } } diff --git a/src/System.CommandLine/Suggestions/Suggest.cs b/src/System.CommandLine/Suggestions/Suggest.cs index cb064f6de8..58a3bb0987 100644 --- a/src/System.CommandLine/Suggestions/Suggest.cs +++ b/src/System.CommandLine/Suggestions/Suggest.cs @@ -5,5 +5,5 @@ namespace System.CommandLine.Suggestions { - public delegate IEnumerable Suggest(string textToMatch); + public delegate IEnumerable Suggest(string? textToMatch); } diff --git a/src/System.CommandLine/Suggestions/Suggestions.cs b/src/System.CommandLine/Suggestions/Suggestions.cs index 8906603d33..93b75b5697 100644 --- a/src/System.CommandLine/Suggestions/Suggestions.cs +++ b/src/System.CommandLine/Suggestions/Suggestions.cs @@ -9,9 +9,9 @@ namespace System.CommandLine.Suggestions { internal static class SuggestionExtensions { - public static IEnumerable Containing( - this IEnumerable candidates, - string textToMatch) => - candidates.Where(c => c.ContainsCaseInsensitive(textToMatch)); + public static IEnumerable Containing( + this IEnumerable candidates, + string? textToMatch) => + candidates.Where(c => c?.ContainsCaseInsensitive(textToMatch) == true); } } diff --git a/src/System.CommandLine/Symbol.cs b/src/System.CommandLine/Symbol.cs index 5ee41c3a10..8010190a52 100644 --- a/src/System.CommandLine/Symbol.cs +++ b/src/System.CommandLine/Symbol.cs @@ -14,7 +14,7 @@ public abstract class Symbol : ISymbol private readonly List _aliases = new List(); private readonly List _rawAliases = new List(); private string _longestAlias = ""; - private string _specifiedName; + private string? _specifiedName; private readonly SymbolSet _parents = new SymbolSet(); @@ -23,10 +23,10 @@ private protected Symbol() } protected Symbol( - IReadOnlyCollection aliases = null, - string description = null) + IReadOnlyCollection? aliases = null, + string? description = null) { - if (aliases == null) + if (aliases is null) { throw new ArgumentNullException(nameof(aliases)); } @@ -48,7 +48,7 @@ protected Symbol( public IReadOnlyList RawAliases => _rawAliases; - public string Description { get; set; } + public string? Description { get; set; } public virtual string Name { @@ -78,7 +78,7 @@ private protected virtual void AddSymbol(Symbol symbol) private protected void AddArgumentInner(Argument argument) { - if (argument == null) + if (argument is null) { throw new ArgumentNullException(nameof(argument)); } @@ -104,7 +104,7 @@ public void AddAlias(string alias) throw new ArgumentException("An alias cannot be null, empty, or consist entirely of whitespace."); } - for (var i = 0; i < alias.Length; i++) + for (var i = 0; i < alias!.Length; i++) { if (char.IsWhiteSpace(alias[i])) { @@ -113,9 +113,9 @@ public void AddAlias(string alias) } _rawAliases.Add(alias); - _aliases.Add(unprefixedAlias); + _aliases.Add(unprefixedAlias!); - if (unprefixedAlias.Length > Name?.Length) + if (unprefixedAlias!.Length > Name?.Length) { _longestAlias = unprefixedAlias; } @@ -135,7 +135,7 @@ public bool HasAlias(string alias) public bool IsHidden { get; set; } - public virtual IEnumerable GetSuggestions(string textToMatch = null) + public virtual IEnumerable GetSuggestions(string? textToMatch = null) { var argumentSuggestions = Children @@ -147,7 +147,8 @@ public virtual IEnumerable GetSuggestions(string textToMatch = null) .Concat(argumentSuggestions) .Distinct() .Containing(textToMatch) - .OrderBy(symbol => symbol.IndexOfCaseInsensitive(textToMatch)) + .Where(symbol => symbol != null) + .OrderBy(symbol => symbol!.IndexOfCaseInsensitive(textToMatch)) .ThenBy(symbol => symbol, StringComparer.OrdinalIgnoreCase); } diff --git a/src/System.CommandLine/System.CommandLine.csproj b/src/System.CommandLine/System.CommandLine.csproj index 15e29f459b..5841d89c0d 100644 --- a/src/System.CommandLine/System.CommandLine.csproj +++ b/src/System.CommandLine/System.CommandLine.csproj @@ -1,10 +1,11 @@ - + true System.CommandLine netstandard2.0 8 + enable This package includes a powerful command line parser and other tools for building command line applications, including: * Shell-agnostic support for command line completions @@ -17,6 +18,10 @@ portable + + + + diff --git a/src/System.Diagnostics.CodeAnalysis.cs b/src/System.Diagnostics.CodeAnalysis.cs new file mode 100644 index 0000000000..8df0ee9dd7 --- /dev/null +++ b/src/System.Diagnostics.CodeAnalysis.cs @@ -0,0 +1,70 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#pragma warning disable CA1801, CA1822 + +namespace System.Diagnostics.CodeAnalysis +{ + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)] + internal sealed class AllowNullAttribute : Attribute + { + } + + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)] + internal sealed class DisallowNullAttribute : Attribute + { + } + + [AttributeUsage(AttributeTargets.Method, Inherited = false)] + internal sealed class DoesNotReturnAttribute : Attribute + { + } + + [AttributeUsage(AttributeTargets.Parameter)] + internal sealed class DoesNotReturnIfAttribute : Attribute + { + public DoesNotReturnIfAttribute(bool parameterValue) { } + + public bool ParameterValue { get { throw null!; } } + } + + [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Constructor | AttributeTargets.Event | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Struct, Inherited = false, AllowMultiple = false)] + internal sealed class ExcludeFromCodeCoverageAttribute : Attribute + { + } + + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)] + internal sealed class MaybeNullAttribute : Attribute + { + } + + [AttributeUsage(AttributeTargets.Parameter)] + internal sealed class MaybeNullWhenAttribute : Attribute + { + public MaybeNullWhenAttribute(bool returnValue) { } + + public bool ReturnValue { get { throw null!; } } + } + + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)] + internal sealed class NotNullAttribute : Attribute + { + } + + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, AllowMultiple = true, Inherited = false)] + internal sealed class NotNullIfNotNullAttribute : Attribute + { + public NotNullIfNotNullAttribute(string parameterName) { } + + public string ParameterName { get { throw null!; } } + } + + [AttributeUsage(AttributeTargets.Parameter)] + internal sealed class NotNullWhenAttribute : Attribute + { + public NotNullWhenAttribute(bool returnValue) { } + + public bool ReturnValue { get { throw null!; } } + } +} \ No newline at end of file