提交 8690221f 编写于 作者: C Cyrus Najmabadi

And logical op inversion.

上级 dd43cb02
// 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.Composition;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeRefactorings;
using Microsoft.CodeAnalysis.CSharp.Extensions;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Editing;
using Microsoft.CodeAnalysis.Shared.Extensions;
namespace Microsoft.CodeAnalysis.CSharp.InvertLogical
{
[ExportCodeRefactoringProvider(LanguageNames.CSharp), Shared]
internal class CSharpInvertLogicalCodeRefactoringProvider : CodeRefactoringProvider
{
private static readonly SyntaxAnnotation s_annotation = new SyntaxAnnotation();
public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
{
var document = context.Document;
var span = context.Span;
var cancellationToken = context.CancellationToken;
var position = span.Start;
var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
var token = root.FindToken(position);
if (span.Length > 0 && span != token.Span)
{
return;
}
if (span.Length == 0 && !token.Span.IntersectsWith(position))
{
return;
}
var parent = token.Parent;
if (!parent.IsKind(SyntaxKind.LogicalAndExpression) &&
!parent.IsKind(SyntaxKind.LogicalOrExpression))
{
return;
}
context.RegisterRefactoring(new MyCodeAction(
GetTitle(parent.Kind()),
c => InvertLogicalAsync(document, position, c)));
}
private async Task<Document> InvertLogicalAsync(
Document document, int position, CancellationToken cancellationToken)
{
var updatedDocument1 = await InvertLeftAndRightOfBinaryAsync(document, position, cancellationToken).ConfigureAwait(false);
var updatedDocument2 = await InvertBinaryAsync(updatedDocument1, cancellationToken).ConfigureAwait(false);
return updatedDocument2;
}
private async Task<Document> InvertBinaryAsync(Document document, CancellationToken cancellationToken)
{
var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
var node = root.GetAnnotatedNodes(s_annotation).Single();
while (node.IsParentKind(SyntaxKind.ParenthesizedExpression) ||
node.IsParentKind(SyntaxKind.LogicalNotExpression))
{
node = node.Parent;
}
var generator = SyntaxGenerator.GetGenerator(document);
var updatedNode = generator.Negate(node, semanticModel, negateBinary: false, cancellationToken);
var updatedRoot = root.ReplaceNode(node, updatedNode);
return document.WithSyntaxRoot(updatedRoot);
}
private static async Task<Document> InvertLeftAndRightOfBinaryAsync(Document document, int position, CancellationToken cancellationToken)
{
var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
var generator = SyntaxGenerator.GetGenerator(document);
var token = root.FindToken(position);
var binary = (BinaryExpressionSyntax)token.Parent;
var left = binary.Left;
var op = binary.OperatorToken;
var right = binary.Right;
var newLeft = (ExpressionSyntax)generator.Negate(left, semanticModel, cancellationToken);
var newRight = (ExpressionSyntax)generator.Negate(right, semanticModel, cancellationToken);
var newOp = binary.Kind() == SyntaxKind.LogicalAndExpression
? SyntaxFactory.Token(SyntaxKind.BarBarToken)
: SyntaxFactory.Token(SyntaxKind.AmpersandAmpersandToken);
var newBinary = SyntaxFactory.BinaryExpression(
InvertedKind(binary.Kind()), newLeft, newOp, newRight).WithAdditionalAnnotations(s_annotation);
var newRoot = root.ReplaceNode(binary, newBinary);
var updatedDocument = document.WithSyntaxRoot(newRoot);
return updatedDocument;
}
private string GetTitle(SyntaxKind kind)
=> string.Format(FeaturesResources.Replace_0_with_1,
GetText(kind), GetText(InvertedKind(kind)));
private string GetText(SyntaxKind syntaxKind)
=> syntaxKind == SyntaxKind.LogicalAndExpression
? SyntaxFacts.GetText(SyntaxKind.AmpersandAmpersandToken)
: SyntaxFacts.GetText(SyntaxKind.BarBarToken);
private static SyntaxKind InvertedKind(SyntaxKind syntaxKind)
=> syntaxKind == SyntaxKind.LogicalAndExpression ? SyntaxKind.LogicalOrExpression : SyntaxKind.LogicalAndExpression;
private class MyCodeAction : CodeAction.DocumentChangeAction
{
public MyCodeAction(string title, Func<CancellationToken, Task<Document>> createChangedDocument)
: base(title, createChangedDocument)
{
}
}
}
}
......@@ -2908,6 +2908,15 @@ internal class FeaturesResources {
}
}
/// <summary>
/// Looks up a localized string similar to Replace &apos;{0}&apos; with &apos;{1}&apos; .
/// </summary>
internal static string Replace_0_with_1 {
get {
return ResourceManager.GetString("Replace_0_with_1", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Replace &apos;{0}&apos; with method.
/// </summary>
......
......@@ -1433,4 +1433,7 @@ This version used in: {2}</value>
<data name="Invert_conditional" xml:space="preserve">
<value>Invert conditional</value>
</data>
<data name="Replace_0_with_1" xml:space="preserve">
<value>Replace '{0}' with '{1}' </value>
</data>
</root>
\ No newline at end of file
......@@ -92,6 +92,11 @@
<target state="new">Remove unused private members</target>
<note />
</trans-unit>
<trans-unit id="Replace_0_with_1">
<source>Replace '{0}' with '{1}' </source>
<target state="new">Replace '{0}' with '{1}' </target>
<note />
</trans-unit>
<trans-unit id="Type_0_has_a_private_member_1_that_can_be_removed_as_the_value_assigned_to_it_is_never_read">
<source>Type '{0}' has a private member '{1}' that can be removed as the value assigned to it is never read.</source>
<target state="new">Type '{0}' has a private member '{1}' that can be removed as the value assigned to it is never read.</target>
......
......@@ -92,6 +92,11 @@
<target state="new">Remove unused private members</target>
<note />
</trans-unit>
<trans-unit id="Replace_0_with_1">
<source>Replace '{0}' with '{1}' </source>
<target state="new">Replace '{0}' with '{1}' </target>
<note />
</trans-unit>
<trans-unit id="Type_0_has_a_private_member_1_that_can_be_removed_as_the_value_assigned_to_it_is_never_read">
<source>Type '{0}' has a private member '{1}' that can be removed as the value assigned to it is never read.</source>
<target state="new">Type '{0}' has a private member '{1}' that can be removed as the value assigned to it is never read.</target>
......
......@@ -92,6 +92,11 @@
<target state="new">Remove unused private members</target>
<note />
</trans-unit>
<trans-unit id="Replace_0_with_1">
<source>Replace '{0}' with '{1}' </source>
<target state="new">Replace '{0}' with '{1}' </target>
<note />
</trans-unit>
<trans-unit id="Type_0_has_a_private_member_1_that_can_be_removed_as_the_value_assigned_to_it_is_never_read">
<source>Type '{0}' has a private member '{1}' that can be removed as the value assigned to it is never read.</source>
<target state="new">Type '{0}' has a private member '{1}' that can be removed as the value assigned to it is never read.</target>
......
......@@ -92,6 +92,11 @@
<target state="new">Remove unused private members</target>
<note />
</trans-unit>
<trans-unit id="Replace_0_with_1">
<source>Replace '{0}' with '{1}' </source>
<target state="new">Replace '{0}' with '{1}' </target>
<note />
</trans-unit>
<trans-unit id="Type_0_has_a_private_member_1_that_can_be_removed_as_the_value_assigned_to_it_is_never_read">
<source>Type '{0}' has a private member '{1}' that can be removed as the value assigned to it is never read.</source>
<target state="new">Type '{0}' has a private member '{1}' that can be removed as the value assigned to it is never read.</target>
......
......@@ -92,6 +92,11 @@
<target state="new">Remove unused private members</target>
<note />
</trans-unit>
<trans-unit id="Replace_0_with_1">
<source>Replace '{0}' with '{1}' </source>
<target state="new">Replace '{0}' with '{1}' </target>
<note />
</trans-unit>
<trans-unit id="Type_0_has_a_private_member_1_that_can_be_removed_as_the_value_assigned_to_it_is_never_read">
<source>Type '{0}' has a private member '{1}' that can be removed as the value assigned to it is never read.</source>
<target state="new">Type '{0}' has a private member '{1}' that can be removed as the value assigned to it is never read.</target>
......
......@@ -92,6 +92,11 @@
<target state="new">Remove unused private members</target>
<note />
</trans-unit>
<trans-unit id="Replace_0_with_1">
<source>Replace '{0}' with '{1}' </source>
<target state="new">Replace '{0}' with '{1}' </target>
<note />
</trans-unit>
<trans-unit id="Type_0_has_a_private_member_1_that_can_be_removed_as_the_value_assigned_to_it_is_never_read">
<source>Type '{0}' has a private member '{1}' that can be removed as the value assigned to it is never read.</source>
<target state="new">Type '{0}' has a private member '{1}' that can be removed as the value assigned to it is never read.</target>
......
......@@ -92,6 +92,11 @@
<target state="new">Remove unused private members</target>
<note />
</trans-unit>
<trans-unit id="Replace_0_with_1">
<source>Replace '{0}' with '{1}' </source>
<target state="new">Replace '{0}' with '{1}' </target>
<note />
</trans-unit>
<trans-unit id="Type_0_has_a_private_member_1_that_can_be_removed_as_the_value_assigned_to_it_is_never_read">
<source>Type '{0}' has a private member '{1}' that can be removed as the value assigned to it is never read.</source>
<target state="new">Type '{0}' has a private member '{1}' that can be removed as the value assigned to it is never read.</target>
......
......@@ -92,6 +92,11 @@
<target state="new">Remove unused private members</target>
<note />
</trans-unit>
<trans-unit id="Replace_0_with_1">
<source>Replace '{0}' with '{1}' </source>
<target state="new">Replace '{0}' with '{1}' </target>
<note />
</trans-unit>
<trans-unit id="Type_0_has_a_private_member_1_that_can_be_removed_as_the_value_assigned_to_it_is_never_read">
<source>Type '{0}' has a private member '{1}' that can be removed as the value assigned to it is never read.</source>
<target state="new">Type '{0}' has a private member '{1}' that can be removed as the value assigned to it is never read.</target>
......
......@@ -92,6 +92,11 @@
<target state="new">Remove unused private members</target>
<note />
</trans-unit>
<trans-unit id="Replace_0_with_1">
<source>Replace '{0}' with '{1}' </source>
<target state="new">Replace '{0}' with '{1}' </target>
<note />
</trans-unit>
<trans-unit id="Type_0_has_a_private_member_1_that_can_be_removed_as_the_value_assigned_to_it_is_never_read">
<source>Type '{0}' has a private member '{1}' that can be removed as the value assigned to it is never read.</source>
<target state="new">Type '{0}' has a private member '{1}' that can be removed as the value assigned to it is never read.</target>
......
......@@ -92,6 +92,11 @@
<target state="new">Remove unused private members</target>
<note />
</trans-unit>
<trans-unit id="Replace_0_with_1">
<source>Replace '{0}' with '{1}' </source>
<target state="new">Replace '{0}' with '{1}' </target>
<note />
</trans-unit>
<trans-unit id="Type_0_has_a_private_member_1_that_can_be_removed_as_the_value_assigned_to_it_is_never_read">
<source>Type '{0}' has a private member '{1}' that can be removed as the value assigned to it is never read.</source>
<target state="new">Type '{0}' has a private member '{1}' that can be removed as the value assigned to it is never read.</target>
......
......@@ -92,6 +92,11 @@
<target state="new">Remove unused private members</target>
<note />
</trans-unit>
<trans-unit id="Replace_0_with_1">
<source>Replace '{0}' with '{1}' </source>
<target state="new">Replace '{0}' with '{1}' </target>
<note />
</trans-unit>
<trans-unit id="Type_0_has_a_private_member_1_that_can_be_removed_as_the_value_assigned_to_it_is_never_read">
<source>Type '{0}' has a private member '{1}' that can be removed as the value assigned to it is never read.</source>
<target state="new">Type '{0}' has a private member '{1}' that can be removed as the value assigned to it is never read.</target>
......
......@@ -92,6 +92,11 @@
<target state="new">Remove unused private members</target>
<note />
</trans-unit>
<trans-unit id="Replace_0_with_1">
<source>Replace '{0}' with '{1}' </source>
<target state="new">Replace '{0}' with '{1}' </target>
<note />
</trans-unit>
<trans-unit id="Type_0_has_a_private_member_1_that_can_be_removed_as_the_value_assigned_to_it_is_never_read">
<source>Type '{0}' has a private member '{1}' that can be removed as the value assigned to it is never read.</source>
<target state="new">Type '{0}' has a private member '{1}' that can be removed as the value assigned to it is never read.</target>
......
......@@ -92,6 +92,11 @@
<target state="new">Remove unused private members</target>
<note />
</trans-unit>
<trans-unit id="Replace_0_with_1">
<source>Replace '{0}' with '{1}' </source>
<target state="new">Replace '{0}' with '{1}' </target>
<note />
</trans-unit>
<trans-unit id="Type_0_has_a_private_member_1_that_can_be_removed_as_the_value_assigned_to_it_is_never_read">
<source>Type '{0}' has a private member '{1}' that can be removed as the value assigned to it is never read.</source>
<target state="new">Type '{0}' has a private member '{1}' that can be removed as the value assigned to it is never read.</target>
......
......@@ -6,6 +6,7 @@
using Microsoft.CodeAnalysis.Editing;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.Operations;
using Microsoft.CodeAnalysis.Simplification;
namespace Microsoft.CodeAnalysis.Shared.Extensions
{
......@@ -33,6 +34,16 @@ internal static partial class SyntaxGeneratorExtensions
SyntaxNode expression,
SemanticModel semanticModel,
CancellationToken cancellationToken)
{
return Negate(generator, expression, semanticModel, negateBinary: true, cancellationToken);
}
public static SyntaxNode Negate(
this SyntaxGenerator generator,
SyntaxNode expression,
SemanticModel semanticModel,
bool negateBinary,
CancellationToken cancellationToken)
{
var syntaxFacts = generator.SyntaxFacts;
if (syntaxFacts.IsParenthesizedExpression(expression))
......@@ -41,10 +52,11 @@ internal static partial class SyntaxGeneratorExtensions
generator.Negate(
syntaxFacts.GetExpressionOfParenthesizedExpression(expression),
semanticModel,
negateBinary,
cancellationToken))
.WithTriviaFrom(expression);
}
if (syntaxFacts.IsBinaryExpression(expression))
if (negateBinary && syntaxFacts.IsBinaryExpression(expression))
{
return GetNegationOfBinaryExpression(expression, generator, semanticModel, cancellationToken);
}
......@@ -281,7 +293,8 @@ private static IOperation RemoveImplicitConversion(IOperation operation)
var operatorToken = syntaxFacts.GetOperatorTokenOfPrefixUnaryExpression(expression);
var operand = syntaxFacts.GetOperandOfPrefixUnaryExpression(expression);
return operand.WithPrependedLeadingTrivia(operatorToken.LeadingTrivia);
return operand.WithPrependedLeadingTrivia(operatorToken.LeadingTrivia)
.WithAdditionalAnnotations(Simplifier.Annotation);
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册