From 2e28ad814384fdf1858ea7e7f4a51509ffad4e6d Mon Sep 17 00:00:00 2001 From: Mohammadreza Taikandi Date: Mon, 25 Jan 2021 09:51:57 +0000 Subject: [PATCH] Cleanup. --- src/MapTo/Extensions/RoslynExtensions.cs | 22 ++++++--- src/MapTo/MappingContext.cs | 60 +++++++++++++----------- 2 files changed, 48 insertions(+), 34 deletions(-) diff --git a/src/MapTo/Extensions/RoslynExtensions.cs b/src/MapTo/Extensions/RoslynExtensions.cs index a32fb80..a43fd86 100644 --- a/src/MapTo/Extensions/RoslynExtensions.cs +++ b/src/MapTo/Extensions/RoslynExtensions.cs @@ -36,22 +36,32 @@ namespace MapTo.Extensions ((a.Name as QualifiedNameSyntax)?.Right as IdentifierNameSyntax)?.Identifier.ValueText == attributeName); } - public static bool HasAttribute(this ISymbol symbol, ITypeSymbol attributeSymbol) => + public static bool HasAttribute(this ISymbol symbol, ITypeSymbol attributeSymbol) => symbol.GetAttributes().Any(a => a.AttributeClass?.Equals(attributeSymbol, SymbolEqualityComparer.Default) == true); - + public static IEnumerable GetAttributes(this ISymbol symbol, ITypeSymbol attributeSymbol) => symbol.GetAttributes().Where(a => a.AttributeClass?.Equals(attributeSymbol, SymbolEqualityComparer.Default) == true); public static AttributeData? GetAttribute(this ISymbol symbol, ITypeSymbol attributeSymbol) => symbol.GetAttributes(attributeSymbol).FirstOrDefault(); - - public static string? GetNamespace(this ClassDeclarationSyntax classDeclarationSyntax) - { - return classDeclarationSyntax.Ancestors() + + public static string? GetNamespace(this ClassDeclarationSyntax classDeclarationSyntax) => + classDeclarationSyntax.Ancestors() .OfType() .FirstOrDefault() ?.Name .ToString(); + + public static bool HasCompatibleTypes(this Compilation compilation, IPropertySymbol sourceProperty, IPropertySymbol destinationProperty) => + SymbolEqualityComparer.Default.Equals(destinationProperty.Type, sourceProperty.Type) || compilation.HasImplicitConversion(sourceProperty.Type, destinationProperty.Type); + + public static IPropertySymbol? FindProperty(this IEnumerable properties, IPropertySymbol targetProperty) + { + return properties.SingleOrDefault(p => + p.Name == targetProperty.Name && + (p.NullableAnnotation != NullableAnnotation.Annotated || + p.NullableAnnotation == NullableAnnotation.Annotated && + targetProperty.NullableAnnotation == NullableAnnotation.Annotated)); } } } \ No newline at end of file diff --git a/src/MapTo/MappingContext.cs b/src/MapTo/MappingContext.cs index bc78691..6c7df1c 100644 --- a/src/MapTo/MappingContext.cs +++ b/src/MapTo/MappingContext.cs @@ -11,8 +11,6 @@ namespace MapTo { internal class MappingContext { - private Compilation Compilation { get; } - private MappingContext(Compilation compilation) { Diagnostics = ImmutableArray.Empty; @@ -28,6 +26,8 @@ namespace MapTo ?? throw new TypeLoadException($"Unable to find '{ITypeConverterSource.FullyQualifiedName}' type."); } + private Compilation Compilation { get; } + public INamedTypeSymbol MapTypeConverterAttributeTypeSymbol { get; } public INamedTypeSymbol TypeConverterInterfaceTypeSymbol { get; } @@ -38,12 +38,6 @@ namespace MapTo public INamedTypeSymbol IgnorePropertyAttributeTypeSymbol { get; } - private MappingContext ReportDiagnostic(Diagnostic diagnostic) - { - Diagnostics = Diagnostics.Add(diagnostic); - return this; - } - internal static MappingContext Create(Compilation compilation, ClassDeclarationSyntax classSyntax, SourceGenerationOptions sourceGenerationOptions) { var context = new MappingContext(compilation); @@ -83,6 +77,12 @@ namespace MapTo return context; } + private MappingContext ReportDiagnostic(Diagnostic diagnostic) + { + Diagnostics = Diagnostics.Add(diagnostic); + return this; + } + private static INamedTypeSymbol? GetSourceTypeSymbol(SemanticModel semanticModel, ClassDeclarationSyntax classSyntax) { var sourceTypeExpressionSyntax = classSyntax @@ -102,12 +102,7 @@ namespace MapTo foreach (var property in classProperties) { - var sourceProperty = sourceProperties.SingleOrDefault(p => - p.Name == property.Name && - (p.NullableAnnotation != NullableAnnotation.Annotated || - p.NullableAnnotation == NullableAnnotation.Annotated && - property.NullableAnnotation == NullableAnnotation.Annotated)); - + var sourceProperty = sourceProperties.FindProperty(property); if (sourceProperty is null) { continue; @@ -115,7 +110,8 @@ namespace MapTo string? converterFullyQualifiedName = null; var converterParameters = new List(); - if (!SymbolEqualityComparer.Default.Equals(property.Type, sourceProperty.Type) && !context.Compilation.HasImplicitConversion(sourceProperty.Type, property.Type)) + + if (!context.Compilation.HasCompatibleTypes(sourceProperty, property)) { var typeConverterAttribute = property.GetAttribute(context.MapTypeConverterAttributeTypeSymbol); if (typeConverterAttribute is null) @@ -123,7 +119,7 @@ namespace MapTo context.ReportDiagnostic(DiagnosticProvider.NoMatchingPropertyTypeFoundError(property)); continue; } - + var converterTypeSymbol = typeConverterAttribute.ConstructorArguments.First().Value as INamedTypeSymbol; if (converterTypeSymbol is null) { @@ -131,12 +127,7 @@ namespace MapTo continue; } - var baseInterface = converterTypeSymbol.AllInterfaces - .SingleOrDefault(i => SymbolEqualityComparer.Default.Equals(i.ConstructedFrom, context.TypeConverterInterfaceTypeSymbol) && - i.TypeArguments.Length == 2 && - SymbolEqualityComparer.Default.Equals(sourceProperty.Type, i.TypeArguments[0]) && - SymbolEqualityComparer.Default.Equals(property.Type, i.TypeArguments[1])); - + var baseInterface = GetTypeConverterBaseInterface(context, converterTypeSymbol, property, sourceProperty); if (baseInterface is null) { context.ReportDiagnostic(DiagnosticProvider.InvalidTypeConverterGenericTypesError(property, sourceProperty)); @@ -144,12 +135,7 @@ namespace MapTo } converterFullyQualifiedName = converterTypeSymbol.ToDisplayString(); - - var converterParameter = typeConverterAttribute.ConstructorArguments.Skip(1).FirstOrDefault(); - if (!converterParameter.IsNull ) - { - converterParameters.AddRange(converterParameter.Values.Where(v => v.Value is not null).Select(v => v.Value!.ToSourceCodeString())); - } + converterParameters.AddRange(GetTypeConverterParameters(typeConverterAttribute)); } mappedProperties.Add(new MappedProperty(property.Name, converterFullyQualifiedName, converterParameters.ToImmutableArray())); @@ -157,5 +143,23 @@ namespace MapTo return mappedProperties.ToImmutableArray(); } + + private static INamedTypeSymbol? GetTypeConverterBaseInterface(MappingContext context, ITypeSymbol converterTypeSymbol, IPropertySymbol property, IPropertySymbol sourceProperty) + { + return converterTypeSymbol.AllInterfaces + .SingleOrDefault(i => + i.TypeArguments.Length == 2 && + SymbolEqualityComparer.Default.Equals(i.ConstructedFrom, context.TypeConverterInterfaceTypeSymbol) && + SymbolEqualityComparer.Default.Equals(sourceProperty.Type, i.TypeArguments[0]) && + SymbolEqualityComparer.Default.Equals(property.Type, i.TypeArguments[1])); + } + + private static IEnumerable GetTypeConverterParameters(AttributeData typeConverterAttribute) + { + var converterParameter = typeConverterAttribute.ConstructorArguments.Skip(1).FirstOrDefault(); + return converterParameter.IsNull + ? Enumerable.Empty() + : converterParameter.Values.Where(v => v.Value is not null).Select(v => v.Value!.ToSourceCodeString()); + } } } \ No newline at end of file