提交 c9979d54 编写于 作者: C Cyrus Najmabadi

Extract a service to compute precedence for an expression.

上级 7b0607a5
......@@ -19,6 +19,11 @@ internal class CSharpAddRequiredParenthesesDiagnosticAnalyzer :
AbstractAddRequiredParenthesesDiagnosticAnalyzer<
ExpressionSyntax, ExpressionSyntax, SyntaxKind>
{
public CSharpAddRequiredParenthesesDiagnosticAnalyzer()
: base(CSharpPrecedenceService.Instance)
{
}
private static readonly ImmutableArray<SyntaxKind> s_kinds = ImmutableArray.Create(
SyntaxKind.AddExpression,
SyntaxKind.SubtractExpression,
......@@ -49,9 +54,6 @@ protected override ImmutableArray<SyntaxKind> GetSyntaxNodeKinds()
protected override int GetPrecedence(ExpressionSyntax binaryLike)
=> (int)binaryLike.GetOperatorPrecedence();
protected override PrecedenceKind GetPrecedenceKind(ExpressionSyntax binaryLike)
=> CSharpRemoveUnnecessaryParenthesesDiagnosticAnalyzer.GetPrecedenceKind(binaryLike);
protected override bool IsBinaryLike(ExpressionSyntax node)
=> node is BinaryExpressionSyntax ||
node is IsPatternExpressionSyntax isPattern && isPattern.Pattern is ConstantPatternSyntax;
......
......@@ -5,7 +5,6 @@
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.RemoveUnnecessaryParentheses;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp.RemoveUnnecessaryParentheses
{
......@@ -84,7 +83,7 @@ protected override SyntaxKind GetSyntaxNodeKind()
}
// We're parented by something binary-like.
parentPrecedenceKind = GetPrecedenceKind(parentExpression);
parentPrecedenceKind = CSharpPrecedenceService.Instance.GetPrecedenceKind(parentExpression);
// Precedence is clarified any time we have expression with different precedence
// (and the inner expression is not a primary expression). in other words, this
......@@ -99,26 +98,5 @@ protected override SyntaxKind GetSyntaxNodeKind()
parentExpression.GetOperatorPrecedence() != innerPrecedence;
return true;
}
public static PrecedenceKind GetPrecedenceKind(ExpressionSyntax parentExpression)
{
var precedence = parentExpression.GetOperatorPrecedence();
switch (precedence)
{
case OperatorPrecedence.NullCoalescing: return PrecedenceKind.Coalesce;
case OperatorPrecedence.ConditionalOr:
case OperatorPrecedence.ConditionalAnd: return PrecedenceKind.Logical;
case OperatorPrecedence.LogicalOr:
case OperatorPrecedence.LogicalXor:
case OperatorPrecedence.LogicalAnd: return PrecedenceKind.Bitwise;
case OperatorPrecedence.Equality: return PrecedenceKind.Equality;
case OperatorPrecedence.RelationalAndTypeTesting: return PrecedenceKind.Relational;
case OperatorPrecedence.Shift: return PrecedenceKind.Shift;
case OperatorPrecedence.Additive:
case OperatorPrecedence.Multiplicative: return PrecedenceKind.Arithmetic;
}
throw ExceptionUtilities.UnexpectedValue(precedence);
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.CodeAnalysis.CodeStyle;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.Options;
using Roslyn.Utilities;
......
......@@ -5,6 +5,7 @@
using System.Collections.Immutable;
using Microsoft.CodeAnalysis.CodeStyle;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.RemoveUnnecessaryParentheses;
namespace Microsoft.CodeAnalysis.AddRequiredParentheses
......@@ -19,6 +20,8 @@ internal abstract class AbstractAddRequiredParenthesesDiagnosticAnalyzer<
private static Dictionary<(bool includeInFixAll, string equivalenceKey), ImmutableDictionary<string, string>> s_cachedProperties =
new Dictionary<(bool includeInFixAll, string equivalenceKey), ImmutableDictionary<string, string>>();
private readonly IPrecedenceService _precedenceService;
static AbstractAddRequiredParenthesesDiagnosticAnalyzer()
{
var options = new[]
......@@ -53,16 +56,16 @@ private static string GetEquivalenceKey(Options.PerLanguageOption<CodeStyleOptio
=> s_cachedProperties[(includeInFixAll, equivalenceKey)];
protected abstract int GetPrecedence(TBinaryLikeExpressionSyntax binaryLike);
protected abstract PrecedenceKind GetPrecedenceKind(TBinaryLikeExpressionSyntax binaryLike);
protected abstract TExpressionSyntax TryGetParentExpression(TBinaryLikeExpressionSyntax binaryLike);
protected abstract bool IsBinaryLike(TExpressionSyntax node);
protected abstract (TExpressionSyntax, SyntaxToken, TExpressionSyntax) GetPartsOfBinaryLike(TBinaryLikeExpressionSyntax binaryLike);
protected AbstractAddRequiredParenthesesDiagnosticAnalyzer()
protected AbstractAddRequiredParenthesesDiagnosticAnalyzer(IPrecedenceService precedenceService)
: base(IDEDiagnosticIds.AddRequiredParenthesesDiagnosticId,
new LocalizableResourceString(nameof(FeaturesResources.Add_parentheses_for_clarity), FeaturesResources.ResourceManager, typeof(FeaturesResources)),
new LocalizableResourceString(nameof(FeaturesResources.Parentheses_should_be_added_for_clarity), FeaturesResources.ResourceManager, typeof(FeaturesResources)))
{
_precedenceService = precedenceService;
}
public sealed override DiagnosticAnalyzerCategory GetAnalyzerCategory()
......@@ -99,8 +102,8 @@ private void AnalyzeSyntax(SyntaxNodeAnalysisContext context)
return;
}
var childPrecedence = GetLanguageOption(GetPrecedenceKind(binaryLike));
var parentPrecedence = GetLanguageOption(GetPrecedenceKind(parentBinaryLike));
var childPrecedence = GetLanguageOption(_precedenceService.GetPrecedenceKind(binaryLike));
var parentPrecedence = GetLanguageOption(_precedenceService.GetPrecedenceKind(parentBinaryLike));
// only add parentheses within the same precedence band.
if (parentPrecedence != childPrecedence)
......
......@@ -4,8 +4,6 @@ Imports System.Collections.Immutable
Imports System.Composition
Imports Microsoft.CodeAnalysis.AddRequiredParentheses
Imports Microsoft.CodeAnalysis.Diagnostics
Imports Microsoft.CodeAnalysis.RemoveUnnecessaryParentheses
Imports Microsoft.CodeAnalysis.VisualBasic.RemoveUnnecessaryParentheses
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
Namespace Microsoft.CodeAnalysis.VisualBasic.AddRequiredParentheses
......@@ -14,6 +12,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.AddRequiredParentheses
Inherits AbstractAddRequiredParenthesesDiagnosticAnalyzer(Of
ExpressionSyntax, BinaryExpressionSyntax, SyntaxKind)
Public Sub New()
MyBase.New(VisualBasicPrecedenceService.Instance)
End Sub
Private Shared ReadOnly s_kinds As ImmutableArray(Of SyntaxKind) = ImmutableArray.Create(
SyntaxKind.AddExpression,
SyntaxKind.SubtractExpression,
......@@ -52,10 +54,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.AddRequiredParentheses
Return binary.GetOperatorPrecedence()
End Function
Protected Overrides Function GetPrecedenceKind(binary As BinaryExpressionSyntax) As PrecedenceKind
Return VisualBasicRemoveUnnecessaryParenthesesDiagnosticAnalyzer.GetPrecedenceKind(binary)
End Function
Protected Overrides Function TryGetParentExpression(binary As BinaryExpressionSyntax) As ExpressionSyntax
Return TryCast(binary.Parent, ExpressionSyntax)
End Function
......
......@@ -44,7 +44,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.RemoveUnnecessaryParentheses
Dim parentBinary = TryCast(parenthesizedExpression.Parent, BinaryExpressionSyntax)
If parentBinary IsNot Nothing Then
precedence = GetPrecedenceKind(parentBinary)
precedence = VisualBasicPrecedenceService.Instance.GetPrecedenceKind(parentBinary)
clarifiesPrecedence = Not innerExpressionIsSimple AndAlso
parentBinary.GetOperatorPrecedence() <> innerExpressionPrecedence
Return True
......@@ -54,31 +54,5 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.RemoveUnnecessaryParentheses
clarifiesPrecedence = False
Return True
End Function
Public Shared Function GetPrecedenceKind(binary As BinaryExpressionSyntax) As PrecedenceKind
Dim precedence = binary.GetOperatorPrecedence()
Select Case precedence
Case OperatorPrecedence.PrecedenceXor,
OperatorPrecedence.PrecedenceOr,
OperatorPrecedence.PrecedenceAnd
Return PrecedenceKind.Logical
Case OperatorPrecedence.PrecedenceRelational
Return PrecedenceKind.Relational
Case OperatorPrecedence.PrecedenceShift
Return PrecedenceKind.Shift
Case OperatorPrecedence.PrecedenceConcatenate,
OperatorPrecedence.PrecedenceAdd,
OperatorPrecedence.PrecedenceModulus,
OperatorPrecedence.PrecedenceIntegerDivide,
OperatorPrecedence.PrecedenceMultiply,
OperatorPrecedence.PrecedenceExponentiate
Return PrecedenceKind.Arithmetic
End Select
Throw ExceptionUtilities.UnexpectedValue(precedence)
End Function
End Class
End Namespace
// 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 Microsoft.CodeAnalysis.CSharp.Extensions;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.LanguageServices;
namespace Microsoft.CodeAnalysis.CSharp
{
[ExportLanguageService(typeof(IPrecedenceService), LanguageNames.CSharp), Shared]
internal class CSharpPrecedenceService : AbstractPrecedenceService<ExpressionSyntax, OperatorPrecedence>
{
public static readonly CSharpPrecedenceService Instance = new CSharpPrecedenceService();
public override OperatorPrecedence GetOperatorPrecedence(ExpressionSyntax expression)
=> expression.GetOperatorPrecedence();
public override PrecedenceKind GetPrecedenceKind(OperatorPrecedence precedence)
{
switch (precedence)
{
case OperatorPrecedence.NullCoalescing: return PrecedenceKind.Coalesce;
case OperatorPrecedence.ConditionalOr:
case OperatorPrecedence.ConditionalAnd: return PrecedenceKind.Logical;
case OperatorPrecedence.LogicalOr:
case OperatorPrecedence.LogicalXor:
case OperatorPrecedence.LogicalAnd: return PrecedenceKind.Bitwise;
case OperatorPrecedence.Equality: return PrecedenceKind.Equality;
case OperatorPrecedence.RelationalAndTypeTesting: return PrecedenceKind.Relational;
case OperatorPrecedence.Shift: return PrecedenceKind.Shift;
case OperatorPrecedence.Additive:
case OperatorPrecedence.Multiplicative: return PrecedenceKind.Arithmetic;
default: return PrecedenceKind.Other;
}
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.CodeAnalysis.Host;
namespace Microsoft.CodeAnalysis.LanguageServices
{
interface IPrecedenceService : ILanguageService
{
/// <summary>
/// Returns the precedence of the given expression, mapped down to one of the
/// <see cref="PrecedenceKind"/> values. The mapping is language specific.
/// </summary>
PrecedenceKind GetPrecedenceKind(int operatorPrecedence);
/// <summary>
/// Returns the precedence of this expression in a scale specific to a particular
/// language. These values cannot be compared across languages, but relates the
/// precedence of expressions in the same language. A smaller value means lower
/// precedence.
/// </summary>
int GetOperatorPrecedence(SyntaxNode expression);
}
internal abstract class AbstractPrecedenceService<
TExpressionSyntax,
TOperatorPrecedence> : IPrecedenceService
where TExpressionSyntax : SyntaxNode
where TOperatorPrecedence : struct
{
int IPrecedenceService.GetOperatorPrecedence(SyntaxNode expression)
=> (int)(object)this.GetOperatorPrecedence((TExpressionSyntax)expression);
PrecedenceKind IPrecedenceService.GetPrecedenceKind(int operatorPrecedence)
=> this.GetPrecedenceKind((TOperatorPrecedence)(object)operatorPrecedence);
public abstract TOperatorPrecedence GetOperatorPrecedence(TExpressionSyntax expression);
public abstract PrecedenceKind GetPrecedenceKind(TOperatorPrecedence operatorPrecedence);
}
internal static class PrecedenceServiceExtensions
{
public static PrecedenceKind GetPrecedenceKind(this IPrecedenceService service, SyntaxNode expression)
=> service.GetPrecedenceKind(service.GetOperatorPrecedence(expression));
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Microsoft.CodeAnalysis.RemoveUnnecessaryParentheses
namespace Microsoft.CodeAnalysis.LanguageServices
{
internal enum PrecedenceKind
{
......
' 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 Microsoft.CodeAnalysis.Host.Mef
Imports Microsoft.CodeAnalysis.LanguageServices
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
Namespace Microsoft.CodeAnalysis.VisualBasic
<ExportLanguageService(GetType(IPrecedenceService), LanguageNames.VisualBasic), [Shared]>
Friend Class VisualBasicPrecedenceService
Inherits AbstractPrecedenceService(Of ExpressionSyntax, OperatorPrecedence)
Public Shared ReadOnly Instance As New VisualBasicPrecedenceService()
Public Overrides Function GetOperatorPrecedence(expression As ExpressionSyntax) As OperatorPrecedence
Return expression.GetOperatorPrecedence()
End Function
Public Overrides Function GetPrecedenceKind(operatorPrecedence As OperatorPrecedence) As PrecedenceKind
Select Case operatorPrecedence
Case OperatorPrecedence.PrecedenceXor,
OperatorPrecedence.PrecedenceOr,
OperatorPrecedence.PrecedenceAnd
Return PrecedenceKind.Logical
Case OperatorPrecedence.PrecedenceRelational
Return PrecedenceKind.Relational
Case OperatorPrecedence.PrecedenceShift
Return PrecedenceKind.Shift
Case OperatorPrecedence.PrecedenceConcatenate,
OperatorPrecedence.PrecedenceAdd,
OperatorPrecedence.PrecedenceModulus,
OperatorPrecedence.PrecedenceIntegerDivide,
OperatorPrecedence.PrecedenceMultiply,
OperatorPrecedence.PrecedenceExponentiate
Return PrecedenceKind.Arithmetic
Case Else
Return PrecedenceKind.Other
End Select
End Function
End Class
End Namespace
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册