This repository has been archived by the owner on Jan 16, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 120
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
#76: Refactoring: Extract implementors from MappingGeneratorRefactori…
…ng. Move MappingGeneratorRefactoring to the dedicated subfolder.
- Loading branch information
1 parent
83d8d90
commit 7a603f5
Showing
15 changed files
with
374 additions
and
298 deletions.
There are no files selected for viewing
1 change: 1 addition & 0 deletions
1
...enerator/MappingGenerator/MappingGenerator.Test/MappingGenerator/MappingGeneratorTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
119 changes: 119 additions & 0 deletions
119
...ngGenerator/MappingGenerator/Features/Refactorings/Mapping/MappingGeneratorRefactoring.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
using System.Collections.Generic; | ||
using System.Composition; | ||
using System.Linq; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
using MappingGenerator.Features.Refactorings.Mapping.MappingImplementors; | ||
using MappingGenerator.MethodHelpers; | ||
using Microsoft.CodeAnalysis; | ||
using Microsoft.CodeAnalysis.CodeActions; | ||
using Microsoft.CodeAnalysis.CodeRefactorings; | ||
using Microsoft.CodeAnalysis.CSharp; | ||
using Microsoft.CodeAnalysis.CSharp.Syntax; | ||
using Microsoft.CodeAnalysis.Editing; | ||
using Microsoft.CodeAnalysis.Formatting; | ||
|
||
namespace MappingGenerator.Features.Refactorings.Mapping | ||
{ | ||
[ExportCodeRefactoringProvider(LanguageNames.CSharp, Name = nameof(MappingGeneratorRefactoring)), Shared] | ||
public class MappingGeneratorRefactoring : CodeRefactoringProvider | ||
{ | ||
private const string title = "Generate mapping code"; | ||
|
||
public sealed override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) | ||
{ | ||
var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); | ||
var node = root.FindNode(context.Span); | ||
|
||
await TryToRegisterRefactoring(context, node); | ||
} | ||
|
||
private async Task TryToRegisterRefactoring(CodeRefactoringContext context, SyntaxNode node) | ||
{ | ||
switch (node) | ||
{ | ||
case BaseMethodDeclarationSyntax methodDeclaration when IsMappingMethodCandidate(methodDeclaration): | ||
if (methodDeclaration.Parent.Kind() != SyntaxKind.InterfaceDeclaration ) | ||
{ | ||
var semanticModel = await context.Document.GetSemanticModelAsync(); | ||
var methodSymbol = semanticModel.GetDeclaredSymbol(methodDeclaration); | ||
|
||
if (IsCompleteMethodDeclarationSymbol(methodSymbol) == false) | ||
{ | ||
return; | ||
} | ||
|
||
if (CanProvideMappingImplementationFor(methodSymbol)) | ||
{ | ||
var generateMappingAction = CodeAction.Create(title: title, createChangedDocument: async (c) => await GenerateMappingMethodBody(context.Document, methodDeclaration, c), equivalenceKey: title); | ||
context.RegisterRefactoring(generateMappingAction); | ||
} | ||
} | ||
break; | ||
case IdentifierNameSyntax _: | ||
case ParameterListSyntax _: | ||
await TryToRegisterRefactoring(context, node.Parent); | ||
break; | ||
} | ||
} | ||
|
||
private static bool IsMappingMethodCandidate(BaseMethodDeclarationSyntax methodDeclaration) | ||
{ | ||
if (methodDeclaration is MethodDeclarationSyntax) | ||
{ | ||
return true; | ||
} | ||
|
||
if (methodDeclaration is ConstructorDeclarationSyntax constructorDeclaration && constructorDeclaration.ParameterList.Parameters.Count >= 1) | ||
{ | ||
return true; | ||
} | ||
|
||
return false; | ||
} | ||
|
||
private static bool IsCompleteMethodDeclarationSymbol(IMethodSymbol methodSymbol) | ||
{ | ||
var allParametersHaveNames = methodSymbol.Parameters.All(x => string.IsNullOrWhiteSpace(x.Name) == false); | ||
return allParametersHaveNames; | ||
} | ||
|
||
private bool CanProvideMappingImplementationFor(IMethodSymbol methodSymbol) | ||
{ | ||
return this.implementors.Any(x => x.CanImplement(methodSymbol)); | ||
} | ||
|
||
private async Task<Document> GenerateMappingMethodBody(Document document, BaseMethodDeclarationSyntax methodSyntax, CancellationToken cancellationToken) | ||
{ | ||
var semanticModel = await document.GetSemanticModelAsync(cancellationToken); | ||
var methodSymbol = semanticModel.GetDeclaredSymbol(methodSyntax); | ||
var generator = SyntaxGenerator.GetGenerator(document); | ||
var mappingExpressions = GenerateMappingCode(methodSymbol, generator, semanticModel); | ||
var blockSyntax = SyntaxFactory.Block(mappingExpressions.Select(e => e.AsStatement())).WithAdditionalAnnotations(Formatter.Annotation); | ||
return await document.ReplaceNodes(methodSyntax, methodSyntax.WithOnlyBody(blockSyntax), cancellationToken); | ||
} | ||
|
||
private IEnumerable<SyntaxNode> GenerateMappingCode(IMethodSymbol methodSymbol, SyntaxGenerator generator, SemanticModel semanticModel) | ||
{ | ||
var matchedImplementor = implementors.FirstOrDefault(x => x.CanImplement(methodSymbol)); | ||
if (matchedImplementor != null) | ||
{ | ||
return matchedImplementor.GenerateImplementation(methodSymbol, generator, semanticModel); | ||
} | ||
return Enumerable.Empty<SyntaxNode>(); | ||
} | ||
|
||
private readonly IReadOnlyList<IMappingMethodImplementor> implementors = new List<IMappingMethodImplementor>() | ||
{ | ||
new IdentityMappingMethodImplementor(), | ||
new SingleParameterPureMappingMethodImplementor(), | ||
new MultiParameterPureMappingMethodImplementor(), | ||
new UpdateSecondParameterMappingMethodImplementor(), | ||
new UpdateThisObjectSingleParameterMappingMethodImplementor(), | ||
new UpdateThisObjectMultiParameterMappingMethodImplementor(), | ||
new SingleParameterMappingConstructorImplementor(), | ||
new MultiParameterMappingConstructorImplementor(), | ||
new ThisObjectToOtherMappingMethodImplementor() | ||
}; | ||
} | ||
} |
13 changes: 13 additions & 0 deletions
13
...gGenerator/Features/Refactorings/Mapping/MappingImplementors/IMappingMethodImplementor.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
using System.Collections.Generic; | ||
using Microsoft.CodeAnalysis; | ||
using Microsoft.CodeAnalysis.Editing; | ||
|
||
namespace MappingGenerator.Features.Refactorings.Mapping.MappingImplementors | ||
{ | ||
public interface IMappingMethodImplementor | ||
{ | ||
bool CanImplement(IMethodSymbol methodSymbol); | ||
|
||
IEnumerable<SyntaxNode> GenerateImplementation(IMethodSymbol methodSymbol, SyntaxGenerator generator, SemanticModel semanticModel); | ||
} | ||
} |
26 changes: 26 additions & 0 deletions
26
...tor/Features/Refactorings/Mapping/MappingImplementors/IdentityMappingMethodImplementor.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
using System.Collections.Generic; | ||
using Microsoft.CodeAnalysis; | ||
using Microsoft.CodeAnalysis.CSharp.Syntax; | ||
using Microsoft.CodeAnalysis.Editing; | ||
using Microsoft.CodeAnalysis.Formatting; | ||
|
||
namespace MappingGenerator.Features.Refactorings.Mapping.MappingImplementors | ||
{ | ||
internal class IdentityMappingMethodImplementor: IMappingMethodImplementor | ||
{ | ||
public bool CanImplement(IMethodSymbol methodSymbol) | ||
{ | ||
return methodSymbol.Parameters.Length == 1 && methodSymbol.ReturnType.Equals(methodSymbol.Parameters[0].Type); | ||
} | ||
|
||
public IEnumerable<SyntaxNode> GenerateImplementation(IMethodSymbol methodSymbol, SyntaxGenerator generator, SemanticModel semanticModel) | ||
{ | ||
var cloneMappingEngine = new CloneMappingEngine(semanticModel, generator, methodSymbol.ContainingAssembly); | ||
var source = methodSymbol.Parameters[0]; | ||
var targetType = methodSymbol.ReturnType; | ||
var newExpression = cloneMappingEngine.MapExpression((ExpressionSyntax)generator.IdentifierName(source.Name), | ||
source.Type, targetType); | ||
return new[] { generator.ReturnStatement(newExpression).WithAdditionalAnnotations(Formatter.Annotation) }; | ||
} | ||
} | ||
} |
22 changes: 22 additions & 0 deletions
22
...s/Refactorings/Mapping/MappingImplementors/MultiParameterMappingConstructorImplementor.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
using System.Collections.Generic; | ||
using Microsoft.CodeAnalysis; | ||
using Microsoft.CodeAnalysis.Editing; | ||
|
||
namespace MappingGenerator.Features.Refactorings.Mapping.MappingImplementors | ||
{ | ||
class MultiParameterMappingConstructorImplementor:IMappingMethodImplementor | ||
{ | ||
public bool CanImplement(IMethodSymbol methodSymbol) | ||
{ | ||
return methodSymbol.Parameters.Length > 1 && SymbolHelper.IsConstructor(methodSymbol); | ||
} | ||
|
||
public IEnumerable<SyntaxNode> GenerateImplementation(IMethodSymbol methodSymbol, SyntaxGenerator generator, SemanticModel semanticModel) | ||
{ | ||
var mappingEngine = new MappingEngine(semanticModel, generator, methodSymbol.ContainingAssembly); | ||
var sourceFinder = new LocalScopeMappingSourceFinder(semanticModel, methodSymbol.Parameters); | ||
var targets = ObjectHelper.GetFieldsThaCanBeSetFromConstructor(methodSymbol.ContainingType); | ||
return mappingEngine.MapUsingSimpleAssignment(generator, targets, sourceFinder); | ||
} | ||
} | ||
} |
26 changes: 26 additions & 0 deletions
26
...es/Refactorings/Mapping/MappingImplementors/MultiParameterPureMappingMethodImplementor.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
using System.Collections.Generic; | ||
using Microsoft.CodeAnalysis; | ||
using Microsoft.CodeAnalysis.CSharp.Syntax; | ||
using Microsoft.CodeAnalysis.Editing; | ||
using Microsoft.CodeAnalysis.Formatting; | ||
|
||
namespace MappingGenerator.Features.Refactorings.Mapping.MappingImplementors | ||
{ | ||
class MultiParameterPureMappingMethodImplementor: IMappingMethodImplementor | ||
{ | ||
public bool CanImplement(IMethodSymbol methodSymbol) | ||
{ | ||
return methodSymbol.Parameters.Length > 1 && methodSymbol.ReturnsVoid == false; | ||
} | ||
|
||
public IEnumerable<SyntaxNode> GenerateImplementation(IMethodSymbol methodSymbol, SyntaxGenerator generator, SemanticModel semanticModel) | ||
{ | ||
var mappingEngine = new MappingEngine(semanticModel, generator, methodSymbol.ContainingAssembly); | ||
var targetType = methodSymbol.ReturnType; | ||
var sourceFinder = new LocalScopeMappingSourceFinder(semanticModel, methodSymbol); | ||
var newExpression = mappingEngine.AddInitializerWithMapping( | ||
(ObjectCreationExpressionSyntax)generator.ObjectCreationExpression(targetType), sourceFinder, targetType); | ||
return new[] { generator.ReturnStatement(newExpression).WithAdditionalAnnotations(Formatter.Annotation) }; | ||
} | ||
} | ||
} |
23 changes: 23 additions & 0 deletions
23
.../Refactorings/Mapping/MappingImplementors/SingleParameterMappingConstructorImplementor.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
using System.Collections.Generic; | ||
using Microsoft.CodeAnalysis; | ||
using Microsoft.CodeAnalysis.Editing; | ||
|
||
namespace MappingGenerator.Features.Refactorings.Mapping.MappingImplementors | ||
{ | ||
class SingleParameterMappingConstructorImplementor:IMappingMethodImplementor | ||
{ | ||
public bool CanImplement(IMethodSymbol methodSymbol) | ||
{ | ||
return methodSymbol.Parameters.Length == 1 && SymbolHelper.IsConstructor(methodSymbol); | ||
} | ||
|
||
public IEnumerable<SyntaxNode> GenerateImplementation(IMethodSymbol methodSymbol, SyntaxGenerator generator, SemanticModel semanticModel) | ||
{ | ||
var mappingEngine = new MappingEngine(semanticModel, generator, methodSymbol.ContainingAssembly); | ||
var source = methodSymbol.Parameters[0]; | ||
var sourceFinder = new ObjectMembersMappingSourceFinder(source.Type, generator.IdentifierName(source.Name), generator); | ||
var targets = ObjectHelper.GetFieldsThaCanBeSetFromConstructor(methodSymbol.ContainingType); | ||
return mappingEngine.MapUsingSimpleAssignment(generator, targets, sourceFinder); | ||
} | ||
} | ||
} |
26 changes: 26 additions & 0 deletions
26
...s/Refactorings/Mapping/MappingImplementors/SingleParameterPureMappingMethodImplementor.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
using System.Collections.Generic; | ||
using Microsoft.CodeAnalysis; | ||
using Microsoft.CodeAnalysis.CSharp.Syntax; | ||
using Microsoft.CodeAnalysis.Editing; | ||
using Microsoft.CodeAnalysis.Formatting; | ||
|
||
namespace MappingGenerator.Features.Refactorings.Mapping.MappingImplementors | ||
{ | ||
internal class SingleParameterPureMappingMethodImplementor: IMappingMethodImplementor | ||
{ | ||
public bool CanImplement(IMethodSymbol methodSymbol) | ||
{ | ||
return methodSymbol.Parameters.Length == 1 && methodSymbol.ReturnsVoid == false; | ||
} | ||
|
||
public IEnumerable<SyntaxNode> GenerateImplementation(IMethodSymbol methodSymbol, SyntaxGenerator generator, SemanticModel semanticModel) | ||
{ | ||
var mappingEngine = new MappingEngine(semanticModel, generator, methodSymbol.ContainingAssembly); | ||
var source = methodSymbol.Parameters[0]; | ||
var targetType = methodSymbol.ReturnType; | ||
var newExpression = mappingEngine.MapExpression((ExpressionSyntax)generator.IdentifierName(source.Name), | ||
source.Type, targetType); | ||
return new[] { generator.ReturnStatement(newExpression).WithAdditionalAnnotations(Formatter.Annotation) }; | ||
} | ||
} | ||
} |
27 changes: 27 additions & 0 deletions
27
...res/Refactorings/Mapping/MappingImplementors/ThisObjectToOtherMappingMethodImplementor.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
using System.Collections.Generic; | ||
using Microsoft.CodeAnalysis; | ||
using Microsoft.CodeAnalysis.CSharp.Syntax; | ||
using Microsoft.CodeAnalysis.Editing; | ||
using Microsoft.CodeAnalysis.Formatting; | ||
|
||
namespace MappingGenerator.Features.Refactorings.Mapping.MappingImplementors | ||
{ | ||
class ThisObjectToOtherMappingMethodImplementor:IMappingMethodImplementor | ||
{ | ||
public bool CanImplement(IMethodSymbol methodSymbol) | ||
{ | ||
return methodSymbol.IsStatic == false && | ||
methodSymbol.Parameters.Length == 0 && | ||
methodSymbol.ReturnsVoid == false && | ||
ObjectHelper.IsSimpleType(methodSymbol.ReturnType) == false; | ||
} | ||
|
||
public IEnumerable<SyntaxNode> GenerateImplementation(IMethodSymbol methodSymbol, SyntaxGenerator generator, SemanticModel semanticModel) | ||
{ | ||
var mappingEngine = new MappingEngine(semanticModel, generator, methodSymbol.ContainingAssembly); | ||
var targetType = methodSymbol.ReturnType; | ||
var newExpression = mappingEngine.MapExpression((ExpressionSyntax)generator.ThisExpression(), methodSymbol.ContainingType, targetType); | ||
return new[] { generator.ReturnStatement(newExpression).WithAdditionalAnnotations(Formatter.Annotation) }; | ||
} | ||
} | ||
} |
28 changes: 28 additions & 0 deletions
28
...Refactorings/Mapping/MappingImplementors/UpdateSecondParameterMappingMethodImplementor.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
using System.Collections.Generic; | ||
using Microsoft.CodeAnalysis; | ||
using Microsoft.CodeAnalysis.Editing; | ||
|
||
namespace MappingGenerator.Features.Refactorings.Mapping.MappingImplementors | ||
{ | ||
class UpdateSecondParameterMappingMethodImplementor:IMappingMethodImplementor | ||
{ | ||
public bool CanImplement(IMethodSymbol methodSymbol) | ||
{ | ||
if (SymbolHelper.IsConstructor(methodSymbol)) | ||
{ | ||
return false; | ||
} | ||
return methodSymbol.Parameters.Length == 2 && methodSymbol.ReturnsVoid; | ||
} | ||
|
||
public IEnumerable<SyntaxNode> GenerateImplementation(IMethodSymbol methodSymbol, SyntaxGenerator generator, SemanticModel semanticModel) | ||
{ | ||
var mappingEngine = new MappingEngine(semanticModel, generator, methodSymbol.ContainingAssembly); | ||
var source = methodSymbol.Parameters[0]; | ||
var target = methodSymbol.Parameters[1]; | ||
var targets = ObjectHelper.GetFieldsThaCanBeSetPublicly(target.Type, methodSymbol.ContainingAssembly); | ||
var sourceFinder = new ObjectMembersMappingSourceFinder(source.Type, generator.IdentifierName(source.Name), generator); | ||
return mappingEngine.MapUsingSimpleAssignment(generator, targets, sourceFinder, globalTargetAccessor: generator.IdentifierName(target.Name)); | ||
} | ||
} | ||
} |
26 changes: 26 additions & 0 deletions
26
...ngs/Mapping/MappingImplementors/UpdateThisObjectMultiParameterMappingMethodImplementor.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
using System.Collections.Generic; | ||
using Microsoft.CodeAnalysis; | ||
using Microsoft.CodeAnalysis.Editing; | ||
|
||
namespace MappingGenerator.Features.Refactorings.Mapping.MappingImplementors | ||
{ | ||
class UpdateThisObjectMultiParameterMappingMethodImplementor:IMappingMethodImplementor | ||
{ | ||
public bool CanImplement(IMethodSymbol methodSymbol) | ||
{ | ||
if (SymbolHelper.IsConstructor(methodSymbol)) | ||
{ | ||
return false; | ||
} | ||
return methodSymbol.Parameters.Length > 1 && methodSymbol.ReturnsVoid; | ||
} | ||
|
||
public IEnumerable<SyntaxNode> GenerateImplementation(IMethodSymbol methodSymbol, SyntaxGenerator generator, SemanticModel semanticModel) | ||
{ | ||
var mappingEngine = new MappingEngine(semanticModel, generator, methodSymbol.ContainingAssembly); | ||
var sourceFinder = new LocalScopeMappingSourceFinder(semanticModel, methodSymbol.Parameters); | ||
var targets = ObjectHelper.GetFieldsThaCanBeSetPrivately(methodSymbol.ContainingType); | ||
return mappingEngine.MapUsingSimpleAssignment(generator, targets, sourceFinder); | ||
} | ||
} | ||
} |
27 changes: 27 additions & 0 deletions
27
...gs/Mapping/MappingImplementors/UpdateThisObjectSingleParameterMappingMethodImplementor.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
using System.Collections.Generic; | ||
using Microsoft.CodeAnalysis; | ||
using Microsoft.CodeAnalysis.Editing; | ||
|
||
namespace MappingGenerator.Features.Refactorings.Mapping.MappingImplementors | ||
{ | ||
class UpdateThisObjectSingleParameterMappingMethodImplementor:IMappingMethodImplementor | ||
{ | ||
public bool CanImplement(IMethodSymbol methodSymbol) | ||
{ | ||
if (SymbolHelper.IsConstructor(methodSymbol)) | ||
{ | ||
return false; | ||
} | ||
return methodSymbol.Parameters.Length == 1 && methodSymbol.ReturnsVoid; | ||
} | ||
|
||
public IEnumerable<SyntaxNode> GenerateImplementation(IMethodSymbol methodSymbol, SyntaxGenerator generator, SemanticModel semanticModel) | ||
{ | ||
var mappingEngine = new MappingEngine(semanticModel, generator, methodSymbol.ContainingAssembly); | ||
var source = methodSymbol.Parameters[0]; | ||
var sourceFinder = new ObjectMembersMappingSourceFinder(source.Type, generator.IdentifierName(source.Name), generator); | ||
var targets = ObjectHelper.GetFieldsThaCanBeSetPrivately(methodSymbol.ContainingType); | ||
return mappingEngine.MapUsingSimpleAssignment(generator, targets, sourceFinder); | ||
} | ||
} | ||
} |
Oops, something went wrong.