未验证 提交 41ff5758 编写于 作者: M msftbot[bot] 提交者: GitHub

Merge pull request #45667 from davidwengier/TupleToStructFixArgumentNameCase

Fix "Tuple to Struct" named parameters being cased incorrectly
...@@ -106,6 +106,73 @@ public static implicit operator (int a, int b)(NewStruct value) ...@@ -106,6 +106,73 @@ public static implicit operator (int a, int b)(NewStruct value)
await TestInRegularAndScriptAsync(text, expected, options: GetPreferImplicitTypeOptions(host)); await TestInRegularAndScriptAsync(text, expected, options: GetPreferImplicitTypeOptions(host));
} }
[WorkItem(45451, "https://github.com/dotnet/roslyn/issues/45451")]
[Theory, CombinatorialData, Trait(Traits.Feature, Traits.Features.CodeActionsConvertTupleToStruct)]
public async Task ConvertSingleTupleType_ChangeArgumentNameCase(TestHost host)
{
var text = @"
class Test
{
void Method()
{
var t1 = [||](A: 1, B: 2);
}
}
";
var expected = @"
class Test
{
void Method()
{
var t1 = new {|Rename:NewStruct|}(a: 1, b: 2);
}
}
internal struct NewStruct
{
public int A;
public int B;
public NewStruct(int a, int b)
{
A = a;
B = b;
}
public override bool Equals(object obj)
{
return obj is NewStruct other &&
A == other.A &&
B == other.B;
}
public override int GetHashCode()
{
var hashCode = -1817952719;
hashCode = hashCode * -1521134295 + A.GetHashCode();
hashCode = hashCode * -1521134295 + B.GetHashCode();
return hashCode;
}
public void Deconstruct(out int a, out int b)
{
a = A;
b = B;
}
public static implicit operator (int A, int B)(NewStruct value)
{
return (value.A, value.B);
}
public static implicit operator NewStruct((int A, int B) value)
{
return new NewStruct(value.A, value.B);
}
}";
await TestInRegularAndScriptAsync(text, expected, options: GetPreferImplicitTypeOptions(host));
}
[WorkItem(39916, "https://github.com/dotnet/roslyn/issues/39916")] [WorkItem(39916, "https://github.com/dotnet/roslyn/issues/39916")]
[Theory, CombinatorialData, Trait(Traits.Feature, Traits.Features.CodeActionsConvertTupleToStruct)] [Theory, CombinatorialData, Trait(Traits.Feature, Traits.Features.CodeActionsConvertTupleToStruct)]
public async Task ConvertSingleTupleType_Explicit(TestHost host) public async Task ConvertSingleTupleType_Explicit(TestHost host)
...@@ -1991,8 +2058,8 @@ void Method() ...@@ -1991,8 +2058,8 @@ void Method()
var t1 = new {|Rename:NewStruct|}(1, 2); var t1 = new {|Rename:NewStruct|}(1, 2);
var t2 = new NewStruct(1, 2); var t2 = new NewStruct(1, 2);
var t3 = (a: 1, b: 2); var t3 = (a: 1, b: 2);
var t4 = new NewStruct(Item1: 1, Item2: 2); var t4 = new NewStruct(item1: 1, item2: 2);
var t5 = new NewStruct(Item1: 1, Item2: 2); var t5 = new NewStruct(item1: 1, item2: 2);
} }
} }
...@@ -2069,8 +2136,8 @@ void Method() ...@@ -2069,8 +2136,8 @@ void Method()
var t1 = new NewStruct(1, 2); var t1 = new NewStruct(1, 2);
var t2 = new NewStruct(1, 2); var t2 = new NewStruct(1, 2);
var t3 = (a: 1, b: 2); var t3 = (a: 1, b: 2);
var t4 = new {|Rename:NewStruct|}(Item1: 1, Item2: 2); var t4 = new {|Rename:NewStruct|}(item1: 1, item2: 2);
var t5 = new NewStruct(Item1: 1, Item2: 2); var t5 = new NewStruct(item1: 1, item2: 2);
} }
} }
......
...@@ -19,7 +19,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.ConvertTupleToStru ...@@ -19,7 +19,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.ConvertTupleToStru
Public Class ConvertTupleToStructTests Public Class ConvertTupleToStructTests
Inherits AbstractVisualBasicCodeActionTest Inherits AbstractVisualBasicCodeActionTest
Protected Overrides Function CreateCodeRefactoringProvider(Workspace As Workspace, parameters As TestParameters) As CodeRefactoringProvider Protected Overrides Function CreateCodeRefactoringProvider(workspace As Workspace, parameters As TestParameters) As CodeRefactoringProvider
Return New VisualBasicConvertTupleToStructCodeRefactoringProvider() Return New VisualBasicConvertTupleToStructCodeRefactoringProvider()
End Function End Function
...@@ -89,6 +89,63 @@ End Structure ...@@ -89,6 +89,63 @@ End Structure
Await TestInRegularAndScriptAsync(text, expected, options:=GetTestOptions(host)) Await TestInRegularAndScriptAsync(text, expected, options:=GetTestOptions(host))
End Function End Function
<WorkItem(45451, "https://github.com/dotnet/roslyn/issues/45451")>
<Theory, CombinatorialData, Trait(Traits.Feature, Traits.Features.CodeActionsConvertTupleToStruct)>
Public Async Function ConvertSingleTupleType_ChangeArgumentNameCase(host As TestHost) As Task
Dim text = "
class Test
sub Method()
dim t1 = [||](A:=1, B:=2)
end sub
end class
"
Dim expected = "
class Test
sub Method()
dim t1 = New {|Rename:NewStruct|}(a:=1, b:=2)
end sub
end class
Friend Structure NewStruct
Public A As Integer
Public B As Integer
Public Sub New(a As Integer, b As Integer)
Me.A = a
Me.B = b
End Sub
Public Overrides Function Equals(obj As Object) As Boolean
If Not (TypeOf obj Is NewStruct) Then
Return False
End If
Dim other = DirectCast(obj, NewStruct)
Return A = other.A AndAlso
B = other.B
End Function
Public Overrides Function GetHashCode() As Integer
Return (A, B).GetHashCode()
End Function
Public Sub Deconstruct(ByRef a As Integer, ByRef b As Integer)
a = Me.A
b = Me.B
End Sub
Public Shared Widening Operator CType(value As NewStruct) As (A As Integer, B As Integer)
Return (value.A, value.B)
End Operator
Public Shared Widening Operator CType(value As (A As Integer, B As Integer)) As NewStruct
Return New NewStruct(value.A, value.B)
End Operator
End Structure
"
Await TestInRegularAndScriptAsync(text, expected, options:=GetTestOptions(host))
End Function
<Theory, CombinatorialData, Trait(Traits.Feature, Traits.Features.CodeActionsConvertTupleToStruct)> <Theory, CombinatorialData, Trait(Traits.Feature, Traits.Features.CodeActionsConvertTupleToStruct)>
Public Async Function ConvertSingleTupleTypeNoNames(host As TestHost) As Task Public Async Function ConvertSingleTupleTypeNoNames(host As TestHost) As Task
Dim text = " Dim text = "
...@@ -671,7 +728,7 @@ end class" ...@@ -671,7 +728,7 @@ end class"
class Test class Test
sub Method() sub Method()
dim t1 = New {|Rename:NewStruct|}(a:=1, b:=2) dim t1 = New {|Rename:NewStruct|}(a:=1, b:=2)
dim t2 = New NewStruct(A:=3, B:=4) dim t2 = New NewStruct(a:=3, b:=4)
end sub end sub
end class end class
...@@ -843,10 +900,6 @@ End Structure ...@@ -843,10 +900,6 @@ End Structure
Await TestInRegularAndScriptAsync(text, expected, options:=GetTestOptions(host)) Await TestInRegularAndScriptAsync(text, expected, options:=GetTestOptions(host))
End Function End Function
Sub foo(a As Integer, b As Integer)
End Sub
<Theory, CombinatorialData, Trait(Traits.Feature, Traits.Features.CodeActionsConvertTupleToStruct)> <Theory, CombinatorialData, Trait(Traits.Feature, Traits.Features.CodeActionsConvertTupleToStruct)>
Public Async Function TestFixAllMatchesInSingleMethod(host As TestHost) As Task Public Async Function TestFixAllMatchesInSingleMethod(host As TestHost) As Task
Dim text = " Dim text = "
...@@ -975,8 +1028,8 @@ End Structure ...@@ -975,8 +1028,8 @@ End Structure
Await TestInRegularAndScriptAsync(text, expected, options:=GetTestOptions(host)) Await TestInRegularAndScriptAsync(text, expected, options:=GetTestOptions(host))
End Function End Function
<Theory, CombinatorialData, Trait(Traits.Feature, Traits.Features.CodeActionsConvertTupleToStruct)> <Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertTupleToStruct)>
Public Async Function NotIfReferencesAnonymousTypeInternally(host As TestHost) As Task Public Async Function NotIfReferencesAnonymousTypeInternally() As Task
Dim text = " Dim text = "
class Test class Test
sub Method() sub Method()
...@@ -1547,7 +1600,7 @@ class Test ...@@ -1547,7 +1600,7 @@ class Test
dim t1 = New {|Rename:NewStruct|}(1, 2) dim t1 = New {|Rename:NewStruct|}(1, 2)
dim t2 = New NewStruct(1, 2) dim t2 = New NewStruct(1, 2)
dim t3 = (a:=1, b:=2) dim t3 = (a:=1, b:=2)
dim t4 = New NewStruct(Item1:=1, Item2:=2) dim t4 = New NewStruct(item1:=1, item2:=2)
dim t5 = New NewStruct(item1:=1, item2:=2) dim t5 = New NewStruct(item1:=1, item2:=2)
end sub end sub
end class end class
...@@ -1616,7 +1669,7 @@ class Test ...@@ -1616,7 +1669,7 @@ class Test
dim t1 = New NewStruct(1, 2) dim t1 = New NewStruct(1, 2)
dim t2 = New NewStruct(1, 2) dim t2 = New NewStruct(1, 2)
dim t3 = (a:=1, b:=2) dim t3 = (a:=1, b:=2)
dim t4 = New {|Rename:NewStruct|}(Item1:=1, Item2:=2) dim t4 = New {|Rename:NewStruct|}(item1:=1, item2:=2)
dim t5 = New NewStruct(item1:=1, item2:=2) dim t5 = New NewStruct(item1:=1, item2:=2)
end sub end sub
end class end class
...@@ -1829,7 +1882,7 @@ End Structure ...@@ -1829,7 +1882,7 @@ End Structure
FeaturesResources.updating_usages_in_containing_member, FeaturesResources.updating_usages_in_containing_member,
FeaturesResources.updating_usages_in_containing_type FeaturesResources.updating_usages_in_containing_type
}) })
Await TestInRegularAndScriptAsync(text, expected, index:=1) Await TestInRegularAndScriptAsync(text, expected, index:=1, options:=GetTestOptions(host))
End Function End Function
<Theory, CombinatorialData, Trait(Traits.Feature, Traits.Features.CodeActionsConvertTupleToStruct)> <Theory, CombinatorialData, Trait(Traits.Feature, Traits.Features.CodeActionsConvertTupleToStruct)>
...@@ -1906,7 +1959,7 @@ Friend Structure NewStruct ...@@ -1906,7 +1959,7 @@ Friend Structure NewStruct
End Operator End Operator
End Structure End Structure
" "
Await TestInRegularAndScriptAsync(text, expected, index:=1) Await TestInRegularAndScriptAsync(text, expected, index:=1, options:=GetTestOptions(host))
End Function End Function
<Theory, CombinatorialData, Trait(Traits.Feature, Traits.Features.CodeActionsConvertTupleToStruct)> <Theory, CombinatorialData, Trait(Traits.Feature, Traits.Features.CodeActionsConvertTupleToStruct)>
...@@ -1985,7 +2038,7 @@ Friend Structure NewStruct ...@@ -1985,7 +2038,7 @@ Friend Structure NewStruct
End Operator End Operator
End Structure End Structure
" "
Await TestInRegularAndScriptAsync(text, expected, index:=1) Await TestInRegularAndScriptAsync(text, expected, index:=1, options:=GetTestOptions(host))
End Function End Function
<Theory, CombinatorialData, Trait(Traits.Feature, Traits.Features.CodeActionsConvertTupleToStruct)> <Theory, CombinatorialData, Trait(Traits.Feature, Traits.Features.CodeActionsConvertTupleToStruct)>
...@@ -2101,7 +2154,7 @@ end class ...@@ -2101,7 +2154,7 @@ end class
</Document> </Document>
</Project> </Project>
</Workspace>" </Workspace>"
Await TestInRegularAndScriptAsync(text, expected, index:=1) Await TestInRegularAndScriptAsync(text, expected, index:=1, options:=GetTestOptions(host))
End Function End Function
#End Region #End Region
...@@ -2225,7 +2278,7 @@ end class ...@@ -2225,7 +2278,7 @@ end class
</Document> </Document>
</Project> </Project>
</Workspace>" </Workspace>"
Await TestInRegularAndScriptAsync(text, expected, index:=2) Await TestInRegularAndScriptAsync(text, expected, index:=2, options:=GetTestOptions(host))
End Function End Function
#End Region #End Region
...@@ -2338,7 +2391,7 @@ end class ...@@ -2338,7 +2391,7 @@ end class
</Document> </Document>
</Project> </Project>
</Workspace>" </Workspace>"
Await TestInRegularAndScriptAsync(text, expected, index:=3) Await TestInRegularAndScriptAsync(text, expected, index:=3, options:=GetTestOptions(host))
End Function End Function
<Theory, CombinatorialData, Trait(Traits.Feature, Traits.Features.CodeActionsConvertTupleToStruct)> <Theory, CombinatorialData, Trait(Traits.Feature, Traits.Features.CodeActionsConvertTupleToStruct)>
...@@ -2445,7 +2498,7 @@ end class ...@@ -2445,7 +2498,7 @@ end class
</Document> </Document>
</Project> </Project>
</Workspace>" </Workspace>"
Await TestInRegularAndScriptAsync(text, expected, index:=3) Await TestInRegularAndScriptAsync(text, expected, index:=3, options:=GetTestOptions(host))
End Function End Function
#End Region #End Region
......
...@@ -9,6 +9,8 @@ ...@@ -9,6 +9,8 @@
using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Host.Mef;
#nullable enable
namespace Microsoft.CodeAnalysis.CSharp.ConvertTupleToStruct namespace Microsoft.CodeAnalysis.CSharp.ConvertTupleToStruct
{ {
[ExtensionOrder(Before = PredefinedCodeRefactoringProviderNames.IntroduceVariable)] [ExtensionOrder(Before = PredefinedCodeRefactoringProviderNames.IntroduceVariable)]
...@@ -32,5 +34,19 @@ internal class CSharpConvertTupleToStructCodeRefactoringProvider : ...@@ -32,5 +34,19 @@ internal class CSharpConvertTupleToStructCodeRefactoringProvider :
public CSharpConvertTupleToStructCodeRefactoringProvider() public CSharpConvertTupleToStructCodeRefactoringProvider()
{ {
} }
protected override ArgumentSyntax GetArgumentWithChangedName(ArgumentSyntax argument, string name)
=> argument.WithNameColon(ChangeName(argument.NameColon, name));
private static NameColonSyntax? ChangeName(NameColonSyntax? nameColon, string name)
{
if (nameColon == null)
{
return null;
}
var newName = SyntaxFactory.IdentifierName(name).WithTriviaFrom(nameColon.Name);
return nameColon.WithName(newName);
}
} }
} }
...@@ -53,6 +53,8 @@ internal abstract partial class AbstractConvertTupleToStructCodeRefactoringProvi ...@@ -53,6 +53,8 @@ internal abstract partial class AbstractConvertTupleToStructCodeRefactoringProvi
where TTypeBlockSyntax : SyntaxNode where TTypeBlockSyntax : SyntaxNode
where TNamespaceDeclarationSyntax : SyntaxNode where TNamespaceDeclarationSyntax : SyntaxNode
{ {
protected abstract TArgumentSyntax GetArgumentWithChangedName(TArgumentSyntax argument, string name);
public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
{ {
var (document, textSpan, cancellationToken) = context; var (document, textSpan, cancellationToken) = context;
...@@ -203,7 +205,7 @@ private static string GetTitle(Scope scope) ...@@ -203,7 +205,7 @@ private static string GetTitle(Scope scope)
return document.WithSyntaxRoot(newRoot).Project.Solution; return document.WithSyntaxRoot(newRoot).Project.Solution;
} }
private static async Task<Solution> ConvertToStructInCurrentProcessAsync( private async Task<Solution> ConvertToStructInCurrentProcessAsync(
Document document, TextSpan span, Scope scope, CancellationToken cancellationToken) Document document, TextSpan span, Scope scope, CancellationToken cancellationToken)
{ {
var (tupleExprOrTypeNode, tupleType) = await TryGetTupleInfoAsync( var (tupleExprOrTypeNode, tupleType) = await TryGetTupleInfoAsync(
...@@ -259,7 +261,7 @@ private static string GetTitle(Scope scope) ...@@ -259,7 +261,7 @@ private static string GetTitle(Scope scope)
return updatedSolution; return updatedSolution;
} }
private static async Task ReplaceExpressionAndTypesInScopeAsync( private async Task ReplaceExpressionAndTypesInScopeAsync(
Dictionary<Document, SyntaxEditor> documentToEditorMap, Dictionary<Document, SyntaxEditor> documentToEditorMap,
ImmutableArray<DocumentToUpdate> documentsToUpdate, ImmutableArray<DocumentToUpdate> documentsToUpdate,
SyntaxNode tupleExprOrTypeNode, INamedTypeSymbol tupleType, SyntaxNode tupleExprOrTypeNode, INamedTypeSymbol tupleType,
...@@ -305,7 +307,7 @@ private static string GetTitle(Scope scope) ...@@ -305,7 +307,7 @@ private static string GetTitle(Scope scope)
// We should only ever get a default array (meaning, update the root), or a // We should only ever get a default array (meaning, update the root), or a
// non-empty array. We should never be asked to update exactly '0' nodes. // non-empty array. We should never be asked to update exactly '0' nodes.
Debug.Assert(documentToUpdate.NodesToUpdate.IsDefault || Debug.Assert(documentToUpdate.NodesToUpdate.IsDefault ||
documentToUpdate.NodesToUpdate.Length >= 1); !documentToUpdate.NodesToUpdate.IsEmpty);
// If we were given specific nodes to update, only update those. Otherwise // If we were given specific nodes to update, only update those. Otherwise
// updated everything from the root down. // updated everything from the root down.
...@@ -347,7 +349,7 @@ private static string GetTitle(Scope scope) ...@@ -347,7 +349,7 @@ private static string GetTitle(Scope scope)
structNameToken = structNameToken.WithAdditionalAnnotations(RenameAnnotation.Create()); structNameToken = structNameToken.WithAdditionalAnnotations(RenameAnnotation.Create());
} }
return typeParameters.Length == 0 return typeParameters.IsEmpty
? (TNameSyntax)generator.IdentifierName(structNameToken) ? (TNameSyntax)generator.IdentifierName(structNameToken)
: (TNameSyntax)generator.GenericName(structNameToken, typeParameters.Select(tp => generator.IdentifierName(tp.Name))); : (TNameSyntax)generator.GenericName(structNameToken, typeParameters.Select(tp => generator.IdentifierName(tp.Name)));
} }
...@@ -546,7 +548,7 @@ private static bool InfoProbablyContainsTupleFieldNames(SyntaxTreeIndex info, Im ...@@ -546,7 +548,7 @@ private static bool InfoProbablyContainsTupleFieldNames(SyntaxTreeIndex info, Im
return currentSolution; return currentSolution;
} }
private static async Task<bool> ReplaceTupleExpressionsAndTypesInDocumentAsync( private async Task<bool> ReplaceTupleExpressionsAndTypesInDocumentAsync(
Document document, SyntaxEditor editor, SyntaxNode startingNode, Document document, SyntaxEditor editor, SyntaxNode startingNode,
INamedTypeSymbol tupleType, TNameSyntax fullyQualifiedStructName, INamedTypeSymbol tupleType, TNameSyntax fullyQualifiedStructName,
string structName, ImmutableArray<ITypeParameterSymbol> typeParameters, string structName, ImmutableArray<ITypeParameterSymbol> typeParameters,
...@@ -566,7 +568,7 @@ private static bool InfoProbablyContainsTupleFieldNames(SyntaxTreeIndex info, Im ...@@ -566,7 +568,7 @@ private static bool InfoProbablyContainsTupleFieldNames(SyntaxTreeIndex info, Im
return changed; return changed;
} }
private static async Task<bool> ReplaceMatchingTupleExpressionsAsync( private async Task<bool> ReplaceMatchingTupleExpressionsAsync(
Document document, SyntaxEditor editor, SyntaxNode startingNode, Document document, SyntaxEditor editor, SyntaxNode startingNode,
INamedTypeSymbol tupleType, TNameSyntax qualifiedTypeName, INamedTypeSymbol tupleType, TNameSyntax qualifiedTypeName,
string typeName, ImmutableArray<ITypeParameterSymbol> typeParameters, string typeName, ImmutableArray<ITypeParameterSymbol> typeParameters,
...@@ -622,7 +624,7 @@ private static bool AreEquivalent(StringComparer comparer, INamedTypeSymbol tupl ...@@ -622,7 +624,7 @@ private static bool AreEquivalent(StringComparer comparer, INamedTypeSymbol tupl
return true; return true;
} }
private static void ReplaceWithObjectCreation( private void ReplaceWithObjectCreation(
SyntaxEditor editor, string typeName, ImmutableArray<ITypeParameterSymbol> typeParameters, SyntaxEditor editor, string typeName, ImmutableArray<ITypeParameterSymbol> typeParameters,
TNameSyntax qualifiedTypeName, SyntaxNode startingCreationNode, TTupleExpressionSyntax childCreation) TNameSyntax qualifiedTypeName, SyntaxNode startingCreationNode, TTupleExpressionSyntax childCreation)
{ {
...@@ -649,27 +651,31 @@ private static bool AreEquivalent(StringComparer comparer, INamedTypeSymbol tupl ...@@ -649,27 +651,31 @@ private static bool AreEquivalent(StringComparer comparer, INamedTypeSymbol tupl
}); });
} }
private static SeparatedSyntaxList<TArgumentSyntax> ConvertArguments(SyntaxGenerator generator, SeparatedSyntaxList<TArgumentSyntax> arguments) private SeparatedSyntaxList<TArgumentSyntax> ConvertArguments(SyntaxGenerator generator, SeparatedSyntaxList<TArgumentSyntax> arguments)
=> generator.SeparatedList<TArgumentSyntax>(ConvertArguments(generator, arguments.GetWithSeparators())); => generator.SeparatedList<TArgumentSyntax>(ConvertArguments(generator, arguments.GetWithSeparators()));
private static SyntaxNodeOrTokenList ConvertArguments(SyntaxGenerator generator, SyntaxNodeOrTokenList list) private SyntaxNodeOrTokenList ConvertArguments(SyntaxGenerator generator, SyntaxNodeOrTokenList list)
=> new SyntaxNodeOrTokenList(list.Select(v => ConvertArgumentOrToken(generator, v))); => new SyntaxNodeOrTokenList(list.Select(v => ConvertArgumentOrToken(generator, v)));
private static SyntaxNodeOrToken ConvertArgumentOrToken(SyntaxGenerator generator, SyntaxNodeOrToken arg) private SyntaxNodeOrToken ConvertArgumentOrToken(SyntaxGenerator generator, SyntaxNodeOrToken arg)
=> arg.IsToken => arg.IsToken
? arg ? arg
: ConvertArgument(generator, (TArgumentSyntax)arg.AsNode()); : ConvertArgument(generator, (TArgumentSyntax)arg.AsNode());
private static TArgumentSyntax ConvertArgument( private TArgumentSyntax ConvertArgument(
SyntaxGenerator generator, TArgumentSyntax argument) SyntaxGenerator generator, TArgumentSyntax argument)
{ {
// Keep named arguments for literal args. It helps keep the code self-documenting. // If the original arguments had names then we keep them, but convert the case to match the
// the constructor parameters they now refer to. It helps keep the code self-documenting.
// Remove for complex args as it's most likely just clutter a person doesn't need // Remove for complex args as it's most likely just clutter a person doesn't need
// when instantiating their new type. // when instantiating their new type.
var expr = generator.SyntaxFacts.GetExpressionOfArgument(argument); var expr = generator.SyntaxFacts.GetExpressionOfArgument(argument);
if (expr is TLiteralExpressionSyntax) if (expr is TLiteralExpressionSyntax)
{ {
return argument; var argumentName = generator.SyntaxFacts.GetNameForArgument(argument);
var newArgumentName = GetConstructorParameterName(argumentName);
return GetArgumentWithChangedName(argument, newArgumentName);
} }
return (TArgumentSyntax)generator.Argument(expr).WithTriviaFrom(argument); return (TArgumentSyntax)generator.Argument(expr).WithTriviaFrom(argument);
...@@ -800,9 +806,9 @@ private static SyntaxNodeOrToken ConvertArgumentOrToken(SyntaxGenerator generato ...@@ -800,9 +806,9 @@ private static SyntaxNodeOrToken ConvertArgumentOrToken(SyntaxGenerator generato
SyntaxGenerator generator, ArrayBuilder<ISymbol> members, SyntaxGenerator generator, ArrayBuilder<ISymbol> members,
INamedTypeSymbol tupleType, INamedTypeSymbol structType) INamedTypeSymbol tupleType, INamedTypeSymbol structType)
{ {
const string valueName = "value"; const string ValueName = "value";
var valueNode = generator.IdentifierName(valueName); var valueNode = generator.IdentifierName(ValueName);
var arguments = tupleType.TupleElements.SelectAsArray<IFieldSymbol, SyntaxNode>( var arguments = tupleType.TupleElements.SelectAsArray<IFieldSymbol, SyntaxNode>(
field => generator.Argument( field => generator.Argument(
generator.MemberAccessExpression(valueNode, field.Name))); generator.MemberAccessExpression(valueNode, field.Name)));
...@@ -818,7 +824,7 @@ private static SyntaxNodeOrToken ConvertArgumentOrToken(SyntaxGenerator generato ...@@ -818,7 +824,7 @@ private static SyntaxNodeOrToken ConvertArgumentOrToken(SyntaxGenerator generato
Accessibility.Public, Accessibility.Public,
DeclarationModifiers.Static, DeclarationModifiers.Static,
tupleType, tupleType,
CodeGenerationSymbolFactory.CreateParameterSymbol(structType, valueName), CodeGenerationSymbolFactory.CreateParameterSymbol(structType, ValueName),
isImplicit: true, isImplicit: true,
ImmutableArray.Create(convertToTupleStatement))); ImmutableArray.Create(convertToTupleStatement)));
members.Add(CodeGenerationSymbolFactory.CreateConversionSymbol( members.Add(CodeGenerationSymbolFactory.CreateConversionSymbol(
...@@ -826,7 +832,7 @@ private static SyntaxNodeOrToken ConvertArgumentOrToken(SyntaxGenerator generato ...@@ -826,7 +832,7 @@ private static SyntaxNodeOrToken ConvertArgumentOrToken(SyntaxGenerator generato
Accessibility.Public, Accessibility.Public,
DeclarationModifiers.Static, DeclarationModifiers.Static,
structType, structType,
CodeGenerationSymbolFactory.CreateParameterSymbol(tupleType, valueName), CodeGenerationSymbolFactory.CreateParameterSymbol(tupleType, ValueName),
isImplicit: true, isImplicit: true,
ImmutableArray.Create(convertToStructStatement))); ImmutableArray.Create(convertToStructStatement)));
} }
...@@ -854,7 +860,7 @@ private static SyntaxNodeOrToken ConvertArgumentOrToken(SyntaxGenerator generato ...@@ -854,7 +860,7 @@ private static SyntaxNodeOrToken ConvertArgumentOrToken(SyntaxGenerator generato
var parameters = fields.SelectAsArray<IFieldSymbol, IParameterSymbol>(field => var parameters = fields.SelectAsArray<IFieldSymbol, IParameterSymbol>(field =>
{ {
var parameter = CodeGenerationSymbolFactory.CreateParameterSymbol( var parameter = CodeGenerationSymbolFactory.CreateParameterSymbol(
field.Type, field.Name.ToCamelCase(trimLeadingTypePrefix: false)); field.Type, GetConstructorParameterName(field.Name));
parameterToPropMap[parameter.Name] = field; parameterToPropMap[parameter.Name] = field;
...@@ -872,6 +878,9 @@ private static SyntaxNodeOrToken ConvertArgumentOrToken(SyntaxGenerator generato ...@@ -872,6 +878,9 @@ private static SyntaxNodeOrToken ConvertArgumentOrToken(SyntaxGenerator generato
return constructor; return constructor;
} }
private static string GetConstructorParameterName(string name)
=> name.ToCamelCase(trimLeadingTypePrefix: false); // TODO: This is the common case, but should ideally match the users style preference
private class MyCodeAction : CodeAction.SolutionChangeAction private class MyCodeAction : CodeAction.SolutionChangeAction
{ {
public MyCodeAction(string title, Func<CancellationToken, Task<Solution>> createChangedSolution) public MyCodeAction(string title, Func<CancellationToken, Task<Solution>> createChangedSolution)
......
...@@ -30,5 +30,26 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ConvertTupleToStruct ...@@ -30,5 +30,26 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ConvertTupleToStruct
<SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification:="Used in test code: https://github.com/dotnet/roslyn/issues/42814")> <SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification:="Used in test code: https://github.com/dotnet/roslyn/issues/42814")>
Public Sub New() Public Sub New()
End Sub End Sub
Protected Overrides Function GetArgumentWithChangedName(argument As ArgumentSyntax, name As String) As ArgumentSyntax
Dim simpleArgument = TryCast(argument, SimpleArgumentSyntax)
If simpleArgument Is Nothing Then
Return argument
End If
Dim nameColonEquals = simpleArgument.NameColonEquals
Return simpleArgument.WithNameColonEquals(ChangeName(nameColonEquals, name))
End Function
Private Shared Function ChangeName(nameColonEquals As NameColonEqualsSyntax, name As String) As NameColonEqualsSyntax
If nameColonEquals Is Nothing Then
Return Nothing
End If
Dim newName = SyntaxFactory.IdentifierName(name).WithTriviaFrom(nameColonEquals.Name)
Return nameColonEquals.WithName(newName)
End Function
End Class End Class
End Namespace End Namespace
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册