未验证 提交 edc02b0b 编写于 作者: M Manish Vasani 提交者: GitHub

Merge pull request #29631 from allisonchou/AccessibilityFix

Fix generate field doesn't recognize accessibility modifier configuration
......@@ -2,8 +2,10 @@
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeRefactorings;
using Microsoft.CodeAnalysis.CodeStyle;
using Microsoft.CodeAnalysis.CSharp.InitializeParameter;
using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.CodeRefactorings;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
......@@ -625,7 +627,7 @@ public C(string s)
[WorkItem(29190, "https://github.com/dotnet/roslyn/issues/29190")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsInitializeParameter)]
public async Task TestInitializeFieldWithParameterNameSelected2()
public async Task TestInitializeField_ParameterNameSelected2()
{
await TestInRegularAndScript1Async(
@"
......@@ -648,5 +650,306 @@ public C(string s, int i)
}
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsInitializeParameter)]
public async Task TestInitializeClassProperty_RequiredAccessibilityOmitIfDefault()
{
await TestInRegularAndScript1Async(
@"
class C
{
readonly int test = 5;
public C(int test, int [|test2|])
{
}
}",
@"
class C
{
readonly int test = 5;
public C(int test, int test2)
{
Test2 = test2;
}
public int Test2 { get; }
}", index: 0, parameters: OmitIfDefault_Warning);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsInitializeParameter)]
public async Task TestInitializeClassProperty_RequiredAccessibilityNever()
{
await TestInRegularAndScript1Async(
@"
class C
{
readonly int test = 5;
public C(int test, int [|test2|])
{
}
}",
@"
class C
{
readonly int test = 5;
public C(int test, int test2)
{
Test2 = test2;
}
public int Test2 { get; }
}", index: 0, parameters: Never_Warning);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsInitializeParameter)]
public async Task TestInitializeClassProperty_RequiredAccessibilityAlways()
{
await TestInRegularAndScript1Async(
@"
class C
{
readonly int test = 5;
public C(int test, int [|test2|])
{
}
}",
@"
class C
{
readonly int test = 5;
public C(int test, int test2)
{
Test2 = test2;
}
public int Test2 { get; }
}", index: 0, parameters: Always_Warning);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsInitializeParameter)]
public async Task TestInitializeClassField_RequiredAccessibilityOmitIfDefault()
{
await TestInRegularAndScript1Async(
@"
class C
{
readonly int test = 5;
public C(int test, int [|test2|])
{
}
}",
@"
class C
{
readonly int test = 5;
readonly int test2;
public C(int test, int test2)
{
this.test2 = test2;
}
}", index: 1, parameters: OmitIfDefault_Warning);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsInitializeParameter)]
public async Task TestInitializeClassField_RequiredAccessibilityNever()
{
await TestInRegularAndScript1Async(
@"
class C
{
readonly int test = 5;
public C(int test, int [|test2|])
{
}
}",
@"
class C
{
readonly int test = 5;
readonly int test2;
public C(int test, int test2)
{
this.test2 = test2;
}
}", index: 1, parameters: Never_Warning);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsInitializeParameter)]
public async Task TestInitializeClassField_RequiredAccessibilityAlways()
{
await TestInRegularAndScript1Async(
@"
class C
{
readonly int test = 5;
public C(int test, int [|test2|])
{
}
}",
@"
class C
{
readonly int test = 5;
private readonly int test2;
public C(int test, int test2)
{
this.test2 = test2;
}
}", index: 1, parameters: Always_Warning);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsInitializeParameter)]
public async Task TestInitializeStructProperty_RequiredAccessibilityOmitIfDefault()
{
await TestInRegularAndScript1Async(
@"
struct S
{
public Test(int [|test|])
{
}
}",
@"
struct S
{
public Test(int test)
{
Test = test;
}
public int Test { get; }
}", index: 0, parameters: OmitIfDefault_Warning);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsInitializeParameter)]
public async Task TestInitializeStructProperty_RequiredAccessibilityNever()
{
await TestInRegularAndScript1Async(
@"
struct S
{
public Test(int [|test|])
{
}
}",
@"
struct S
{
public Test(int test)
{
Test = test;
}
public int Test { get; }
}", index: 0, parameters: Never_Warning);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsInitializeParameter)]
public async Task TestInitializeStructProperty_RequiredAccessibilityAlways()
{
await TestInRegularAndScript1Async(
@"
struct S
{
public Test(int [|test|])
{
}
}",
@"
struct S
{
public Test(int test)
{
Test = test;
}
public int Test { get; }
}", index: 0, parameters: Always_Warning);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsInitializeParameter)]
public async Task TestInitializeStructField_RequiredAccessibilityOmitIfDefault()
{
await TestInRegularAndScript1Async(
@"
struct S
{
public Test(int [|test|])
{
}
}",
@"
struct S
{
readonly int test;
public Test(int test)
{
this.test = test;
}
}", index: 1, parameters: OmitIfDefault_Warning);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsInitializeParameter)]
public async Task TestInitializeStructField_RequiredAccessibilityNever()
{
await TestInRegularAndScript1Async(
@"
struct S
{
public Test(int [|test|])
{
}
}",
@"
struct S
{
readonly int test;
public Test(int test)
{
this.test = test;
}
}", index: 1, parameters: Never_Warning);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsInitializeParameter)]
public async Task TestInitializeStructField_RequiredAccessibilityAlways()
{
await TestInRegularAndScript1Async(
@"
struct S
{
public Test(int [|test|])
{
}
}",
@"
struct S
{
private readonly int test;
public Test(int test)
{
this.test = test;
}
}", index: 1, parameters: Always_Warning);
}
private TestParameters OmitIfDefault_Warning => new TestParameters(options: Option(CodeStyleOptions.RequireAccessibilityModifiers, AccessibilityModifiersRequired.OmitIfDefault, NotificationOption.Warning));
private TestParameters Never_Warning => new TestParameters(options: Option(CodeStyleOptions.RequireAccessibilityModifiers, AccessibilityModifiersRequired.Never, NotificationOption.Warning));
private TestParameters Always_Warning => new TestParameters(options: Option(CodeStyleOptions.RequireAccessibilityModifiers, AccessibilityModifiersRequired.Always, NotificationOption.Warning));
}
}
' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
Imports Microsoft.CodeAnalysis.CodeRefactorings
Imports Microsoft.CodeAnalysis.CodeStyle
Imports Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.CodeRefactorings
Imports Microsoft.CodeAnalysis.VisualBasic.InitializeParameter
......@@ -455,5 +456,260 @@ class C
end sub
end class")
End Function
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsInitializeParameter)>
Public Async Function TestInitializeClassProperty_RequiredAccessibilityOmitIfDefault() As Task
Await TestInRegularAndScript1Async("
Class C
ReadOnly test As Integer = 5
Public Sub New(ByVal test As Integer, ByVal [|test2|] As Integer)
End Sub
End Class
", "
Class C
ReadOnly test As Integer = 5
Public Sub New(ByVal test As Integer, ByVal test2 As Integer)
Me.Test2 = test2
End Sub
ReadOnly Property Test2 As Integer
End Class
", index:=0, parameters:=OmitIfDefault_Warning)
End Function
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsInitializeParameter)>
Public Async Function TestInitializeClassProperty_RequiredAccessibilityNever() As Task
Await TestInRegularAndScript1Async("
Class C
ReadOnly test As Integer = 5
Public Sub New(ByVal test As Integer, ByVal [|test2|] As Integer)
End Sub
End Class
", "
Class C
ReadOnly test As Integer = 5
Public Sub New(ByVal test As Integer, ByVal test2 As Integer)
Me.Test2 = test2
End Sub
ReadOnly Property Test2 As Integer
End Class
", index:=0, parameters:=Never_Warning)
End Function
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsInitializeParameter)>
Public Async Function TestInitializeClassProperty_RequiredAccessibilityAlways() As Task
Await TestInRegularAndScript1Async("
Class C
ReadOnly test As Integer = 5
Public Sub New(ByVal test As Integer, ByVal [|test2|] As Integer)
End Sub
End Class
", "
Class C
ReadOnly test As Integer = 5
Public Sub New(ByVal test As Integer, ByVal test2 As Integer)
Me.Test2 = test2
End Sub
Public ReadOnly Property Test2 As Integer
End Class
", index:=0, parameters:=Always_Warning)
End Function
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsInitializeParameter)>
Public Async Function TestInitializeClassField_RequiredAccessibilityOmitIfDefault() As Task
Await TestInRegularAndScript1Async("
Class C
ReadOnly test As Integer = 5
Public Sub New(ByVal test As Integer, ByVal [|test2|] As Integer)
End Sub
End Class
", "
Class C
ReadOnly test2 As Integer
ReadOnly test As Integer = 5
Public Sub New(ByVal test As Integer, ByVal test2 As Integer)
Me.test2 = test2
End Sub
End Class
", index:=1, parameters:=OmitIfDefault_Warning)
End Function
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsInitializeParameter)>
Public Async Function TestInitializeClassField_RequiredAccessibilityNever() As Task
Await TestInRegularAndScript1Async("
Class C
ReadOnly test As Integer = 5
Public Sub New(ByVal test As Integer, ByVal [|test2|] As Integer)
End Sub
End Class
", "
Class C
ReadOnly test2 As Integer
ReadOnly test As Integer = 5
Public Sub New(ByVal test As Integer, ByVal test2 As Integer)
Me.test2 = test2
End Sub
End Class
", index:=1, parameters:=Never_Warning)
End Function
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsInitializeParameter)>
Public Async Function TestInitializeClassField_RequiredAccessibilityAlways() As Task
Await TestInRegularAndScript1Async("
Class C
ReadOnly test As Integer = 5
Public Sub New(ByVal test As Integer, ByVal [|test2|] As Integer)
End Sub
End Class
", "
Class C
ReadOnly test As Integer = 5
Private ReadOnly test2 As Integer
Public Sub New(ByVal test As Integer, ByVal test2 As Integer)
Me.test2 = test2
End Sub
End Class
", index:=1, parameters:=Always_Warning)
End Function
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsInitializeParameter)>
Public Async Function TestInitializeStructProperty_RequiredAccessibilityOmitIfDefault() As Task
Await TestInRegularAndScript1Async("
Structure S
Public Sub New(ByVal [|test|] As Integer)
End Sub
End Structure
", "
Structure S
Public Sub New(ByVal test As Integer)
Me.Test = test
End Sub
ReadOnly Property Test As Integer
End Structure
", index:=0, parameters:=OmitIfDefault_Warning)
End Function
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsInitializeParameter)>
Public Async Function TestInitializeStructProperty_RequiredAccessibilityNever() As Task
Await TestInRegularAndScript1Async("
Structure S
Public Sub New(ByVal [|test|] As Integer)
End Sub
End Structure
", "
Structure S
Public Sub New(ByVal test As Integer)
Me.Test = test
End Sub
ReadOnly Property Test As Integer
End Structure
", index:=0, parameters:=Never_Warning)
End Function
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsInitializeParameter)>
Public Async Function TestInitializeStructProperty_RequiredAccessibilityAlways() As Task
Await TestInRegularAndScript1Async("
Structure S
Public Sub New(ByVal [|test|] As Integer)
End Sub
End Structure
", "
Structure S
Public Sub New(ByVal test As Integer)
Me.Test = test
End Sub
Public ReadOnly Property Test As Integer
End Structure
", index:=0, parameters:=Always_Warning)
End Function
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsInitializeParameter)>
Public Async Function TestInitializeStructField_RequiredAccessibilityOmitIfDefault() As Task
Await TestInRegularAndScript1Async("
Structure S
Public Sub New(ByVal [|test|] As Integer)
End Sub
End Structure
", "
Structure S
Private ReadOnly test As Integer
Public Sub New(ByVal test As Integer)
Me.test = test
End Sub
End Structure
", index:=1, parameters:=OmitIfDefault_Warning)
End Function
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsInitializeParameter)>
Public Async Function TestInitializeStructField_RequiredAccessibilityNever() As Task
Await TestInRegularAndScript1Async("
Structure S
Public Sub New(ByVal [|test|] As Integer)
End Sub
End Structure
", "
Structure S
Private ReadOnly test As Integer
Public Sub New(ByVal test As Integer)
Me.test = test
End Sub
End Structure
", index:=1, parameters:=Never_Warning)
End Function
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsInitializeParameter)>
Public Async Function TestInitializeStructField_RequiredAccessibilityAlways() As Task
Await TestInRegularAndScript1Async("
Structure S
Public Sub New(ByVal [|test|] As Integer)
End Sub
End Structure
", "
Structure S
Private ReadOnly test As Integer
Public Sub New(ByVal test As Integer)
Me.test = test
End Sub
End Structure
", index:=1, parameters:=Always_Warning)
End Function
Private ReadOnly Property OmitIfDefault_Warning As TestParameters
Get
Return New TestParameters(options:=[Option](CodeStyleOptions.RequireAccessibilityModifiers, AccessibilityModifiersRequired.OmitIfDefault, NotificationOption.Warning))
End Get
End Property
Private ReadOnly Property Never_Warning As TestParameters
Get
Return New TestParameters(options:=[Option](CodeStyleOptions.RequireAccessibilityModifiers, AccessibilityModifiersRequired.Never, NotificationOption.Warning))
End Get
End Property
Private ReadOnly Property Always_Warning As TestParameters
Get
Return New TestParameters(options:=[Option](CodeStyleOptions.RequireAccessibilityModifiers, AccessibilityModifiersRequired.Always, NotificationOption.Warning))
End Get
End Property
End Class
End Namespace
......@@ -35,5 +35,13 @@ protected override void InsertStatement(SyntaxEditor editor, SyntaxNode function
protected override bool IsImplicitConversion(Compilation compilation, ITypeSymbol source, ITypeSymbol destination)
=> InitializeParameterHelpers.IsImplicitConversion(compilation, source, destination);
// Fields are always private by default in C#.
protected override Accessibility DetermineDefaultFieldAccessibility(INamedTypeSymbol containingType)
=> Accessibility.Private;
// Properties are always private by default in C#.
protected override Accessibility DetermineDefaultPropertyAccessibility()
=> Accessibility.Private;
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeGeneration;
using Microsoft.CodeAnalysis.CodeStyle;
using Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles;
using Microsoft.CodeAnalysis.Editing;
using Microsoft.CodeAnalysis.ErrorReporting;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Operations;
using Microsoft.CodeAnalysis.Shared.Extensions;
......@@ -32,6 +31,12 @@ internal abstract partial class AbstractInitializeMemberFromParameterCodeRefacto
where TStatementSyntax : SyntaxNode
where TExpressionSyntax : SyntaxNode
{
protected abstract SyntaxNode TryGetLastStatement(IBlockOperation blockStatementOpt);
protected abstract Accessibility DetermineDefaultFieldAccessibility(INamedTypeSymbol containingType);
protected abstract Accessibility DetermineDefaultPropertyAccessibility();
// Standard field/property names we look for when we have a parameter with a given name.
// We also use the rules to help generate fresh fields/properties. Note that we always
// look at these rules *after* the user's own rules. That way we respect user naming, but
......@@ -53,8 +58,6 @@ internal abstract partial class AbstractInitializeMemberFromParameterCodeRefacto
new NamingStyles.NamingStyle(Guid.NewGuid(), prefix: "_", capitalizationScheme: Capitalization.CamelCase),
enforcementLevel: ReportDiagnostic.Hidden));
protected abstract SyntaxNode TryGetLastStatement(IBlockOperation blockStatementOpt);
protected override async Task<ImmutableArray<CodeAction>> GetRefactoringsAsync(
Document document, IParameterSymbol parameter, SyntaxNode functionDeclaration, IMethodSymbol method,
IBlockOperation blockStatementOpt, CancellationToken cancellationToken)
......@@ -108,8 +111,11 @@ internal abstract partial class AbstractInitializeMemberFromParameterCodeRefacto
var parameterNameParts = this.GetParameterWordParts(parameter);
var rules = await this.GetNamingRulesAsync(document, cancellationToken).ConfigureAwait(false);
var field = CreateField(parameter, rules, parameterNameParts);
var property = CreateProperty(parameter, rules, parameterNameParts);
var options = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false);
var requireAccessibilityModifiers = options.GetOption(CodeStyleOptions.RequireAccessibilityModifiers);
var field = CreateField(requireAccessibilityModifiers, parameter, rules, parameterNameParts);
var property = CreateProperty(requireAccessibilityModifiers, parameter, rules, parameterNameParts);
// Offer to generate either a property or a field. Currently we place the property
// suggestion first (to help users with the immutable object+property pattern). But
......@@ -123,7 +129,10 @@ internal abstract partial class AbstractInitializeMemberFromParameterCodeRefacto
}
private IFieldSymbol CreateField(
IParameterSymbol parameter, ImmutableArray<NamingRule> rules, ImmutableArray<string> parameterNameParts)
CodeStyleOption<AccessibilityModifiersRequired> requireAccessibilityModifiers,
IParameterSymbol parameter,
ImmutableArray<NamingRule> rules,
ImmutableArray<string> parameterNameParts)
{
foreach (var rule in rules)
{
......@@ -131,9 +140,19 @@ internal abstract partial class AbstractInitializeMemberFromParameterCodeRefacto
{
var uniqueName = GenerateUniqueName(parameter, parameterNameParts, rule);
var accessibilityLevel = Accessibility.Private;
if (requireAccessibilityModifiers.Value == AccessibilityModifiersRequired.Never || requireAccessibilityModifiers.Value == AccessibilityModifiersRequired.OmitIfDefault)
{
var defaultAccessibility = DetermineDefaultFieldAccessibility(parameter.ContainingType);
if (defaultAccessibility == Accessibility.Private)
{
accessibilityLevel = Accessibility.NotApplicable;
}
}
return CodeGenerationSymbolFactory.CreateFieldSymbol(
default,
Accessibility.Private,
accessibilityLevel,
DeclarationModifiers.ReadOnly,
parameter.Type, uniqueName);
}
......@@ -158,7 +177,10 @@ private static string GenerateUniqueName(IParameterSymbol parameter, ImmutableAr
}
private IPropertySymbol CreateProperty(
IParameterSymbol parameter, ImmutableArray<NamingRule> rules, ImmutableArray<string> parameterNameParts)
CodeStyleOption<AccessibilityModifiersRequired> requireAccessibilityModifiers,
IParameterSymbol parameter,
ImmutableArray<NamingRule> rules,
ImmutableArray<string> parameterNameParts)
{
foreach (var rule in rules)
{
......@@ -166,6 +188,16 @@ private static string GenerateUniqueName(IParameterSymbol parameter, ImmutableAr
{
var uniqueName = GenerateUniqueName(parameter, parameterNameParts, rule);
var accessibilityLevel = Accessibility.Public;
if (requireAccessibilityModifiers.Value == AccessibilityModifiersRequired.Never || requireAccessibilityModifiers.Value == AccessibilityModifiersRequired.OmitIfDefault)
{
var defaultAccessibility = DetermineDefaultPropertyAccessibility();
if (defaultAccessibility == Accessibility.Public)
{
accessibilityLevel = Accessibility.NotApplicable;
}
}
var getMethod = CodeGenerationSymbolFactory.CreateAccessorSymbol(
default,
Accessibility.Public,
......@@ -173,7 +205,7 @@ private static string GenerateUniqueName(IParameterSymbol parameter, ImmutableAr
return CodeGenerationSymbolFactory.CreatePropertySymbol(
default,
Accessibility.Public,
accessibilityLevel,
new DeclarationModifiers(),
parameter.Type,
RefKind.None,
......@@ -484,7 +516,7 @@ private IOperation TryFindFieldOrPropertyAssignmentStatement(IParameterSymbol pa
private ImmutableArray<string> GetParameterWordParts(IParameterSymbol parameter)
{
var parts = StringBreaker.GetWordParts(parameter.Name);
var result = CreateWords(parts, parameter.Name);
var result = CreateWords(parts, parameter.Name);
parts.Free();
return result;
}
......
......@@ -5,6 +5,7 @@ Imports System.Threading
Imports Microsoft.CodeAnalysis.CodeRefactorings
Imports Microsoft.CodeAnalysis.Editing
Imports Microsoft.CodeAnalysis.InitializeParameter
Imports Microsoft.CodeAnalysis.LanguageServices
Imports Microsoft.CodeAnalysis.Operations
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
......@@ -40,5 +41,15 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.InitializeParameter
Protected Overrides Sub InsertStatement(editor As SyntaxEditor, functionDeclaration As SyntaxNode, method As IMethodSymbol, statementToAddAfterOpt As SyntaxNode, statement As StatementSyntax)
InitializeParameterHelpers.InsertStatement(editor, functionDeclaration, statementToAddAfterOpt, statement)
End Sub
' Fields are public by default in VB, except in the case of classes and modules.
Protected Overrides Function DetermineDefaultFieldAccessibility(containingType As INamedTypeSymbol) As Accessibility
Return If(containingType.TypeKind = TypeKind.Class Or containingType.TypeKind = TypeKind.Module, Accessibility.Private, Accessibility.Public)
End Function
' Properties are always public by default in VB.
Protected Overrides Function DetermineDefaultPropertyAccessibility() As Accessibility
Return Accessibility.Public
End Function
End Class
End Namespace
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册