Separated context verification and model creation.

This commit is contained in:
Mohammadreza Taikandi 2020-12-22 07:53:46 +00:00
parent 2a671a9dd4
commit 804a0c4eb3
3 changed files with 68 additions and 47 deletions

View File

@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
namespace MapTo.Extensions
{
internal static class EnumerableExtensions
{
internal static void ForEach<T>(this IEnumerable<T> enumerable, Action<T> action)
{
foreach (var item in enumerable)
{
action(item);
}
}
}
}

View File

@ -1,5 +1,6 @@
using System.Collections.Generic;
using System.Linq;
using MapTo.Extensions;
using MapTo.Models;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
@ -28,19 +29,25 @@ namespace MapTo
private static void AddGeneratedMappingsClasses(GeneratorExecutionContext context, IEnumerable<ClassDeclarationSyntax> candidateClasses)
{
foreach (var classDeclarationSyntax in candidateClasses)
foreach (var classSyntax in candidateClasses)
{
var (model, diagnostic) = MapModel.Create(context.Compilation, classDeclarationSyntax);
if (model is null)
var root = classSyntax.GetCompilationUnit();
var classSemanticModel = context.Compilation.GetSemanticModel(classSyntax.SyntaxTree);
var classSymbol = classSemanticModel.GetDeclaredSymbol(classSyntax) as INamedTypeSymbol;
var sourceTypeSymbol = GetSourceTypeSymbol(classSyntax, classSemanticModel);
var (isValid, diagnostics) = Verify(root, classSyntax, classSemanticModel, classSymbol, sourceTypeSymbol);
if (!isValid)
{
context.ReportDiagnostic(diagnostic!);
diagnostics.ForEach(context.ReportDiagnostic);
continue;
}
var model = new MapModel(root, classSyntax, classSymbol!, sourceTypeSymbol!);
var (source, hintName) = SourceBuilder.GenerateSource(model);
context.AddSource(hintName, source);
context.ReportDiagnostic(Diagnostics.ClassMappingsGenerated(classDeclarationSyntax.GetLocation(), model.ClassName));
context.ReportDiagnostic(Diagnostics.ClassMappingsGenerated(classSyntax.GetLocation(), model.ClassName));
}
}
@ -49,5 +56,33 @@ namespace MapTo
var (source, hintName) = SourceBuilder.GenerateMapFromAttribute();
context.AddSource(hintName, source);
}
private static INamedTypeSymbol? GetSourceTypeSymbol(ClassDeclarationSyntax classSyntax, SemanticModel model)
{
var sourceTypeExpressionSyntax = classSyntax
.GetAttribute(SourceBuilder.MapFromAttributeName)
?.DescendantNodes()
.OfType<TypeOfExpressionSyntax>()
.SingleOrDefault();
return sourceTypeExpressionSyntax is not null ? model.GetTypeInfo(sourceTypeExpressionSyntax.Type).Type as INamedTypeSymbol : null;
}
private static (bool isValid, IEnumerable<Diagnostic> diagnostics) Verify(CompilationUnitSyntax root, ClassDeclarationSyntax classSyntax, SemanticModel classSemanticModel, INamedTypeSymbol? classSymbol, INamedTypeSymbol? sourceTypeSymbol)
{
var diagnostics = new List<Diagnostic>();
if (classSymbol is null)
{
diagnostics.Add(Diagnostics.SymbolNotFound(classSyntax.GetLocation(), classSyntax.Identifier.ValueText));
}
if (sourceTypeSymbol is null)
{
diagnostics.Add(Diagnostics.SymbolNotFound(classSyntax.GetLocation(), classSyntax.Identifier.ValueText));
}
return (!diagnostics.Any(), diagnostics);
}
}
}

View File

@ -1,5 +1,4 @@
using System.Collections.Generic;
using System.Linq;
using MapTo.Extensions;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
@ -28,6 +27,17 @@ namespace MapTo.Models
SourceTypeProperties = sourceTypeProperties;
}
internal MapModel(CompilationUnitSyntax root, ClassDeclarationSyntax classSyntax, ITypeSymbol classSymbol, ITypeSymbol sourceTypeSymbol)
: this(
root.GetNamespace(),
classSyntax.Modifiers,
classSyntax.GetClassName(),
classSymbol.GetAllMembersOfType<IPropertySymbol>(),
sourceTypeSymbol.ContainingNamespace.ToString(),
sourceTypeSymbol.Name,
sourceTypeSymbol.ToString(),
sourceTypeSymbol.GetAllMembersOfType<IPropertySymbol>()) { }
public string? Namespace { get; }
public SyntaxTokenList ClassModifiers { get; }
@ -43,45 +53,5 @@ namespace MapTo.Models
public string SourceClassFullName { get; }
public IEnumerable<IPropertySymbol> SourceTypeProperties { get; }
internal static (MapModel? model, Diagnostic? diagnostic) Create(Compilation compilation, ClassDeclarationSyntax classSyntax)
{
var root = classSyntax.GetCompilationUnit();
var classSemanticModel = compilation.GetSemanticModel(classSyntax.SyntaxTree);
if (!(classSemanticModel.GetDeclaredSymbol(classSyntax) is INamedTypeSymbol classSymbol))
{
return (default, Diagnostics.SymbolNotFound(classSyntax.GetLocation(), classSyntax.Identifier.ValueText));
}
var sourceTypeSymbol = GetSourceTypeSymbol(classSyntax, classSemanticModel);
if (sourceTypeSymbol is null)
{
return (default, Diagnostics.SymbolNotFound(classSyntax.GetLocation(), classSyntax.Identifier.ValueText));
}
var model = new MapModel(
root.GetNamespace(),
classSyntax.Modifiers,
classSyntax.GetClassName(),
classSymbol.GetAllMembersOfType<IPropertySymbol>(),
sourceTypeSymbol.ContainingNamespace.ToString(),
sourceTypeSymbol.Name,
sourceTypeSymbol.ToString(),
sourceTypeSymbol.GetAllMembersOfType<IPropertySymbol>());
return (model, default);
}
private static ITypeSymbol? GetSourceTypeSymbol(ClassDeclarationSyntax classSyntax, SemanticModel model)
{
var sourceTypeExpressionSyntax = classSyntax
.GetAttribute(SourceBuilder.MapFromAttributeName)
?.DescendantNodes()
.OfType<TypeOfExpressionSyntax>()
.SingleOrDefault();
return sourceTypeExpressionSyntax is not null ? model.GetTypeInfo(sourceTypeExpressionSyntax.Type).Type : null;
}
}
}