From 9ab0e4eb253e70bd1064f8d7451e0d665287b509 Mon Sep 17 00:00:00 2001 From: Mohammadreza Taikandi Date: Fri, 2 Jul 2021 14:55:50 +0100 Subject: [PATCH] Optimized namespace discovery. --- src/MapTo/MappingContext.cs | 30 ++++++++-------- test/MapTo.Tests/MapPropertyTests.cs | 40 +++++++++++++-------- test/MapTo.Tests/MapToTests.cs | 7 ++-- test/MapTo.Tests/MappedClassesTests.cs | 49 ++++++++++++++++++++++++-- 4 files changed, 92 insertions(+), 34 deletions(-) diff --git a/src/MapTo/MappingContext.cs b/src/MapTo/MappingContext.cs index 9981bd9..59160c4 100644 --- a/src/MapTo/MappingContext.cs +++ b/src/MapTo/MappingContext.cs @@ -11,7 +11,7 @@ namespace MapTo { internal abstract class MappingContext { - private readonly List _ignoredNamespaces; + private readonly List _ignoredNamespaces; protected MappingContext(Compilation compilation, SourceGenerationOptions sourceGenerationOptions, TypeDeclarationSyntax typeSyntax) { @@ -76,14 +76,14 @@ namespace MapTo } protected void AddUsingIfRequired(ISymbol? namedTypeSymbol) => - AddUsingIfRequired(namedTypeSymbol?.ContainingNamespace.IsGlobalNamespace == false, namedTypeSymbol?.ContainingNamespace.ToDisplayString()); + AddUsingIfRequired(namedTypeSymbol?.ContainingNamespace.IsGlobalNamespace == false, namedTypeSymbol?.ContainingNamespace); + + protected void AddUsingIfRequired(bool condition, INamespaceSymbol? ns) => + AddUsingIfRequired(condition && ns is not null && !_ignoredNamespaces.Contains(ns.ToDisplayParts().First()), ns?.ToDisplayString()); protected void AddUsingIfRequired(bool condition, string? ns) { - if (condition && ns is not null && - ns != TypeSyntax.GetNamespace() && - !_ignoredNamespaces.Contains(ns) && - !Usings.Contains(ns)) + if (ns is not null && condition && ns != TypeSyntax.GetNamespace() && !Usings.Contains(ns)) { Usings = Usings.Add(ns); } @@ -156,7 +156,7 @@ namespace MapTo return new MappedProperty( property.Name, - propertyType.Name, + ToQualifiedDisplayName(propertyType) ?? propertyType.Name, converterFullyQualifiedName, converterParameters.ToImmutableArray(), sourceProperty.Name, @@ -253,8 +253,7 @@ namespace MapTo return null; } - var sourceTypeNamespace = sourceTypeSymbol.ContainingNamespace.ToDisplayString(); - _ignoredNamespaces.Add(sourceTypeNamespace); + _ignoredNamespaces.Add(sourceTypeSymbol.ContainingNamespace.ToDisplayParts().First()); var typeIdentifierName = TypeSyntax.GetIdentifierName(); var sourceTypeIdentifierName = sourceTypeSymbol.Name; @@ -276,7 +275,7 @@ namespace MapTo TypeSyntax.Modifiers, TypeSyntax.Keyword.Text, typeIdentifierName, - sourceTypeNamespace, + sourceTypeSymbol.ContainingNamespace.ToDisplayString(), sourceTypeIdentifierName, sourceTypeSymbol.ToDisplayString(), mappedProperties, @@ -324,15 +323,18 @@ namespace MapTo return false; } - private string? ToQualifiedDisplayName(ISymbol? typeSymbol) + private string? ToQualifiedDisplayName(ISymbol? symbol) { - if (typeSymbol is null) + if (symbol is null) { return null; } - var typeNamespace = typeSymbol.ContainingNamespace.ToDisplayString(); - return _ignoredNamespaces.Contains(typeNamespace) ? typeSymbol.ToDisplayString() : typeSymbol.Name; + var containingNamespace = TypeSyntax.GetNamespace(); + var symbolNamespace = symbol.ContainingNamespace.ToDisplayString(); + return containingNamespace != symbolNamespace && _ignoredNamespaces.Contains(symbol.ContainingNamespace.ToDisplayParts().First()) + ? symbol.ToDisplayString() + : symbol.Name; } } } \ No newline at end of file diff --git a/test/MapTo.Tests/MapPropertyTests.cs b/test/MapTo.Tests/MapPropertyTests.cs index a8d7595..54af284 100644 --- a/test/MapTo.Tests/MapPropertyTests.cs +++ b/test/MapTo.Tests/MapPropertyTests.cs @@ -108,15 +108,15 @@ namespace MapTo new object[] { @" -namespace Test +namespace Test { using System.Collections.Generic; public class InnerClass { public int Prop1 { get; set; } } - public class OuterClass - { - public int Id { get; set; } - public List InnerProp { get; set; } + public class OuterClass + { + public int Id { get; set; } + public List InnerProp { get; set; } } } @@ -129,10 +129,10 @@ namespace Test.Models public partial class InnerClass { public int Prop1 { get; set; } } [MapFrom(typeof(Test.OuterClass))] - public partial class OuterClass - { - public int Id { get; set; } - public IReadOnlyList InnerProp { get; set; } + public partial class OuterClass + { + public int Id { get; set; } + public IReadOnlyList InnerProp { get; set; } } } ", @@ -155,27 +155,39 @@ namespace Test.Models @" namespace Test { + using System; using System.Collections.Generic; - public record InnerClass(int Prop1); - public record OuterClass(int Id, List InnerProp); + public class InnerClass + { + public int Id { get; set; } + public string Name { get; set; } + } + + public class OuterClass + { + public int Id { get; set; } + public List InnerClasses { get; set; } + public DateTime? SomeDate { get; set; } + } } namespace Test.Models { using MapTo; + using System; using System.Collections.Generic; [MapFrom(typeof(Test.InnerClass))] - public partial record InnerClass(int Prop1); + public partial record InnerClass(int Id, string Name); [MapFrom(typeof(Test.OuterClass))] - public partial record OuterClass(int Id, IReadOnlyList InnerProp); + public partial record OuterClass(int Id, DateTime? SomeDate, IReadOnlyList InnerClasses); } ", @" private protected OuterClass(MappingContext context, Test.OuterClass outerClass) - : this(Id: outerClass.Id, InnerProp: outerClass.InnerProp.Select(context.MapFromWithContext).ToList()) + : this(Id: outerClass.Id, SomeDate: outerClass.SomeDate, InnerClasses: outerClass.InnerClasses.Select(context.MapFromWithContext).ToList()) { if (context == null) throw new ArgumentNullException(nameof(context)); if (outerClass == null) throw new ArgumentNullException(nameof(outerClass)); diff --git a/test/MapTo.Tests/MapToTests.cs b/test/MapTo.Tests/MapToTests.cs index 4130e77..a919de3 100644 --- a/test/MapTo.Tests/MapToTests.cs +++ b/test/MapTo.Tests/MapToTests.cs @@ -387,7 +387,7 @@ namespace Test Prop1 = baz.Prop1; Prop2 = baz.Prop2; Prop3 = baz.Prop3; - InnerProp1 = context.MapFromWithContext(baz.InnerProp1); + InnerProp1 = context.MapFromWithContext(baz.InnerProp1); } ".Trim(); @@ -571,11 +571,10 @@ namespace Test.ViewModels2 using System; using System.Collections.Generic; using System.Linq; - using Test.ViewModels; partial class ManagerViewModel { - public ManagerViewModel(Test.Data.Models.Manager manager) + public ManagerViewModel(Test.Data.Models.Manager manager) : this(new MappingContext(), manager) { } private protected ManagerViewModel(MappingContext context, Test.Data.Models.Manager manager) : base(context, manager) @@ -586,7 +585,7 @@ namespace Test.ViewModels2 context.Register(manager, this); Level = manager.Level; - Employees = manager.Employees.Select(context.MapFromWithContext).ToList(); + Employees = manager.Employees.Select(context.MapFromWithContext).ToList(); } "; diff --git a/test/MapTo.Tests/MappedClassesTests.cs b/test/MapTo.Tests/MappedClassesTests.cs index a4e4313..e9d463d 100644 --- a/test/MapTo.Tests/MappedClassesTests.cs +++ b/test/MapTo.Tests/MappedClassesTests.cs @@ -324,7 +324,51 @@ namespace Test public static IEnumerable VerifyMappedTypesData => new List { new object[] { new[] { MainSourceClass, NestedSourceClass, MainDestinationClass, NestedDestinationClass }, LanguageVersion.CSharp7_3 }, - new object[] { new[] { MainSourceRecord, NestedSourceRecord, MainDestinationRecord, NestedDestinationRecord }, LanguageVersion.CSharp9 } + new object[] { new[] { MainSourceRecord, NestedSourceRecord, MainDestinationRecord, NestedDestinationRecord }, LanguageVersion.CSharp9 }, + new object[] + { + new[] + { + @" +namespace Test.Classes.Classes1 +{ + public class Class1 + { + public int Id { get; set; } + public string Name { get; set; } + } +}", + @" +using System; +using System.Collections.Generic; +using Test.Classes.Classes1; + +namespace Test.Classes.Classes2 +{ + public class Class2 + { + public int Id { get; set; } + public List Genres { get; set; } + public DateTime? ReleaseDate { get; set; } + } +}", + @" +using MapTo; +using System; +using System.Collections.Generic; +using TC = Test.Classes; + +namespace Tests.Records +{ + [MapFrom(typeof(Test.Classes.Classes1.Class1))] + public partial record Class1(int Id, string Name); + + [MapFrom(typeof(Test.Classes.Classes2.Class2))] + public partial record Class2(int Id, IReadOnlyList Genres); +}" + }, + LanguageVersion.CSharp9 + } }; [Fact] @@ -444,7 +488,8 @@ public partial record UserViewModel( [MapProperty(SourcePropertyName = nameof(User.Id))] [MapTypeConverter(typeof(UserViewModel.IdConverter))] string Key, - DateTimeOffset RegisteredAt) + DateTimeOffset RegisteredAt, + Profile Profile) { private class IdConverter : ITypeConverter {