diff --git a/CliFx.Analyzers.Tests/CliFx.Analyzers.Tests.csproj b/CliFx.Analyzers.Tests/CliFx.Analyzers.Tests.csproj index 09a4d41..bbb4ed3 100644 --- a/CliFx.Analyzers.Tests/CliFx.Analyzers.Tests.csproj +++ b/CliFx.Analyzers.Tests/CliFx.Analyzers.Tests.csproj @@ -9,15 +9,15 @@ - - - + + + - - - - + + + + diff --git a/CliFx.Analyzers.Tests/GeneralSpecs.cs b/CliFx.Analyzers.Tests/GeneralSpecs.cs index 1fc1d40..0aaa23a 100644 --- a/CliFx.Analyzers.Tests/GeneralSpecs.cs +++ b/CliFx.Analyzers.Tests/GeneralSpecs.cs @@ -13,8 +13,7 @@ public class GeneralSpecs { // Arrange var analyzers = typeof(AnalyzerBase) - .Assembly - .GetTypes() + .Assembly.GetTypes() .Where(t => !t.IsAbstract && t.IsAssignableTo(typeof(DiagnosticAnalyzer))) .Select(t => (DiagnosticAnalyzer)Activator.CreateInstance(t)!) .ToArray(); diff --git a/CliFx.Analyzers.Tests/OptionMustHaveNameOrShortNameAnalyzerSpecs.cs b/CliFx.Analyzers.Tests/OptionMustHaveNameOrShortNameAnalyzerSpecs.cs index e9fae73..2eff6f5 100644 --- a/CliFx.Analyzers.Tests/OptionMustHaveNameOrShortNameAnalyzerSpecs.cs +++ b/CliFx.Analyzers.Tests/OptionMustHaveNameOrShortNameAnalyzerSpecs.cs @@ -20,7 +20,7 @@ public class OptionMustHaveNameOrShortNameAnalyzerSpecs { [CommandOption(null)] public string? Foo { get; init; } - + public ValueTask ExecuteAsync(IConsole console) => default; } """; @@ -40,7 +40,7 @@ public class OptionMustHaveNameOrShortNameAnalyzerSpecs { [CommandOption("foo")] public string? Foo { get; init; } - + public ValueTask ExecuteAsync(IConsole console) => default; } """; @@ -60,7 +60,7 @@ public class OptionMustHaveNameOrShortNameAnalyzerSpecs { [CommandOption('f')] public string? Foo { get; init; } - + public ValueTask ExecuteAsync(IConsole console) => default; } """; @@ -79,7 +79,7 @@ public class OptionMustHaveNameOrShortNameAnalyzerSpecs public class MyCommand : ICommand { public string? Foo { get; init; } - + public ValueTask ExecuteAsync(IConsole console) => default; } """; diff --git a/CliFx.Analyzers.Tests/OptionMustHaveUniqueNameAnalyzerSpecs.cs b/CliFx.Analyzers.Tests/OptionMustHaveUniqueNameAnalyzerSpecs.cs index d242695..3a70039 100644 --- a/CliFx.Analyzers.Tests/OptionMustHaveUniqueNameAnalyzerSpecs.cs +++ b/CliFx.Analyzers.Tests/OptionMustHaveUniqueNameAnalyzerSpecs.cs @@ -19,10 +19,10 @@ public class OptionMustHaveUniqueNameAnalyzerSpecs { [CommandOption("foo")] public string? Foo { get; init; } - + [CommandOption("foo")] public string? Bar { get; init; } - + public ValueTask ExecuteAsync(IConsole console) => default; } """; @@ -42,10 +42,10 @@ public class OptionMustHaveUniqueNameAnalyzerSpecs { [CommandOption("foo")] public string? Foo { get; init; } - + [CommandOption("bar")] public string? Bar { get; init; } - + public ValueTask ExecuteAsync(IConsole console) => default; } """; @@ -65,7 +65,7 @@ public class OptionMustHaveUniqueNameAnalyzerSpecs { [CommandOption('f')] public string? Foo { get; init; } - + public ValueTask ExecuteAsync(IConsole console) => default; } """; @@ -84,7 +84,7 @@ public class OptionMustHaveUniqueNameAnalyzerSpecs public class MyCommand : ICommand { public string? Foo { get; init; } - + public ValueTask ExecuteAsync(IConsole console) => default; } """; diff --git a/CliFx.Analyzers.Tests/OptionMustHaveUniqueShortNameAnalyzerSpecs.cs b/CliFx.Analyzers.Tests/OptionMustHaveUniqueShortNameAnalyzerSpecs.cs index 8a09a1b..09c2f82 100644 --- a/CliFx.Analyzers.Tests/OptionMustHaveUniqueShortNameAnalyzerSpecs.cs +++ b/CliFx.Analyzers.Tests/OptionMustHaveUniqueShortNameAnalyzerSpecs.cs @@ -20,10 +20,10 @@ public class OptionMustHaveUniqueShortNameAnalyzerSpecs { [CommandOption('f')] public string? Foo { get; init; } - + [CommandOption('f')] public string? Bar { get; init; } - + public ValueTask ExecuteAsync(IConsole console) => default; } """; @@ -43,10 +43,10 @@ public class OptionMustHaveUniqueShortNameAnalyzerSpecs { [CommandOption('f')] public string? Foo { get; init; } - + [CommandOption('b')] public string? Bar { get; init; } - + public ValueTask ExecuteAsync(IConsole console) => default; } """; @@ -66,10 +66,10 @@ public class OptionMustHaveUniqueShortNameAnalyzerSpecs { [CommandOption('f')] public string? Foo { get; init; } - + [CommandOption('F')] public string? Bar { get; init; } - + public ValueTask ExecuteAsync(IConsole console) => default; } """; @@ -89,7 +89,7 @@ public class OptionMustHaveUniqueShortNameAnalyzerSpecs { [CommandOption("foo")] public string? Foo { get; init; } - + public ValueTask ExecuteAsync(IConsole console) => default; } """; @@ -108,7 +108,7 @@ public class OptionMustHaveUniqueShortNameAnalyzerSpecs public class MyCommand : ICommand { public string? Foo { get; init; } - + public ValueTask ExecuteAsync(IConsole console) => default; } """; diff --git a/CliFx.Analyzers.Tests/OptionMustHaveValidNameAnalyzerSpecs.cs b/CliFx.Analyzers.Tests/OptionMustHaveValidNameAnalyzerSpecs.cs index f55e161..2f4ab73 100644 --- a/CliFx.Analyzers.Tests/OptionMustHaveValidNameAnalyzerSpecs.cs +++ b/CliFx.Analyzers.Tests/OptionMustHaveValidNameAnalyzerSpecs.cs @@ -19,7 +19,7 @@ public class OptionMustHaveValidNameAnalyzerSpecs { [CommandOption("f")] public string? Foo { get; init; } - + public ValueTask ExecuteAsync(IConsole console) => default; } """; @@ -39,7 +39,7 @@ public class OptionMustHaveValidNameAnalyzerSpecs { [CommandOption("1foo")] public string? Foo { get; init; } - + public ValueTask ExecuteAsync(IConsole console) => default; } """; @@ -59,7 +59,7 @@ public class OptionMustHaveValidNameAnalyzerSpecs { [CommandOption("foo")] public string? Foo { get; init; } - + public ValueTask ExecuteAsync(IConsole console) => default; } """; @@ -79,7 +79,7 @@ public class OptionMustHaveValidNameAnalyzerSpecs { [CommandOption('f')] public string? Foo { get; init; } - + public ValueTask ExecuteAsync(IConsole console) => default; } """; @@ -98,7 +98,7 @@ public class OptionMustHaveValidNameAnalyzerSpecs public class MyCommand : ICommand { public string? Foo { get; init; } - + public ValueTask ExecuteAsync(IConsole console) => default; } """; diff --git a/CliFx.Analyzers.Tests/OptionMustHaveValidShortNameAnalyzerSpecs.cs b/CliFx.Analyzers.Tests/OptionMustHaveValidShortNameAnalyzerSpecs.cs index a086b40..e810e79 100644 --- a/CliFx.Analyzers.Tests/OptionMustHaveValidShortNameAnalyzerSpecs.cs +++ b/CliFx.Analyzers.Tests/OptionMustHaveValidShortNameAnalyzerSpecs.cs @@ -20,7 +20,7 @@ public class OptionMustHaveValidShortNameAnalyzerSpecs { [CommandOption('1')] public string? Foo { get; init; } - + public ValueTask ExecuteAsync(IConsole console) => default; } """; @@ -40,7 +40,7 @@ public class OptionMustHaveValidShortNameAnalyzerSpecs { [CommandOption('f')] public string? Foo { get; init; } - + public ValueTask ExecuteAsync(IConsole console) => default; } """; @@ -60,7 +60,7 @@ public class OptionMustHaveValidShortNameAnalyzerSpecs { [CommandOption("foo")] public string? Foo { get; init; } - + public ValueTask ExecuteAsync(IConsole console) => default; } """; @@ -79,7 +79,7 @@ public class OptionMustHaveValidShortNameAnalyzerSpecs public class MyCommand : ICommand { public string? Foo { get; init; } - + public ValueTask ExecuteAsync(IConsole console) => default; } """; diff --git a/CliFx.Analyzers.Tests/OptionMustHaveValidValidatorsAnalyzerSpecs.cs b/CliFx.Analyzers.Tests/OptionMustHaveValidValidatorsAnalyzerSpecs.cs index d454d36..ebd2546 100644 --- a/CliFx.Analyzers.Tests/OptionMustHaveValidValidatorsAnalyzerSpecs.cs +++ b/CliFx.Analyzers.Tests/OptionMustHaveValidValidatorsAnalyzerSpecs.cs @@ -19,13 +19,13 @@ public class OptionMustHaveValidValidatorsAnalyzerSpecs { public void Validate(string value) {} } - + [Command] public class MyCommand : ICommand { [CommandOption("foo", Validators = new[] { typeof(MyValidator) })] public string? Foo { get; init; } - + public ValueTask ExecuteAsync(IConsole console) => default; } """; @@ -44,13 +44,13 @@ public class OptionMustHaveValidValidatorsAnalyzerSpecs { public override BindingValidationError Validate(int value) => Ok(); } - + [Command] public class MyCommand : ICommand { [CommandOption("foo", Validators = new[] { typeof(MyValidator) })] public string? Foo { get; init; } - + public ValueTask ExecuteAsync(IConsole console) => default; } """; @@ -69,13 +69,13 @@ public class OptionMustHaveValidValidatorsAnalyzerSpecs { public override BindingValidationError Validate(string value) => Ok(); } - + [Command] public class MyCommand : ICommand { [CommandOption("foo", Validators = new[] { typeof(MyValidator) })] public string? Foo { get; init; } - + public ValueTask ExecuteAsync(IConsole console) => default; } """; @@ -95,7 +95,7 @@ public class OptionMustHaveValidValidatorsAnalyzerSpecs { [CommandOption("foo")] public string? Foo { get; init; } - + public ValueTask ExecuteAsync(IConsole console) => default; } """; @@ -114,7 +114,7 @@ public class OptionMustHaveValidValidatorsAnalyzerSpecs public class MyCommand : ICommand { public string? Foo { get; init; } - + public ValueTask ExecuteAsync(IConsole console) => default; } """; diff --git a/CliFx.Analyzers.Tests/SystemConsoleShouldBeAvoidedAnalyzerSpecs.cs b/CliFx.Analyzers.Tests/SystemConsoleShouldBeAvoidedAnalyzerSpecs.cs index 6216cc4..a2db943 100644 --- a/CliFx.Analyzers.Tests/SystemConsoleShouldBeAvoidedAnalyzerSpecs.cs +++ b/CliFx.Analyzers.Tests/SystemConsoleShouldBeAvoidedAnalyzerSpecs.cs @@ -103,7 +103,7 @@ public class SystemConsoleShouldBeAvoidedAnalyzerSpecs public class MyCommand : ICommand { public void SomeOtherMethod() => Console.WriteLine("Test"); - + public ValueTask ExecuteAsync(IConsole console) => default; } """; diff --git a/CliFx.Analyzers.Tests/Utils/AnalyzerAssertions.cs b/CliFx.Analyzers.Tests/Utils/AnalyzerAssertions.cs index 100caa7..4475db6 100644 --- a/CliFx.Analyzers.Tests/Utils/AnalyzerAssertions.cs +++ b/CliFx.Analyzers.Tests/Utils/AnalyzerAssertions.cs @@ -30,8 +30,7 @@ internal class AnalyzerAssertions(DiagnosticAnalyzer analyzer) // Get default CliFx namespaces var defaultCliFxNamespaces = typeof(ICommand) - .Assembly - .GetTypes() + .Assembly.GetTypes() .Where(t => t.IsPublic) .Select(t => t.Namespace) .Distinct() @@ -54,10 +53,9 @@ internal class AnalyzerAssertions(DiagnosticAnalyzer analyzer) var compilation = CSharpCompilation.Create( "CliFxTests_DynamicAssembly_" + Guid.NewGuid(), [ast], - Net80 - .References - .All - .Append(MetadataReference.CreateFromFile(typeof(ICommand).Assembly.Location)), + Net80.References.All.Append( + MetadataReference.CreateFromFile(typeof(ICommand).Assembly.Location) + ), // DLL to avoid having to define the Main() method new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary) ); @@ -105,8 +103,7 @@ internal class AnalyzerAssertions(DiagnosticAnalyzer analyzer) == expectedDiagnosticIds.Length; Execute - .Assertion - .ForCondition(isSuccessfulAssertion) + .Assertion.ForCondition(isSuccessfulAssertion) .FailWith(() => { var buffer = new StringBuilder(); @@ -150,8 +147,7 @@ internal class AnalyzerAssertions(DiagnosticAnalyzer analyzer) var isSuccessfulAssertion = !producedDiagnostics.Any(); Execute - .Assertion - .ForCondition(isSuccessfulAssertion) + .Assertion.ForCondition(isSuccessfulAssertion) .FailWith(() => { var buffer = new StringBuilder(); diff --git a/CliFx.Analyzers/CliFx.Analyzers.csproj b/CliFx.Analyzers/CliFx.Analyzers.csproj index 6c1d415..72d720a 100644 --- a/CliFx.Analyzers/CliFx.Analyzers.csproj +++ b/CliFx.Analyzers/CliFx.Analyzers.csproj @@ -17,11 +17,11 @@ - + - + \ No newline at end of file diff --git a/CliFx.Analyzers/CommandMustBeAnnotatedAnalyzer.cs b/CliFx.Analyzers/CommandMustBeAnnotatedAnalyzer.cs index ea22c34..78c98f1 100644 --- a/CliFx.Analyzers/CommandMustBeAnnotatedAnalyzer.cs +++ b/CliFx.Analyzers/CommandMustBeAnnotatedAnalyzer.cs @@ -26,8 +26,8 @@ public class CommandMustBeAnnotatedAnalyzer() if (type.IsAbstract) return; - var implementsCommandInterface = type.AllInterfaces.Any( - i => i.DisplayNameMatches(SymbolNames.CliFxCommandInterface) + var implementsCommandInterface = type.AllInterfaces.Any(i => + i.DisplayNameMatches(SymbolNames.CliFxCommandInterface) ); var hasCommandAttribute = type.GetAttributes() diff --git a/CliFx.Analyzers/CommandMustImplementInterfaceAnalyzer.cs b/CliFx.Analyzers/CommandMustImplementInterfaceAnalyzer.cs index 31a83e0..94321b4 100644 --- a/CliFx.Analyzers/CommandMustImplementInterfaceAnalyzer.cs +++ b/CliFx.Analyzers/CommandMustImplementInterfaceAnalyzer.cs @@ -24,8 +24,8 @@ public class CommandMustImplementInterfaceAnalyzer() .Select(a => a.AttributeClass) .Any(c => c.DisplayNameMatches(SymbolNames.CliFxCommandAttribute)); - var implementsCommandInterface = type.AllInterfaces.Any( - i => i.DisplayNameMatches(SymbolNames.CliFxCommandInterface) + var implementsCommandInterface = type.AllInterfaces.Any(i => + i.DisplayNameMatches(SymbolNames.CliFxCommandInterface) ); // If the attribute is present, but the interface is not implemented, diff --git a/CliFx.Analyzers/ObjectModel/CommandOptionSymbol.cs b/CliFx.Analyzers/ObjectModel/CommandOptionSymbol.cs index eba71dd..1307035 100644 --- a/CliFx.Analyzers/ObjectModel/CommandOptionSymbol.cs +++ b/CliFx.Analyzers/ObjectModel/CommandOptionSymbol.cs @@ -32,10 +32,9 @@ internal partial class CommandOptionSymbol private static AttributeData? TryGetOptionAttribute(IPropertySymbol property) => property .GetAttributes() - .FirstOrDefault( - a => - a.AttributeClass?.DisplayNameMatches(SymbolNames.CliFxCommandOptionAttribute) - == true + .FirstOrDefault(a => + a.AttributeClass?.DisplayNameMatches(SymbolNames.CliFxCommandOptionAttribute) + == true ); public static CommandOptionSymbol? TryResolve(IPropertySymbol property) @@ -46,35 +45,30 @@ internal partial class CommandOptionSymbol var name = attribute - .ConstructorArguments - .Where(a => a.Type?.SpecialType == SpecialType.System_String) + .ConstructorArguments.Where(a => a.Type?.SpecialType == SpecialType.System_String) .Select(a => a.Value) .FirstOrDefault() as string; var shortName = attribute - .ConstructorArguments - .Where(a => a.Type?.SpecialType == SpecialType.System_Char) + .ConstructorArguments.Where(a => a.Type?.SpecialType == SpecialType.System_Char) .Select(a => a.Value) .FirstOrDefault() as char?; var isRequired = attribute - .NamedArguments - .Where(a => a.Key == "IsRequired") + .NamedArguments.Where(a => a.Key == "IsRequired") .Select(a => a.Value.Value) .FirstOrDefault() as bool?; var converter = attribute - .NamedArguments - .Where(a => a.Key == "Converter") + .NamedArguments.Where(a => a.Key == "Converter") .Select(a => a.Value.Value) .Cast() .FirstOrDefault(); var validators = attribute - .NamedArguments - .Where(a => a.Key == "Validators") + .NamedArguments.Where(a => a.Key == "Validators") .SelectMany(a => a.Value.Values) .Select(c => c.Value) .Cast() diff --git a/CliFx.Analyzers/ObjectModel/CommandParameterSymbol.cs b/CliFx.Analyzers/ObjectModel/CommandParameterSymbol.cs index a748a1d..ac5b6e6 100644 --- a/CliFx.Analyzers/ObjectModel/CommandParameterSymbol.cs +++ b/CliFx.Analyzers/ObjectModel/CommandParameterSymbol.cs @@ -32,10 +32,9 @@ internal partial class CommandParameterSymbol private static AttributeData? TryGetParameterAttribute(IPropertySymbol property) => property .GetAttributes() - .FirstOrDefault( - a => - a.AttributeClass?.DisplayNameMatches(SymbolNames.CliFxCommandParameterAttribute) - == true + .FirstOrDefault(a => + a.AttributeClass?.DisplayNameMatches(SymbolNames.CliFxCommandParameterAttribute) + == true ); public static CommandParameterSymbol? TryResolve(IPropertySymbol property) @@ -48,28 +47,24 @@ internal partial class CommandParameterSymbol var name = attribute - .NamedArguments - .Where(a => a.Key == "Name") + .NamedArguments.Where(a => a.Key == "Name") .Select(a => a.Value.Value) .FirstOrDefault() as string; var isRequired = attribute - .NamedArguments - .Where(a => a.Key == "IsRequired") + .NamedArguments.Where(a => a.Key == "IsRequired") .Select(a => a.Value.Value) .FirstOrDefault() as bool?; var converter = attribute - .NamedArguments - .Where(a => a.Key == "Converter") + .NamedArguments.Where(a => a.Key == "Converter") .Select(a => a.Value.Value) .Cast() .FirstOrDefault(); var validators = attribute - .NamedArguments - .Where(a => a.Key == "Validators") + .NamedArguments.Where(a => a.Key == "Validators") .SelectMany(a => a.Value.Values) .Select(c => c.Value) .Cast() diff --git a/CliFx.Analyzers/OptionMustBeInsideCommandAnalyzer.cs b/CliFx.Analyzers/OptionMustBeInsideCommandAnalyzer.cs index 84f9842..82f3121 100644 --- a/CliFx.Analyzers/OptionMustBeInsideCommandAnalyzer.cs +++ b/CliFx.Analyzers/OptionMustBeInsideCommandAnalyzer.cs @@ -29,10 +29,9 @@ public class OptionMustBeInsideCommandAnalyzer() if (!CommandOptionSymbol.IsOptionProperty(property)) return; - var isInsideCommand = property - .ContainingType - .AllInterfaces - .Any(i => i.DisplayNameMatches(SymbolNames.CliFxCommandInterface)); + var isInsideCommand = property.ContainingType.AllInterfaces.Any(i => + i.DisplayNameMatches(SymbolNames.CliFxCommandInterface) + ); if (!isInsideCommand) { diff --git a/CliFx.Analyzers/OptionMustHaveUniqueNameAnalyzer.cs b/CliFx.Analyzers/OptionMustHaveUniqueNameAnalyzer.cs index 730a68c..3e779e8 100644 --- a/CliFx.Analyzers/OptionMustHaveUniqueNameAnalyzer.cs +++ b/CliFx.Analyzers/OptionMustHaveUniqueNameAnalyzer.cs @@ -34,8 +34,7 @@ public class OptionMustHaveUniqueNameAnalyzer() return; var otherProperties = property - .ContainingType - .GetMembers() + .ContainingType.GetMembers() .OfType() .Where(m => !m.Equals(property)) .ToArray(); diff --git a/CliFx.Analyzers/OptionMustHaveUniqueShortNameAnalyzer.cs b/CliFx.Analyzers/OptionMustHaveUniqueShortNameAnalyzer.cs index 84f686a..6f9bb4c 100644 --- a/CliFx.Analyzers/OptionMustHaveUniqueShortNameAnalyzer.cs +++ b/CliFx.Analyzers/OptionMustHaveUniqueShortNameAnalyzer.cs @@ -33,8 +33,7 @@ public class OptionMustHaveUniqueShortNameAnalyzer() return; var otherProperties = property - .ContainingType - .GetMembers() + .ContainingType.GetMembers() .OfType() .Where(m => !m.Equals(property)) .ToArray(); diff --git a/CliFx.Analyzers/OptionMustHaveValidConverterAnalyzer.cs b/CliFx.Analyzers/OptionMustHaveValidConverterAnalyzer.cs index 515a164..a8e3ef6 100644 --- a/CliFx.Analyzers/OptionMustHaveValidConverterAnalyzer.cs +++ b/CliFx.Analyzers/OptionMustHaveValidConverterAnalyzer.cs @@ -28,13 +28,11 @@ public class OptionMustHaveValidConverterAnalyzer() return; var converterValueType = option - .ConverterType - .GetBaseTypes() - .FirstOrDefault( - t => t.ConstructedFrom.DisplayNameMatches(SymbolNames.CliFxBindingConverterClass) + .ConverterType.GetBaseTypes() + .FirstOrDefault(t => + t.ConstructedFrom.DisplayNameMatches(SymbolNames.CliFxBindingConverterClass) ) - ?.TypeArguments - .FirstOrDefault(); + ?.TypeArguments.FirstOrDefault(); // Value returned by the converter must be assignable to the property type var isCompatible = @@ -45,9 +43,10 @@ public class OptionMustHaveValidConverterAnalyzer() ? context.Compilation.IsAssignable(converterValueType, property.Type) // Non-scalar (assume we can handle all IEnumerable types for simplicity) : property.Type.TryGetEnumerableUnderlyingType() is { } enumerableUnderlyingType - && context - .Compilation - .IsAssignable(converterValueType, enumerableUnderlyingType) + && context.Compilation.IsAssignable( + converterValueType, + enumerableUnderlyingType + ) ); if (!isCompatible) diff --git a/CliFx.Analyzers/OptionMustHaveValidValidatorsAnalyzer.cs b/CliFx.Analyzers/OptionMustHaveValidValidatorsAnalyzer.cs index 8561cbd..e1be507 100644 --- a/CliFx.Analyzers/OptionMustHaveValidValidatorsAnalyzer.cs +++ b/CliFx.Analyzers/OptionMustHaveValidValidatorsAnalyzer.cs @@ -28,12 +28,10 @@ public class OptionMustHaveValidValidatorsAnalyzer() { var validatorValueType = validatorType .GetBaseTypes() - .FirstOrDefault( - t => - t.ConstructedFrom.DisplayNameMatches(SymbolNames.CliFxBindingValidatorClass) + .FirstOrDefault(t => + t.ConstructedFrom.DisplayNameMatches(SymbolNames.CliFxBindingValidatorClass) ) - ?.TypeArguments - .FirstOrDefault(); + ?.TypeArguments.FirstOrDefault(); // Value passed to the validator must be assignable from the property type var isCompatible = diff --git a/CliFx.Analyzers/ParameterMustBeInsideCommandAnalyzer.cs b/CliFx.Analyzers/ParameterMustBeInsideCommandAnalyzer.cs index 104dc5f..f7bb43f 100644 --- a/CliFx.Analyzers/ParameterMustBeInsideCommandAnalyzer.cs +++ b/CliFx.Analyzers/ParameterMustBeInsideCommandAnalyzer.cs @@ -29,10 +29,9 @@ public class ParameterMustBeInsideCommandAnalyzer() if (!CommandParameterSymbol.IsParameterProperty(property)) return; - var isInsideCommand = property - .ContainingType - .AllInterfaces - .Any(i => i.DisplayNameMatches(SymbolNames.CliFxCommandInterface)); + var isInsideCommand = property.ContainingType.AllInterfaces.Any(i => + i.DisplayNameMatches(SymbolNames.CliFxCommandInterface) + ); if (!isInsideCommand) { diff --git a/CliFx.Analyzers/ParameterMustBeLastIfNonRequiredAnalyzer.cs b/CliFx.Analyzers/ParameterMustBeLastIfNonRequiredAnalyzer.cs index 7bde97b..578e815 100644 --- a/CliFx.Analyzers/ParameterMustBeLastIfNonRequiredAnalyzer.cs +++ b/CliFx.Analyzers/ParameterMustBeLastIfNonRequiredAnalyzer.cs @@ -32,8 +32,7 @@ public class ParameterMustBeLastIfNonRequiredAnalyzer() return; var otherProperties = property - .ContainingType - .GetMembers() + .ContainingType.GetMembers() .OfType() .Where(m => !m.Equals(property)) .ToArray(); diff --git a/CliFx.Analyzers/ParameterMustBeLastIfNonScalarAnalyzer.cs b/CliFx.Analyzers/ParameterMustBeLastIfNonScalarAnalyzer.cs index 8dbbd4e..3eee558 100644 --- a/CliFx.Analyzers/ParameterMustBeLastIfNonScalarAnalyzer.cs +++ b/CliFx.Analyzers/ParameterMustBeLastIfNonScalarAnalyzer.cs @@ -32,8 +32,7 @@ public class ParameterMustBeLastIfNonScalarAnalyzer() return; var otherProperties = property - .ContainingType - .GetMembers() + .ContainingType.GetMembers() .OfType() .Where(m => !m.Equals(property)) .ToArray(); diff --git a/CliFx.Analyzers/ParameterMustBeSingleIfNonRequiredAnalyzer.cs b/CliFx.Analyzers/ParameterMustBeSingleIfNonRequiredAnalyzer.cs index ac1710a..5c0e186 100644 --- a/CliFx.Analyzers/ParameterMustBeSingleIfNonRequiredAnalyzer.cs +++ b/CliFx.Analyzers/ParameterMustBeSingleIfNonRequiredAnalyzer.cs @@ -32,8 +32,7 @@ public class ParameterMustBeSingleIfNonRequiredAnalyzer() return; var otherProperties = property - .ContainingType - .GetMembers() + .ContainingType.GetMembers() .OfType() .Where(m => !m.Equals(property)) .ToArray(); diff --git a/CliFx.Analyzers/ParameterMustBeSingleIfNonScalarAnalyzer.cs b/CliFx.Analyzers/ParameterMustBeSingleIfNonScalarAnalyzer.cs index 1a3a767..d25c2aa 100644 --- a/CliFx.Analyzers/ParameterMustBeSingleIfNonScalarAnalyzer.cs +++ b/CliFx.Analyzers/ParameterMustBeSingleIfNonScalarAnalyzer.cs @@ -32,8 +32,7 @@ public class ParameterMustBeSingleIfNonScalarAnalyzer() return; var otherProperties = property - .ContainingType - .GetMembers() + .ContainingType.GetMembers() .OfType() .Where(m => !m.Equals(property)) .ToArray(); diff --git a/CliFx.Analyzers/ParameterMustHaveUniqueNameAnalyzer.cs b/CliFx.Analyzers/ParameterMustHaveUniqueNameAnalyzer.cs index 4397313..7d8d55d 100644 --- a/CliFx.Analyzers/ParameterMustHaveUniqueNameAnalyzer.cs +++ b/CliFx.Analyzers/ParameterMustHaveUniqueNameAnalyzer.cs @@ -34,8 +34,7 @@ public class ParameterMustHaveUniqueNameAnalyzer() return; var otherProperties = property - .ContainingType - .GetMembers() + .ContainingType.GetMembers() .OfType() .Where(m => !m.Equals(property)) .ToArray(); diff --git a/CliFx.Analyzers/ParameterMustHaveUniqueOrderAnalyzer.cs b/CliFx.Analyzers/ParameterMustHaveUniqueOrderAnalyzer.cs index 8a26e7d..c46643b 100644 --- a/CliFx.Analyzers/ParameterMustHaveUniqueOrderAnalyzer.cs +++ b/CliFx.Analyzers/ParameterMustHaveUniqueOrderAnalyzer.cs @@ -30,8 +30,7 @@ public class ParameterMustHaveUniqueOrderAnalyzer() return; var otherProperties = property - .ContainingType - .GetMembers() + .ContainingType.GetMembers() .OfType() .Where(m => !m.Equals(property)) .ToArray(); diff --git a/CliFx.Analyzers/ParameterMustHaveValidConverterAnalyzer.cs b/CliFx.Analyzers/ParameterMustHaveValidConverterAnalyzer.cs index e1b1abb..5e59790 100644 --- a/CliFx.Analyzers/ParameterMustHaveValidConverterAnalyzer.cs +++ b/CliFx.Analyzers/ParameterMustHaveValidConverterAnalyzer.cs @@ -28,13 +28,11 @@ public class ParameterMustHaveValidConverterAnalyzer() return; var converterValueType = parameter - .ConverterType - .GetBaseTypes() - .FirstOrDefault( - t => t.ConstructedFrom.DisplayNameMatches(SymbolNames.CliFxBindingConverterClass) + .ConverterType.GetBaseTypes() + .FirstOrDefault(t => + t.ConstructedFrom.DisplayNameMatches(SymbolNames.CliFxBindingConverterClass) ) - ?.TypeArguments - .FirstOrDefault(); + ?.TypeArguments.FirstOrDefault(); // Value returned by the converter must be assignable to the property type var isCompatible = @@ -45,9 +43,10 @@ public class ParameterMustHaveValidConverterAnalyzer() ? context.Compilation.IsAssignable(converterValueType, property.Type) // Non-scalar (assume we can handle all IEnumerable types for simplicity) : property.Type.TryGetEnumerableUnderlyingType() is { } enumerableUnderlyingType - && context - .Compilation - .IsAssignable(converterValueType, enumerableUnderlyingType) + && context.Compilation.IsAssignable( + converterValueType, + enumerableUnderlyingType + ) ); if (!isCompatible) diff --git a/CliFx.Analyzers/ParameterMustHaveValidValidatorsAnalyzer.cs b/CliFx.Analyzers/ParameterMustHaveValidValidatorsAnalyzer.cs index b6c1f61..4a64c02 100644 --- a/CliFx.Analyzers/ParameterMustHaveValidValidatorsAnalyzer.cs +++ b/CliFx.Analyzers/ParameterMustHaveValidValidatorsAnalyzer.cs @@ -28,12 +28,10 @@ public class ParameterMustHaveValidValidatorsAnalyzer() { var validatorValueType = validatorType .GetBaseTypes() - .FirstOrDefault( - t => - t.ConstructedFrom.DisplayNameMatches(SymbolNames.CliFxBindingValidatorClass) + .FirstOrDefault(t => + t.ConstructedFrom.DisplayNameMatches(SymbolNames.CliFxBindingValidatorClass) ) - ?.TypeArguments - .FirstOrDefault(); + ?.TypeArguments.FirstOrDefault(); // Value passed to the validator must be assignable from the property type var isCompatible = diff --git a/CliFx.Analyzers/SystemConsoleShouldBeAvoidedAnalyzer.cs b/CliFx.Analyzers/SystemConsoleShouldBeAvoidedAnalyzer.cs index 9e8d881..d4718a5 100644 --- a/CliFx.Analyzers/SystemConsoleShouldBeAvoidedAnalyzer.cs +++ b/CliFx.Analyzers/SystemConsoleShouldBeAvoidedAnalyzer.cs @@ -52,8 +52,7 @@ public class SystemConsoleShouldBeAvoidedAnalyzer() // Check if IConsole is available in scope as an alternative to System.Console var isConsoleInterfaceAvailable = context - .Node - .Ancestors() + .Node.Ancestors() .OfType() .SelectMany(m => m.ParameterList.Parameters) .Select(p => p.Type) diff --git a/CliFx.Analyzers/Utils/Extensions/RoslynExtensions.cs b/CliFx.Analyzers/Utils/Extensions/RoslynExtensions.cs index 6af6801..1e01aff 100644 --- a/CliFx.Analyzers/Utils/Extensions/RoslynExtensions.cs +++ b/CliFx.Analyzers/Utils/Extensions/RoslynExtensions.cs @@ -30,11 +30,10 @@ internal static class RoslynExtensions } public static ITypeSymbol? TryGetEnumerableUnderlyingType(this ITypeSymbol type) => - type.AllInterfaces - .FirstOrDefault( - i => - i.ConstructedFrom.SpecialType - == SpecialType.System_Collections_Generic_IEnumerable_T + type + .AllInterfaces.FirstOrDefault(i => + i.ConstructedFrom.SpecialType + == SpecialType.System_Collections_Generic_IEnumerable_T ) ?.TypeArguments[0]; @@ -44,8 +43,7 @@ internal static class RoslynExtensions property // Can't rely on the RequiredMemberAttribute because it's generated by the compiler, not added by the user, // so we have to check for the presence of the `required` modifier in the syntax tree instead. - .DeclaringSyntaxReferences - .Select(r => r.GetSyntax()) + .DeclaringSyntaxReferences.Select(r => r.GetSyntax()) .OfType() .SelectMany(p => p.Modifiers) .Any(m => m.IsKind((SyntaxKind)8447)); diff --git a/CliFx.Benchmarks/CliFx.Benchmarks.csproj b/CliFx.Benchmarks/CliFx.Benchmarks.csproj index 3b54813..53158c2 100644 --- a/CliFx.Benchmarks/CliFx.Benchmarks.csproj +++ b/CliFx.Benchmarks/CliFx.Benchmarks.csproj @@ -6,12 +6,12 @@ - + - - + + diff --git a/CliFx.Demo/CliFx.Demo.csproj b/CliFx.Demo/CliFx.Demo.csproj index 4367a0e..4d4439a 100644 --- a/CliFx.Demo/CliFx.Demo.csproj +++ b/CliFx.Demo/CliFx.Demo.csproj @@ -7,7 +7,7 @@ - + diff --git a/CliFx.Tests.Dummy/CliFx.Tests.Dummy.csproj b/CliFx.Tests.Dummy/CliFx.Tests.Dummy.csproj index 5b3203a..7feda9b 100644 --- a/CliFx.Tests.Dummy/CliFx.Tests.Dummy.csproj +++ b/CliFx.Tests.Dummy/CliFx.Tests.Dummy.csproj @@ -7,7 +7,7 @@ - + diff --git a/CliFx.Tests/CliFx.Tests.csproj b/CliFx.Tests/CliFx.Tests.csproj index 55a21bc..53d6aa5 100644 --- a/CliFx.Tests/CliFx.Tests.csproj +++ b/CliFx.Tests/CliFx.Tests.csproj @@ -9,18 +9,18 @@ - - - - + + + + - + - - - - + + + + diff --git a/CliFx.Tests/Utils/DynamicCommandBuilder.cs b/CliFx.Tests/Utils/DynamicCommandBuilder.cs index 43b9c26..9a2f3f7 100644 --- a/CliFx.Tests/Utils/DynamicCommandBuilder.cs +++ b/CliFx.Tests/Utils/DynamicCommandBuilder.cs @@ -32,8 +32,7 @@ internal static class DynamicCommandBuilder // Get default CliFx namespaces var defaultCliFxNamespaces = typeof(ICommand) - .Assembly - .GetTypes() + .Assembly.GetTypes() .Where(t => t.IsPublic) .Select(t => t.Namespace) .Distinct() @@ -57,9 +56,9 @@ internal static class DynamicCommandBuilder "CliFxTests_DynamicAssembly_" + Guid.NewGuid(), [ast], Net80 - .References - .All - .Append(MetadataReference.CreateFromFile(typeof(ICommand).Assembly.Location)) + .References.All.Append( + MetadataReference.CreateFromFile(typeof(ICommand).Assembly.Location) + ) .Append( MetadataReference.CreateFromFile( typeof(DynamicCommandBuilder).Assembly.Location @@ -88,8 +87,8 @@ internal static class DynamicCommandBuilder using var buffer = new MemoryStream(); var emit = compilation.Emit(buffer); - var emitErrors = emit.Diagnostics - .Where(d => d.Severity >= DiagnosticSeverity.Error) + var emitErrors = emit + .Diagnostics.Where(d => d.Severity >= DiagnosticSeverity.Error) .ToArray(); if (emitErrors.Any()) diff --git a/CliFx.Tests/Utils/Extensions/AssertionExtensions.cs b/CliFx.Tests/Utils/Extensions/AssertionExtensions.cs index c6d470e..f4f03a9 100644 --- a/CliFx.Tests/Utils/Extensions/AssertionExtensions.cs +++ b/CliFx.Tests/Utils/Extensions/AssertionExtensions.cs @@ -13,8 +13,7 @@ internal static class AssertionExtensions IEnumerable lines ) => assertions - .Subject - .Split(new[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries) + .Subject.Split(new[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries) .Should() .Equal(lines); @@ -34,11 +33,9 @@ internal static class AssertionExtensions if (index < 0) { - Execute - .Assertion - .FailWith( - $"Expected string '{assertions.Subject}' to contain '{value}' after position {lastIndex}." - ); + Execute.Assertion.FailWith( + $"Expected string '{assertions.Subject}' to contain '{value}' after position {lastIndex}." + ); } lastIndex = index; diff --git a/CliFx/CliApplication.cs b/CliFx/CliApplication.cs index bb06d07..945feef 100644 --- a/CliFx/CliApplication.cs +++ b/CliFx/CliApplication.cs @@ -56,11 +56,9 @@ public class CliApplication( { using (console.WithForegroundColor(ConsoleColor.Green)) { - console - .Output - .WriteLine( - $"Attach the debugger to process with ID {ProcessEx.GetCurrentProcessId()} to continue." - ); + console.Output.WriteLine( + $"Attach the debugger to process with ID {ProcessEx.GetCurrentProcessId()} to continue." + ); } // Try to also launch the debugger ourselves (only works with Visual Studio) diff --git a/CliFx/CliApplicationBuilder.cs b/CliFx/CliApplicationBuilder.cs index 80b4671..c8d90b9 100644 --- a/CliFx/CliApplicationBuilder.cs +++ b/CliFx/CliApplicationBuilder.cs @@ -186,7 +186,8 @@ public partial class CliApplicationBuilder /// Configures the application to use the specified service provider for activating types. /// public CliApplicationBuilder UseTypeActivator(IServiceProvider serviceProvider) => - UseTypeActivator(serviceProvider.GetService); + // Null returns are handled by DelegateTypeActivator + UseTypeActivator(serviceProvider.GetService!); /// /// Configures the application to use the specified service provider for activating types. diff --git a/CliFx/CliFx.csproj b/CliFx/CliFx.csproj index 67d306b..8fa2e0b 100644 --- a/CliFx/CliFx.csproj +++ b/CliFx/CliFx.csproj @@ -23,9 +23,9 @@ - + - + diff --git a/CliFx/CommandBinder.cs b/CliFx/CommandBinder.cs index e9fdbf2..5ea4dba 100644 --- a/CliFx/CommandBinder.cs +++ b/CliFx/CommandBinder.cs @@ -42,13 +42,15 @@ internal class CommandBinder(ITypeActivator typeActivator) // Special case for DateTimeOffset if (targetType == typeof(DateTimeOffset)) { - return DateTimeOffset.Parse(rawValue, _formatProvider); + // Null reference exception will be handled upstream + return DateTimeOffset.Parse(rawValue!, _formatProvider); } // Special case for TimeSpan if (targetType == typeof(TimeSpan)) { - return TimeSpan.Parse(rawValue, _formatProvider); + // Null reference exception will be handled upstream + return TimeSpan.Parse(rawValue!, _formatProvider); } // Enum @@ -143,10 +145,8 @@ internal class CommandBinder(ITypeActivator typeActivator) try { // Non-scalar - var enumerableUnderlyingType = memberSchema - .Property - .Type - .TryGetEnumerableUnderlyingType(); + var enumerableUnderlyingType = + memberSchema.Property.Type.TryGetEnumerableUnderlyingType(); if ( enumerableUnderlyingType is not null @@ -244,8 +244,7 @@ internal class CommandBinder(ITypeActivator typeActivator) // Ensure there are no unexpected parameters and that all parameters are provided var remainingParameterInputs = commandInput.Parameters.ToList(); var remainingRequiredParameterSchemas = commandSchema - .Parameters - .Where(p => p.IsRequired) + .Parameters.Where(p => p.IsRequired) .ToList(); var position = 0; @@ -298,7 +297,9 @@ internal class CommandBinder(ITypeActivator typeActivator) throw CliFxException.UserError( $""" Missing required parameter(s): - {remainingRequiredParameterSchemas.Select(p => p.GetFormattedIdentifier()).JoinToString(" ")} + {remainingRequiredParameterSchemas + .Select(p => p.GetFormattedIdentifier()) + .JoinToString(" ")} """ ); } @@ -313,20 +314,18 @@ internal class CommandBinder(ITypeActivator typeActivator) // Ensure there are no unrecognized options and that all required options are set var remainingOptionInputs = commandInput.Options.ToList(); var remainingRequiredOptionSchemas = commandSchema - .Options - .Where(o => o.IsRequired) + .Options.Where(o => o.IsRequired) .ToList(); foreach (var optionSchema in commandSchema.Options) { var optionInputs = commandInput - .Options - .Where(o => optionSchema.MatchesIdentifier(o.Identifier)) + .Options.Where(o => optionSchema.MatchesIdentifier(o.Identifier)) .ToArray(); - var environmentVariableInput = commandInput - .EnvironmentVariables - .FirstOrDefault(e => optionSchema.MatchesEnvironmentVariable(e.Name)); + var environmentVariableInput = commandInput.EnvironmentVariables.FirstOrDefault(e => + optionSchema.MatchesEnvironmentVariable(e.Name) + ); // Direct input if (optionInputs.Any()) @@ -376,7 +375,9 @@ internal class CommandBinder(ITypeActivator typeActivator) throw CliFxException.UserError( $""" Missing required option(s): - {remainingRequiredOptionSchemas.Select(o => o.GetFormattedIdentifier()).JoinToString(", ")} + {remainingRequiredOptionSchemas + .Select(o => o.GetFormattedIdentifier()) + .JoinToString(", ")} """ ); } diff --git a/CliFx/Formatting/HelpConsoleFormatter.cs b/CliFx/Formatting/HelpConsoleFormatter.cs index 982653b..ba4fec1 100644 --- a/CliFx/Formatting/HelpConsoleFormatter.cs +++ b/CliFx/Formatting/HelpConsoleFormatter.cs @@ -99,9 +99,9 @@ internal class HelpConsoleFormatter(ConsoleWriter consoleWriter, HelpContext con } // Child command usage - var childCommandSchemas = context - .ApplicationSchema - .GetChildCommands(context.CommandSchema.Name); + var childCommandSchemas = context.ApplicationSchema.GetChildCommands( + context.CommandSchema.Name + ); if (childCommandSchemas.Any()) { @@ -359,8 +359,7 @@ internal class HelpConsoleFormatter(ConsoleWriter consoleWriter, HelpContext con private void WriteCommandChildren() { var childCommandSchemas = context - .ApplicationSchema - .GetChildCommands(context.CommandSchema.Name) + .ApplicationSchema.GetChildCommands(context.CommandSchema.Name) .OrderBy(a => a.Name, StringComparer.Ordinal) .ToArray(); @@ -393,8 +392,7 @@ internal class HelpConsoleFormatter(ConsoleWriter consoleWriter, HelpContext con // Child commands of child command var grandChildCommandSchemas = context - .ApplicationSchema - .GetChildCommands(childCommandSchema.Name) + .ApplicationSchema.GetChildCommands(childCommandSchema.Name) .OrderBy(c => c.Name, StringComparer.Ordinal) .ToArray(); @@ -418,8 +416,7 @@ internal class HelpConsoleFormatter(ConsoleWriter consoleWriter, HelpContext con ConsoleColor.Cyan, // Relative to current command (not the parent) grandChildCommandSchema - .Name - ?.Substring(context.CommandSchema.Name?.Length ?? 0) + .Name?.Substring(context.CommandSchema.Name?.Length ?? 0) .Trim() ); } diff --git a/CliFx/Infrastructure/ConsoleWriter.cs b/CliFx/Infrastructure/ConsoleWriter.cs index 9222859..0675599 100644 --- a/CliFx/Infrastructure/ConsoleWriter.cs +++ b/CliFx/Infrastructure/ConsoleWriter.cs @@ -45,7 +45,7 @@ public class ConsoleWriter : StreamWriter /// [ExcludeFromCodeCoverage, MethodImpl(MethodImplOptions.Synchronized)] - public override void Write(char[] buffer) => base.Write(buffer); + public override void Write(char[]? buffer) => base.Write(buffer); /// [ExcludeFromCodeCoverage, MethodImpl(MethodImplOptions.Synchronized)] @@ -147,7 +147,7 @@ public class ConsoleWriter : StreamWriter /// [ExcludeFromCodeCoverage, MethodImpl(MethodImplOptions.Synchronized)] - public override void WriteLine(char[] buffer) => base.WriteLine(buffer); + public override void WriteLine(char[]? buffer) => base.WriteLine(buffer); /// [ExcludeFromCodeCoverage, MethodImpl(MethodImplOptions.Synchronized)] diff --git a/CliFx/Infrastructure/DefaultTypeActivator.cs b/CliFx/Infrastructure/DefaultTypeActivator.cs index 4abfbbb..78e5afb 100644 --- a/CliFx/Infrastructure/DefaultTypeActivator.cs +++ b/CliFx/Infrastructure/DefaultTypeActivator.cs @@ -14,7 +14,13 @@ public class DefaultTypeActivator : ITypeActivator { try { - return Activator.CreateInstance(type); + return Activator.CreateInstance(type) + ?? throw CliFxException.InternalError( + $""" + Failed to create an instance of type `{type.FullName}`, received instead. + This may be caused by the type's constructor being trimmed away. + """ + ); } // Only catch MemberAccessException because the constructor can throw for its own reasons too catch (MemberAccessException ex) diff --git a/CliFx/Infrastructure/DelegateTypeActivator.cs b/CliFx/Infrastructure/DelegateTypeActivator.cs index 0de5be8..faf0987 100644 --- a/CliFx/Infrastructure/DelegateTypeActivator.cs +++ b/CliFx/Infrastructure/DelegateTypeActivator.cs @@ -9,21 +9,13 @@ namespace CliFx.Infrastructure; public class DelegateTypeActivator(Func createInstance) : ITypeActivator { /// - public object CreateInstance(Type type) - { - var instance = createInstance(type); - - if (instance is null) - { - throw CliFxException.InternalError( - $""" - Failed to create an instance of type `{type.FullName}`, received instead. - To fix this, ensure that the provided type activator is configured correctly, as it's not expected to return . - If you are relying on a dependency container, this error may indicate that the specified type has not been registered. - """ - ); - } - - return instance; - } + public object CreateInstance(Type type) => + createInstance(type) + ?? throw CliFxException.InternalError( + $""" + Failed to create an instance of type `{type.FullName}`, received instead. + To fix this, ensure that the provided type activator is configured correctly, as it's not expected to return . + If you are relying on a dependency container, this error may indicate that the specified type has not been registered. + """ + ); } diff --git a/CliFx/Schema/ApplicationSchema.cs b/CliFx/Schema/ApplicationSchema.cs index e84906e..54d5bd5 100644 --- a/CliFx/Schema/ApplicationSchema.cs +++ b/CliFx/Schema/ApplicationSchema.cs @@ -39,9 +39,10 @@ internal partial class ApplicationSchema(IReadOnlyList commands) string.IsNullOrWhiteSpace(parentCommandName) || // Otherwise a command is a descendant if it starts with the same name segments - potentialParentCommandSchema - .Name - .StartsWith(parentCommandName + ' ', StringComparison.OrdinalIgnoreCase); + potentialParentCommandSchema.Name.StartsWith( + parentCommandName + ' ', + StringComparison.OrdinalIgnoreCase + ); if (isDescendant) result.Add(potentialParentCommandSchema); diff --git a/CliFx/Schema/CommandSchema.cs b/CliFx/Schema/CommandSchema.cs index bad5cec..0587984 100644 --- a/CliFx/Schema/CommandSchema.cs +++ b/CliFx/Schema/CommandSchema.cs @@ -86,10 +86,14 @@ internal partial class CommandSchema type.GetInterfaces() // Only interfaces implementing ICommand for explicitness .Where(i => i != typeof(ICommand) && i.IsAssignableTo(typeof(ICommand))) - .SelectMany( - i => - i.GetProperties() - .Where(p => !p.GetMethod.IsAbstract && !p.SetMethod.IsAbstract) + .SelectMany(i => + i.GetProperties() + .Where(p => + p.GetMethod is not null + && !p.GetMethod.IsAbstract + && p.SetMethod is not null + && !p.SetMethod.IsAbstract + ) ) ) .ToArray(); diff --git a/CliFx/Utils/Extensions/CollectionExtensions.cs b/CliFx/Utils/Extensions/CollectionExtensions.cs index bd4c471..1600c7b 100644 --- a/CliFx/Utils/Extensions/CollectionExtensions.cs +++ b/CliFx/Utils/Extensions/CollectionExtensions.cs @@ -42,10 +42,11 @@ internal static class CollectionExtensions public static Dictionary ToDictionary( this IDictionary dictionary, IEqualityComparer comparer - ) => + ) + where TKey : notnull => dictionary .Cast() - .ToDictionary(entry => (TKey)entry.Key, entry => (TValue)entry.Value, comparer); + .ToDictionary(entry => (TKey)entry.Key, entry => (TValue)entry.Value!, comparer); public static Array ToNonGenericArray(this IEnumerable source, Type elementType) { diff --git a/CliFx/Utils/Extensions/PropertyExtensions.cs b/CliFx/Utils/Extensions/PropertyExtensions.cs index c590fcf..3b013ed 100644 --- a/CliFx/Utils/Extensions/PropertyExtensions.cs +++ b/CliFx/Utils/Extensions/PropertyExtensions.cs @@ -10,12 +10,11 @@ internal static class PropertyExtensions // Match attribute by name to avoid depending on .NET 7.0+ and to allow polyfilling propertyInfo .GetCustomAttributes() - .Any( - a => - string.Equals( - a.GetType().FullName, - "System.Runtime.CompilerServices.RequiredMemberAttribute", - StringComparison.Ordinal - ) + .Any(a => + string.Equals( + a.GetType().FullName, + "System.Runtime.CompilerServices.RequiredMemberAttribute", + StringComparison.Ordinal + ) ); } diff --git a/CliFx/Utils/Extensions/StringExtensions.cs b/CliFx/Utils/Extensions/StringExtensions.cs index 997ad15..5032a20 100644 --- a/CliFx/Utils/Extensions/StringExtensions.cs +++ b/CliFx/Utils/Extensions/StringExtensions.cs @@ -15,7 +15,7 @@ internal static class StringExtensions public static string JoinToString(this IEnumerable source, string separator) => string.Join(separator, source); - public static string ToString( + public static string? ToString( this object obj, IFormatProvider? formatProvider = null, string? format = null diff --git a/CliFx/Utils/StackFrame.cs b/CliFx/Utils/StackFrame.cs index 4bbab48..21f12aa 100644 --- a/CliFx/Utils/StackFrame.cs +++ b/CliFx/Utils/StackFrame.cs @@ -41,33 +41,33 @@ internal partial class StackFrame private static readonly Regex Pattern = new( $$""" - ^ - {{Space}}* - \w+ {{Space}}+ - (? - (? {{NotSpace}}+ ) \. - (? {{NotSpace}}+? ) {{Space}}* - (? \( ( {{Space}}* \) - | (? .+?) {{Space}}+ (? .+?) - (, {{Space}}* (? .+?) {{Space}}+ (? .+?) )* \) ) ) - ( {{Space}}+ - ( # Microsoft .NET stack traces - \w+ {{Space}}+ - (? ( [a-z] \: # Windows rooted path starting with a drive letter - | / ) # Unix rooted path starting with a forward-slash - .+? ) - \: \w+ {{Space}}+ - (? [0-9]+ ) \p{P}? - | # Mono stack traces - \[0x[0-9a-f]+\] {{Space}}+ \w+ {{Space}}+ - <(? [^>]+ )> - :(? [0-9]+ ) - ) - )? - ) - \s* - $ - """, + ^ + {{Space}}* + \w+ {{Space}}+ + (? + (? {{NotSpace}}+ ) \. + (? {{NotSpace}}+? ) {{Space}}* + (? \( ( {{Space}}* \) + | (? .+?) {{Space}}+ (? .+?) + (, {{Space}}* (? .+?) {{Space}}+ (? .+?) )* \) ) ) + ( {{Space}}+ + ( # Microsoft .NET stack traces + \w+ {{Space}}+ + (? ( [a-z] \: # Windows rooted path starting with a drive letter + | / ) # Unix rooted path starting with a forward-slash + .+? ) + \: \w+ {{Space}}+ + (? [0-9]+ ) \p{P}? + | # Mono stack traces + \[0x[0-9a-f]+\] {{Space}}+ \w+ {{Space}}+ + <(? [^>]+ )> + :(? [0-9]+ ) + ) + )? + ) + \s* + $ + """, RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.ExplicitCapture