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
{
private readonly List<string> _ignoredNamespaces;
private readonly List<SymbolDisplayPart> _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;
}
}
}

View File

@ -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<InnerClass> InnerProp { get; set; }
public class OuterClass
{
public int Id { get; set; }
public List<InnerClass> 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<InnerClass> InnerProp { get; set; }
public partial class OuterClass
{
public int Id { get; set; }
public IReadOnlyList<InnerClass> 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<InnerClass> InnerProp);
public class InnerClass
{
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
{
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<InnerClass> InnerProp);
public partial record OuterClass(int Id, DateTime? SomeDate, IReadOnlyList<InnerClass> InnerClasses);
}
",
@"
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 (outerClass == null) throw new ArgumentNullException(nameof(outerClass));

View File

@ -387,7 +387,7 @@ namespace Test
Prop1 = baz.Prop1;
Prop2 = baz.Prop2;
Prop3 = baz.Prop3;
InnerProp1 = context.MapFromWithContext<Test.A, B>(baz.InnerProp1);
InnerProp1 = context.MapFromWithContext<A, B>(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<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[]>
{
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]
@ -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<int, string>
{