Initial work to add records support.

This commit is contained in:
Mohammadreza Taikandi 2021-06-29 07:15:17 +01:00
parent 98c899e078
commit 91f5e9bcf5
6 changed files with 61 additions and 59 deletions

View File

@ -28,11 +28,11 @@ namespace MapTo.Extensions
public static CompilationUnitSyntax GetCompilationUnit(this SyntaxNode syntaxNode) => syntaxNode.Ancestors().OfType<CompilationUnitSyntax>().Single(); public static CompilationUnitSyntax GetCompilationUnit(this SyntaxNode syntaxNode) => syntaxNode.Ancestors().OfType<CompilationUnitSyntax>().Single();
public static string GetClassName(this ClassDeclarationSyntax classSyntax) => classSyntax.Identifier.Text; public static string GetIdentifierName(this TypeDeclarationSyntax typeSyntax) => typeSyntax.Identifier.Text;
public static AttributeSyntax? GetAttribute(this ClassDeclarationSyntax classSyntax, string attributeName) public static AttributeSyntax? GetAttribute(this TypeDeclarationSyntax typeDeclarationSyntax, string attributeName)
{ {
return classSyntax.AttributeLists return typeDeclarationSyntax.AttributeLists
.SelectMany(al => al.Attributes) .SelectMany(al => al.Attributes)
.SingleOrDefault(a => .SingleOrDefault(a =>
(a.Name as IdentifierNameSyntax)?.Identifier.ValueText == attributeName || (a.Name as IdentifierNameSyntax)?.Identifier.ValueText == attributeName ||
@ -48,8 +48,8 @@ namespace MapTo.Extensions
public static AttributeData? GetAttribute(this ISymbol symbol, ITypeSymbol attributeSymbol) => public static AttributeData? GetAttribute(this ISymbol symbol, ITypeSymbol attributeSymbol) =>
symbol.GetAttributes(attributeSymbol).FirstOrDefault(); symbol.GetAttributes(attributeSymbol).FirstOrDefault();
public static string? GetNamespace(this ClassDeclarationSyntax classDeclarationSyntax) => public static string? GetNamespace(this TypeDeclarationSyntax typeDeclarationSyntax) =>
classDeclarationSyntax.Ancestors() typeDeclarationSyntax.Ancestors()
.OfType<NamespaceDeclarationSyntax>() .OfType<NamespaceDeclarationSyntax>()
.FirstOrDefault() .FirstOrDefault()
?.Name ?.Name

View File

@ -35,9 +35,9 @@ namespace MapTo
.AddSource(ref context, MapPropertyAttributeSource.Generate(options)) .AddSource(ref context, MapPropertyAttributeSource.Generate(options))
.AddSource(ref context, MappingContextSource.Generate(options)); .AddSource(ref context, MappingContextSource.Generate(options));
if (context.SyntaxReceiver is MapToSyntaxReceiver receiver && receiver.CandidateClasses.Any()) if (context.SyntaxReceiver is MapToSyntaxReceiver receiver && receiver.CandidateTypes.Any())
{ {
AddGeneratedMappingsClasses(context, compilation, receiver.CandidateClasses, options); AddGeneratedMappingsClasses(context, compilation, receiver.CandidateTypes, options);
} }
} }
catch (Exception ex) catch (Exception ex)
@ -47,7 +47,7 @@ namespace MapTo
} }
} }
private static void AddGeneratedMappingsClasses(GeneratorExecutionContext context, Compilation compilation, IEnumerable<ClassDeclarationSyntax> candidateClasses, SourceGenerationOptions options) private static void AddGeneratedMappingsClasses(GeneratorExecutionContext context, Compilation compilation, IEnumerable<TypeDeclarationSyntax> candidateClasses, SourceGenerationOptions options)
{ {
foreach (var classSyntax in candidateClasses) foreach (var classSyntax in candidateClasses)
{ {

View File

@ -8,12 +8,12 @@ namespace MapTo
{ {
internal class MapToSyntaxReceiver : ISyntaxReceiver internal class MapToSyntaxReceiver : ISyntaxReceiver
{ {
public List<ClassDeclarationSyntax> CandidateClasses { get; } = new(); public List<TypeDeclarationSyntax> CandidateTypes { get; } = new();
/// <inheritdoc /> /// <inheritdoc />
public void OnVisitSyntaxNode(SyntaxNode syntaxNode) public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
{ {
if (syntaxNode is not ClassDeclarationSyntax { AttributeLists: { Count: >= 1 } attributes } classDeclaration) if (syntaxNode is not TypeDeclarationSyntax { AttributeLists: { Count: >= 1 } attributes } typeDeclarationSyntax)
{ {
return; return;
} }
@ -21,7 +21,7 @@ namespace MapTo
var attributeSyntax = attributes var attributeSyntax = attributes
.SelectMany(a => a.Attributes) .SelectMany(a => a.Attributes)
.SingleOrDefault(a => a.Name is .SingleOrDefault(a => a.Name is
IdentifierNameSyntax { Identifier: { ValueText: MapFromAttributeSource.AttributeName } } // For: [MapFrom] IdentifierNameSyntax { Identifier: { ValueText: MapFromAttributeSource.AttributeName } } // For: [MapFrom]
or or
QualifiedNameSyntax // For: [MapTo.MapFrom] QualifiedNameSyntax // For: [MapTo.MapFrom]
{ {
@ -32,7 +32,7 @@ namespace MapTo
if (attributeSyntax is not null) if (attributeSyntax is not null)
{ {
CandidateClasses.Add(classDeclaration); CandidateTypes.Add(typeDeclarationSyntax);
} }
} }
} }

View File

@ -11,7 +11,7 @@ namespace MapTo
{ {
internal class MappingContext internal class MappingContext
{ {
private readonly ClassDeclarationSyntax _classSyntax; private readonly TypeDeclarationSyntax _typeSyntax;
private readonly Compilation _compilation; private readonly Compilation _compilation;
private readonly List<Diagnostic> _diagnostics; private readonly List<Diagnostic> _diagnostics;
private readonly INamedTypeSymbol _ignorePropertyAttributeTypeSymbol; private readonly INamedTypeSymbol _ignorePropertyAttributeTypeSymbol;
@ -23,12 +23,12 @@ namespace MapTo
private readonly INamedTypeSymbol _typeConverterInterfaceTypeSymbol; private readonly INamedTypeSymbol _typeConverterInterfaceTypeSymbol;
private readonly List<string> _usings; private readonly List<string> _usings;
internal MappingContext(Compilation compilation, SourceGenerationOptions sourceGenerationOptions, ClassDeclarationSyntax classSyntax) internal MappingContext(Compilation compilation, SourceGenerationOptions sourceGenerationOptions, TypeDeclarationSyntax typeSyntax)
{ {
_diagnostics = new List<Diagnostic>(); _diagnostics = new List<Diagnostic>();
_usings = new List<string> { "System", Constants.RootNamespace }; _usings = new List<string> { "System", Constants.RootNamespace };
_sourceGenerationOptions = sourceGenerationOptions; _sourceGenerationOptions = sourceGenerationOptions;
_classSyntax = classSyntax; _typeSyntax = typeSyntax;
_compilation = compilation; _compilation = compilation;
_ignorePropertyAttributeTypeSymbol = compilation.GetTypeByMetadataNameOrThrow(IgnorePropertyAttributeSource.FullyQualifiedName); _ignorePropertyAttributeTypeSymbol = compilation.GetTypeByMetadataNameOrThrow(IgnorePropertyAttributeSource.FullyQualifiedName);
@ -49,29 +49,29 @@ namespace MapTo
private void Initialize() private void Initialize()
{ {
var semanticModel = _compilation.GetSemanticModel(_classSyntax.SyntaxTree); var semanticModel = _compilation.GetSemanticModel(_typeSyntax.SyntaxTree);
if (!(ModelExtensions.GetDeclaredSymbol(semanticModel, _classSyntax) is INamedTypeSymbol classTypeSymbol)) if (ModelExtensions.GetDeclaredSymbol(semanticModel, _typeSyntax) is not INamedTypeSymbol classTypeSymbol)
{ {
_diagnostics.Add(DiagnosticsFactory.TypeNotFoundError(_classSyntax.GetLocation(), _classSyntax.Identifier.ValueText)); _diagnostics.Add(DiagnosticsFactory.TypeNotFoundError(_typeSyntax.GetLocation(), _typeSyntax.Identifier.ValueText));
return; return;
} }
var sourceTypeSymbol = GetSourceTypeSymbol(_classSyntax, semanticModel); var sourceTypeSymbol = GetSourceTypeSymbol(_typeSyntax, semanticModel);
if (sourceTypeSymbol is null) if (sourceTypeSymbol is null)
{ {
_diagnostics.Add(DiagnosticsFactory.MapFromAttributeNotFoundError(_classSyntax.GetLocation())); _diagnostics.Add(DiagnosticsFactory.MapFromAttributeNotFoundError(_typeSyntax.GetLocation()));
return; return;
} }
var className = _classSyntax.GetClassName(); var typeIdentifierName = _typeSyntax.GetIdentifierName();
var sourceClassName = sourceTypeSymbol.Name; var sourceTypeIdentifierName = sourceTypeSymbol.Name;
var isClassInheritFromMappedBaseClass = IsClassInheritFromMappedBaseClass(semanticModel); var isTypeInheritFromMappedBaseClass = IsTypeInheritFromMappedBaseClass(semanticModel);
var shouldGenerateSecondaryConstructor = ShouldGenerateSecondaryConstructor(semanticModel, sourceTypeSymbol); var shouldGenerateSecondaryConstructor = ShouldGenerateSecondaryConstructor(semanticModel, sourceTypeSymbol);
var mappedProperties = GetMappedProperties(classTypeSymbol, sourceTypeSymbol, isClassInheritFromMappedBaseClass); var mappedProperties = GetMappedProperties(classTypeSymbol, sourceTypeSymbol, isTypeInheritFromMappedBaseClass);
if (!mappedProperties.Any()) if (!mappedProperties.Any())
{ {
_diagnostics.Add(DiagnosticsFactory.NoMatchingPropertyFoundError(_classSyntax.GetLocation(), classTypeSymbol, sourceTypeSymbol)); _diagnostics.Add(DiagnosticsFactory.NoMatchingPropertyFoundError(_typeSyntax.GetLocation(), classTypeSymbol, sourceTypeSymbol));
return; return;
} }
@ -80,21 +80,22 @@ namespace MapTo
Model = new MappingModel( Model = new MappingModel(
_sourceGenerationOptions, _sourceGenerationOptions,
_classSyntax.GetNamespace(), _typeSyntax.GetNamespace(),
_classSyntax.Modifiers, _typeSyntax.Modifiers,
className, _typeSyntax.Keyword.Text,
typeIdentifierName,
sourceTypeSymbol.ContainingNamespace.ToString(), sourceTypeSymbol.ContainingNamespace.ToString(),
sourceClassName, sourceTypeIdentifierName,
sourceTypeSymbol.ToString(), sourceTypeSymbol.ToString(),
mappedProperties.ToImmutableArray(), mappedProperties.ToImmutableArray(),
isClassInheritFromMappedBaseClass, isTypeInheritFromMappedBaseClass,
_usings.ToImmutableArray(), _usings.ToImmutableArray(),
shouldGenerateSecondaryConstructor); shouldGenerateSecondaryConstructor);
} }
private bool ShouldGenerateSecondaryConstructor(SemanticModel semanticModel, ISymbol sourceTypeSymbol) private bool ShouldGenerateSecondaryConstructor(SemanticModel semanticModel, ISymbol sourceTypeSymbol)
{ {
var constructorSyntax = _classSyntax.DescendantNodes() var constructorSyntax = _typeSyntax.DescendantNodes()
.OfType<ConstructorDeclarationSyntax>() .OfType<ConstructorDeclarationSyntax>()
.SingleOrDefault(c => .SingleOrDefault(c =>
c.ParameterList.Parameters.Count == 1 && c.ParameterList.Parameters.Count == 1 &&
@ -116,18 +117,18 @@ namespace MapTo
return false; return false;
} }
private bool IsClassInheritFromMappedBaseClass(SemanticModel semanticModel) private bool IsTypeInheritFromMappedBaseClass(SemanticModel semanticModel)
{ {
return _classSyntax.BaseList is not null && _classSyntax.BaseList.Types return _typeSyntax.BaseList is not null && _typeSyntax.BaseList.Types
.Select(t => ModelExtensions.GetTypeInfo(semanticModel, t.Type).Type) .Select(t => ModelExtensions.GetTypeInfo(semanticModel, t.Type).Type)
.Any(t => t?.GetAttribute(_mapFromAttributeTypeSymbol) != null); .Any(t => t?.GetAttribute(_mapFromAttributeTypeSymbol) != null);
} }
private ImmutableArray<MappedProperty> GetMappedProperties(ITypeSymbol classSymbol, ITypeSymbol sourceTypeSymbol, bool isClassInheritFromMappedBaseClass) private ImmutableArray<MappedProperty> GetMappedProperties(ITypeSymbol typeSymbol, ITypeSymbol sourceTypeSymbol, bool isClassInheritFromMappedBaseClass)
{ {
var mappedProperties = new List<MappedProperty>(); var mappedProperties = new List<MappedProperty>();
var sourceProperties = sourceTypeSymbol.GetAllMembers().OfType<IPropertySymbol>().ToArray(); var sourceProperties = sourceTypeSymbol.GetAllMembers().OfType<IPropertySymbol>().ToArray();
var classProperties = classSymbol.GetAllMembers(!isClassInheritFromMappedBaseClass) var classProperties = typeSymbol.GetAllMembers(!isClassInheritFromMappedBaseClass)
.OfType<IPropertySymbol>() .OfType<IPropertySymbol>()
.Where(p => !p.HasAttribute(_ignorePropertyAttributeTypeSymbol)); .Where(p => !p.HasAttribute(_ignorePropertyAttributeTypeSymbol));
@ -207,7 +208,7 @@ namespace MapTo
private void AddUsingIfRequired(bool condition, string? ns) private void AddUsingIfRequired(bool condition, string? ns)
{ {
if (condition && ns is not null && ns != _classSyntax.GetNamespace() && !_usings.Contains(ns)) if (condition && ns is not null && ns != _typeSyntax.GetNamespace() && !_usings.Contains(ns))
{ {
_usings.Add(ns); _usings.Add(ns);
} }
@ -270,8 +271,8 @@ namespace MapTo
: converterParameter.Values.Where(v => v.Value is not null).Select(v => v.Value!.ToSourceCodeString()).ToImmutableArray(); : converterParameter.Values.Where(v => v.Value is not null).Select(v => v.Value!.ToSourceCodeString()).ToImmutableArray();
} }
private INamedTypeSymbol? GetSourceTypeSymbol(ClassDeclarationSyntax classDeclarationSyntax, SemanticModel? semanticModel = null) => private INamedTypeSymbol? GetSourceTypeSymbol(TypeDeclarationSyntax typeDeclarationSyntax, SemanticModel? semanticModel = null) =>
GetSourceTypeSymbol(classDeclarationSyntax.GetAttribute(MapFromAttributeSource.AttributeName), semanticModel); GetSourceTypeSymbol(typeDeclarationSyntax.GetAttribute(MapFromAttributeSource.AttributeName), semanticModel);
private INamedTypeSymbol? GetSourceTypeSymbol(AttributeSyntax? attributeSyntax, SemanticModel? semanticModel = null) private INamedTypeSymbol? GetSourceTypeSymbol(AttributeSyntax? attributeSyntax, SemanticModel? semanticModel = null)
{ {

View File

@ -22,11 +22,12 @@ namespace MapTo
internal record MappingModel ( internal record MappingModel (
SourceGenerationOptions Options, SourceGenerationOptions Options,
string? Namespace, string? Namespace,
SyntaxTokenList ClassModifiers, SyntaxTokenList Modifiers,
string ClassName, string Type,
string TypeIdentifierName,
string SourceNamespace, string SourceNamespace,
string SourceClassName, string SourceTypeIdentifierName,
string SourceClassFullName, string SourceTypeFullName,
ImmutableArray<MappedProperty> MappedProperties, ImmutableArray<MappedProperty> MappedProperties,
bool HasMappedBaseClass, bool HasMappedBaseClass,
ImmutableArray<string> Usings, ImmutableArray<string> Usings,

View File

@ -18,7 +18,7 @@ namespace MapTo.Sources
.WriteLine() .WriteLine()
// Class declaration // Class declaration
.WriteLine($"partial class {model.ClassName}") .WriteLine($"partial class {model.TypeIdentifierName}")
.WriteOpeningBracket(); .WriteOpeningBracket();
// Class body // Class body
@ -44,37 +44,37 @@ namespace MapTo.Sources
// End namespace declaration // End namespace declaration
.WriteClosingBracket(); .WriteClosingBracket();
return new(builder.ToString(), $"{model.ClassName}.g.cs"); return new(builder.ToString(), $"{model.TypeIdentifierName}.g.cs");
} }
private static SourceBuilder GenerateSecondaryConstructor(this SourceBuilder builder, MappingModel model) private static SourceBuilder GenerateSecondaryConstructor(this SourceBuilder builder, MappingModel model)
{ {
var sourceClassParameterName = model.SourceClassName.ToCamelCase(); var sourceClassParameterName = model.SourceTypeIdentifierName.ToCamelCase();
if (model.Options.GenerateXmlDocument) if (model.Options.GenerateXmlDocument)
{ {
builder builder
.WriteLine("/// <summary>") .WriteLine("/// <summary>")
.WriteLine($"/// Initializes a new instance of the <see cref=\"{model.ClassName}\"/> class") .WriteLine($"/// Initializes a new instance of the <see cref=\"{model.TypeIdentifierName}\"/> class")
.WriteLine($"/// using the property values from the specified <paramref name=\"{sourceClassParameterName}\"/>.") .WriteLine($"/// using the property values from the specified <paramref name=\"{sourceClassParameterName}\"/>.")
.WriteLine("/// </summary>") .WriteLine("/// </summary>")
.WriteLine($"/// <exception cref=\"ArgumentNullException\">{sourceClassParameterName} is null</exception>"); .WriteLine($"/// <exception cref=\"ArgumentNullException\">{sourceClassParameterName} is null</exception>");
} }
return builder return builder
.WriteLine($"{model.Options.ConstructorAccessModifier.ToLowercaseString()} {model.ClassName}({model.SourceClassName} {sourceClassParameterName})") .WriteLine($"{model.Options.ConstructorAccessModifier.ToLowercaseString()} {model.TypeIdentifierName}({model.SourceTypeIdentifierName} {sourceClassParameterName})")
.WriteLine($" : this(new {MappingContextSource.ClassName}(), {sourceClassParameterName}) {{ }}"); .WriteLine($" : this(new {MappingContextSource.ClassName}(), {sourceClassParameterName}) {{ }}");
} }
private static SourceBuilder GeneratePrivateConstructor(this SourceBuilder builder, MappingModel model) private static SourceBuilder GeneratePrivateConstructor(this SourceBuilder builder, MappingModel model)
{ {
var sourceClassParameterName = model.SourceClassName.ToCamelCase(); var sourceClassParameterName = model.SourceTypeIdentifierName.ToCamelCase();
const string mappingContextParameterName = "context"; const string mappingContextParameterName = "context";
var baseConstructor = model.HasMappedBaseClass ? $" : base({mappingContextParameterName}, {sourceClassParameterName})" : string.Empty; var baseConstructor = model.HasMappedBaseClass ? $" : base({mappingContextParameterName}, {sourceClassParameterName})" : string.Empty;
builder builder
.WriteLine($"private protected {model.ClassName}({MappingContextSource.ClassName} {mappingContextParameterName}, {model.SourceClassName} {sourceClassParameterName}){baseConstructor}") .WriteLine($"private protected {model.TypeIdentifierName}({MappingContextSource.ClassName} {mappingContextParameterName}, {model.SourceTypeIdentifierName} {sourceClassParameterName}){baseConstructor}")
.WriteOpeningBracket() .WriteOpeningBracket()
.WriteLine($"if ({mappingContextParameterName} == null) throw new ArgumentNullException(nameof({mappingContextParameterName}));") .WriteLine($"if ({mappingContextParameterName} == null) throw new ArgumentNullException(nameof({mappingContextParameterName}));")
.WriteLine($"if ({sourceClassParameterName} == null) throw new ArgumentNullException(nameof({sourceClassParameterName}));") .WriteLine($"if ({sourceClassParameterName} == null) throw new ArgumentNullException(nameof({sourceClassParameterName}));")
@ -113,14 +113,14 @@ namespace MapTo.Sources
private static SourceBuilder GenerateFactoryMethod(this SourceBuilder builder, MappingModel model) private static SourceBuilder GenerateFactoryMethod(this SourceBuilder builder, MappingModel model)
{ {
var sourceClassParameterName = model.SourceClassName.ToCamelCase(); var sourceClassParameterName = model.SourceTypeIdentifierName.ToCamelCase();
return builder return builder
.GenerateConvertorMethodsXmlDocs(model, sourceClassParameterName) .GenerateConvertorMethodsXmlDocs(model, sourceClassParameterName)
.WriteLineIf(model.Options.SupportNullableStaticAnalysis, $"[return: NotNullIfNotNull(\"{sourceClassParameterName}\")]") .WriteLineIf(model.Options.SupportNullableStaticAnalysis, $"[return: NotNullIfNotNull(\"{sourceClassParameterName}\")]")
.WriteLine($"{model.Options.GeneratedMethodsAccessModifier.ToLowercaseString()} static {model.ClassName}{model.Options.NullableReferenceSyntax} From({model.SourceClassName}{model.Options.NullableReferenceSyntax} {sourceClassParameterName})") .WriteLine($"{model.Options.GeneratedMethodsAccessModifier.ToLowercaseString()} static {model.TypeIdentifierName}{model.Options.NullableReferenceSyntax} From({model.SourceTypeIdentifierName}{model.Options.NullableReferenceSyntax} {sourceClassParameterName})")
.WriteOpeningBracket() .WriteOpeningBracket()
.WriteLine($"return {sourceClassParameterName} == null ? null : {MappingContextSource.ClassName}.{MappingContextSource.FactoryMethodName}<{model.SourceClassName}, {model.ClassName}>({sourceClassParameterName});") .WriteLine($"return {sourceClassParameterName} == null ? null : {MappingContextSource.ClassName}.{MappingContextSource.FactoryMethodName}<{model.SourceTypeIdentifierName}, {model.TypeIdentifierName}>({sourceClassParameterName});")
.WriteClosingBracket(); .WriteClosingBracket();
} }
@ -133,17 +133,17 @@ namespace MapTo.Sources
return builder return builder
.WriteLine("/// <summary>") .WriteLine("/// <summary>")
.WriteLine($"/// Creates a new instance of <see cref=\"{model.ClassName}\"/> and sets its participating properties") .WriteLine($"/// Creates a new instance of <see cref=\"{model.TypeIdentifierName}\"/> and sets its participating properties")
.WriteLine($"/// using the property values from <paramref name=\"{sourceClassParameterName}\"/>.") .WriteLine($"/// using the property values from <paramref name=\"{sourceClassParameterName}\"/>.")
.WriteLine("/// </summary>") .WriteLine("/// </summary>")
.WriteLine($"/// <param name=\"{sourceClassParameterName}\">The instance of <see cref=\"{model.SourceClassName}\"/> to use as source.</param>") .WriteLine($"/// <param name=\"{sourceClassParameterName}\">The instance of <see cref=\"{model.SourceTypeIdentifierName}\"/> to use as source.</param>")
.WriteLine($"/// <returns>A new instance of <see cred=\"{model.ClassName}\"/> -or- <c>null</c> if <paramref name=\"{sourceClassParameterName}\"/> is <c>null</c>.</returns>"); .WriteLine($"/// <returns>A new instance of <see cred=\"{model.TypeIdentifierName}\"/> -or- <c>null</c> if <paramref name=\"{sourceClassParameterName}\"/> is <c>null</c>.</returns>");
} }
private static SourceBuilder GenerateSourceTypeExtensionClass(this SourceBuilder builder, MappingModel model) private static SourceBuilder GenerateSourceTypeExtensionClass(this SourceBuilder builder, MappingModel model)
{ {
return builder return builder
.WriteLine($"{model.Options.GeneratedMethodsAccessModifier.ToLowercaseString()} static partial class {model.SourceClassName}To{model.ClassName}Extensions") .WriteLine($"{model.Options.GeneratedMethodsAccessModifier.ToLowercaseString()} static partial class {model.SourceTypeIdentifierName}To{model.TypeIdentifierName}Extensions")
.WriteOpeningBracket() .WriteOpeningBracket()
.GenerateSourceTypeExtensionMethod(model) .GenerateSourceTypeExtensionMethod(model)
.WriteClosingBracket(); .WriteClosingBracket();
@ -151,14 +151,14 @@ namespace MapTo.Sources
private static SourceBuilder GenerateSourceTypeExtensionMethod(this SourceBuilder builder, MappingModel model) private static SourceBuilder GenerateSourceTypeExtensionMethod(this SourceBuilder builder, MappingModel model)
{ {
var sourceClassParameterName = model.SourceClassName.ToCamelCase(); var sourceClassParameterName = model.SourceTypeIdentifierName.ToCamelCase();
return builder return builder
.GenerateConvertorMethodsXmlDocs(model, sourceClassParameterName) .GenerateConvertorMethodsXmlDocs(model, sourceClassParameterName)
.WriteLineIf(model.Options.SupportNullableStaticAnalysis, $"[return: NotNullIfNotNull(\"{sourceClassParameterName}\")]") .WriteLineIf(model.Options.SupportNullableStaticAnalysis, $"[return: NotNullIfNotNull(\"{sourceClassParameterName}\")]")
.WriteLine($"{model.Options.GeneratedMethodsAccessModifier.ToLowercaseString()} static {model.ClassName}{model.Options.NullableReferenceSyntax} To{model.ClassName}(this {model.SourceClassName}{model.Options.NullableReferenceSyntax} {sourceClassParameterName})") .WriteLine($"{model.Options.GeneratedMethodsAccessModifier.ToLowercaseString()} static {model.TypeIdentifierName}{model.Options.NullableReferenceSyntax} To{model.TypeIdentifierName}(this {model.SourceTypeIdentifierName}{model.Options.NullableReferenceSyntax} {sourceClassParameterName})")
.WriteOpeningBracket() .WriteOpeningBracket()
.WriteLine($"return {sourceClassParameterName} == null ? null : new {model.ClassName}({sourceClassParameterName});") .WriteLine($"return {sourceClassParameterName} == null ? null : new {model.TypeIdentifierName}({sourceClassParameterName});")
.WriteClosingBracket(); .WriteClosingBracket();
} }
} }