提交 110163ef 编写于 作者: C CyrusNajmabadi

Better respect lang version when generating expression bodies.

上级 d010af63
......@@ -427,6 +427,38 @@ void M()
}", options: UseExpressionBody, parseOptions: CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp5));
}
[WorkItem(20352, "https://github.com/dotnet/roslyn/issues/20352")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseExpressionBody)]
public async Task TestDoNotOfferToConvertToBlockIfExpressionBodyPreferredIfCSharp6()
{
await TestMissingAsync(
@"
using System;
class C
{
void M() [|=>|] 0;
}", new TestParameters(options: UseExpressionBody, parseOptions: CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp6)));
}
[WorkItem(20352, "https://github.com/dotnet/roslyn/issues/20352")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseExpressionBody)]
public async Task TestOfferToConvertToExpressionIfCSharp6()
{
await TestAsync(
@"
using System;
class C
{
void M() { [|return|] 0; }
}",
@"
using System;
class C
{
void M() => 0;
}", options: UseExpressionBody, parseOptions: CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp6));
}
[WorkItem(20362, "https://github.com/dotnet/roslyn/issues/20362")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseExpressionBody)]
public async Task TestOfferToConvertToBlockEvenIfExpressionBodyPreferredIfPriorToCSharp6_FixAll()
......
......@@ -95,7 +95,7 @@ public void RemoveSetMethod(SyntaxEditor editor, SyntaxNode setMethodDeclaration
}
else if (getAccessor.Body != null &&
getAccessor.Body.TryConvertToExpressionBody(
parseOptions, expressionBodyPreference,
propertyDeclaration.Kind(), parseOptions, expressionBodyPreference,
out var arrowExpression, out var semicolonToken))
{
return propertyDeclaration.WithExpressionBody(arrowExpression)
......@@ -183,7 +183,7 @@ private SyntaxToken GetPropertyName(SyntaxToken identifier, string propertyName,
if (accessorDeclaration?.Body != null && expressionBodyPreference != ExpressionBodyPreference.Never)
{
if (accessorDeclaration.Body.TryConvertToExpressionBody(
parseOptions, expressionBodyPreference,
accessorDeclaration.Kind(), parseOptions, expressionBodyPreference,
out var arrowExpression, out var semicolonToken))
{
return accessorDeclaration.WithBody(null)
......
......@@ -227,7 +227,8 @@ private static SyntaxTrivia ConvertDocumentationComment(SyntaxTrivia trivia, CSh
if (methodDeclaration?.Body != null && expressionBodyPreference != ExpressionBodyPreference.Never)
{
if (methodDeclaration.Body.TryConvertToExpressionBody(
parseOptions, expressionBodyPreference, out var arrowExpression, out var semicolonToken))
methodDeclaration.Kind(), parseOptions, expressionBodyPreference,
out var arrowExpression, out var semicolonToken))
{
return methodDeclaration.WithBody(null)
.WithExpressionBody(arrowExpression)
......
......@@ -2,7 +2,9 @@
using System;
using System.Collections.Immutable;
using Microsoft.CodeAnalysis.CodeStyle;
using Microsoft.CodeAnalysis.CSharp.CodeStyle;
using Microsoft.CodeAnalysis.CSharp.Extensions;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Options;
......@@ -58,5 +60,16 @@ protected override IndexerDeclarationSyntax WithBody(IndexerDeclarationSyntax de
}
protected override bool CreateReturnStatementForExpression(IndexerDeclarationSyntax declaration) => true;
protected override bool TryConvertToExpressionBody(
IndexerDeclarationSyntax declaration, ParseOptions options,
ExpressionBodyPreference conversionPreference,
out ArrowExpressionClauseSyntax arrowExpression,
out SyntaxToken semicolonToken)
{
return this.TryConvertToExpressionBodyForBaseProperty(
declaration, options, conversionPreference,
out arrowExpression, out semicolonToken);
}
}
}
......@@ -67,21 +67,9 @@ protected override PropertyDeclarationSyntax WithBody(PropertyDeclarationSyntax
out ArrowExpressionClauseSyntax arrowExpression,
out SyntaxToken semicolonToken)
{
if (base.TryConvertToExpressionBody(declaration, options, conversionPreference, out arrowExpression, out semicolonToken))
{
return true;
}
var getAccessor = GetSingleGetAccessor(declaration.AccessorList);
if (getAccessor?.ExpressionBody != null &&
BlockSyntaxExtensions.MatchesPreference(getAccessor.ExpressionBody.Expression, conversionPreference))
{
arrowExpression = SyntaxFactory.ArrowExpressionClause(getAccessor.ExpressionBody.Expression);
semicolonToken = getAccessor.SemicolonToken;
return true;
}
return false;
return this.TryConvertToExpressionBodyForBaseProperty(
declaration, options, conversionPreference,
out arrowExpression, out semicolonToken);
}
protected override Location GetDiagnosticLocation(PropertyDeclarationSyntax declaration)
......
......@@ -111,13 +111,48 @@ protected virtual Location GetDiagnosticLocation(TDeclaration declaration)
ParseOptions options, ExpressionBodyPreference conversionPreference,
out ArrowExpressionClauseSyntax expressionWhenOnSingleLine,
out SyntaxToken semicolonWhenOnSingleLine)
{
return TryConvertToExpressionBodyWorker(
declaration, options, conversionPreference,
out expressionWhenOnSingleLine, out semicolonWhenOnSingleLine);
}
private bool TryConvertToExpressionBodyWorker(
SyntaxNode declaration, ParseOptions options, ExpressionBodyPreference conversionPreference,
out ArrowExpressionClauseSyntax expressionWhenOnSingleLine, out SyntaxToken semicolonWhenOnSingleLine)
{
var body = this.GetBody(declaration);
return body.TryConvertToExpressionBody(options, conversionPreference,
return body.TryConvertToExpressionBody(
declaration.Kind(), options, conversionPreference,
out expressionWhenOnSingleLine, out semicolonWhenOnSingleLine);
}
protected bool TryConvertToExpressionBodyForBaseProperty(
BasePropertyDeclarationSyntax declaration, ParseOptions options,
ExpressionBodyPreference conversionPreference,
out ArrowExpressionClauseSyntax arrowExpression,
out SyntaxToken semicolonToken)
{
if (this.TryConvertToExpressionBodyWorker(
declaration, options, conversionPreference,
out arrowExpression, out semicolonToken))
{
return true;
}
var getAccessor = GetSingleGetAccessor(declaration.AccessorList);
if (getAccessor?.ExpressionBody != null &&
BlockSyntaxExtensions.MatchesPreference(getAccessor.ExpressionBody.Expression, conversionPreference))
{
arrowExpression = SyntaxFactory.ArrowExpressionClause(getAccessor.ExpressionBody.Expression);
semicolonToken = getAccessor.SemicolonToken;
return true;
}
return false;
}
public (bool canOffer, bool fixesError) CanOfferUseBlockBody(
OptionSet optionSet, TDeclaration declaration, bool forAnalyzer)
{
......@@ -171,8 +206,9 @@ protected virtual Location GetDiagnosticLocation(TDeclaration declaration)
{
if (useExpressionBody)
{
TryConvertToExpressionBody(declaration, declaration.SyntaxTree.Options,
ExpressionBodyPreference.WhenPossible, out var expressionBody, out var semicolonToken);
TryConvertToExpressionBody(
declaration, declaration.SyntaxTree.Options, ExpressionBodyPreference.WhenPossible,
out var expressionBody, out var semicolonToken);
var trailingTrivia = semicolonToken.TrailingTrivia
.Where(t => t.Kind() != SyntaxKind.EndOfLineTrivia)
......
......@@ -74,7 +74,8 @@ private static MemberDeclarationSyntax LastConstructorOrField(SyntaxList<MemberD
{
var expressionBodyPreference = workspace.Options.GetOption(CSharpCodeStyleOptions.PreferExpressionBodiedConstructors).Value;
if (declaration.Body.TryConvertToExpressionBody(
options, expressionBodyPreference, out var expressionBody, out var semicolonToken))
declaration.Kind(), options, expressionBodyPreference,
out var expressionBody, out var semicolonToken))
{
return declaration.WithBody(null)
.WithExpressionBody(expressionBody)
......
......@@ -86,7 +86,8 @@ internal static class ConversionGenerator
var expressionBodyPreference = workspace.Options.GetOption(CSharpCodeStyleOptions.PreferExpressionBodiedOperators).Value;
if (declaration.Body.TryConvertToExpressionBody(
options, expressionBodyPreference, out var expressionBody, out var semicolonToken))
declaration.Kind(), options, expressionBodyPreference,
out var expressionBody, out var semicolonToken))
{
return declaration.WithBody(null)
.WithExpressionBody(expressionBody)
......
......@@ -119,7 +119,8 @@ internal static class MethodGenerator
{
var expressionBodyPreference = workspace.Options.GetOption(CSharpCodeStyleOptions.PreferExpressionBodiedMethods).Value;
if (methodDeclaration.Body.TryConvertToExpressionBody(
options, expressionBodyPreference, out var expressionBody, out var semicolonToken))
methodDeclaration.Kind(), options, expressionBodyPreference,
out var expressionBody, out var semicolonToken))
{
return methodDeclaration.WithBody(null)
.WithExpressionBody(expressionBody)
......
......@@ -58,7 +58,8 @@ internal static class OperatorGenerator
{
var expressionBodyPreference = workspace.Options.GetOption(CSharpCodeStyleOptions.PreferExpressionBodiedOperators).Value;
if (declaration.Body.TryConvertToExpressionBody(
options, expressionBodyPreference, out var expressionBody, out var semicolonToken))
declaration.Kind(), options, expressionBodyPreference,
out var expressionBody, out var semicolonToken))
{
return declaration.WithBody(null)
.WithExpressionBody(expressionBody)
......
......@@ -146,16 +146,19 @@ private static TypeSyntax GeneratePropertyType(IPropertySymbol property)
}
private static bool TryGetExpressionBody(
AccessorListSyntax accessorList, ParseOptions options, ExpressionBodyPreference preference,
BasePropertyDeclarationSyntax baseProperty, ParseOptions options, ExpressionBodyPreference preference,
out ArrowExpressionClauseSyntax arrowExpression, out SyntaxToken semicolonToken)
{
var accessorList = baseProperty.AccessorList;
if (preference != ExpressionBodyPreference.Never &&
accessorList.Accessors.Count == 1)
{
var accessor = accessorList.Accessors[0];
if (accessor.IsKind(SyntaxKind.GetAccessorDeclaration))
{
return TryGetExpressionBody(accessor, options, preference, out arrowExpression, out semicolonToken);
return TryGetExpressionBody(
baseProperty.Kind(), accessor, options, preference,
out arrowExpression, out semicolonToken);
}
}
......@@ -172,8 +175,9 @@ private static TypeSyntax GeneratePropertyType(IPropertySymbol property)
var expressionBodyPreference = workspace.Options.GetOption(CSharpCodeStyleOptions.PreferExpressionBodiedProperties).Value;
if (declaration.Initializer == null)
{
if (TryGetExpressionBody(declaration.AccessorList, options,
expressionBodyPreference, out var expressionBody, out var semicolonToken))
if (TryGetExpressionBody(
declaration, options, expressionBodyPreference,
out var expressionBody, out var semicolonToken))
{
declaration = declaration.WithAccessorList(null)
.WithExpressionBody(expressionBody)
......@@ -191,8 +195,9 @@ private static TypeSyntax GeneratePropertyType(IPropertySymbol property)
if (declaration.ExpressionBody == null)
{
var expressionBodyPreference = workspace.Options.GetOption(CSharpCodeStyleOptions.PreferExpressionBodiedIndexers).Value;
if (TryGetExpressionBody(declaration.AccessorList,
options, expressionBodyPreference, out var expressionBody, out var semicolonToken))
if (TryGetExpressionBody(
declaration, options, expressionBodyPreference,
out var expressionBody, out var semicolonToken))
{
declaration = declaration.WithAccessorList(null)
.WithExpressionBody(expressionBody)
......@@ -210,7 +215,8 @@ private static TypeSyntax GeneratePropertyType(IPropertySymbol property)
{
var expressionBodyPreference = workspace.Options.GetOption(CSharpCodeStyleOptions.PreferExpressionBodiedAccessors).Value;
if (declaration.Body.TryConvertToExpressionBody(
options, expressionBodyPreference, out var expressionBody, out var semicolonToken))
declaration.Kind(), options, expressionBodyPreference,
out var expressionBody, out var semicolonToken))
{
declaration = declaration.WithBody(null)
.WithExpressionBody(expressionBody)
......@@ -222,7 +228,7 @@ private static TypeSyntax GeneratePropertyType(IPropertySymbol property)
}
private static bool TryGetExpressionBody(
AccessorDeclarationSyntax accessor, ParseOptions options, ExpressionBodyPreference preference,
SyntaxKind declaratoinKind, AccessorDeclarationSyntax accessor, ParseOptions options, ExpressionBodyPreference preference,
out ArrowExpressionClauseSyntax arrowExpression, out SyntaxToken semicolonToken)
{
// If the accessor has an expression body already, then use that as the expression body
......@@ -235,7 +241,7 @@ private static TypeSyntax GeneratePropertyType(IPropertySymbol property)
}
return accessor.Body.TryConvertToExpressionBody(
options, preference, out arrowExpression, out semicolonToken);
declaratoinKind, options, preference, out arrowExpression, out semicolonToken);
}
private static AccessorListSyntax GenerateAccessorList(
......
......@@ -13,13 +13,19 @@ namespace Microsoft.CodeAnalysis.CSharp.Extensions
internal static class BlockSyntaxExtensions
{
public static bool TryConvertToExpressionBody(
this BlockSyntax block, ParseOptions options,
ExpressionBodyPreference preference,
this BlockSyntax block, SyntaxKind declarationKind,
ParseOptions options, ExpressionBodyPreference preference,
out ArrowExpressionClauseSyntax arrowExpression,
out SyntaxToken semicolonToken)
{
if (preference != ExpressionBodyPreference.Never &&
(options as CSharpParseOptions)?.LanguageVersion >= LanguageVersion.CSharp7)
if (preference != ExpressionBodyPreference.Never)
{
var csharpOptions = (CSharpParseOptions)options;
var acceptableVersion =
csharpOptions.LanguageVersion >= LanguageVersion.CSharp7 ||
(csharpOptions.LanguageVersion >= LanguageVersion.CSharp6 && !RequiresCSharp7(declarationKind));
if (acceptableVersion)
{
if (block != null && block.Statements.Count == 1)
{
......@@ -39,12 +45,29 @@ internal static class BlockSyntaxExtensions
}
}
}
}
arrowExpression = null;
semicolonToken = default;
return false;
}
private static bool RequiresCSharp7(SyntaxKind declarationKind)
{
switch (declarationKind)
{
case SyntaxKind.ConstructorDeclaration:
case SyntaxKind.DestructorDeclaration:
case SyntaxKind.AddAccessorDeclaration:
case SyntaxKind.RemoveAccessorDeclaration:
case SyntaxKind.GetAccessorDeclaration:
case SyntaxKind.SetAccessorDeclaration:
return true;
}
return false;
}
public static bool MatchesPreference(
ExpressionSyntax expression, ExpressionBodyPreference preference)
{
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册