Optimized namespace discovery.

This commit is contained in:
Mohammadreza Taikandi 2021-07-02 14:55:50 +01:00
parent bfd6dafe78
commit 9ab0e4eb25
4 changed files with 92 additions and 34 deletions

View File

@ -11,7 +11,7 @@ namespace MapTo
{ {
internal abstract class MappingContext internal abstract class MappingContext
{ {
private readonly List<string> _ignoredNamespaces; private readonly List<SymbolDisplayPart> _ignoredNamespaces;
protected MappingContext(Compilation compilation, SourceGenerationOptions sourceGenerationOptions, TypeDeclarationSyntax typeSyntax) protected MappingContext(Compilation compilation, SourceGenerationOptions sourceGenerationOptions, TypeDeclarationSyntax typeSyntax)
{ {
@ -76,14 +76,14 @@ namespace MapTo
} }
protected void AddUsingIfRequired(ISymbol? namedTypeSymbol) => 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) protected void AddUsingIfRequired(bool condition, string? ns)
{ {
if (condition && ns is not null && if (ns is not null && condition && ns != TypeSyntax.GetNamespace() && !Usings.Contains(ns))
ns != TypeSyntax.GetNamespace() &&
!_ignoredNamespaces.Contains(ns) &&
!Usings.Contains(ns))
{ {
Usings = Usings.Add(ns); Usings = Usings.Add(ns);
} }
@ -156,7 +156,7 @@ namespace MapTo
return new MappedProperty( return new MappedProperty(
property.Name, property.Name,
propertyType.Name, ToQualifiedDisplayName(propertyType) ?? propertyType.Name,
converterFullyQualifiedName, converterFullyQualifiedName,
converterParameters.ToImmutableArray(), converterParameters.ToImmutableArray(),
sourceProperty.Name, sourceProperty.Name,
@ -253,8 +253,7 @@ namespace MapTo
return null; return null;
} }
var sourceTypeNamespace = sourceTypeSymbol.ContainingNamespace.ToDisplayString(); _ignoredNamespaces.Add(sourceTypeSymbol.ContainingNamespace.ToDisplayParts().First());
_ignoredNamespaces.Add(sourceTypeNamespace);
var typeIdentifierName = TypeSyntax.GetIdentifierName(); var typeIdentifierName = TypeSyntax.GetIdentifierName();
var sourceTypeIdentifierName = sourceTypeSymbol.Name; var sourceTypeIdentifierName = sourceTypeSymbol.Name;
@ -276,7 +275,7 @@ namespace MapTo
TypeSyntax.Modifiers, TypeSyntax.Modifiers,
TypeSyntax.Keyword.Text, TypeSyntax.Keyword.Text,
typeIdentifierName, typeIdentifierName,
sourceTypeNamespace, sourceTypeSymbol.ContainingNamespace.ToDisplayString(),
sourceTypeIdentifierName, sourceTypeIdentifierName,
sourceTypeSymbol.ToDisplayString(), sourceTypeSymbol.ToDisplayString(),
mappedProperties, mappedProperties,
@ -324,15 +323,18 @@ namespace MapTo
return false; return false;
} }
private string? ToQualifiedDisplayName(ISymbol? typeSymbol) private string? ToQualifiedDisplayName(ISymbol? symbol)
{ {
if (typeSymbol is null) if (symbol is null)
{ {
return null; return null;
} }
var typeNamespace = typeSymbol.ContainingNamespace.ToDisplayString(); var containingNamespace = TypeSyntax.GetNamespace();
return _ignoredNamespaces.Contains(typeNamespace) ? typeSymbol.ToDisplayString() : typeSymbol.Name; var symbolNamespace = symbol.ContainingNamespace.ToDisplayString();
return containingNamespace != symbolNamespace && _ignoredNamespaces.Contains(symbol.ContainingNamespace.ToDisplayParts().First())
? symbol.ToDisplayString()
: symbol.Name;
} }
} }
} }

View File

@ -108,15 +108,15 @@ namespace MapTo
new object[] new object[]
{ {
@" @"
namespace Test namespace Test
{ {
using System.Collections.Generic; using System.Collections.Generic;
public class InnerClass { public int Prop1 { get; set; } } public class InnerClass { public int Prop1 { get; set; } }
public class OuterClass public class OuterClass
{ {
public int Id { get; set; } public int Id { get; set; }
public List<InnerClass> InnerProp { get; set; } public List<InnerClass> InnerProp { get; set; }
} }
} }
@ -129,10 +129,10 @@ namespace Test.Models
public partial class InnerClass { public int Prop1 { get; set; } } public partial class InnerClass { public int Prop1 { get; set; } }
[MapFrom(typeof(Test.OuterClass))] [MapFrom(typeof(Test.OuterClass))]
public partial class OuterClass public partial class OuterClass
{ {
public int Id { get; set; } public int Id { get; set; }
public IReadOnlyList<InnerClass> InnerProp { get; set; } public IReadOnlyList<InnerClass> InnerProp { get; set; }
} }
} }
", ",
@ -155,27 +155,39 @@ namespace Test.Models
@" @"
namespace Test namespace Test
{ {
using System;
using System.Collections.Generic; using System.Collections.Generic;
public record InnerClass(int Prop1); public class InnerClass
public record OuterClass(int Id, List<InnerClass> InnerProp); {
public int Id { get; set; }
public string Name { get; set; }
}
public class OuterClass
{
public int Id { get; set; }
public List<InnerClass> InnerClasses { get; set; }
public DateTime? SomeDate { get; set; }
}
} }
namespace Test.Models namespace Test.Models
{ {
using MapTo; using MapTo;
using System;
using System.Collections.Generic; using System.Collections.Generic;
[MapFrom(typeof(Test.InnerClass))] [MapFrom(typeof(Test.InnerClass))]
public partial record InnerClass(int Prop1); public partial record InnerClass(int Id, string Name);
[MapFrom(typeof(Test.OuterClass))] [MapFrom(typeof(Test.OuterClass))]
public partial record OuterClass(int Id, IReadOnlyList<InnerClass> InnerProp); public partial record OuterClass(int Id, DateTime? SomeDate, IReadOnlyList<InnerClass> InnerClasses);
} }
", ",
@" @"
private protected OuterClass(MappingContext context, Test.OuterClass outerClass) private protected OuterClass(MappingContext context, Test.OuterClass outerClass)
: this(Id: outerClass.Id, InnerProp: outerClass.InnerProp.Select(context.MapFromWithContext<Test.InnerClass, InnerClass>).ToList()) : this(Id: outerClass.Id, SomeDate: outerClass.SomeDate, InnerClasses: outerClass.InnerClasses.Select(context.MapFromWithContext<Test.InnerClass, InnerClass>).ToList())
{ {
if (context == null) throw new ArgumentNullException(nameof(context)); if (context == null) throw new ArgumentNullException(nameof(context));
if (outerClass == null) throw new ArgumentNullException(nameof(outerClass)); if (outerClass == null) throw new ArgumentNullException(nameof(outerClass));

View File

@ -387,7 +387,7 @@ namespace Test
Prop1 = baz.Prop1; Prop1 = baz.Prop1;
Prop2 = baz.Prop2; Prop2 = baz.Prop2;
Prop3 = baz.Prop3; Prop3 = baz.Prop3;
InnerProp1 = context.MapFromWithContext<Test.A, B>(baz.InnerProp1); InnerProp1 = context.MapFromWithContext<A, B>(baz.InnerProp1);
} }
".Trim(); ".Trim();
@ -571,11 +571,10 @@ namespace Test.ViewModels2
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Test.ViewModels;
partial class ManagerViewModel partial class ManagerViewModel
{ {
public ManagerViewModel(Test.Data.Models.Manager manager) public ManagerViewModel(Test.Data.Models.Manager manager)
: this(new MappingContext(), manager) { } : this(new MappingContext(), manager) { }
private protected ManagerViewModel(MappingContext context, Test.Data.Models.Manager manager) : base(context, 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); context.Register(manager, this);
Level = manager.Level; Level = manager.Level;
Employees = manager.Employees.Select(context.MapFromWithContext<Test.Data.Models.Employee, EmployeeViewModel>).ToList(); Employees = manager.Employees.Select(context.MapFromWithContext<Test.Data.Models.Employee, Test.ViewModels.EmployeeViewModel>).ToList();
} }
"; ";

View File

@ -324,7 +324,51 @@ namespace Test
public static IEnumerable<object[]> VerifyMappedTypesData => new List<object[]> public static IEnumerable<object[]> VerifyMappedTypesData => new List<object[]>
{ {
new object[] { new[] { MainSourceClass, NestedSourceClass, MainDestinationClass, NestedDestinationClass }, LanguageVersion.CSharp7_3 }, 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<Class1> 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<Class1> Genres);
}"
},
LanguageVersion.CSharp9
}
}; };
[Fact] [Fact]
@ -444,7 +488,8 @@ public partial record UserViewModel(
[MapProperty(SourcePropertyName = nameof(User.Id))] [MapProperty(SourcePropertyName = nameof(User.Id))]
[MapTypeConverter(typeof(UserViewModel.IdConverter))] [MapTypeConverter(typeof(UserViewModel.IdConverter))]
string Key, string Key,
DateTimeOffset RegisteredAt) DateTimeOffset RegisteredAt,
Profile Profile)
{ {
private class IdConverter : ITypeConverter<int, string> private class IdConverter : ITypeConverter<int, string>
{ {