提交 3506fcad 编写于 作者: C CyrusNajmabadi 提交者: GitHub

Merge pull request #19426 from CyrusNajmabadi/blockSimplification

	Respect user settings around 'Blocks' when adding parameter null checks.
......@@ -755,5 +755,34 @@ static void Main(String bar)
CodeStyleOptions.PreferIntrinsicPredefinedTypeKeywordInMemberAccess,
CodeStyleOptions.FalseWithSuggestionEnforcement)));
}
[WorkItem(19172, "https://github.com/dotnet/roslyn/issues/19172")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsInitializeParameter)]
public async Task TestPreferNoBlock()
{
await TestInRegularAndScript1Async(
@"
using System;
class C
{
public C([||]string s)
{
}
}",
@"
using System;
class C
{
public C(string s)
{
if (s == null)
throw new ArgumentNullException(nameof(s));
}
}", ignoreTrivia: false,
parameters: new TestParameters(options:
Option(CSharpCodeStyleOptions.PreferBraces, CodeStyleOptions.FalseWithNoneEnforcement)));
}
}
}
\ No newline at end of file
......@@ -249,6 +249,7 @@
<Compile Include="IntelliSense\CompletionRulesTests.vb" />
<Compile Include="LanguageServices\SyntaxFactsServiceTests.vb" />
<Compile Include="NamingStyles\NamingStylesTests.vb" />
<Compile Include="Simplification\BlockSimplificationTests.vb" />
<Compile Include="Simplification\SimplifierAPITests.vb" />
<Compile Include="CodeFixes\CodeFixServiceTests.vb" />
<Compile Include="Compilation\CompilationTests.vb" />
......
' 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 System.Threading.Tasks
Imports Microsoft.CodeAnalysis.CodeStyle
Imports Microsoft.CodeAnalysis.CSharp.CodeStyle
Imports Microsoft.CodeAnalysis.Options
Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Simplification
Public Class SimplificationTests
Inherits AbstractSimplificationTests
Private Shared ReadOnly DoNotPreferBraces As Dictionary(Of OptionKey, Object) = New Dictionary(Of OptionKey, Object) From {{New OptionKey(CSharpCodeStyleOptions.PreferBraces), CodeStyleOptions.FalseWithNoneEnforcement}}
<Fact, Trait(Traits.Feature, Traits.Features.Simplification)>
Public Async Function TestCSharp_DoNotSimplifyIfBlock() As Task
Dim input =
<Workspace>
<Project Language="C#" CommonReferences="true">
<Document>
class Program
{
void M()
{
if (true)
{|Simplify:{
return;
}|}
}
}
</Document>
</Project>
</Workspace>
Dim expected =
<code>
class Program
{
void M()
{
if (true)
{
return;
}
}
}
</code>
Await TestAsync(input, expected)
End Function
<Fact, Trait(Traits.Feature, Traits.Features.Simplification)>
Public Async Function TestCSharp_DoNotSimplifyMethodBlock() As Task
Dim input =
<Workspace>
<Project Language="C#" CommonReferences="true">
<Document>
class Program
{
void M()
{|Simplify:{
return;
}|}
}
</Document>
</Project>
</Workspace>
Dim expected =
<code>
class Program
{
void M()
{
return;
}
}
</code>
Await TestAsync(input, expected, DoNotPreferBraces)
End Function
<Fact, Trait(Traits.Feature, Traits.Features.Simplification)>
Public Async Function TestCSharp_DoNotSimplifyTryBlock() As Task
Dim input =
<Workspace>
<Project Language="C#" CommonReferences="true">
<Document>
class Program
{
void M()
{
try
{|Simplify:{
return;
}|}
finally
{
}
}
}
</Document>
</Project>
</Workspace>
Dim expected =
<code>
class Program
{
void M()
{
try
{
return;
}
finally
{
}
}
}
</code>
Await TestAsync(input, expected, DoNotPreferBraces)
End Function
<Fact, Trait(Traits.Feature, Traits.Features.Simplification)>
Public Async Function TestCSharp_SimplifyIfBlock() As Task
Dim input =
<Workspace>
<Project Language="C#" CommonReferences="true">
<Document>
class Program
{
void M()
{
if (true)
{|Simplify:{
return;
}|}
}
}
</Document>
</Project>
</Workspace>
Dim expected =
<code>
class Program
{
void M()
{
if (true)
return;
}
}
</code>
Await TestAsync(input, expected, DoNotPreferBraces)
End Function
<Fact, Trait(Traits.Feature, Traits.Features.Simplification)>
Public Async Function TestCSharp_SimplifyElseBlock() As Task
Dim input =
<Workspace>
<Project Language="C#" CommonReferences="true">
<Document>
class Program
{
void M()
{
if (true)
{
}
else
{|Simplify:{
return;
}|}
}
}
</Document>
</Project>
</Workspace>
Dim expected =
<code>
class Program
{
void M()
{
if (true)
{
}
else
return;
}
}
</code>
Await TestAsync(input, expected, DoNotPreferBraces)
End Function
<Fact, Trait(Traits.Feature, Traits.Features.Simplification)>
Public Async Function TestCSharp_SimplifyWhileBlock() As Task
Dim input =
<Workspace>
<Project Language="C#" CommonReferences="true">
<Document>
class Program
{
void M()
{
while (true)
{|Simplify:{
return;
}|}
}
}
</Document>
</Project>
</Workspace>
Dim expected =
<code>
class Program
{
void M()
{
while (true)
return;
}
}
</code>
Await TestAsync(input, expected, DoNotPreferBraces)
End Function
<Fact, Trait(Traits.Feature, Traits.Features.Simplification)>
Public Async Function TestCSharp_SimplifyDoBlock() As Task
Dim input =
<Workspace>
<Project Language="C#" CommonReferences="true">
<Document>
class Program
{
void M()
{
do
{|Simplify:{
return;
}|}
while (true);
}
}
</Document>
</Project>
</Workspace>
Dim expected =
<code>
class Program
{
void M()
{
do
return;
while (true);
}
}
</code>
Await TestAsync(input, expected, DoNotPreferBraces)
End Function
<Fact, Trait(Traits.Feature, Traits.Features.Simplification)>
Public Async Function TestCSharp_SimplifyUsingBlock() As Task
Dim input =
<Workspace>
<Project Language="C#" CommonReferences="true">
<Document>
class Program
{
void M()
{
using (x)
{|Simplify:{
return;
}|}
}
}
</Document>
</Project>
</Workspace>
Dim expected =
<code>
class Program
{
void M()
{
using (x)
return;
}
}
</code>
Await TestAsync(input, expected, DoNotPreferBraces)
End Function
<Fact, Trait(Traits.Feature, Traits.Features.Simplification)>
Public Async Function TestCSharp_SimplifyLockBlock() As Task
Dim input =
<Workspace>
<Project Language="C#" CommonReferences="true">
<Document>
class Program
{
void M()
{
lock (x)
{|Simplify:{
return;
}|}
}
}
</Document>
</Project>
</Workspace>
Dim expected =
<code>
class Program
{
void M()
{
lock (x)
return;
}
}
</code>
Await TestAsync(input, expected, DoNotPreferBraces)
End Function
<Fact, Trait(Traits.Feature, Traits.Features.Simplification)>
Public Async Function TestCSharp_SimplifyForBlock() As Task
Dim input =
<Workspace>
<Project Language="C#" CommonReferences="true">
<Document>
class Program
{
void M()
{
for (;;)
{|Simplify:{
return;
}|}
}
}
</Document>
</Project>
</Workspace>
Dim expected =
<code>
class Program
{
void M()
{
for (;;)
return;
}
}
</code>
Await TestAsync(input, expected, DoNotPreferBraces)
End Function
<Fact, Trait(Traits.Feature, Traits.Features.Simplification)>
Public Async Function TestCSharp_SimplifyForeachBlock() As Task
Dim input =
<Workspace>
<Project Language="C#" CommonReferences="true">
<Document>
class Program
{
void M()
{
foreach (var x in y)
{|Simplify:{
return;
}|}
}
}
</Document>
</Project>
</Workspace>
Dim expected =
<code>
class Program
{
void M()
{
foreach (var x in y)
return;
}
}
</code>
Await TestAsync(input, expected, DoNotPreferBraces)
End Function
End Class
End Namespace
\ No newline at end of file
......@@ -663,7 +663,6 @@ class Foo{
</code>
Await TestAsync(input, expected)
End Function
<WorkItem(619292, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/619292")>
......
......@@ -3524,9 +3524,7 @@ public override SyntaxNode IfStatement(SyntaxNode condition, IEnumerable<SyntaxN
}
private BlockSyntax CreateBlock(IEnumerable<SyntaxNode> statements)
{
return SyntaxFactory.Block(AsStatementList(statements));
}
=> SyntaxFactory.Block(AsStatementList(statements)).WithAdditionalAnnotations(Simplifier.Annotation);
private SyntaxList<StatementSyntax> AsStatementList(IEnumerable<SyntaxNode> nodes)
{
......
......@@ -31,6 +31,15 @@ public override SyntaxNode VisitParenthesizedLambdaExpression(ParenthesizedLambd
parentNode: node.Parent,
simplifier: s_simplifyParenthesizedLambdaExpression);
}
public override SyntaxNode VisitBlock(BlockSyntax node)
{
return SimplifyNode(
node,
newNode: base.VisitBlock(node),
parentNode: node.Parent,
simplifier: s_simplifyBlock);
}
}
}
}
\ No newline at end of file
......@@ -3,6 +3,7 @@
using System;
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis.CSharp.CodeStyle;
using Microsoft.CodeAnalysis.CSharp.Extensions;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.CSharp.Utilities;
......@@ -22,20 +23,20 @@ public CSharpMiscellaneousReducer() : base(s_pool)
}
private static bool CanRemoveTypeFromParameter(
SyntaxNode node,
ParameterSyntax parameterSyntax,
SemanticModel semanticModel,
CancellationToken cancellationToken)
{
// We reduce any the parameters that are contained inside ParameterList
if (node != null && node.IsParentKind(SyntaxKind.ParameterList) && node.Parent.IsParentKind(SyntaxKind.ParenthesizedLambdaExpression))
if (parameterSyntax.IsParentKind(SyntaxKind.ParameterList) &&
parameterSyntax.Parent.IsParentKind(SyntaxKind.ParenthesizedLambdaExpression))
{
var parameterSyntax = (ParameterSyntax)node;
if (parameterSyntax.Type != null)
{
var annotation = new SyntaxAnnotation();
var newParameterSyntax = parameterSyntax.WithType(null).WithAdditionalAnnotations(annotation);
var oldLambda = node.FirstAncestorOrSelf<ParenthesizedLambdaExpressionSyntax>();
var oldLambda = parameterSyntax.FirstAncestorOrSelf<ParenthesizedLambdaExpressionSyntax>();
var newLambda = oldLambda.ReplaceNode(parameterSyntax, newParameterSyntax);
var speculationAnalyzer = new SpeculationAnalyzer(oldLambda, newLambda, semanticModel, cancellationToken);
newParameterSyntax = (ParameterSyntax)speculationAnalyzer.ReplacedExpression.GetAnnotatedNodesAndTokens(annotation).First();
......@@ -54,17 +55,17 @@ public CSharpMiscellaneousReducer() : base(s_pool)
return false;
}
private static Func<SyntaxNode, SemanticModel, OptionSet, CancellationToken, SyntaxNode> s_simplifyParameter = SimplifyParameter;
private static Func<ParameterSyntax, SemanticModel, OptionSet, CancellationToken, SyntaxNode> s_simplifyParameter = SimplifyParameter;
private static SyntaxNode SimplifyParameter(
SyntaxNode node,
ParameterSyntax node,
SemanticModel semanticModel,
OptionSet optionSet,
CancellationToken cancellationToken)
{
if (CanRemoveTypeFromParameter(node, semanticModel, cancellationToken))
{
var newParameterSyntax = ((ParameterSyntax)node).WithType(null);
var newParameterSyntax = node.WithType(null);
newParameterSyntax = SimplificationHelpers.CopyAnnotations(node, newParameterSyntax).WithoutAnnotations(Simplifier.Annotation);
return newParameterSyntax;
}
......@@ -72,36 +73,71 @@ public CSharpMiscellaneousReducer() : base(s_pool)
return node;
}
private static readonly Func<SyntaxNode, SemanticModel, OptionSet, CancellationToken, SyntaxNode> s_simplifyParenthesizedLambdaExpression = SimplifyParenthesizedLambdaExpression;
private static readonly Func<ParenthesizedLambdaExpressionSyntax, SemanticModel, OptionSet, CancellationToken, SyntaxNode> s_simplifyParenthesizedLambdaExpression = SimplifyParenthesizedLambdaExpression;
private static SyntaxNode SimplifyParenthesizedLambdaExpression(
SyntaxNode node,
ParenthesizedLambdaExpressionSyntax parenthesizedLambda,
SemanticModel semanticModel,
OptionSet optionSet,
CancellationToken cancellationToken)
{
if (node != null && node is ParenthesizedLambdaExpressionSyntax)
if (parenthesizedLambda.ParameterList != null &&
parenthesizedLambda.ParameterList.Parameters.Count == 1)
{
var parenthesizedLambda = (ParenthesizedLambdaExpressionSyntax)node;
if (parenthesizedLambda.ParameterList != null &&
parenthesizedLambda.ParameterList.Parameters.Count == 1)
var parameter = parenthesizedLambda.ParameterList.Parameters.First();
if (CanRemoveTypeFromParameter(parameter, semanticModel, cancellationToken))
{
var parameter = parenthesizedLambda.ParameterList.Parameters.First();
if (CanRemoveTypeFromParameter(parameter, semanticModel, cancellationToken))
{
var newParameterSyntax = parameter.WithType(null);
var newSimpleLambda = SyntaxFactory.SimpleLambdaExpression(
parenthesizedLambda.AsyncKeyword,
newParameterSyntax.WithTrailingTrivia(parenthesizedLambda.ParameterList.GetTrailingTrivia()),
parenthesizedLambda.ArrowToken,
parenthesizedLambda.Body);
return SimplificationHelpers.CopyAnnotations(parenthesizedLambda, newSimpleLambda).WithoutAnnotations(Simplifier.Annotation);
}
var newParameterSyntax = parameter.WithType(null);
var newSimpleLambda = SyntaxFactory.SimpleLambdaExpression(
parenthesizedLambda.AsyncKeyword,
newParameterSyntax.WithTrailingTrivia(parenthesizedLambda.ParameterList.GetTrailingTrivia()),
parenthesizedLambda.ArrowToken,
parenthesizedLambda.Body);
return SimplificationHelpers.CopyAnnotations(parenthesizedLambda, newSimpleLambda).WithoutAnnotations(Simplifier.Annotation);
}
}
return parenthesizedLambda;
}
private static readonly Func<BlockSyntax, SemanticModel, OptionSet, CancellationToken, SyntaxNode> s_simplifyBlock = SimplifyBlock;
private static SyntaxNode SimplifyBlock(
BlockSyntax node,
SemanticModel semanticModel,
OptionSet optionSet,
CancellationToken cancellationToken)
{
if (node.Statements.Count == 1 &&
CanHaveEmbeddedStatement(node.Parent) &&
!optionSet.GetOption(CSharpCodeStyleOptions.PreferBraces).Value)
{
return node.Statements[0];
}
return node;
}
private static bool CanHaveEmbeddedStatement(SyntaxNode node)
{
if (node != null)
{
switch (node.Kind())
{
case SyntaxKind.IfStatement:
case SyntaxKind.ElseClause:
case SyntaxKind.ForStatement:
case SyntaxKind.ForEachStatement:
case SyntaxKind.ForEachVariableStatement:
case SyntaxKind.WhileStatement:
case SyntaxKind.DoStatement:
case SyntaxKind.UsingStatement:
case SyntaxKind.LockStatement:
return true;
}
}
return false;
}
}
}
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册