Fix converter analyzer false positive when handling non-scalars or nullable types

This commit is contained in:
Oleksii Holub
2022-04-20 20:09:14 +03:00
parent 7f206a0c77
commit 864efd3179
14 changed files with 205 additions and 75 deletions

View File

@@ -5,8 +5,10 @@ using Microsoft.CodeAnalysis;
namespace CliFx.Analyzers.ObjectModel;
internal partial class CommandOptionSymbol
internal partial class CommandOptionSymbol : ICommandMemberSymbol
{
public IPropertySymbol Property { get; }
public string? Name { get; }
public char? ShortName { get; }
@@ -16,11 +18,13 @@ internal partial class CommandOptionSymbol
public IReadOnlyList<ITypeSymbol> ValidatorTypes { get; }
public CommandOptionSymbol(
IPropertySymbol property,
string? name,
char? shortName,
ITypeSymbol? converterType,
IReadOnlyList<ITypeSymbol> validatorTypes)
{
Property = property;
Name = name;
ShortName = shortName;
ConverterType = converterType;
@@ -30,22 +34,25 @@ internal partial class CommandOptionSymbol
internal partial class CommandOptionSymbol
{
private static AttributeData? TryGetOptionAttribute(IPropertySymbol property) =>
property
.GetAttributes()
.FirstOrDefault(a => a.AttributeClass.DisplayNameMatches(SymbolNames.CliFxCommandOptionAttribute));
private static AttributeData? TryGetOptionAttribute(IPropertySymbol property) => property
.GetAttributes()
.FirstOrDefault(a => a.AttributeClass?.DisplayNameMatches(SymbolNames.CliFxCommandOptionAttribute) == true);
private static CommandOptionSymbol FromAttribute(AttributeData attribute)
public static CommandOptionSymbol? TryResolve(IPropertySymbol property)
{
var attribute = TryGetOptionAttribute(property);
if (attribute is null)
return null;
var name = attribute
.ConstructorArguments
.Where(a => a.Type.DisplayNameMatches("string") || a.Type.DisplayNameMatches("System.String"))
.Where(a => a.Type?.SpecialType == SpecialType.System_String)
.Select(a => a.Value)
.FirstOrDefault() as string;
var shortName = attribute
.ConstructorArguments
.Where(a => a.Type.DisplayNameMatches("char") || a.Type.DisplayNameMatches("System.Char"))
.Where(a => a.Type?.SpecialType == SpecialType.System_Char)
.Select(a => a.Value)
.FirstOrDefault() as char?;
@@ -64,16 +71,7 @@ internal partial class CommandOptionSymbol
.Cast<ITypeSymbol>()
.ToArray();
return new CommandOptionSymbol(name, shortName, converter, validators);
}
public static CommandOptionSymbol? TryResolve(IPropertySymbol property)
{
var attribute = TryGetOptionAttribute(property);
return attribute is not null
? FromAttribute(attribute)
: null;
return new CommandOptionSymbol(property, name, shortName, converter, validators);
}
public static bool IsOptionProperty(IPropertySymbol property) =>

View File

@@ -5,8 +5,10 @@ using Microsoft.CodeAnalysis;
namespace CliFx.Analyzers.ObjectModel;
internal partial class CommandParameterSymbol
internal partial class CommandParameterSymbol : ICommandMemberSymbol
{
public IPropertySymbol Property { get; }
public int Order { get; }
public string? Name { get; }
@@ -18,12 +20,14 @@ internal partial class CommandParameterSymbol
public IReadOnlyList<ITypeSymbol> ValidatorTypes { get; }
public CommandParameterSymbol(
IPropertySymbol property,
int order,
string? name,
bool? isRequired,
ITypeSymbol? converterType,
IReadOnlyList<ITypeSymbol> validatorTypes)
{
Property = property;
Order = order;
Name = name;
IsRequired = isRequired;
@@ -34,13 +38,16 @@ internal partial class CommandParameterSymbol
internal partial class CommandParameterSymbol
{
private static AttributeData? TryGetParameterAttribute(IPropertySymbol property) =>
property
.GetAttributes()
.FirstOrDefault(a => a.AttributeClass.DisplayNameMatches(SymbolNames.CliFxCommandParameterAttribute));
private static AttributeData? TryGetParameterAttribute(IPropertySymbol property) => property
.GetAttributes()
.FirstOrDefault(a => a.AttributeClass?.DisplayNameMatches(SymbolNames.CliFxCommandParameterAttribute) == true);
private static CommandParameterSymbol FromAttribute(AttributeData attribute)
public static CommandParameterSymbol? TryResolve(IPropertySymbol property)
{
var attribute = TryGetParameterAttribute(property);
if (attribute is null)
return null;
var order = (int)attribute
.ConstructorArguments
.Select(a => a.Value)
@@ -73,16 +80,7 @@ internal partial class CommandParameterSymbol
.Cast<ITypeSymbol>()
.ToArray();
return new CommandParameterSymbol(order, name, isRequired, converter, validators);
}
public static CommandParameterSymbol? TryResolve(IPropertySymbol property)
{
var attribute = TryGetParameterAttribute(property);
return attribute is not null
? FromAttribute(attribute)
: null;
return new CommandParameterSymbol(property, order, name, isRequired, converter, validators);
}
public static bool IsParameterProperty(IPropertySymbol property) =>

View File

@@ -0,0 +1,21 @@
using System.Collections.Generic;
using CliFx.Analyzers.Utils.Extensions;
using Microsoft.CodeAnalysis;
namespace CliFx.Analyzers.ObjectModel;
internal interface ICommandMemberSymbol
{
IPropertySymbol Property { get; }
ITypeSymbol? ConverterType { get; }
IReadOnlyList<ITypeSymbol> ValidatorTypes { get; }
}
internal static class CommandMemberSymbolExtensions
{
public static bool IsScalar(this ICommandMemberSymbol member) =>
member.Property.Type.SpecialType == SpecialType.System_String ||
member.Property.Type.TryGetEnumerableUnderlyingType() is null;
}