From 4929b2e60abbdbb6cbe72c856d6f370c8cf13b35 Mon Sep 17 00:00:00 2001 From: David Wengier Date: Thu, 17 Dec 2020 21:13:33 +1100 Subject: [PATCH] Generate fields with the right naming scheme (#50028) * Async-ify a bunch of things * Failing tests * Use the field naming style when generating types --- .../GenerateType/GenerateTypeTests.cs | 35 +++++++++++++++++++ .../GenerateType/GenerateTypeTests.vb | 29 +++++++++++++++ .../AbstractGenerateTypeService.Editor.cs | 12 ++++--- ...ctGenerateTypeService.GenerateNamedType.cs | 21 +++++------ 4 files changed, 83 insertions(+), 14 deletions(-) diff --git a/src/EditorFeatures/CSharpTest/Diagnostics/GenerateType/GenerateTypeTests.cs b/src/EditorFeatures/CSharpTest/Diagnostics/GenerateType/GenerateTypeTests.cs index fa2e2af87d3..c7c03aa65be 100644 --- a/src/EditorFeatures/CSharpTest/Diagnostics/GenerateType/GenerateTypeTests.cs +++ b/src/EditorFeatures/CSharpTest/Diagnostics/GenerateType/GenerateTypeTests.cs @@ -14,6 +14,7 @@ using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editor.UnitTests; using Microsoft.CodeAnalysis.Editor.UnitTests.Diagnostics; +using Microsoft.CodeAnalysis.Editor.UnitTests.Diagnostics.NamingStyles; using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; using Xunit; @@ -2879,6 +2880,40 @@ class B index: 1); } + [WorkItem(49924, "https://github.com/dotnet/roslyn/issues/49924")] + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateType)] + public async Task GenerateCorrectFieldNaming() + { + var options = new NamingStylesTestOptionSets(LanguageNames.CSharp); + + await TestInRegularAndScriptAsync( + @"class Class +{ + void M(int i) + { + D d = new [|D|](i); + } +}", + @"class Class +{ + void M(int i) + { + D d = new D(i); + } +} + +internal class D +{ + private int _i; + + public D(int i) + { + _i = i; + } +}", + index: 1, options: options.FieldNamesAreCamelCaseWithUnderscorePrefix); + } + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateType)] public async Task GenerateWithCallToProperty1() { diff --git a/src/EditorFeatures/VisualBasicTest/Diagnostics/GenerateType/GenerateTypeTests.vb b/src/EditorFeatures/VisualBasicTest/Diagnostics/GenerateType/GenerateTypeTests.vb index 69c154739a5..a06531070b2 100644 --- a/src/EditorFeatures/VisualBasicTest/Diagnostics/GenerateType/GenerateTypeTests.vb +++ b/src/EditorFeatures/VisualBasicTest/Diagnostics/GenerateType/GenerateTypeTests.vb @@ -9,6 +9,7 @@ Imports Microsoft.CodeAnalysis.CodeStyle Imports Microsoft.CodeAnalysis.Diagnostics Imports Microsoft.CodeAnalysis.Editor.UnitTests Imports Microsoft.CodeAnalysis.Editor.UnitTests.Diagnostics +Imports Microsoft.CodeAnalysis.Editor.UnitTests.Diagnostics.NamingStyles Imports Microsoft.CodeAnalysis.Editor.UnitTests.Extensions Imports Microsoft.CodeAnalysis.VisualBasic.CodeFixes.GenerateType Imports Microsoft.CodeAnalysis.VisualBasic.Diagnostics @@ -1878,6 +1879,34 @@ End Class", index:=2) End Function + + + Public Async Function GenerateCorrectFieldNaming() As Task + Dim options = New NamingStylesTestOptionSets(LanguageNames.VisualBasic) + + Await TestInRegularAndScriptAsync( +"Public Class A + Public Sub M(i As Integer) + Dim d = New [|D|](i) + End Sub +End Class", +"Public Class A + Public Sub M(i As Integer) + Dim d = New [|D|](i) + End Sub +End Class + +Friend Class D + Private _i As Integer + + Public Sub New(i As Integer) + _i = i + End Sub +End Class +", + index:=1, options:=options.FieldNamesAreCamelCaseWithUnderscorePrefix) + End Function + Public Class AddImportTestsWithAddImportDiagnosticProvider Inherits AbstractVisualBasicDiagnosticProviderBasedUserDiagnosticTest diff --git a/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.Editor.cs b/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.Editor.cs index 79540e91c58..e461be90597 100644 --- a/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.Editor.cs +++ b/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.Editor.cs @@ -14,8 +14,10 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeGeneration; +using Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles; using Microsoft.CodeAnalysis.LanguageServices; using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Shared.Utilities; using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.Utilities; using Roslyn.Utilities; @@ -88,7 +90,7 @@ internal async Task> GetOperationsAsync() if (!_fromDialog) { // Generate the actual type declaration. - var namedType = GenerateNamedType(); + var namedType = await GenerateNamedTypeAsync().ConfigureAwait(false); if (_intoNamespace) { @@ -119,7 +121,7 @@ internal async Task> GetOperationsAsync() } else { - var namedType = GenerateNamedType(_generateTypeOptionsResult); + var namedType = await GenerateNamedTypeAsync(_generateTypeOptionsResult).ConfigureAwait(false); // Honor the options from the dialog // Check to see if the type is requested to be generated in cross language Project @@ -572,7 +574,7 @@ private ImmutableArray GetArgumentExpressions(IList FindExistingOrCreateNewMemberAsync( ParameterName parameterName, ITypeSymbol parameterType, ImmutableDictionary.Builder parameterToFieldMap, @@ -599,7 +601,9 @@ where IsViableFieldOrProperty(parameterType, m) } } - parameterToNewFieldMap[parameterName.BestNameForParameter] = parameterName.NameBasedOnArgument; + var fieldNamingRule = await _semanticDocument.Document.GetApplicableNamingRuleAsync(SymbolKind.Field, Accessibility.Private, _cancellationToken).ConfigureAwait(false); + var nameToUse = fieldNamingRule.NamingStyle.MakeCompliant(parameterName.NameBasedOnArgument).First(); + parameterToNewFieldMap[parameterName.BestNameForParameter] = nameToUse; return false; } diff --git a/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.GenerateNamedType.cs b/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.GenerateNamedType.cs index 9a3d1067370..9baef773125 100644 --- a/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.GenerateNamedType.cs +++ b/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.GenerateNamedType.cs @@ -8,6 +8,7 @@ using System.Collections.Immutable; using System.Linq; using System.Threading; +using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Editing; @@ -23,7 +24,7 @@ internal abstract partial class AbstractGenerateTypeService GenerateNamedTypeAsync() { return CodeGenerationSymbolFactory.CreateNamedTypeSymbol( DetermineAttributes(), @@ -34,10 +35,10 @@ private INamedTypeSymbol GenerateNamedType() DetermineTypeParameters(), DetermineBaseType(), DetermineInterfaces(), - members: DetermineMembers()); + members: await DetermineMembersAsync().ConfigureAwait(false)); } - private INamedTypeSymbol GenerateNamedType(GenerateTypeOptionsResult options) + private async Task GenerateNamedTypeAsync(GenerateTypeOptionsResult options) { if (options.TypeKind == TypeKind.Delegate) { @@ -61,7 +62,7 @@ private INamedTypeSymbol GenerateNamedType(GenerateTypeOptionsResult options) DetermineTypeParameters(), DetermineBaseType(), DetermineInterfaces(), - members: DetermineMembers(options)); + members: await DetermineMembersAsync(options).ConfigureAwait(false)); } private ITypeSymbol DetermineReturnType() @@ -100,10 +101,10 @@ private ImmutableArray DetermineParameters() return default; } - private ImmutableArray DetermineMembers(GenerateTypeOptionsResult options = null) + private async Task> DetermineMembersAsync(GenerateTypeOptionsResult options = null) { using var _ = ArrayBuilder.GetInstance(out var members); - AddMembers(members, options); + await AddMembersAsync(members, options).ConfigureAwait(false); if (_state.IsException) AddExceptionConstructors(members); @@ -111,7 +112,7 @@ private ImmutableArray DetermineMembers(GenerateTypeOptionsResult optio return members.ToImmutable(); } - private void AddMembers(ArrayBuilder members, GenerateTypeOptionsResult options = null) + private async Task AddMembersAsync(ArrayBuilder members, GenerateTypeOptionsResult options = null) { AddProperties(members); if (!_service.TryGetArgumentList(_state.ObjectCreationExpressionOpt, out var argumentList)) @@ -166,7 +167,7 @@ private void AddMembers(ArrayBuilder members, GenerateTypeOptionsResult // Otherwise, just generate a normal constructor that assigns any provided // parameters into fields. - AddFieldDelegatingConstructor(argumentList, members, options); + await AddFieldDelegatingConstructorAsync(argumentList, members, options).ConfigureAwait(false); } private void AddProperties(ArrayBuilder members) @@ -181,7 +182,7 @@ private void AddProperties(ArrayBuilder members) } } - private void AddFieldDelegatingConstructor( + private async Task AddFieldDelegatingConstructorAsync( IList argumentList, ArrayBuilder members, GenerateTypeOptionsResult options = null) { var factory = _semanticDocument.Document.GetLanguageService(); @@ -204,7 +205,7 @@ private void AddProperties(ArrayBuilder members) parameterType = parameterType.RemoveUnavailableTypeParameters( _semanticDocument.SemanticModel.Compilation, availableTypeParameters); - FindExistingOrCreateNewMember(parameterName, parameterType, parameterToExistingFieldMap, parameterToNewFieldMap); + await FindExistingOrCreateNewMemberAsync(parameterName, parameterType, parameterToExistingFieldMap, parameterToNewFieldMap).ConfigureAwait(false); parameters.Add(CodeGenerationSymbolFactory.CreateParameterSymbol( attributes: default, -- GitLab