未验证 提交 6fa232d1 编写于 作者: C Cheryl Borley 提交者: GitHub

Merge pull request #25233 from chborl/enableinvertif

Enable InvertIf
......@@ -557,6 +557,15 @@ internal class CSharpFeaturesResources {
}
}
/// <summary>
/// Looks up a localized string similar to Invert if.
/// </summary>
internal static string Invert_if {
get {
return ResourceManager.GetString("Invert_if", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to is pattern.
/// </summary>
......
......@@ -123,8 +123,8 @@
<data name="Conflict_s_detected" xml:space="preserve">
<value>Conflict(s) detected.</value>
</data>
<data name="Invert_if_statement" xml:space="preserve">
<value>Invert if statement</value>
<data name="Invert_if" xml:space="preserve">
<value>Invert if</value>
</data>
<data name="Simplify_lambda_expression" xml:space="preserve">
<value>Simplify lambda expression</value>
......
// 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.Composition;
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis.CodeRefactorings;
using Microsoft.CodeAnalysis.CodeRefactorings.InvertIf;
using Microsoft.CodeAnalysis.CSharp.Extensions;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Editing;
using Microsoft.CodeAnalysis.Formatting;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.Operations;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.CodeAnalysis.CSharp.CodeRefactorings.InvertIf
{
[ExportCodeRefactoringProvider(LanguageNames.CSharp, Name = PredefinedCodeRefactoringProviderNames.InvertIf), Shared]
internal partial class CSharpInvertIfCodeRefactoringProvider : AbstractInvertIfCodeRefactoringProvider
{
protected override SyntaxNode GetIfStatement(TextSpan textSpan, SyntaxToken token, CancellationToken cancellationToken)
{
var ifStatement = token.GetAncestor<IfStatementSyntax>();
if (ifStatement == null || ifStatement.Else == null)
{
return null;
}
var span = TextSpan.FromBounds(ifStatement.IfKeyword.Span.Start, ifStatement.CloseParenToken.Span.End);
if (!span.IntersectsWith(textSpan))
{
return null;
}
return ifStatement;
}
protected override SyntaxNode GetRootWithInvertIfStatement(
Document document,
SemanticModel model,
SyntaxNode ifStatementSyntax,
CancellationToken cancellationToken)
{
var generator = SyntaxGenerator.GetGenerator(document);
var syntaxFacts = GetSyntaxFactsService();
var oldIfStatement = (IfStatementSyntax)ifStatementSyntax;
// For single line statement, we swap the TrailingTrivia to preserve the single line
StatementSyntax newIfNodeStatement = null;
ElseClauseSyntax newElseStatement = null;
var hasNewLineAfterClosingBrace = oldIfStatement.Statement.GetTrailingTrivia().Any(trivia => trivia.Kind() == SyntaxKind.EndOfLineTrivia);
if (hasNewLineAfterClosingBrace)
{
newIfNodeStatement = oldIfStatement.Else.Statement.Kind() != SyntaxKind.Block
? SyntaxFactory.Block(oldIfStatement.Else.Statement)
: oldIfStatement.Else.Statement;
newElseStatement = oldIfStatement.Else.WithStatement(oldIfStatement.Statement);
}
else
{
var elseTrailingTrivia = oldIfStatement.Else.GetTrailingTrivia();
var ifTrailingTrivia = oldIfStatement.Statement.GetTrailingTrivia();
newIfNodeStatement = oldIfStatement.Else.Statement.WithTrailingTrivia(ifTrailingTrivia);
newElseStatement = oldIfStatement.Else.WithStatement(oldIfStatement.Statement).WithTrailingTrivia(elseTrailingTrivia);
}
var newIfStatment = oldIfStatement.Else.Statement.Kind() == SyntaxKind.IfStatement && newIfNodeStatement.Kind() != SyntaxKind.Block
? SyntaxFactory.Block(newIfNodeStatement)
: newIfNodeStatement;
oldIfStatement = oldIfStatement.WithCondition((ExpressionSyntax)(Negate(oldIfStatement.Condition, generator, syntaxFacts, model, cancellationToken)))
.WithStatement(newIfStatment)
.WithElse(newElseStatement);
if (hasNewLineAfterClosingBrace)
{
oldIfStatement = oldIfStatement.WithAdditionalAnnotations(Formatter.Annotation);
}
// get new root
return model.SyntaxTree.GetRoot(cancellationToken).ReplaceNode(ifStatementSyntax, oldIfStatement);
}
protected override ISyntaxFactsService GetSyntaxFactsService()
=> CSharpSyntaxFactsService.Instance;
protected override string GetTitle()
=> CSharpFeaturesResources.Invert_if;
}
}
......@@ -12,11 +12,6 @@
<target state="translated">Zjistily se konflikty.</target>
<note />
</trans-unit>
<trans-unit id="Invert_if_statement">
<source>Invert if statement</source>
<target state="translated">Obrátit příkaz If</target>
<note />
</trans-unit>
<trans-unit id="Simplify_lambda_expression">
<source>Simplify lambda expression</source>
<target state="translated">Zjednodušit výraz lambda</target>
......@@ -642,6 +637,11 @@
<target state="new">Convert to 'for'</target>
<note />
</trans-unit>
<trans-unit id="Invert_if">
<source>Invert if</source>
<target state="new">Invert if</target>
<note />
</trans-unit>
</body>
</file>
</xliff>
\ No newline at end of file
......@@ -12,11 +12,6 @@
<target state="translated">Konflikt(e) erkannt.</target>
<note />
</trans-unit>
<trans-unit id="Invert_if_statement">
<source>Invert if statement</source>
<target state="translated">if-Anweisung invertieren</target>
<note />
</trans-unit>
<trans-unit id="Simplify_lambda_expression">
<source>Simplify lambda expression</source>
<target state="translated">Lambdaausdruck vereinfachen</target>
......@@ -642,6 +637,11 @@
<target state="new">Convert to 'for'</target>
<note />
</trans-unit>
<trans-unit id="Invert_if">
<source>Invert if</source>
<target state="new">Invert if</target>
<note />
</trans-unit>
</body>
</file>
</xliff>
\ No newline at end of file
......@@ -12,11 +12,6 @@
<target state="translated">Conflicto(s) detectado(s).</target>
<note />
</trans-unit>
<trans-unit id="Invert_if_statement">
<source>Invert if statement</source>
<target state="translated">Invertir instrucción if</target>
<note />
</trans-unit>
<trans-unit id="Simplify_lambda_expression">
<source>Simplify lambda expression</source>
<target state="translated">Simplificar expresión lambda</target>
......@@ -642,6 +637,11 @@
<target state="new">Convert to 'for'</target>
<note />
</trans-unit>
<trans-unit id="Invert_if">
<source>Invert if</source>
<target state="new">Invert if</target>
<note />
</trans-unit>
</body>
</file>
</xliff>
\ No newline at end of file
......@@ -12,11 +12,6 @@
<target state="translated">Conflit(s) détecté(s).</target>
<note />
</trans-unit>
<trans-unit id="Invert_if_statement">
<source>Invert if statement</source>
<target state="translated">Inverser l'instruction if</target>
<note />
</trans-unit>
<trans-unit id="Simplify_lambda_expression">
<source>Simplify lambda expression</source>
<target state="translated">Simplifier l'expression lambda</target>
......@@ -642,6 +637,11 @@
<target state="new">Convert to 'for'</target>
<note />
</trans-unit>
<trans-unit id="Invert_if">
<source>Invert if</source>
<target state="new">Invert if</target>
<note />
</trans-unit>
</body>
</file>
</xliff>
\ No newline at end of file
......@@ -12,11 +12,6 @@
<target state="translated">Sono stati rilevati conflitti</target>
<note />
</trans-unit>
<trans-unit id="Invert_if_statement">
<source>Invert if statement</source>
<target state="translated">Istruzione Invert If</target>
<note />
</trans-unit>
<trans-unit id="Simplify_lambda_expression">
<source>Simplify lambda expression</source>
<target state="translated">Semplifica l'espressione lambda</target>
......@@ -642,6 +637,11 @@
<target state="new">Convert to 'for'</target>
<note />
</trans-unit>
<trans-unit id="Invert_if">
<source>Invert if</source>
<target state="new">Invert if</target>
<note />
</trans-unit>
</body>
</file>
</xliff>
\ No newline at end of file
......@@ -12,11 +12,6 @@
<target state="translated">競合が検出されました。</target>
<note />
</trans-unit>
<trans-unit id="Invert_if_statement">
<source>Invert if statement</source>
<target state="translated">If ステートメントの反転</target>
<note />
</trans-unit>
<trans-unit id="Simplify_lambda_expression">
<source>Simplify lambda expression</source>
<target state="translated">ラムダ式の簡略化</target>
......@@ -642,6 +637,11 @@
<target state="new">Convert to 'for'</target>
<note />
</trans-unit>
<trans-unit id="Invert_if">
<source>Invert if</source>
<target state="new">Invert if</target>
<note />
</trans-unit>
</body>
</file>
</xliff>
\ No newline at end of file
......@@ -12,11 +12,6 @@
<target state="translated">충돌이 감지되었습니다.</target>
<note />
</trans-unit>
<trans-unit id="Invert_if_statement">
<source>Invert if statement</source>
<target state="translated">If 문을 반대로 합니다.</target>
<note />
</trans-unit>
<trans-unit id="Simplify_lambda_expression">
<source>Simplify lambda expression</source>
<target state="translated">람다 식 단순화</target>
......@@ -642,6 +637,11 @@
<target state="new">Convert to 'for'</target>
<note />
</trans-unit>
<trans-unit id="Invert_if">
<source>Invert if</source>
<target state="new">Invert if</target>
<note />
</trans-unit>
</body>
</file>
</xliff>
\ No newline at end of file
......@@ -12,11 +12,6 @@
<target state="translated">Wykryto konflikty.</target>
<note />
</trans-unit>
<trans-unit id="Invert_if_statement">
<source>Invert if statement</source>
<target state="translated">Odwróć instrukcję if</target>
<note />
</trans-unit>
<trans-unit id="Simplify_lambda_expression">
<source>Simplify lambda expression</source>
<target state="translated">Uprość wyrażenie lambda</target>
......@@ -642,6 +637,11 @@
<target state="new">Convert to 'for'</target>
<note />
</trans-unit>
<trans-unit id="Invert_if">
<source>Invert if</source>
<target state="new">Invert if</target>
<note />
</trans-unit>
</body>
</file>
</xliff>
\ No newline at end of file
......@@ -12,11 +12,6 @@
<target state="translated">Conflito(s) detectado(s).</target>
<note />
</trans-unit>
<trans-unit id="Invert_if_statement">
<source>Invert if statement</source>
<target state="translated">Inverter instrução if</target>
<note />
</trans-unit>
<trans-unit id="Simplify_lambda_expression">
<source>Simplify lambda expression</source>
<target state="translated">Simplificar expressão lambda</target>
......@@ -642,6 +637,11 @@
<target state="new">Convert to 'for'</target>
<note />
</trans-unit>
<trans-unit id="Invert_if">
<source>Invert if</source>
<target state="new">Invert if</target>
<note />
</trans-unit>
</body>
</file>
</xliff>
\ No newline at end of file
......@@ -12,11 +12,6 @@
<target state="translated">Обнаружены конфликты.</target>
<note />
</trans-unit>
<trans-unit id="Invert_if_statement">
<source>Invert if statement</source>
<target state="translated">Обратить, если утверждение</target>
<note />
</trans-unit>
<trans-unit id="Simplify_lambda_expression">
<source>Simplify lambda expression</source>
<target state="translated">Упростить лямбда-выражение</target>
......@@ -642,6 +637,11 @@
<target state="new">Convert to 'for'</target>
<note />
</trans-unit>
<trans-unit id="Invert_if">
<source>Invert if</source>
<target state="new">Invert if</target>
<note />
</trans-unit>
</body>
</file>
</xliff>
\ No newline at end of file
......@@ -12,11 +12,6 @@
<target state="translated">Çakışmalar algılandı.</target>
<note />
</trans-unit>
<trans-unit id="Invert_if_statement">
<source>Invert if statement</source>
<target state="translated">If ifadesini ters çevir</target>
<note />
</trans-unit>
<trans-unit id="Simplify_lambda_expression">
<source>Simplify lambda expression</source>
<target state="translated">Lambda ifadesini basitleştir</target>
......@@ -642,6 +637,11 @@
<target state="new">Convert to 'for'</target>
<note />
</trans-unit>
<trans-unit id="Invert_if">
<source>Invert if</source>
<target state="new">Invert if</target>
<note />
</trans-unit>
</body>
</file>
</xliff>
\ No newline at end of file
......@@ -12,11 +12,6 @@
<target state="translated">检测到冲突。</target>
<note />
</trans-unit>
<trans-unit id="Invert_if_statement">
<source>Invert if statement</source>
<target state="translated">反转 if 语句 </target>
<note />
</trans-unit>
<trans-unit id="Simplify_lambda_expression">
<source>Simplify lambda expression</source>
<target state="translated">简化 lambda 表达式</target>
......@@ -642,6 +637,11 @@
<target state="new">Convert to 'for'</target>
<note />
</trans-unit>
<trans-unit id="Invert_if">
<source>Invert if</source>
<target state="new">Invert if</target>
<note />
</trans-unit>
</body>
</file>
</xliff>
\ No newline at end of file
......@@ -12,11 +12,6 @@
<target state="translated">偵測到衝突。</target>
<note />
</trans-unit>
<trans-unit id="Invert_if_statement">
<source>Invert if statement</source>
<target state="translated">反轉 if 陳述式</target>
<note />
</trans-unit>
<trans-unit id="Simplify_lambda_expression">
<source>Simplify lambda expression</source>
<target state="translated">簡化 Lambda 運算式</target>
......@@ -642,6 +637,11 @@
<target state="new">Convert to 'for'</target>
<note />
</trans-unit>
<trans-unit id="Invert_if">
<source>Invert if</source>
<target state="new">Invert if</target>
<note />
</trans-unit>
</body>
</file>
</xliff>
\ No newline at end of file
// 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;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.Editing;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.Operations;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.CodeAnalysis.CodeRefactorings.InvertIf
{
internal abstract partial class AbstractInvertIfCodeRefactoringProvider : CodeRefactoringProvider
{
private const string LongLength = "LongLength";
private static readonly Dictionary<BinaryOperatorKind, BinaryOperatorKind> s_negatedBinaryMap =
new Dictionary<BinaryOperatorKind, BinaryOperatorKind>
{
{BinaryOperatorKind.Equals, BinaryOperatorKind.NotEquals},
{BinaryOperatorKind.NotEquals, BinaryOperatorKind.Equals},
{BinaryOperatorKind.LessThan, BinaryOperatorKind.GreaterThanOrEqual},
{BinaryOperatorKind.GreaterThan, BinaryOperatorKind.LessThanOrEqual},
{BinaryOperatorKind.LessThanOrEqual, BinaryOperatorKind.GreaterThan},
{BinaryOperatorKind.GreaterThanOrEqual, BinaryOperatorKind.LessThan},
{BinaryOperatorKind.Or, BinaryOperatorKind.And},
{BinaryOperatorKind.And, BinaryOperatorKind.Or},
{BinaryOperatorKind.ConditionalOr, BinaryOperatorKind.ConditionalAnd},
{BinaryOperatorKind.ConditionalAnd, BinaryOperatorKind.ConditionalOr},
};
protected abstract SyntaxNode GetIfStatement(TextSpan textSpan, SyntaxToken token, CancellationToken cancellationToken);
protected abstract SyntaxNode GetRootWithInvertIfStatement(Document document, SemanticModel model, SyntaxNode ifStatement, CancellationToken cancellationToken);
protected abstract ISyntaxFactsService GetSyntaxFactsService();
protected abstract string GetTitle();
public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
{
var document = context.Document;
var textSpan = context.Span;
var cancellationToken = context.CancellationToken;
if (!textSpan.IsEmpty)
{
return;
}
var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
var token = root.FindToken(textSpan.Start);
var ifStatement = GetIfStatement(textSpan, token, cancellationToken);
if (ifStatement == null)
{
return;
}
if (ifStatement.OverlapsHiddenPosition(cancellationToken))
{
return;
}
context.RegisterRefactoring(
new MyCodeAction(
GetTitle(),
c => InvertIfAsync(document, ifStatement, c)));
}
private async Task<Document> InvertIfAsync(
Document document,
SyntaxNode ifStatement,
CancellationToken cancellationToken)
{
var model = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
return document.WithSyntaxRoot(
// this returns the root because VB requires changing context around if statement
GetRootWithInvertIfStatement(
document, model, ifStatement, cancellationToken));
}
internal SyntaxNode Negate(
SyntaxNode expression,
SyntaxGenerator generator,
ISyntaxFactsService syntaxFacts,
SemanticModel semanticModel,
CancellationToken cancellationToken)
{
if (syntaxFacts.IsParenthesizedExpression(expression))
{
return syntaxFacts.Parenthesize(
Negate(
syntaxFacts.GetExpressionOfParenthesizedExpression(expression),
generator,
syntaxFacts,
semanticModel,
cancellationToken))
.WithTriviaFrom(expression);
}
if (syntaxFacts.IsBinaryExpression(expression))
{
return GetNegationOfBinaryExpression(expression, generator, syntaxFacts, semanticModel, cancellationToken);
}
else if (syntaxFacts.IsLiteralExpression(expression))
{
return GetNegationOfLiteralExpression(expression, generator, semanticModel);
}
else if (syntaxFacts.IsLogicalNotExpression(expression))
{
return GetNegationOfLogicalNotExpression(expression, syntaxFacts);
}
return generator.LogicalNotExpression(expression);
}
private SyntaxNode GetNegationOfBinaryExpression(
SyntaxNode expressionNode,
SyntaxGenerator generator,
ISyntaxFactsService syntaxFacts,
SemanticModel semanticModel,
CancellationToken cancellationToken)
{
syntaxFacts.GetPartsOfBinaryExpression(expressionNode, out var leftOperand, out var operatorToken, out var rightOperand);
var operation = semanticModel.GetOperation(expressionNode, cancellationToken);
if (operation.Kind == OperationKind.IsPattern)
{
return generator.LogicalNotExpression(expressionNode);
}
var binaryOperation = (IBinaryOperation)operation;
if (!s_negatedBinaryMap.TryGetValue(binaryOperation.OperatorKind, out var negatedKind))
{
return generator.LogicalNotExpression(expressionNode);
}
else
{
var negateOperands = false;
switch (binaryOperation.OperatorKind)
{
case BinaryOperatorKind.Or:
case BinaryOperatorKind.And:
case BinaryOperatorKind.ConditionalAnd:
case BinaryOperatorKind.ConditionalOr:
negateOperands = true;
break;
}
//Workaround for https://github.com/dotnet/roslyn/issues/23956
//Issue to remove this when above is merged
if (binaryOperation.OperatorKind == BinaryOperatorKind.Or && syntaxFacts.IsConditionalOr(expressionNode))
{
negatedKind = BinaryOperatorKind.ConditionalAnd;
}
else if (binaryOperation.OperatorKind == BinaryOperatorKind.And && syntaxFacts.IsConditionalAnd(expressionNode))
{
negatedKind = BinaryOperatorKind.ConditionalOr;
}
var newLeftOperand = leftOperand;
var newRightOperand = rightOperand;
if (negateOperands)
{
newLeftOperand = Negate(leftOperand, generator, syntaxFacts, semanticModel, cancellationToken);
newRightOperand = Negate(rightOperand, generator, syntaxFacts, semanticModel, cancellationToken);
}
var newBinaryExpressionSyntax = NewBinaryOperation(binaryOperation, newLeftOperand, negatedKind, newRightOperand, generator, syntaxFacts, cancellationToken)
.WithTriviaFrom(expressionNode);
syntaxFacts.GetOperatorTokenOfBinaryExpression(newBinaryExpressionSyntax, out var newToken);
var newTokenWithTrivia = newToken.WithTriviaFrom(operatorToken);
return newBinaryExpressionSyntax.ReplaceToken(newToken, newTokenWithTrivia);
}
}
private SyntaxNode NewBinaryOperation(
IBinaryOperation binaryOperation,
SyntaxNode leftOperand,
BinaryOperatorKind operationKind,
SyntaxNode rightOperand,
SyntaxGenerator generator,
ISyntaxFactsService syntaxFacts,
CancellationToken cancellationToken)
{
switch (operationKind)
{
case BinaryOperatorKind.Equals:
return binaryOperation.LeftOperand.Type?.IsValueType == true && binaryOperation.RightOperand.Type?.IsValueType == true
? generator.ValueEqualsExpression(leftOperand, rightOperand)
: generator.ReferenceEqualsExpression(leftOperand, rightOperand);
case BinaryOperatorKind.NotEquals:
return binaryOperation.LeftOperand.Type?.IsValueType == true && binaryOperation.RightOperand.Type?.IsValueType == true
? generator.ValueNotEqualsExpression(leftOperand, rightOperand)
: generator.ReferenceNotEqualsExpression(leftOperand, rightOperand);
case BinaryOperatorKind.LessThanOrEqual:
return IsSpecialCaseBinaryExpression(binaryOperation, operationKind, cancellationToken)
? generator.ValueEqualsExpression(leftOperand, rightOperand)
: generator.LessThanOrEqualExpression(leftOperand, rightOperand);
case BinaryOperatorKind.GreaterThanOrEqual:
return IsSpecialCaseBinaryExpression(binaryOperation, operationKind, cancellationToken)
? generator.ValueEqualsExpression(leftOperand, rightOperand)
: generator.GreaterThanOrEqualExpression(leftOperand, rightOperand);
case BinaryOperatorKind.LessThan:
return generator.LessThanExpression(leftOperand, rightOperand);
case BinaryOperatorKind.GreaterThan:
return generator.GreaterThanExpression(leftOperand, rightOperand);
case BinaryOperatorKind.Or:
return generator.BitwiseOrExpression(leftOperand, rightOperand);
case BinaryOperatorKind.And:
return generator.BitwiseAndExpression(leftOperand, rightOperand);
case BinaryOperatorKind.ConditionalOr:
return generator.LogicalOrExpression(leftOperand, rightOperand);
case BinaryOperatorKind.ConditionalAnd:
return generator.LogicalAndExpression(leftOperand, rightOperand);
}
return null;
}
/// <summary>
/// Returns true if the binaryExpression consists of an expression that can never be negative,
/// such as length or unsigned numeric types, being compared to zero with greater than,
/// less than, or equals relational operator.
/// </summary>
public bool IsSpecialCaseBinaryExpression(
IBinaryOperation binaryOperation,
BinaryOperatorKind operationKind,
CancellationToken cancellationToken)
{
if (binaryOperation == null)
{
return false;
}
var rightOperand = RemoveImplicitConversion(binaryOperation.RightOperand);
var leftOperand = RemoveImplicitConversion(binaryOperation.LeftOperand);
switch (operationKind)
{
case BinaryOperatorKind.LessThanOrEqual when IsNumericLiteral(rightOperand):
return CanSimplifyToLengthEqualsZeroExpression(
leftOperand,
(ILiteralOperation)rightOperand,
cancellationToken);
case BinaryOperatorKind.GreaterThanOrEqual when IsNumericLiteral(leftOperand):
return CanSimplifyToLengthEqualsZeroExpression(
rightOperand,
(ILiteralOperation)leftOperand,
cancellationToken);
}
return false;
}
private bool IsNumericLiteral(IOperation operation)
=> operation.Kind == OperationKind.Literal && operation.Type.IsNumericType();
private IOperation RemoveImplicitConversion(IOperation operation)
{
return operation is IConversionOperation conversion && conversion.IsImplicit
? RemoveImplicitConversion(conversion.Operand)
: operation;
}
private bool CanSimplifyToLengthEqualsZeroExpression(
IOperation variableExpression,
ILiteralOperation numericLiteralExpression,
CancellationToken cancellationToken)
{
var numericValue = numericLiteralExpression.ConstantValue;
if (numericValue.HasValue && numericValue.Value is 0)
{
if (variableExpression is IPropertyReferenceOperation propertyOperation)
{
var property = propertyOperation.Property;
if ((property.Name == nameof(Array.Length) || property.Name == LongLength))
{
var containingType = property.ContainingType;
if (containingType?.SpecialType == SpecialType.System_Array ||
containingType.SpecialType == SpecialType.System_String)
{
return true;
}
}
}
var type = variableExpression.Type;
if (type != null)
{
switch (type.SpecialType)
{
case SpecialType.System_Byte:
case SpecialType.System_UInt16:
case SpecialType.System_UInt32:
case SpecialType.System_UInt64:
return true;
}
}
}
return false;
}
private SyntaxNode GetNegationOfLiteralExpression(
SyntaxNode expression,
SyntaxGenerator generator,
SemanticModel semanticModel)
{
var operation = semanticModel.GetOperation(expression);
SyntaxNode newLiteralExpression;
if (operation?.Kind == OperationKind.Literal && operation.ConstantValue.HasValue && operation.ConstantValue.Value is true)
{
newLiteralExpression = generator.FalseLiteralExpression();
}
else if (operation?.Kind == OperationKind.Literal && operation.ConstantValue.HasValue && operation.ConstantValue.Value is false)
{
newLiteralExpression = generator.TrueLiteralExpression();
}
else
{
newLiteralExpression = generator.LogicalNotExpression(expression.WithoutTrivia());
}
return newLiteralExpression.WithTriviaFrom(expression);
}
private SyntaxNode GetNegationOfLogicalNotExpression(
SyntaxNode expression,
ISyntaxFactsService syntaxFacts)
{
var operatorToken = syntaxFacts.GetOperatorTokenOfPrefixUnaryExpression(expression);
var operand = syntaxFacts.GetOperandOfPrefixUnaryExpression(expression);
return operand.WithPrependedLeadingTrivia(operatorToken.LeadingTrivia);
}
private class MyCodeAction : CodeAction.DocumentChangeAction
{
public MyCodeAction(string title, Func<CancellationToken, Task<Document>> createChangedDocument) :
base(title, createChangedDocument)
{
}
}
}
}
......@@ -16,6 +16,7 @@ internal static class PredefinedCodeRefactoringProviderNames
public const string GenerateOverrides = "Generate Overrides Code Action Provider";
public const string InlineTemporary = "Inline Temporary Code Action Provider";
public const string IntroduceVariable = "Introduce Variable Code Action Provider";
public const string InvertIf = "Invert If Code Action Provider";
public const string MoveDeclarationNearReference = "Move Declaration Near Reference Code Action Provider";
public const string SimplifyLambda = "Simplify Lambda Code Action Provider";
public const string ConvertToInterpolatedString = "Convert To Interpolated String Code Action Provider";
......
' 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.Composition
Imports System.Threading
Imports Microsoft.CodeAnalysis.CodeRefactorings
Imports Microsoft.CodeAnalysis.CodeRefactorings.InvertIf
Imports Microsoft.CodeAnalysis.Editing
Imports Microsoft.CodeAnalysis.LanguageServices
Imports Microsoft.CodeAnalysis.Operations
Imports Microsoft.CodeAnalysis.Simplification
Imports Microsoft.CodeAnalysis.Text
Imports Microsoft.CodeAnalysis.VisualBasic
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
Namespace Microsoft.CodeAnalysis.VisualBasic.CodeRefactorings.InvertIf
<ExportCodeRefactoringProvider(LanguageNames.VisualBasic, Name:=PredefinedCodeRefactoringProviderNames.InvertIf), [Shared]>
Friend Class VisualBasicInvertIfCodeRefactoringProvider
Inherits AbstractInvertIfCodeRefactoringProvider
Private Shared ReadOnly s_ifNodeAnnotation As New SyntaxAnnotation
Protected Overrides Function GetSyntaxFactsService() As ISyntaxFactsService
Return VisualBasicSyntaxFactsService.Instance
End Function
Protected Overrides Function GetIfStatement(textSpan As TextSpan, token As SyntaxToken, cancellationToken As CancellationToken) As SyntaxNode
Dim relevantIfBlockOrIfStatement As ExecutableStatementSyntax = Nothing
Dim relevantSpan As TextSpan = Nothing
Dim singleLineIf = token.GetAncestor(Of SingleLineIfStatementSyntax)()
Dim multiLineIf = token.GetAncestor(Of MultiLineIfBlockSyntax)()
If singleLineIf IsNot Nothing AndAlso
singleLineIf.ElseClause IsNot Nothing Then
relevantIfBlockOrIfStatement = singleLineIf
relevantSpan = TextSpan.FromBounds(singleLineIf.IfKeyword.Span.Start, singleLineIf.Condition.Span.End)
ElseIf multiLineIf IsNot Nothing AndAlso
multiLineIf.ElseBlock IsNot Nothing AndAlso
multiLineIf.ElseIfBlocks.IsEmpty Then
relevantIfBlockOrIfStatement = multiLineIf
relevantSpan = TextSpan.FromBounds(multiLineIf.IfStatement.IfKeyword.Span.Start, multiLineIf.IfStatement.Condition.Span.End)
Else
Return Nothing
End If
If Not relevantSpan.IntersectsWith(textSpan.Start) Then
Return Nothing
End If
If token.SyntaxTree.OverlapsHiddenPosition(relevantSpan, cancellationToken) Then
Return Nothing
End If
Return relevantIfBlockOrIfStatement
End Function
Protected Overrides Function GetRootWithInvertIfStatement(document As Document, model As SemanticModel, ifStatement As SyntaxNode, cancellationToken As CancellationToken) As SyntaxNode
Dim generator = SyntaxGenerator.GetGenerator(document)
Dim syntaxFacts = GetSyntaxFactsService()
Dim result = UpdateSemanticModel(model, model.SyntaxTree.GetRoot().ReplaceNode(ifStatement, ifStatement.WithAdditionalAnnotations(s_ifNodeAnnotation)), cancellationToken)
Dim ifNode = result.Root.GetAnnotatedNodesAndTokens(s_ifNodeAnnotation).Single().AsNode()
'In order to add parentheses for SingleLineIfStatements with commas, such as
'Case Sub() [||]If True Then Dim x Else Return, Nothing
'complexify the top-most statement parenting this if-statement if necessary
Dim topMostExpression = ifNode.Ancestors().OfType(Of ExpressionSyntax).LastOrDefault()
If topMostExpression IsNot Nothing Then
Dim topMostStatement = topMostExpression.Ancestors().OfType(Of StatementSyntax).FirstOrDefault()
If topMostStatement IsNot Nothing Then
Dim explicitTopMostStatement = Simplifier.Expand(topMostStatement, result.Model, document.Project.Solution.Workspace, cancellationToken:=cancellationToken)
result = UpdateSemanticModel(result.Model, result.Root.ReplaceNode(topMostStatement, explicitTopMostStatement), cancellationToken)
ifNode = result.Root.GetAnnotatedNodesAndTokens(s_ifNodeAnnotation).Single().AsNode()
End If
End If
If (TypeOf ifNode Is SingleLineIfStatementSyntax) Then
model = InvertSingleLineIfStatement(document, DirectCast(ifNode, SingleLineIfStatementSyntax), generator, syntaxFacts, result.Model, cancellationToken)
Else
model = InvertMultiLineIfBlock(DirectCast(ifNode, MultiLineIfBlockSyntax), document, generator, syntaxFacts, result.Model, cancellationToken)
End If
' Complexify the inverted if node.
result = (model, model.SyntaxTree.GetRoot())
Dim invertedIfNode = result.Root.GetAnnotatedNodesAndTokens(s_ifNodeAnnotation).Single().AsNode()
Dim explicitInvertedIfNode = Simplifier.Expand(invertedIfNode, result.Model, document.Project.Solution.Workspace, cancellationToken:=cancellationToken)
result = UpdateSemanticModel(result.Model, result.Root.ReplaceNode(invertedIfNode, explicitInvertedIfNode), cancellationToken)
Return result.Root
End Function
Private Function UpdateSemanticModel(model As SemanticModel, root As SyntaxNode, cancellationToken As CancellationToken) As (Model As SemanticModel, Root As SyntaxNode)
Dim newModel = model.Compilation.ReplaceSyntaxTree(model.SyntaxTree, root.SyntaxTree).GetSemanticModel(root.SyntaxTree)
Return (newModel, newModel.SyntaxTree.GetRoot(cancellationToken))
End Function
Private Function InvertSingleLineIfStatement(
document As Document,
originalIfNode As SingleLineIfStatementSyntax,
generator As SyntaxGenerator,
syntaxFacts As ISyntaxFactsService,
model As SemanticModel,
cancellationToken As CancellationToken) As SemanticModel
Dim root = model.SyntaxTree.GetRoot()
Dim invertedIfNode = GetInvertedIfNode(originalIfNode, document, generator, syntaxFacts, model, cancellationToken)
Dim result = UpdateSemanticModel(model, root.ReplaceNode(originalIfNode, invertedIfNode), cancellationToken)
' Complexify the next statement if there is one.
invertedIfNode = DirectCast(result.Root.GetAnnotatedNodesAndTokens(s_ifNodeAnnotation).Single().AsNode(), SingleLineIfStatementSyntax)
Dim currentStatement As StatementSyntax = invertedIfNode
If currentStatement.HasAncestor(Of ExpressionSyntax)() Then
currentStatement = currentStatement _
.Ancestors() _
.OfType(Of ExpressionSyntax) _
.Last() _
.FirstAncestorOrSelf(Of StatementSyntax)()
End If
Dim nextStatement = currentStatement.GetNextStatement()
If nextStatement IsNot Nothing Then
Dim explicitNextStatement = Simplifier.Expand(nextStatement, result.Model, document.Project.Solution.Workspace, cancellationToken:=cancellationToken)
result = UpdateSemanticModel(result.Model, result.Root.ReplaceNode(nextStatement, explicitNextStatement), cancellationToken)
End If
Return result.Model
End Function
Private Function GetInvertedIfNode(
ifNode As SingleLineIfStatementSyntax,
document As Document,
generator As SyntaxGenerator,
syntaxFacts As ISyntaxFactsService,
semanticModel As SemanticModel,
cancellationToken As CancellationToken) As SingleLineIfStatementSyntax
Dim elseClause = ifNode.ElseClause
' If we're moving a single line if from the else body to the if body,
' and it is the last statement in the body, we have to introduce an extra
' StatementTerminator Colon and Else token.
Dim newIfStatements = elseClause.Statements
If newIfStatements.Count > 0 Then
newIfStatements = newIfStatements.Replace(
newIfStatements.Last,
newIfStatements.Last.WithTrailingTrivia(elseClause.ElseKeyword.GetPreviousToken().TrailingTrivia))
End If
If elseClause.Statements.Count > 0 AndAlso
elseClause.Statements.Last().Kind = SyntaxKind.SingleLineIfStatement Then
Dim singleLineIf = DirectCast(elseClause.Statements.Last, SingleLineIfStatementSyntax)
' Create an Extra 'Else'
If singleLineIf.ElseClause Is Nothing Then
' Replace the last EOL of the IfPart with a :
Dim trailing = singleLineIf.GetTrailingTrivia()
If trailing.Any(SyntaxKind.EndOfLineTrivia) Then
Dim eol = trailing.Last(Function(t) t.Kind = SyntaxKind.EndOfLineTrivia)
trailing = trailing.Select(Function(t) If(t = eol, SyntaxFactory.ColonTrivia(syntaxFacts.GetText(SyntaxKind.ColonTrivia)), t)).ToSyntaxTriviaList()
End If
Dim withElsePart = singleLineIf.WithTrailingTrivia(trailing).WithElseClause(
SyntaxFactory.SingleLineElseClause(SyntaxFactory.List(Of StatementSyntax)()))
' Put the if statement with the else into the statement list
newIfStatements = elseClause.Statements.Replace(elseClause.Statements.Last, withElsePart)
End If
End If
Return ifNode.WithCondition(DirectCast(Negate(ifNode.Condition, generator, syntaxFacts, semanticModel, cancellationToken), ExpressionSyntax)) _
.WithStatements(newIfStatements) _
.WithElseClause(elseClause.WithStatements(ifNode.Statements).WithTrailingTrivia(elseClause.GetTrailingTrivia()))
End Function
#If False Then
' If we have a : following the outermost SingleLineIf, we'll want to remove it and use a statementterminator token instead.
' This ensures that the following statement will stand alone instead of becoming part of the if, as discussed in Bug 14259.
Private Function UpdateStatementList(invertedIfNode As SingleLineIfStatementSyntax, originalIfNode As SingleLineIfStatementSyntax, cancellationToken As CancellationToken) As SyntaxList(Of StatementSyntax)
Dim parentMultiLine = originalIfNode.GetContainingMultiLineExecutableBlocks().FirstOrDefault
Dim statements = parentMultiLine.GetExecutableBlockStatements()
Dim index = statements.IndexOf(originalIfNode)
If index < 0 Then
Return Nothing
End If
If Not invertedIfNode.GetTrailingTrivia().Any(Function(t) t.Kind = SyntaxKind.ColonTrivia) Then
Return Nothing
End If
' swap colon trivia to EOL
Return SyntaxFactory.List(
statements.Replace(
originalIfNode,
invertedIfNode.WithTrailingTrivia(
invertedIfNode.GetTrailingTrivia().Select(
Function(t) If(t.Kind = SyntaxKind.ColonTrivia, SyntaxFactory.CarriageReturnLineFeed, t)))))
End Function
#End If
Private Function InvertMultiLineIfBlock(originalIfNode As MultiLineIfBlockSyntax, document As Document, generator As SyntaxGenerator, syntaxFacts As ISyntaxFactsService, model As SemanticModel, cancellationToken As CancellationToken) As SemanticModel
Dim invertedIfNode = GetInvertedIfNode(originalIfNode, document, generator, syntaxFacts, model, cancellationToken)
Dim result = UpdateSemanticModel(model, model.SyntaxTree.GetRoot().ReplaceNode(originalIfNode, invertedIfNode), cancellationToken)
Return result.Model
End Function
Private Function GetInvertedIfNode(
ifNode As MultiLineIfBlockSyntax,
document As Document,
generator As SyntaxGenerator,
syntaxFacts As ISyntaxFactsService,
semanticModel As SemanticModel,
cancellationToken As CancellationToken) As MultiLineIfBlockSyntax
Dim ifPart = ifNode
Dim elseBlock = ifNode.ElseBlock
Dim ifStatement = ifNode.IfStatement
Dim ifLeadingTrivia = ifNode.GetLeadingTrivia()
Dim endifTrailingTrivia = ifNode.EndIfStatement.GetTrailingTrivia()
Dim elseBlockLeadingTrivia = elseBlock.GetLeadingTrivia()
Dim endifLeadingTrivia = ifNode.EndIfStatement.GetLeadingTrivia()
Return ifNode _
.WithIfStatement(ifStatement.WithCondition(DirectCast(Negate(ifStatement.Condition, generator, syntaxFacts, semanticModel, cancellationToken), ExpressionSyntax))) _
.WithStatements(elseBlock.Statements) _
.WithElseBlock(elseBlock.WithStatements(ifPart.Statements).WithLeadingTrivia(endifLeadingTrivia)) _
.WithEndIfStatement(ifNode.EndIfStatement.WithTrailingTrivia(endifTrailingTrivia).WithLeadingTrivia(elseBlockLeadingTrivia)) _
.WithLeadingTrivia(ifLeadingTrivia)
End Function
Protected Overrides Function GetTitle() As String
Return VBFeaturesResources.Invert_If
End Function
End Class
End Namespace
......@@ -1494,11 +1494,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.VBFeaturesResources
End Property
'''<summary>
''' Looks up a localized string similar to Invert If statement.
''' Looks up a localized string similar to Invert If.
'''</summary>
Friend ReadOnly Property Invert_If_statement() As String
Friend ReadOnly Property Invert_If() As String
Get
Return ResourceManager.GetString("Invert_If_statement", resourceCulture)
Return ResourceManager.GetString("Invert_If", resourceCulture)
End Get
End Property
......
......@@ -138,8 +138,8 @@
<data name="Conflict_s_detected" xml:space="preserve">
<value>Conflict(s) detected.</value>
</data>
<data name="Invert_If_statement" xml:space="preserve">
<value>Invert If statement</value>
<data name="Invert_If" xml:space="preserve">
<value>Invert If</value>
</data>
<data name="Move_the_0_statement_to_line_1" xml:space="preserve">
<value>Move the '{0}' statement to line {1}.</value>
......
......@@ -37,11 +37,6 @@
<target state="translated">Zjistily se konflikty.</target>
<note />
</trans-unit>
<trans-unit id="Invert_If_statement">
<source>Invert If statement</source>
<target state="translated">Obrátit příkaz If</target>
<note />
</trans-unit>
<trans-unit id="Move_the_0_statement_to_line_1">
<source>Move the '{0}' statement to line {1}.</source>
<target state="translated">Přesuňte příkaz {0} na řádek {1}.</target>
......@@ -1827,6 +1822,11 @@ Sub(&lt;seznam_parametrů&gt;) &lt;výraz&gt;</target>
<target state="new">Convert to 'For'</target>
<note />
</trans-unit>
<trans-unit id="Invert_If">
<source>Invert If</source>
<target state="new">Invert If</target>
<note />
</trans-unit>
</body>
</file>
</xliff>
\ No newline at end of file
......@@ -37,11 +37,6 @@
<target state="translated">Konflikt(e) erkannt.</target>
<note />
</trans-unit>
<trans-unit id="Invert_If_statement">
<source>Invert If statement</source>
<target state="translated">Invert If-Anweisung</target>
<note />
</trans-unit>
<trans-unit id="Move_the_0_statement_to_line_1">
<source>Move the '{0}' statement to line {1}.</source>
<target state="translated">Verschieben Sie die "{0}"-Anweisung zu Zeile {1}.</target>
......@@ -1827,6 +1822,11 @@ Sub(&lt;Parameterliste&gt;) &lt;Ausdruck&gt;</target>
<target state="new">Convert to 'For'</target>
<note />
</trans-unit>
<trans-unit id="Invert_If">
<source>Invert If</source>
<target state="new">Invert If</target>
<note />
</trans-unit>
</body>
</file>
</xliff>
\ No newline at end of file
......@@ -37,11 +37,6 @@
<target state="translated">Conflicto(s) detectado(s).</target>
<note />
</trans-unit>
<trans-unit id="Invert_If_statement">
<source>Invert If statement</source>
<target state="translated">Instrucción Invert If</target>
<note />
</trans-unit>
<trans-unit id="Move_the_0_statement_to_line_1">
<source>Move the '{0}' statement to line {1}.</source>
<target state="translated">Mueva la instrucción '{0}' a la línea {1}.</target>
......@@ -1827,6 +1822,11 @@ Sub(&lt;listaDeParámetros&gt;) &lt;instrucción&gt;</target>
<target state="new">Convert to 'For'</target>
<note />
</trans-unit>
<trans-unit id="Invert_If">
<source>Invert If</source>
<target state="new">Invert If</target>
<note />
</trans-unit>
</body>
</file>
</xliff>
\ No newline at end of file
......@@ -37,11 +37,6 @@
<target state="translated">Conflit(s) détecté(s).</target>
<note />
</trans-unit>
<trans-unit id="Invert_If_statement">
<source>Invert If statement</source>
<target state="translated">Inverser l'instruction If</target>
<note />
</trans-unit>
<trans-unit id="Move_the_0_statement_to_line_1">
<source>Move the '{0}' statement to line {1}.</source>
<target state="translated">Déplacez l'instruction '{0}' à la ligne {1}.</target>
......@@ -1827,6 +1822,11 @@ Sub(&lt;parameterList&gt;) &lt;statement&gt;</target>
<target state="new">Convert to 'For'</target>
<note />
</trans-unit>
<trans-unit id="Invert_If">
<source>Invert If</source>
<target state="new">Invert If</target>
<note />
</trans-unit>
</body>
</file>
</xliff>
\ No newline at end of file
......@@ -37,11 +37,6 @@
<target state="translated">Sono stati rilevati conflitti</target>
<note />
</trans-unit>
<trans-unit id="Invert_If_statement">
<source>Invert If statement</source>
<target state="translated">Istruzione Invert If</target>
<note />
</trans-unit>
<trans-unit id="Move_the_0_statement_to_line_1">
<source>Move the '{0}' statement to line {1}.</source>
<target state="translated">Spostare l'istruzione '{0}' alla riga {1}.</target>
......@@ -1827,6 +1822,11 @@ Sub(&lt;elencoParametri&gt;) &lt;istruzione&gt;</target>
<target state="new">Convert to 'For'</target>
<note />
</trans-unit>
<trans-unit id="Invert_If">
<source>Invert If</source>
<target state="new">Invert If</target>
<note />
</trans-unit>
</body>
</file>
</xliff>
\ No newline at end of file
......@@ -37,11 +37,6 @@
<target state="translated">競合が検出されました。</target>
<note />
</trans-unit>
<trans-unit id="Invert_If_statement">
<source>Invert If statement</source>
<target state="translated">If ステートメントを反転します</target>
<note />
</trans-unit>
<trans-unit id="Move_the_0_statement_to_line_1">
<source>Move the '{0}' statement to line {1}.</source>
<target state="translated">{0}' ステートメントを行 {1} に移動します。</target>
......@@ -1826,6 +1821,11 @@ Sub(&lt;parameterList&gt;) &lt;statement&gt;</target>
<target state="new">Convert to 'For'</target>
<note />
</trans-unit>
<trans-unit id="Invert_If">
<source>Invert If</source>
<target state="new">Invert If</target>
<note />
</trans-unit>
</body>
</file>
</xliff>
\ No newline at end of file
......@@ -37,11 +37,6 @@
<target state="translated">충돌이 감지되었습니다.</target>
<note />
</trans-unit>
<trans-unit id="Invert_If_statement">
<source>Invert If statement</source>
<target state="translated">If 문을 반대로 합니다.</target>
<note />
</trans-unit>
<trans-unit id="Move_the_0_statement_to_line_1">
<source>Move the '{0}' statement to line {1}.</source>
<target state="translated">{0}' 문을 {1} 줄로 이동합니다.</target>
......@@ -1827,6 +1822,11 @@ Sub(&lt;parameterList&gt;) &lt;statement&gt;</target>
<target state="new">Convert to 'For'</target>
<note />
</trans-unit>
<trans-unit id="Invert_If">
<source>Invert If</source>
<target state="new">Invert If</target>
<note />
</trans-unit>
</body>
</file>
</xliff>
\ No newline at end of file
......@@ -37,11 +37,6 @@
<target state="translated">Wykryto konflikty.</target>
<note />
</trans-unit>
<trans-unit id="Invert_If_statement">
<source>Invert If statement</source>
<target state="translated">Odwróć instrukcję If</target>
<note />
</trans-unit>
<trans-unit id="Move_the_0_statement_to_line_1">
<source>Move the '{0}' statement to line {1}.</source>
<target state="translated">Przenieś instrukcję „{0}” do wiersza {1}.</target>
......@@ -1827,6 +1822,11 @@ Sub(&lt;listaParametrów&gt;) &lt;instrukcja&gt;</target>
<target state="new">Convert to 'For'</target>
<note />
</trans-unit>
<trans-unit id="Invert_If">
<source>Invert If</source>
<target state="new">Invert If</target>
<note />
</trans-unit>
</body>
</file>
</xliff>
\ No newline at end of file
......@@ -37,11 +37,6 @@
<target state="translated">Conflito(s) detectado(s).</target>
<note />
</trans-unit>
<trans-unit id="Invert_If_statement">
<source>Invert If statement</source>
<target state="translated">Instrução Invert If</target>
<note />
</trans-unit>
<trans-unit id="Move_the_0_statement_to_line_1">
<source>Move the '{0}' statement to line {1}.</source>
<target state="translated">Mova a instrução "{0}" para a linha {1}.</target>
......@@ -1827,6 +1822,11 @@ Sub(&lt;parameterList&gt;) &lt;statement&gt;</target>
<target state="new">Convert to 'For'</target>
<note />
</trans-unit>
<trans-unit id="Invert_If">
<source>Invert If</source>
<target state="new">Invert If</target>
<note />
</trans-unit>
</body>
</file>
</xliff>
\ No newline at end of file
......@@ -37,11 +37,6 @@
<target state="translated">Обнаружены конфликты.</target>
<note />
</trans-unit>
<trans-unit id="Invert_If_statement">
<source>Invert If statement</source>
<target state="translated">Оператор Invert If</target>
<note />
</trans-unit>
<trans-unit id="Move_the_0_statement_to_line_1">
<source>Move the '{0}' statement to line {1}.</source>
<target state="translated">Перемещение оператора "{0}" в строку {1}.</target>
......@@ -1827,6 +1822,11 @@ Sub(&lt;parameterList&gt;) &lt;statement&gt;</target>
<target state="new">Convert to 'For'</target>
<note />
</trans-unit>
<trans-unit id="Invert_If">
<source>Invert If</source>
<target state="new">Invert If</target>
<note />
</trans-unit>
</body>
</file>
</xliff>
\ No newline at end of file
......@@ -37,11 +37,6 @@
<target state="translated">Çakışmalar algılandı.</target>
<note />
</trans-unit>
<trans-unit id="Invert_If_statement">
<source>Invert If statement</source>
<target state="translated">If deyimini ters çevir</target>
<note />
</trans-unit>
<trans-unit id="Move_the_0_statement_to_line_1">
<source>Move the '{0}' statement to line {1}.</source>
<target state="translated">{0}' deyimini {1} satırına taşıyın.</target>
......@@ -1827,6 +1822,11 @@ Sub(&lt;parameterList&gt;) &lt;statement&gt;</target>
<target state="new">Convert to 'For'</target>
<note />
</trans-unit>
<trans-unit id="Invert_If">
<source>Invert If</source>
<target state="new">Invert If</target>
<note />
</trans-unit>
</body>
</file>
</xliff>
\ No newline at end of file
......@@ -37,11 +37,6 @@
<target state="translated">检测到冲突。</target>
<note />
</trans-unit>
<trans-unit id="Invert_If_statement">
<source>Invert If statement</source>
<target state="translated">反转 If 语句</target>
<note />
</trans-unit>
<trans-unit id="Move_the_0_statement_to_line_1">
<source>Move the '{0}' statement to line {1}.</source>
<target state="translated">将“{0}”语句移动到第 {1} 行。</target>
......@@ -1827,6 +1822,11 @@ Sub(&lt;parameterList&gt;) &lt;statement&gt;</target>
<target state="new">Convert to 'For'</target>
<note />
</trans-unit>
<trans-unit id="Invert_If">
<source>Invert If</source>
<target state="new">Invert If</target>
<note />
</trans-unit>
</body>
</file>
</xliff>
\ No newline at end of file
......@@ -37,11 +37,6 @@
<target state="translated">偵測到衝突。</target>
<note />
</trans-unit>
<trans-unit id="Invert_If_statement">
<source>Invert If statement</source>
<target state="translated">反轉 If 陳述式</target>
<note />
</trans-unit>
<trans-unit id="Move_the_0_statement_to_line_1">
<source>Move the '{0}' statement to line {1}.</source>
<target state="translated">將 '{0}' 陳述式移至行 {1}。</target>
......@@ -1827,6 +1822,11 @@ Sub(&lt;parameterList&gt;) &lt;statement&gt;</target>
<target state="new">Convert to 'For'</target>
<note />
</trans-unit>
<trans-unit id="Invert_If">
<source>Invert If</source>
<target state="new">Invert If</target>
<note />
</trans-unit>
</body>
</file>
</xliff>
\ No newline at end of file
......@@ -725,6 +725,21 @@ public SyntaxNode GetNameOfAttribute(SyntaxNode node)
return ((AttributeSyntax)node).Name;
}
public bool IsParenthesizedExpression(SyntaxNode node)
{
return node.Kind() == SyntaxKind.ParenthesizedExpression;
}
public SyntaxNode GetExpressionOfParenthesizedExpression(SyntaxNode node)
{
return ((ParenthesizedExpressionSyntax)node).Expression;
}
public bool IsIfStatement(SyntaxNode node)
{
return (node.Kind() == SyntaxKind.IfStatement);
}
public bool IsAttribute(SyntaxNode node)
{
return node is AttributeSyntax;
......@@ -1603,13 +1618,17 @@ public bool IsDefaultLiteralExpression(SyntaxNode node)
public bool IsBinaryExpression(SyntaxNode node)
=> node is BinaryExpressionSyntax;
public void GetPartsOfBinaryExpression(SyntaxNode node, out SyntaxNode left, out SyntaxNode right)
public void GetPartsOfBinaryExpression(SyntaxNode node, out SyntaxNode left, out SyntaxToken token, out SyntaxNode right)
{
var binaryExpression = (BinaryExpressionSyntax)node;
left = binaryExpression.Left;
right = binaryExpression.Right;
token = binaryExpression.OperatorToken;
}
public SyntaxToken GetOperatorTokenOfBinaryExpression(SyntaxNode node)
=> ((BinaryExpressionSyntax)node).OperatorToken;
public void GetPartsOfConditionalExpression(SyntaxNode node, out SyntaxNode condition, out SyntaxNode whenTrue, out SyntaxNode whenFalse)
{
var conditionalExpression = (ConditionalExpressionSyntax)node;
......@@ -1624,12 +1643,24 @@ public SyntaxNode WalkDownParentheses(SyntaxNode node)
public bool IsLogicalAndExpression(SyntaxNode node)
=> node.Kind() == SyntaxKind.LogicalAndExpression;
public bool IsLogicalOrExpression(SyntaxNode node)
=> node.Kind() == SyntaxKind.LogicalOrExpression;
public bool IsLogicalNotExpression(SyntaxNode node)
=> node.Kind() == SyntaxKind.LogicalNotExpression;
public bool IsConditionalAnd(SyntaxNode node)
=> node.Kind() == SyntaxKind.LogicalAndExpression;
public bool IsConditionalOr(SyntaxNode node)
=> node.Kind() == SyntaxKind.LogicalOrExpression;
public SyntaxNode GetOperandOfPrefixUnaryExpression(SyntaxNode node)
=> ((PrefixUnaryExpressionSyntax)node).Operand;
public SyntaxToken GetOperatorTokenOfPrefixUnaryExpression(SyntaxNode node)
=> ((PrefixUnaryExpressionSyntax)node).OperatorToken;
public SyntaxNode GetNextExecutableStatement(SyntaxNode statement)
=> ((StatementSyntax)statement).GetNextStatement();
......@@ -1805,6 +1836,12 @@ public SyntaxNode WithModifiers(SyntaxNode node, SyntaxTokenList modifiers)
public bool IsLiteralExpression(SyntaxNode node)
=> node is LiteralExpressionSyntax;
public bool IsFalseLiteralExpression(SyntaxNode expression)
=> expression.IsKind(SyntaxKind.FalseLiteralExpression);
public bool IsTrueLiteralExpression(SyntaxNode expression)
=> expression.IsKind(SyntaxKind.TrueLiteralExpression);
public SeparatedSyntaxList<SyntaxNode> GetVariablesOfLocalDeclarationStatement(SyntaxNode node)
=> ((LocalDeclarationStatementSyntax)node).Declaration.Variables;
......
......@@ -60,6 +60,9 @@ internal interface ISyntaxFactsService : ILanguageService
bool IsNullLiteralExpression(SyntaxNode node);
bool IsDefaultLiteralExpression(SyntaxNode node);
bool IsLiteralExpression(SyntaxNode node);
bool IsFalseLiteralExpression(SyntaxNode expression);
bool IsTrueLiteralExpression(SyntaxNode expression);
string GetText(int kind);
bool IsInInactiveRegion(SyntaxTree syntaxTree, int position, CancellationToken cancellationToken);
......@@ -77,7 +80,8 @@ internal interface ISyntaxFactsService : ILanguageService
SyntaxNode GetObjectCreationType(SyntaxNode node);
bool IsBinaryExpression(SyntaxNode node);
void GetPartsOfBinaryExpression(SyntaxNode node, out SyntaxNode left, out SyntaxNode right);
void GetPartsOfBinaryExpression(SyntaxNode node, out SyntaxNode left, out SyntaxToken token, out SyntaxNode right);
void GetPartsOfConditionalExpression(SyntaxNode node, out SyntaxNode condition, out SyntaxNode whenTrue, out SyntaxNode whenFalse);
bool IsCastExpression(SyntaxNode node);
......@@ -93,8 +97,13 @@ internal interface ISyntaxFactsService : ILanguageService
SyntaxNode GetExpressionOfAwaitExpression(SyntaxNode node);
bool IsLogicalAndExpression(SyntaxNode node);
bool IsLogicalOrExpression(SyntaxNode node);
bool IsLogicalNotExpression(SyntaxNode node);
bool IsConditionalAnd(SyntaxNode node);
bool IsConditionalOr(SyntaxNode node);
SyntaxNode GetOperandOfPrefixUnaryExpression(SyntaxNode node);
SyntaxToken GetOperatorTokenOfPrefixUnaryExpression(SyntaxNode node);
// Left side of = assignment.
bool IsLeftSideOfAssignment(SyntaxNode node);
......@@ -156,6 +165,11 @@ internal interface ISyntaxFactsService : ILanguageService
bool IsConditionalMemberAccessExpression(SyntaxNode node);
SyntaxNode GetNameOfAttribute(SyntaxNode node);
bool IsParenthesizedExpression(SyntaxNode node);
SyntaxNode GetExpressionOfParenthesizedExpression(SyntaxNode node);
bool IsIfStatement(SyntaxNode node);
SyntaxToken GetIdentifierOfGenericName(SyntaxNode node);
SyntaxToken GetIdentifierOfSimpleName(SyntaxNode node);
SyntaxToken GetIdentifierOfVariableDeclarator(SyntaxNode node);
......
......@@ -46,5 +46,15 @@ public static bool SpansPreprocessorDirective(this ISyntaxFactsService service,
public static bool IsWhitespaceOrEndOfLineTrivia(this ISyntaxFactsService syntaxFacts, SyntaxTrivia trivia)
=> syntaxFacts.IsWhitespaceTrivia(trivia) || syntaxFacts.IsEndOfLineTrivia(trivia);
public static void GetPartsOfBinaryExpression(this ISyntaxFactsService syntaxFacts, SyntaxNode node, out SyntaxNode left, out SyntaxNode right)
{
syntaxFacts.GetPartsOfBinaryExpression(node, out left, out _, out right);
}
public static void GetOperatorTokenOfBinaryExpression(this ISyntaxFactsService syntaxFacts, SyntaxNode node, out SyntaxToken token)
{
syntaxFacts.GetPartsOfBinaryExpression(node, out _, out token, out _);
}
}
}
......@@ -659,6 +659,18 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Return DirectCast(node, AttributeSyntax).Name
End Function
Public Function IsParenthesizedExpression(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsParenthesizedExpression
Return node.Kind() = SyntaxKind.ParenthesizedExpression
End Function
Public Function GetExpressionOfParenthesizedExpression(node As SyntaxNode) As SyntaxNode Implements ISyntaxFactsService.GetExpressionOfParenthesizedExpression
Return DirectCast(node, ParenthesizedExpressionSyntax).Expression
End Function
Public Function IsIfStatement(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsIfStatement
Return (node.Kind() = SyntaxKind.IfStatement)
End Function
Public Function IsAttribute(node As Microsoft.CodeAnalysis.SyntaxNode) As Boolean Implements ISyntaxFactsService.IsAttribute
Return TypeOf node Is AttributeSyntax
End Function
......@@ -1541,10 +1553,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Return TypeOf node Is BinaryExpressionSyntax
End Function
Public Sub GetPartsOfBinaryExpression(node As SyntaxNode, ByRef left As SyntaxNode, ByRef right As SyntaxNode) Implements ISyntaxFactsService.GetPartsOfBinaryExpression
Public Sub GetPartsOfBinaryExpression(node As SyntaxNode, ByRef left As SyntaxNode, ByRef token As SyntaxToken, ByRef right As SyntaxNode) Implements ISyntaxFactsService.GetPartsOfBinaryExpression
Dim binaryExpression = DirectCast(node, BinaryExpressionSyntax)
left = binaryExpression.Left
right = binaryExpression.Right
token = binaryExpression.OperatorToken
End Sub
Public Sub GetPartsOfConditionalExpression(node As SyntaxNode, ByRef condition As SyntaxNode, ByRef whenTrue As SyntaxNode, ByRef whenFalse As SyntaxNode) Implements ISyntaxFactsService.GetPartsOfConditionalExpression
......@@ -1562,14 +1575,30 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Return node.IsKind(SyntaxKind.AndAlsoExpression)
End Function
Public Function IsLogicalOrExpression(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsLogicalOrExpression
Return node.IsKind(SyntaxKind.OrElseExpression)
End Function
Public Function IsLogicalNotExpression(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsLogicalNotExpression
Return node.IsKind(SyntaxKind.NotExpression)
End Function
Public Function IsConditionalAnd(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsConditionalAnd
Return node.Kind() = SyntaxKind.AndAlsoExpression
End Function
Public Function IsConditionalOr(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsConditionalOr
Return node.Kind() = SyntaxKind.OrElseExpression
End Function
Public Function GetOperandOfPrefixUnaryExpression(node As SyntaxNode) As SyntaxNode Implements ISyntaxFactsService.GetOperandOfPrefixUnaryExpression
Return DirectCast(node, UnaryExpressionSyntax).Operand
End Function
Public Function GetOperatorTokenOfPrefixUnaryExpression(node As SyntaxNode) As SyntaxToken Implements ISyntaxFactsService.GetOperatorTokenOfPrefixUnaryExpression
Return DirectCast(node, UnaryExpressionSyntax).OperatorToken
End Function
Public Sub GetPartsOfMemberAccessExpression(node As SyntaxNode, ByRef expression As SyntaxNode, ByRef name As SyntaxNode) Implements ISyntaxFactsService.GetPartsOfMemberAccessExpression
Dim memberAccess = DirectCast(node, MemberAccessExpressionSyntax)
expression = memberAccess.Expression
......@@ -1717,6 +1746,14 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Return TypeOf node Is LiteralExpressionSyntax
End Function
Public Function IsFalseLiteralExpression(expression As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsFalseLiteralExpression
Return expression.IsKind(SyntaxKind.FalseLiteralExpression)
End Function
Public Function IsTrueLiteralExpression(expression As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsTrueLiteralExpression
Return expression.IsKind(SyntaxKind.TrueLiteralExpression)
End Function
Public Function GetVariablesOfLocalDeclarationStatement(node As SyntaxNode) As SeparatedSyntaxList(Of SyntaxNode) Implements ISyntaxFactsService.GetVariablesOfLocalDeclarationStatement
Return DirectCast(node, LocalDeclarationStatementSyntax).Declarators
End Function
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册