Tyrrrz / CliFx

Class-first framework for building command-line interfaces
MIT License
1.48k stars 60 forks source link

Check `BindingConverter<T>` and `BindingValidator<T>` types in analyzers #103

Closed Tyrrrz closed 2 years ago

Tyrrrz commented 3 years ago

Ensure that, on a property of type (example) int, specified converter must be of type BindingConverter<int> and specified validators must be of type BindingValidator<int>. Additionally, types that are assignable to int should also be allowed.

This will require some more complex logic in the analyzers, because currently they're just checking for an internal non-generic interface:

https://github.com/Tyrrrz/CliFx/blob/65eaa912cf4f9147809b46ccefa83290825c2fbb/CliFx.Analyzers/ParameterMustHaveValidConverterAnalyzer.cs#L32-L41

https://github.com/Tyrrrz/CliFx/blob/65eaa912cf4f9147809b46ccefa83290825c2fbb/CliFx.Analyzers/ObjectModel/SymbolNames.cs#L10-L13

Example of incorrect usage:

// Should be BindingConverter<int>
public class MyConverter : BindingConverter<string> { /* ... */ }

// Should be BindingValidator<int>
public class MyValidator : BindingValidator<string> { /* ... */ }

// ...

// Analyzer error here:
[CommandParameter(0, Converter = typeof(MyConverter), Validators = new[] {typeof(MyValidator)})]
public int MyValue { get; init; }

Example of correct usage:

public class MyConverter : BindingConverter<int> { /* ... */ }
public class MyValidator : BindingValidator<int> { /* ... */ }

// ...

[CommandParameter(0, Converter = typeof(MyConverter), Validators = new[] {typeof(MyValidator)})]
public int MyValue { get; init; }

Example of another correct usage:

// This is fine too, because typeof(int).IsAssignableFrom(typeof(byte)) is true
public class MyConverter : BindingConverter<byte> { /* ... */ }
public class MyValidator : BindingValidator<byte> { /* ... */ }

// ...

[CommandParameter(0, Converter = typeof(MyConverter), Validators = new[] {typeof(MyValidator)})]
public int MyValue { get; init; }