提交 6bb8d9f5 编写于 作者: C Cyrus Najmabadi

PR feedback. Also handle fields with initializers.

上级 ab9cc113
......@@ -19,11 +19,21 @@ protected override bool SupportsReadOnlyProperties(Compilation compilation)
return ((CSharpCompilation)compilation).LanguageVersion >= LanguageVersion.CSharp6;
}
protected override bool SupportsPropertyInitializer(Compilation compilation)
{
return ((CSharpCompilation)compilation).LanguageVersion >= LanguageVersion.CSharp6;
}
protected override void RegisterIneligibleFieldsAction(CompilationStartAnalysisContext context, ConcurrentBag<IFieldSymbol> ineligibleFields)
{
context.RegisterSyntaxNodeAction(snac => AnalyzeArgument(ineligibleFields, snac), SyntaxKind.Argument);
}
protected override ExpressionSyntax GetFieldInitializer(VariableDeclaratorSyntax variable, CancellationToken cancellationToken)
{
return variable.Initializer?.Value;
}
private void AnalyzeArgument(ConcurrentBag<IFieldSymbol> ineligibleFields, SyntaxNodeAnalysisContext context)
{
// An argument will disqualify a field if that field is used in a ref/out position.
......
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Composition;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
......@@ -24,7 +26,7 @@ protected override SyntaxNode GetNodeToRemove(VariableDeclaratorSyntax declarato
return nodeToRemove;
}
protected override SyntaxNode UpdateProperty(
protected override async Task<SyntaxNode> UpdatePropertyAsync(
Project project, Compilation compilation, IFieldSymbol fieldSymbol, IPropertySymbol propertySymbol,
PropertyDeclarationSyntax propertyDeclaration, bool isWrittenOutsideOfConstructor, CancellationToken cancellationToken)
{
......@@ -46,9 +48,22 @@ protected override SyntaxNode GetNodeToRemove(VariableDeclaratorSyntax declarato
updatedProperty = updatedProperty.AddAccessorListAccessors(accessor);
}
var fieldInitializer = await GetFieldInitializerAsync(fieldSymbol, cancellationToken).ConfigureAwait(false);
if (fieldInitializer != null)
{
updatedProperty = updatedProperty.WithInitializer(SyntaxFactory.EqualsValueClause(fieldInitializer))
.WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken));
}
return updatedProperty;
}
private async Task<ExpressionSyntax> GetFieldInitializerAsync(IFieldSymbol fieldSymbol, CancellationToken cancellationToken)
{
var variableDeclarator = (VariableDeclaratorSyntax)await fieldSymbol.DeclaringSyntaxReferences[0].GetSyntaxAsync(cancellationToken).ConfigureAwait(false);
return variableDeclarator.Initializer?.Value;
}
private bool NeedsSetter(Compilation compilation, PropertyDeclarationSyntax propertyDeclaration, bool isWrittenOutsideOfConstructor)
{
if (propertyDeclaration.AccessorList.Accessors.Any(SyntaxKind.SetAccessorDeclaration))
......
......@@ -41,6 +41,22 @@ public void TestCSharp5_2()
CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp5));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseAutoProperty)]
public void TestInitializer()
{
Test(
@"class Class { [|int i = 1|]; int P { get { return i; } } }",
@"class Class { int P { get; } = 1; }");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseAutoProperty)]
public void TestInitializer_CSharp5()
{
TestMissing(
@"class Class { [|int i = 1|]; int P { get { return i; } } }",
CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp5));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseAutoProperty)]
public void TestSingleGetter2()
{
......
......@@ -17,9 +17,18 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UseAutoProperty
Return True
End Function
Protected Overrides Function SupportsPropertyInitializer(compilation As Compilation) As Boolean
Return True
End Function
Protected Overrides Sub RegisterIneligibleFieldsAction(context As CompilationStartAnalysisContext, ineligibleFields As ConcurrentBag(Of IFieldSymbol))
End Sub
Protected Overrides Function GetFieldInitializer(variable As ModifiedIdentifierSyntax, cancellationToken As CancellationToken) As ExpressionSyntax
Dim declarator = TryCast(variable.Parent, VariableDeclaratorSyntax)
Return declarator?.Initializer?.Value
End Function
Private Function CheckExpressionSyntactically(expression As ExpressionSyntax) As Boolean
If expression?.Kind() = SyntaxKind.SimpleMemberAccessExpression Then
Dim memberAccessExpression = DirectCast(expression, MemberAccessExpressionSyntax)
......
Imports System.Composition
Imports System.Threading
Imports System.Threading.Tasks
Imports Microsoft.CodeAnalysis.CodeFixes
Imports Microsoft.CodeAnalysis.Editing
Imports Microsoft.CodeAnalysis.UseAutoProperty
......@@ -15,19 +16,31 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UseAutoProperty
Return Utilities.GetNodeToRemove(identifier)
End Function
Protected Overrides Function UpdateProperty(project As Project,
compilation As Compilation,
fieldSymbol As IFieldSymbol,
propertySymbol As IPropertySymbol,
propertyDeclaration As PropertyBlockSyntax,
isWrittenToOutsideOfConstructor As Boolean,
cancellationToken As CancellationToken) As SyntaxNode
Protected Overrides Async Function UpdatePropertyAsync(project As Project,
compilation As Compilation,
fieldSymbol As IFieldSymbol,
propertySymbol As IPropertySymbol,
propertyDeclaration As PropertyBlockSyntax,
isWrittenToOutsideOfConstructor As Boolean,
cancellationToken As CancellationToken) As Task(Of SyntaxNode)
Dim statement = propertyDeclaration.PropertyStatement
If Not isWrittenToOutsideOfConstructor AndAlso Not propertyDeclaration.Accessors.Any(SyntaxKind.SetAccessorBlock) Then
Dim generator = SyntaxGenerator.GetGenerator(project)
statement = DirectCast(generator.WithModifiers(statement, DeclarationModifiers.ReadOnly), PropertyStatementSyntax)
End If
Dim initializer = Await GetFieldInitializer(fieldSymbol, cancellationToken).ConfigureAwait(False)
If initializer IsNot Nothing Then
statement = statement.WithInitializer(SyntaxFactory.EqualsValue(initializer))
End If
Return statement
End Function
Private Async Function GetFieldInitializer(fieldSymbol As IFieldSymbol, cancellationToken As CancellationToken) As Task(Of ExpressionSyntax)
Dim identifier = TryCast(Await fieldSymbol.DeclaringSyntaxReferences(0).GetSyntaxAsync(cancellationToken).ConfigureAwait(False), ModifiedIdentifierSyntax)
Dim declarator = TryCast(identifier?.Parent, VariableDeclaratorSyntax)
Return declarator?.Initializer?.Value
End Function
End Class
End Namespace
\ No newline at end of file
......@@ -38,6 +38,13 @@ NewLines("class Class1 \n [|dim i as integer|] \n property P as Integer \n get \
NewLines("class Class1 \n property P as Integer \n end class"))
End Sub
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseAutoProperty)>
Public Sub TestInitializer()
Test(
NewLines("class Class1 \n dim i as Integer = 1 \n [|readonly property P as integer \n get \n return i \n end get \n end property|] \n end class"),
NewLines("class Class1 \n readonly property P as integer = 1 \n end class"))
End Sub
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseAutoProperty)>
Public Sub TestDifferentValueName()
Test(
......
......@@ -29,6 +29,8 @@ internal abstract class AbstractUseAutoPropertyAnalyzer<TPropertyDeclaration, TF
protected abstract void RegisterIneligibleFieldsAction(CompilationStartAnalysisContext context, ConcurrentBag<IFieldSymbol> ineligibleFields);
protected abstract bool SupportsReadOnlyProperties(Compilation compilation);
protected abstract bool SupportsPropertyInitializer(Compilation compilation);
protected abstract TExpression GetFieldInitializer(TVariableDeclarator variable, CancellationToken cancellationToken);
protected abstract TExpression GetGetterExpression(IMethodSymbol getMethod, CancellationToken cancellationToken);
protected abstract TExpression GetSetterExpression(IMethodSymbol setMethod, SemanticModel semanticModel, CancellationToken cancellationToken);
protected abstract SyntaxNode GetNodeToFade(TFieldDeclaration fieldDeclaration, TVariableDeclarator variableDeclarator);
......@@ -160,6 +162,12 @@ private void AnalyzeProperty(ConcurrentBag<AnalysisResult> analysisResults, Symb
return;
}
var initializer = GetFieldInitializer(variableDeclarator, cancellationToken);
if (initializer != null && !SupportsPropertyInitializer(symbolContext.Compilation))
{
return;
}
var fieldDeclaration = variableDeclarator?.Parent?.Parent as TFieldDeclaration;
if (fieldDeclaration == null)
{
......
......@@ -29,7 +29,7 @@ internal abstract class AbstractUseAutoPropertyCodeFixProvider<TPropertyDeclarat
protected abstract SyntaxNode GetNodeToRemove(TVariableDeclarator declarator);
protected abstract SyntaxNode UpdateProperty(
protected abstract Task<SyntaxNode> UpdatePropertyAsync(
Project project, Compilation compilation, IFieldSymbol fieldSymbol, IPropertySymbol propertySymbol,
TPropertyDeclaration propertyDeclaration, bool isWrittenOutsideConstructor, CancellationToken cancellationToken);
......@@ -74,8 +74,9 @@ private async Task<Solution> ProcessResult(CodeFixContext context, Diagnostic di
var fieldLocations = await Renamer.GetRenameLocationsAsync(solution, fieldSymbol, solution.Workspace.Options, cancellationToken).ConfigureAwait(false);
// First, create the updated property we want to replace the old property with
var updatedProperty = UpdateProperty(project, compilation, fieldSymbol, propertySymbol, property,
IsWrittenToOutsideOfConstructorOrProperty(fieldSymbol, fieldLocations, property, cancellationToken), cancellationToken);
var isWrittenToOutsideOfConstructor = IsWrittenToOutsideOfConstructorOrProperty(fieldSymbol, fieldLocations, property, cancellationToken);
var updatedProperty = await UpdatePropertyAsync(project, compilation, fieldSymbol, propertySymbol, property,
isWrittenToOutsideOfConstructor, cancellationToken).ConfigureAwait(false);
// Now, rename all usages of the field to point at the property. Except don't actually
// rename the field itself. We want to be able to find it again post rename.
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册