提交 6abf8303 编写于 作者: C CyrusNajmabadi

Respect code style when converting properties to methods.

上级 9f1988a6
......@@ -681,7 +681,8 @@ public async Task TestComputedPropWithTrailingTriviaAfterArrow()
{
public int GetProp()
{
return /* return 42 */ 42;
/* return 42 */
return 42;
}
}", compareTokens: false);
}
......@@ -1160,18 +1161,18 @@ public static void Bar()
}",
@"public class Foo
{
private readonly bool any;
private readonly bool any;
public bool GetAny()
{
return any;
}
public bool GetAny()
{
return any;
}
public static void Bar()
{
var foo = new Foo();
bool f = foo?.GetAny() == true;
}
public static void Bar()
{
var foo = new Foo();
bool f = foo?.GetAny() == true;
}
}");
}
}
......
......@@ -4,11 +4,14 @@
using System.Composition;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CSharp.CodeStyle;
using Microsoft.CodeAnalysis.CSharp.Extensions;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Editing;
using Microsoft.CodeAnalysis.Formatting;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.ReplacePropertyWithMethods;
using Roslyn.Utilities;
......@@ -40,7 +43,7 @@ public override SyntaxNode GetPropertyDeclaration(SyntaxToken token)
return containingProperty;
}
public override IList<SyntaxNode> GetReplacementMembers(
public override async Task<IList<SyntaxNode>> GetReplacementMembersAsync(
Document document,
IPropertySymbol property,
SyntaxNode propertyDeclarationNode,
......@@ -55,7 +58,12 @@ public override SyntaxNode GetPropertyDeclaration(SyntaxToken token)
return SpecializedCollections.EmptyList<SyntaxNode>();
}
var documentOptions = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false);
var syntaxTree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);
var parseOptions = syntaxTree.Options;
return ConvertPropertyToMembers(
documentOptions, parseOptions,
SyntaxGenerator.GetGenerator(document), property,
propertyDeclaration, propertyBackingField,
desiredGetMethodName, desiredSetMethodName,
......@@ -63,6 +71,8 @@ public override SyntaxNode GetPropertyDeclaration(SyntaxToken token)
}
private List<SyntaxNode> ConvertPropertyToMembers(
DocumentOptionSet documentOptions,
ParseOptions parseOptions,
SyntaxGenerator generator,
IPropertySymbol property,
PropertyDeclarationSyntax propertyDeclaration,
......@@ -83,6 +93,7 @@ public override SyntaxNode GetPropertyDeclaration(SyntaxToken token)
if (getMethod != null)
{
result.Add(GetGetMethod(
documentOptions, parseOptions,
generator, propertyDeclaration, propertyBackingField,
getMethod, desiredGetMethodName, cancellationToken));
}
......@@ -91,6 +102,7 @@ public override SyntaxNode GetPropertyDeclaration(SyntaxToken token)
if (setMethod != null)
{
result.Add(GetSetMethod(
documentOptions, parseOptions,
generator, propertyDeclaration, propertyBackingField,
setMethod, desiredSetMethodName, cancellationToken));
}
......@@ -99,6 +111,25 @@ public override SyntaxNode GetPropertyDeclaration(SyntaxToken token)
}
private static SyntaxNode GetSetMethod(
DocumentOptionSet documentOptions,
ParseOptions parseOptions,
SyntaxGenerator generator,
PropertyDeclarationSyntax propertyDeclaration,
IFieldSymbol propertyBackingField,
IMethodSymbol setMethod,
string desiredSetMethodName,
CancellationToken cancellationToken)
{
var methodDeclaration = GetSetMethodWorker(
generator, propertyDeclaration, propertyBackingField,
setMethod, desiredSetMethodName, cancellationToken);
return UseExpressionOrBlockBodyIfDesired(
documentOptions, parseOptions, methodDeclaration,
createReturnStatementForExpression: false);
}
private static MethodDeclarationSyntax GetSetMethodWorker(
SyntaxGenerator generator,
PropertyDeclarationSyntax propertyDeclaration,
IFieldSymbol propertyBackingField,
......@@ -107,27 +138,79 @@ public override SyntaxNode GetPropertyDeclaration(SyntaxToken token)
CancellationToken cancellationToken)
{
var setAccessorDeclaration = (AccessorDeclarationSyntax)setMethod.DeclaringSyntaxReferences[0].GetSyntax(cancellationToken);
var methodDeclaration = (MethodDeclarationSyntax)generator.MethodDeclaration(setMethod, desiredSetMethodName);
var statements = new List<SyntaxNode>();
if (setAccessorDeclaration?.Body != null)
if (setAccessorDeclaration.Body != null)
{
return methodDeclaration.WithBody(setAccessorDeclaration.Body)
.WithAdditionalAnnotations(Formatter.Annotation);
}
else if (setAccessorDeclaration.ExpressionBody != null)
{
statements.AddRange(setAccessorDeclaration.Body.Statements.Select(WithFormattingAnnotation));
return methodDeclaration.WithBody(null)
.WithExpressionBody(setAccessorDeclaration.ExpressionBody)
.WithSemicolonToken(setAccessorDeclaration.SemicolonToken);
}
else if (propertyBackingField != null)
{
statements.Add(generator.ExpressionStatement(
generator.AssignmentStatement(
GetFieldReference(generator, propertyBackingField),
generator.IdentifierName("value"))));
return methodDeclaration.WithBody(SyntaxFactory.Block(
(StatementSyntax)generator.ExpressionStatement(
generator.AssignmentStatement(
GetFieldReference(generator, propertyBackingField),
generator.IdentifierName("value")))));
}
return generator.MethodDeclaration(setMethod, desiredSetMethodName, statements);
return methodDeclaration;
}
private static StatementSyntax WithFormattingAnnotation(StatementSyntax statement)
=> statement.WithAdditionalAnnotations(Formatter.Annotation);
private static SyntaxNode GetGetMethod(
DocumentOptionSet documentOptions,
ParseOptions parseOptions,
SyntaxGenerator generator,
PropertyDeclarationSyntax propertyDeclaration,
IFieldSymbol propertyBackingField,
IMethodSymbol getMethod,
string desiredGetMethodName,
CancellationToken cancellationToken)
{
var methodDeclaration = GetGetMethodWorker(
generator, propertyDeclaration, propertyBackingField, getMethod,
desiredGetMethodName, cancellationToken);
return UseExpressionOrBlockBodyIfDesired(
documentOptions, parseOptions, methodDeclaration,
createReturnStatementForExpression: true);
}
private static SyntaxNode UseExpressionOrBlockBodyIfDesired(
DocumentOptionSet documentOptions, ParseOptions parseOptions,
MethodDeclarationSyntax methodDeclaration, bool createReturnStatementForExpression)
{
var preferExpressionBody = documentOptions.GetOption(CSharpCodeStyleOptions.PreferExpressionBodiedMethods).Value;
if (methodDeclaration?.Body != null && preferExpressionBody)
{
if (methodDeclaration.Body.TryConvertToExpressionBody(
parseOptions, out var arrowExpression, out var semicolonToken))
{
return methodDeclaration.WithBody(null)
.WithExpressionBody(arrowExpression)
.WithSemicolonToken(semicolonToken)
.WithAdditionalAnnotations(Formatter.Annotation);
}
}
else if (methodDeclaration?.ExpressionBody != null && !preferExpressionBody)
{
var block = methodDeclaration?.ExpressionBody.ConvertToBlock(
methodDeclaration.SemicolonToken, createReturnStatementForExpression);
return methodDeclaration.WithExpressionBody(null)
.WithSemicolonToken(default(SyntaxToken))
.WithBody(block)
.WithAdditionalAnnotations(Formatter.Annotation);
}
return methodDeclaration;
}
private static MethodDeclarationSyntax GetGetMethodWorker(
SyntaxGenerator generator,
PropertyDeclarationSyntax propertyDeclaration,
IFieldSymbol propertyBackingField,
......@@ -135,34 +218,31 @@ private static StatementSyntax WithFormattingAnnotation(StatementSyntax statemen
string desiredGetMethodName,
CancellationToken cancellationToken)
{
var statements = new List<SyntaxNode>();
var methodDeclaration = (MethodDeclarationSyntax)generator.MethodDeclaration(getMethod, desiredGetMethodName);
if (propertyDeclaration.ExpressionBody != null)
{
var returnKeyword = SyntaxFactory.Token(SyntaxKind.ReturnKeyword)
.WithTrailingTrivia(propertyDeclaration.ExpressionBody.ArrowToken.TrailingTrivia);
var returnStatement = SyntaxFactory.ReturnStatement(
returnKeyword,
propertyDeclaration.ExpressionBody.Expression,
propertyDeclaration.SemicolonToken);
statements.Add(returnStatement);
methodDeclaration = methodDeclaration.WithBody(null)
.WithExpressionBody(propertyDeclaration.ExpressionBody)
.WithSemicolonToken(propertyDeclaration.SemicolonToken);
}
else
{
var getAccessorDeclaration = (AccessorDeclarationSyntax)getMethod.DeclaringSyntaxReferences[0].GetSyntax(cancellationToken);
if (getAccessorDeclaration?.Body != null)
{
statements.AddRange(getAccessorDeclaration.Body.Statements.Select(WithFormattingAnnotation));
methodDeclaration = methodDeclaration.WithBody(getAccessorDeclaration.Body);
}
else if (propertyBackingField != null)
{
var fieldReference = GetFieldReference(generator, propertyBackingField);
statements.Add(generator.ReturnStatement(fieldReference));
methodDeclaration = methodDeclaration.WithBody(
SyntaxFactory.Block(
(StatementSyntax)generator.ReturnStatement(fieldReference)));
}
}
return generator.MethodDeclaration(getMethod, desiredGetMethodName, statements);
return methodDeclaration;
}
public override SyntaxNode GetPropertyNodeToReplace(SyntaxNode propertyDeclaration)
......
using System;
// 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.Threading;
using System.Threading.Tasks;
......@@ -18,7 +20,7 @@ internal abstract class AbstractReplacePropertyWithMethodsService<TIdentifierNam
{
public abstract SyntaxNode GetPropertyDeclaration(SyntaxToken token);
public abstract SyntaxNode GetPropertyNodeToReplace(SyntaxNode propertyDeclaration);
public abstract IList<SyntaxNode> GetReplacementMembers(Document document, IPropertySymbol property, SyntaxNode propertyDeclaration, IFieldSymbol propertyBackingField, string desiredGetMethodName, string desiredSetMethodName, CancellationToken cancellationToken);
public abstract Task<IList<SyntaxNode>> GetReplacementMembersAsync(Document document, IPropertySymbol property, SyntaxNode propertyDeclaration, IFieldSymbol propertyBackingField, string desiredGetMethodName, string desiredSetMethodName, CancellationToken cancellationToken);
protected abstract TExpressionSyntax UnwrapCompoundAssignment(SyntaxNode compoundAssignment, TExpressionSyntax readExpression);
......
using System.Collections.Generic;
// 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.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Editing;
......@@ -17,7 +19,7 @@ internal interface IReplacePropertyWithMethodsService : ILanguageService
string desiredGetMethodName, string desiredSetMethodName,
CancellationToken cancellationToken);
IList<SyntaxNode> GetReplacementMembers(
Task<IList<SyntaxNode>> GetReplacementMembersAsync(
Document document,
IPropertySymbol property, SyntaxNode propertyDeclaration,
IFieldSymbol propertyBackingField,
......
using System;
// 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.Composition;
......@@ -347,12 +349,12 @@ private string GetDefinitionIssues(IEnumerable<ReferencedSymbol> getMethodRefere
var propertyDefinition = definition.property;
var propertyDeclaration = definition.declaration;
var members = service.GetReplacementMembers(
var members = await service.GetReplacementMembersAsync(
updatedDocument,
propertyDefinition, propertyDeclaration,
definitionToBackingField.GetValueOrDefault(propertyDefinition),
desiredGetMethodName, desiredSetMethodName,
cancellationToken);
cancellationToken).ConfigureAwait(false);
// Properly make the members fit within an interface if that's what
// we're generating into.
......
......@@ -42,25 +42,25 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeRefactorings.ReplaceMethodWithP
Return containingProperty
End Function
Public Overrides Function GetReplacementMembers(
Public Overrides Function GetReplacementMembersAsync(
document As Document,
[property] As IPropertySymbol,
propertyDeclarationNode As SyntaxNode,
propertyBackingField As IFieldSymbol,
desiredGetMethodName As String,
desiredSetMethodName As String,
cancellationToken As CancellationToken) As IList(Of SyntaxNode)
cancellationToken As CancellationToken) As Task(Of IList(Of SyntaxNode))
Dim propertyStatement = TryCast(propertyDeclarationNode, PropertyStatementSyntax)
If propertyStatement Is Nothing Then
Return SpecializedCollections.EmptyList(Of SyntaxNode)
Return Task.FromResult(SpecializedCollections.EmptyList(Of SyntaxNode))
End If
Return ConvertPropertyToMembers(
Return Task.FromResult(ConvertPropertyToMembers(
SyntaxGenerator.GetGenerator(document), [property],
propertyStatement, propertyBackingField,
desiredGetMethodName, desiredSetMethodName,
cancellationToken)
cancellationToken))
End Function
Private Function ConvertPropertyToMembers(
......
// 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 Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Shared.Extensions;
namespace Microsoft.CodeAnalysis.CSharp.Extensions
{
......@@ -12,6 +13,7 @@ internal static class ArrowExpressionClauseSyntaxExtensions
bool createReturnStatementForExpression)
{
var statement = ConvertToStatement(arrowExpression.Expression, semicolonToken, createReturnStatementForExpression);
statement = statement.WithPrependedLeadingTrivia(arrowExpression.ArrowToken.TrailingTrivia);
return SyntaxFactory.Block(statement);
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册