diff --git a/MappingGenerator/MappingGenerator/MappingGenerator.Test/ExplicitConversions/ExplicitConversionTestCases.Designer.cs b/MappingGenerator/MappingGenerator/MappingGenerator.Test/ExplicitConversions/ExplicitConversionTestCases.Designer.cs index c220364..8e3c2ce 100644 --- a/MappingGenerator/MappingGenerator/MappingGenerator.Test/ExplicitConversions/ExplicitConversionTestCases.Designer.cs +++ b/MappingGenerator/MappingGenerator/MappingGenerator.Test/ExplicitConversions/ExplicitConversionTestCases.Designer.cs @@ -19,7 +19,7 @@ namespace MappingGenerator.Test.ExplicitConversions { // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class ExplicitConversionTestCases { @@ -74,14 +74,14 @@ internal ExplicitConversionTestCases() { /// public void DoSomething() /// { /// var addressEntity = new AddressEntity(); - /// this.Address = addressEntity; + /// this.Address = [|addressEntity|]; /// } /// } /// /// public class AddressDTO /// { /// public string FlatNo { get; set; } - /// public string BuildtingNo { get; [rest of string was truncated]";. + /// public string BuildtingNo { g [rest of string was truncated]";. /// internal static string _001_ExplicitConversionForInvalidAssigment { get { @@ -103,11 +103,11 @@ internal static string _001_ExplicitConversionForInvalidAssigment { /// public void DoSomething() /// { /// var addressEntity = new AddressEntity(); - /// this.Address = new AddressDTO() + /// this.Address = new AddressDTO /// { /// FlatNo = addressEntity.FlatNo, /// BuildtingNo = addressEntity.BuildtingNo, - /// St [rest of string was truncated]";. + /// Stre [rest of string was truncated]";. /// internal static string _001_ExplicitConversionForInvalidAssigment_FIXED { get { @@ -129,14 +129,14 @@ internal static string _001_ExplicitConversionForInvalidAssigment_FIXED { /// /// public ReadOnlyCollection<AddressDTO> DoSomething(IList<AddressEntity> addresses) /// { - /// return addresses; + /// return [|addresses|]; /// } /// } /// /// public class AddressDTO /// { /// public string FlatNo { get; set; } - /// publ [rest of string was truncated]";. + /// [rest of string was truncated]";. /// internal static string _002_ExplicitConversionForInvalidReturn { get { @@ -158,10 +158,10 @@ internal static string _002_ExplicitConversionForInvalidReturn { /// /// public ReadOnlyCollection<AddressDTO> DoSomething(IList<AddressEntity> addresses) /// { - /// return addresses.Select(address => new AddressDTO() + /// return addresses.Select(address => new AddressDTO /// { /// FlatNo = address.FlatNo, - /// Build [rest of string was truncated]";. + /// Buildti [rest of string was truncated]";. /// internal static string _002_ExplicitConversionForInvalidReturn_FIXED { get { @@ -180,7 +180,7 @@ internal static string _002_ExplicitConversionForInvalidReturn_FIXED { /// /// public IEnumerable<AddressDTO> DoSomething(AddressEntity address) /// { - /// yield return address; + /// yield return [|address|]; /// } /// } /// @@ -189,7 +189,7 @@ internal static string _002_ExplicitConversionForInvalidReturn_FIXED { /// public string FlatNo { get; set; } /// public string BuildtingNo { get; set; } /// public string Street { get; set; } - /// [rest of string was truncated]";. + /// [rest of string was truncated]";. /// internal static string _003_ExplicitConversionForInvalidYield { get { @@ -208,12 +208,12 @@ internal static string _003_ExplicitConversionForInvalidYield { /// /// public IEnumerable<AddressDTO> DoSomething(AddressEntity address) /// { - /// yield return new AddressDTO() + /// yield return new AddressDTO /// { /// FlatNo = address.FlatNo, /// BuildtingNo = address.BuildtingNo, /// Street = address.Street, - /// ZipCode = address.ZipCo [rest of string was truncated]";. + /// ZipCode = address.ZipCode [rest of string was truncated]";. /// internal static string _003_ExplicitConversionForInvalidYield_FIXED { get { @@ -236,13 +236,13 @@ internal static string _003_ExplicitConversionForInvalidYield_FIXED { /// { /// var addressEntity = new AddressEntity(); /// return new UserDTO{ - /// Address = addressEntity + /// Address = [|addressEntity|] /// } /// } /// } /// /// public class UserDTO{ - /// public AddressDTO Address {get; set;} [rest of string was truncated]";. + /// public AddressDTO Address {get; s [rest of string was truncated]";. /// internal static string _004_ExplicitConversionForInvalidAssigmentInInitBlock { get { @@ -265,17 +265,123 @@ internal static string _004_ExplicitConversionForInvalidAssigmentInInitBlock { /// { /// var addressEntity = new AddressEntity(); /// return new UserDTO{ - /// Address = addressEntity + /// Address = new AddressDTO + /// { + /// FlatNo = addressEntity.FlatNo, + /// BuildtingNo = a [rest of string was truncated]";. + /// + internal static string _004_ExplicitConversionForInvalidAssigmentInInitBlock_FIXED { + get { + return ResourceManager.GetString("_004_ExplicitConversionForInvalidAssigmentInInitBlock_FIXED", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to using System; + ///using System.Collections.Generic; + ///using System.Text; + /// + ///namespace MappingGenerator.Test.ExplicitConversions.TestCaseData + ///{ + /// public class TestMapper + /// { + /// public AddressDTO Address { get; set; } + /// + /// public void DoSomething() + /// { + /// var addressEntity = new AddressEntity(); + /// this.Address = [|addressEntity|]; + /// } + /// } + /// + /// public class AddressDTO + /// { + /// public string FlatNo { get; set; } + /// public string BuildtingNo { g [rest of string was truncated]";. + /// + internal static string _005_ExplicitConversionReUseInstance { + get { + return ResourceManager.GetString("_005_ExplicitConversionReUseInstance", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to using System; + ///using System.Collections.Generic; + ///using System.Text; + /// + ///namespace MappingGenerator.Test.ExplicitConversions.TestCaseData + ///{ + /// public class TestMapper + /// { + /// public AddressDTO Address { get; set; } + /// + /// public void DoSomething() + /// { + /// var addressEntity = new AddressEntity(); + /// this.Address.FlatNo = addressEntity.FlatNo; + /// this.Address.BuildtingNo = addressEntity.BuildtingNo; + /// this.Address.Street = addressEntity.Street; + /// [rest of string was truncated]";. + /// + internal static string _005_ExplicitConversionReUseInstance_FIXED { + get { + return ResourceManager.GetString("_005_ExplicitConversionReUseInstance_FIXED", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to using System; + ///using System.Collections.Generic; + ///using System.Text; + /// + ///namespace MappingGenerator.Test.ExplicitConversions.TestCaseData + ///{ + /// public class TestMapper + /// { + /// public AddressDTO Address { get; set; } + /// + /// public UserDTO DoSomething() + /// { + /// var addressEntity = new AddressEntity(); + /// return new UserDTO{ + /// Address = [|addressEntity|] /// } /// } /// } /// /// public class UserDTO{ - /// public AddressDTO Address {get; set;} [rest of string was truncated]";. + /// public AddressDTO Address {get; s [rest of string was truncated]";. /// - internal static string _004_ExplicitConversionForInvalidAssigmentInInitBlock_FIXED { + internal static string _006_ExplicitConversionForInvalidAssigmentInInitBlockReuseInstance { get { - return ResourceManager.GetString("_004_ExplicitConversionForInvalidAssigmentInInitBlock_FIXED", resourceCulture); + return ResourceManager.GetString("_006_ExplicitConversionForInvalidAssigmentInInitBlockReuseInstance", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to using System; + ///using System.Collections.Generic; + ///using System.Text; + /// + ///namespace MappingGenerator.Test.ExplicitConversions.TestCaseData + ///{ + /// public class TestMapper + /// { + /// public AddressDTO Address { get; set; } + /// + /// public UserDTO DoSomething() + /// { + /// var addressEntity = new AddressEntity(); + /// return new UserDTO{ + /// Address = + /// { + /// FlatNo = addressEntity.FlatNo, + /// BuildtingNo = addressEntity.Bu [rest of string was truncated]";. + /// + internal static string _006_ExplicitConversionForInvalidAssigmentInInitBlockReuseInstance_FIXED { + get { + return ResourceManager.GetString("_006_ExplicitConversionForInvalidAssigmentInInitBlockReuseInstance_FIXED", resourceCulture); } } } diff --git a/MappingGenerator/MappingGenerator/MappingGenerator.Test/ExplicitConversions/ExplicitConversionTestCases.resx b/MappingGenerator/MappingGenerator/MappingGenerator.Test/ExplicitConversions/ExplicitConversionTestCases.resx index e45bca4..d67a9e2 100644 --- a/MappingGenerator/MappingGenerator/MappingGenerator.Test/ExplicitConversions/ExplicitConversionTestCases.resx +++ b/MappingGenerator/MappingGenerator/MappingGenerator.Test/ExplicitConversions/ExplicitConversionTestCases.resx @@ -1,145 +1,157 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - - TestCaseData\001_ExplicitConversionForInvalidAssigment.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 - - - TestCaseData\001_ExplicitConversionForInvalidAssigment_FIXED.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 - - - TestCaseData\002_ExplicitConversionForInvalidReturn.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 - - - TestCaseData\002_ExplicitConversionForInvalidReturn_FIXED.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 - - - TestCaseData\003_ExplicitConversionForInvalidYield.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 - - - TestCaseData\003_ExplicitConversionForInvalidYield_FIXED.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 - - - TestCaseData\004_ExplicitConversionForInvalidAssigmentInInitBlock.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 - - - TestCaseData\004_ExplicitConversionForInvalidAssigmentInInitBlock_FIXED.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + TestCaseData\001_ExplicitConversionForInvalidAssigment.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + + TestCaseData\001_ExplicitConversionForInvalidAssigment_FIXED.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + + TestCaseData\002_ExplicitConversionForInvalidReturn.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + + TestCaseData\002_ExplicitConversionForInvalidReturn_FIXED.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + + TestCaseData\003_ExplicitConversionForInvalidYield.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + + TestCaseData\003_ExplicitConversionForInvalidYield_FIXED.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + + TestCaseData\004_ExplicitConversionForInvalidAssigmentInInitBlock.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + + TestCaseData\004_ExplicitConversionForInvalidAssigmentInInitBlock_FIXED.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + + TestCaseData\005_ExplicitConversionReUseInstance.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + + TestCaseData\005_ExplicitConversionReUseInstance_FIXED.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + + TestCaseData\006_ExplicitConversionForInvalidAssigmentInInitBlockReuseInstance.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + + TestCaseData\006_ExplicitConversionForInvalidAssigmentInInitBlockReuseInstance_FIXED.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + \ No newline at end of file diff --git a/MappingGenerator/MappingGenerator/MappingGenerator.Test/ExplicitConversions/ExplicitConversionTests.cs b/MappingGenerator/MappingGenerator/MappingGenerator.Test/ExplicitConversions/ExplicitConversionTests.cs index e590218..df6c97a 100644 --- a/MappingGenerator/MappingGenerator/MappingGenerator.Test/ExplicitConversions/ExplicitConversionTests.cs +++ b/MappingGenerator/MappingGenerator/MappingGenerator.Test/ExplicitConversions/ExplicitConversionTests.cs @@ -34,6 +34,18 @@ public void should_be_able_to_generate_conversion_for_invalid_assignment_stateme { TestCodeFix(ExplicitConversionTestCases._004_ExplicitConversionForInvalidAssigmentInInitBlock, ExplicitConversionTestCases._004_ExplicitConversionForInvalidAssigmentInInitBlock_FIXED, ExplicitConversionCodeFixProvider.CS0029, 0); } + + [Test] + public void should_be_able_to_generate_conversion_by_re_using_instance() + { + TestCodeFix(ExplicitConversionTestCases._005_ExplicitConversionReUseInstance, ExplicitConversionTestCases._005_ExplicitConversionReUseInstance_FIXED, ExplicitConversionCodeFixProvider.CS0029, 1); + } + + [Test] + public void should_be_able_to_generate_conversion_by_re_using_instance_inside_init_block() + { + TestCodeFix(ExplicitConversionTestCases._006_ExplicitConversionForInvalidAssigmentInInitBlockReuseInstance, ExplicitConversionTestCases._006_ExplicitConversionForInvalidAssigmentInInitBlockReuseInstance_FIXED, ExplicitConversionCodeFixProvider.CS0029, 1); + } protected override string LanguageName => LanguageNames.CSharp; protected override CodeFixProvider CreateProvider() diff --git a/MappingGenerator/MappingGenerator/MappingGenerator.Test/ExplicitConversions/TestCaseData/005_ExplicitConversionReUseInstance.txt b/MappingGenerator/MappingGenerator/MappingGenerator.Test/ExplicitConversions/TestCaseData/005_ExplicitConversionReUseInstance.txt new file mode 100644 index 0000000..30f22e9 --- /dev/null +++ b/MappingGenerator/MappingGenerator/MappingGenerator.Test/ExplicitConversions/TestCaseData/005_ExplicitConversionReUseInstance.txt @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace MappingGenerator.Test.ExplicitConversions.TestCaseData +{ + public class TestMapper + { + public AddressDTO Address { get; set; } + + public void DoSomething() + { + var addressEntity = new AddressEntity(); + this.Address = [|addressEntity|]; + } + } + + public class AddressDTO + { + public string FlatNo { get; set; } + public string BuildtingNo { get; set; } + public string Street { get; set; } + public string ZipCode { get; set; } + public string City { get; set; } + } + + public class AddressEntity + { + public string FlatNo { get; set; } + public string BuildtingNo { get; set; } + public string Street { get; set; } + public string ZipCode { get; set; } + public string City { get; set; } + } +} \ No newline at end of file diff --git a/MappingGenerator/MappingGenerator/MappingGenerator.Test/ExplicitConversions/TestCaseData/005_ExplicitConversionReUseInstance_FIXED.txt b/MappingGenerator/MappingGenerator/MappingGenerator.Test/ExplicitConversions/TestCaseData/005_ExplicitConversionReUseInstance_FIXED.txt new file mode 100644 index 0000000..e148eaa --- /dev/null +++ b/MappingGenerator/MappingGenerator/MappingGenerator.Test/ExplicitConversions/TestCaseData/005_ExplicitConversionReUseInstance_FIXED.txt @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace MappingGenerator.Test.ExplicitConversions.TestCaseData +{ + public class TestMapper + { + public AddressDTO Address { get; set; } + + public void DoSomething() + { + var addressEntity = new AddressEntity(); + this.Address.FlatNo = addressEntity.FlatNo; + this.Address.BuildtingNo = addressEntity.BuildtingNo; + this.Address.Street = addressEntity.Street; + this.Address.ZipCode = addressEntity.ZipCode; + this.Address.City = addressEntity.City; + } + } + + public class AddressDTO + { + public string FlatNo { get; set; } + public string BuildtingNo { get; set; } + public string Street { get; set; } + public string ZipCode { get; set; } + public string City { get; set; } + } + + public class AddressEntity + { + public string FlatNo { get; set; } + public string BuildtingNo { get; set; } + public string Street { get; set; } + public string ZipCode { get; set; } + public string City { get; set; } + } +} \ No newline at end of file diff --git a/MappingGenerator/MappingGenerator/MappingGenerator.Test/ExplicitConversions/TestCaseData/006_ExplicitConversionForInvalidAssigmentInInitBlockReuseInstance.txt b/MappingGenerator/MappingGenerator/MappingGenerator.Test/ExplicitConversions/TestCaseData/006_ExplicitConversionForInvalidAssigmentInInitBlockReuseInstance.txt new file mode 100644 index 0000000..f6e9220 --- /dev/null +++ b/MappingGenerator/MappingGenerator/MappingGenerator.Test/ExplicitConversions/TestCaseData/006_ExplicitConversionForInvalidAssigmentInInitBlockReuseInstance.txt @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace MappingGenerator.Test.ExplicitConversions.TestCaseData +{ + public class TestMapper + { + public AddressDTO Address { get; set; } + + public UserDTO DoSomething() + { + var addressEntity = new AddressEntity(); + return new UserDTO{ + Address = [|addressEntity|] + } + } + } + + public class UserDTO{ + public AddressDTO Address {get; set;} + } + + public class AddressDTO + { + public string FlatNo { get; set; } + public string BuildtingNo { get; set; } + public string Street { get; set; } + public string ZipCode { get; set; } + public string City { get; set; } + } + + public class AddressEntity + { + public string FlatNo { get; set; } + public string BuildtingNo { get; set; } + public string Street { get; set; } + public string ZipCode { get; set; } + public string City { get; set; } + } +} \ No newline at end of file diff --git a/MappingGenerator/MappingGenerator/MappingGenerator.Test/ExplicitConversions/TestCaseData/006_ExplicitConversionForInvalidAssigmentInInitBlockReuseInstance_FIXED.txt b/MappingGenerator/MappingGenerator/MappingGenerator.Test/ExplicitConversions/TestCaseData/006_ExplicitConversionForInvalidAssigmentInInitBlockReuseInstance_FIXED.txt new file mode 100644 index 0000000..0707283 --- /dev/null +++ b/MappingGenerator/MappingGenerator/MappingGenerator.Test/ExplicitConversions/TestCaseData/006_ExplicitConversionForInvalidAssigmentInInitBlockReuseInstance_FIXED.txt @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace MappingGenerator.Test.ExplicitConversions.TestCaseData +{ + public class TestMapper + { + public AddressDTO Address { get; set; } + + public UserDTO DoSomething() + { + var addressEntity = new AddressEntity(); + return new UserDTO{ + Address = + { + FlatNo = addressEntity.FlatNo, + BuildtingNo = addressEntity.BuildtingNo, + Street = addressEntity.Street, + ZipCode = addressEntity.ZipCode, + City = addressEntity.City + } + } + } + } + + public class UserDTO{ + public AddressDTO Address {get; set;} + } + + public class AddressDTO + { + public string FlatNo { get; set; } + public string BuildtingNo { get; set; } + public string Street { get; set; } + public string ZipCode { get; set; } + public string City { get; set; } + } + + public class AddressEntity + { + public string FlatNo { get; set; } + public string BuildtingNo { get; set; } + public string Street { get; set; } + public string ZipCode { get; set; } + public string City { get; set; } + } +} \ No newline at end of file diff --git a/MappingGenerator/MappingGenerator/MappingGenerator/Features/CodeFixes/ExplicitConversionCodeFixProvider.cs b/MappingGenerator/MappingGenerator/MappingGenerator/Features/CodeFixes/ExplicitConversionCodeFixProvider.cs index cbfb7e1..14abcf0 100644 --- a/MappingGenerator/MappingGenerator/MappingGenerator/Features/CodeFixes/ExplicitConversionCodeFixProvider.cs +++ b/MappingGenerator/MappingGenerator/MappingGenerator/Features/CodeFixes/ExplicitConversionCodeFixProvider.cs @@ -1,3 +1,4 @@ +using System.Collections.Generic; using System.Collections.Immutable; using System.Composition; using System.Linq; @@ -5,10 +6,13 @@ using System.Threading.Tasks; using MappingGenerator.Mappings; using MappingGenerator.Mappings.SourceFinders; +using MappingGenerator.RoslynHelpers; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Editing; namespace MappingGenerator.Features.CodeFixes { @@ -16,6 +20,7 @@ namespace MappingGenerator.Features.CodeFixes public class ExplicitConversionCodeFixProvider : CodeFixProvider { private const string title = "Generate explicit conversion"; + private const string title2 = "Generate explicit conversion (Try re-use instance)"; public const string CS0029 = nameof(CS0029); public const string CS0266 = nameof(CS0266); @@ -43,7 +48,12 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) switch (statement) { case AssignmentExpressionSyntax assignmentExpression: - context.RegisterCodeFix(CodeAction.Create(title: title, createChangedDocument: c => GenerateExplicitConversion(context.Document, assignmentExpression, c), equivalenceKey: title), diagnostic); + context.RegisterCodeFix(CodeAction.Create(title: title, createChangedDocument: c => GenerateExplicitConversion(context.Document, assignmentExpression, false, c), equivalenceKey: title), diagnostic); + + if (assignmentExpression.Parent is InitializerExpressionSyntax || assignmentExpression.Parent is StatementSyntax) + { + context.RegisterCodeFix(CodeAction.Create(title: title2, createChangedDocument: c => GenerateExplicitConversion(context.Document, assignmentExpression, true, c), equivalenceKey: title), diagnostic); + } break; case ReturnStatementSyntax returnStatement: context.RegisterCodeFix(CodeAction.Create(title: title, createChangedDocument: c => GenerateExplicitConversion(context.Document, returnStatement, c), equivalenceKey: title), diagnostic); @@ -54,13 +64,32 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) } } - private async Task GenerateExplicitConversion(Document document, AssignmentExpressionSyntax assignmentExpression, CancellationToken cancellationToken) + private async Task GenerateExplicitConversion(Document document, AssignmentExpressionSyntax assignmentExpression, bool reUseInstance, CancellationToken cancellationToken) { var (mappingEngine, semanticModel) = await CreateMappingEngine(document, cancellationToken).ConfigureAwait(false); var sourceType = mappingEngine.GetExpressionTypeInfo(assignmentExpression.Right).GetAnnotatedType(); var destinationType = mappingEngine.GetExpressionTypeInfo(assignmentExpression.Left).GetAnnotatedType(); var mappingContext = new MappingContext(assignmentExpression, semanticModel); - var mappingExpression = await mappingEngine.MapExpression(assignmentExpression.Right.WithoutTrivia(), sourceType, destinationType, mappingContext).ConfigureAwait(false); + var mappingExpression = await mappingEngine.MapExpression(assignmentExpression.Right.WithoutTrivia(), sourceType, destinationType, mappingContext).ConfigureAwait(false); + + if (reUseInstance && mappingExpression is ObjectCreationExpressionSyntax objectCreation && objectCreation.Initializer is {} initializer && initializer.Expressions.Count > 0 ) + { + if (assignmentExpression.Parent is InitializerExpressionSyntax) + { + return await ReplaceNode(document, assignmentExpression, assignmentExpression.WithRight(initializer), cancellationToken).ConfigureAwait(false); + } + else + { + var targetAccessor = assignmentExpression.Left; + var newInitExpressions = initializer.Expressions.OfType().Select(expr => + { + var left = SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, targetAccessor, (SimpleNameSyntax) expr.Left); + return expr.WithLeft(left).AsStatement(); + }).ToList(); + return await ReplaceNodes(document, assignmentExpression.Parent, newInitExpressions, cancellationToken).ConfigureAwait(false); + } + } + return await ReplaceNode(document, assignmentExpression, assignmentExpression.WithRight(mappingExpression), cancellationToken).ConfigureAwait(false); } @@ -92,7 +121,14 @@ private async Task GenerateExplicitConversion(Document document, Yield private static async Task ReplaceNode(Document document, SyntaxNode oldNode, SyntaxNode newNode, CancellationToken cancellationToken) { var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - var newRoot = root!.ReplaceNode(oldNode, newNode); + var newRoot = root.ReplaceNode(oldNode, newNode); + return document.WithSyntaxRoot(newRoot); + } + + private static async Task ReplaceNodes(Document document, SyntaxNode oldNode, IReadOnlyList newNodes, CancellationToken cancellationToken) + { + var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + var newRoot = root.ReplaceNode(oldNode, newNodes); return document.WithSyntaxRoot(newRoot); }