Ejemplo n.º 1
0
        private static void AnalyzeBitwiseAndExpression(SyntaxNodeAnalysisContext context)
        {
            var bitwiseAnd = (BinaryExpressionSyntax)context.Node;

            ExpressionSyntax expression = bitwiseAnd.WalkUpParentheses();

            if (!expression.IsParentKind(SyntaxKind.EqualsExpression, SyntaxKind.NotEqualsExpression))
            {
                return;
            }

            var equalsOrNotEquals = (BinaryExpressionSyntax)expression.Parent;

            ExpressionSyntax otherExpression = (ReferenceEquals(equalsOrNotEquals.Left, expression))
                ? equalsOrNotEquals.Right
                : equalsOrNotEquals.Left;

            otherExpression = otherExpression.WalkDownParentheses();

            ExpressionSyntax right = bitwiseAnd.Right.WalkDownParentheses();

            SemanticModel     semanticModel     = context.SemanticModel;
            CancellationToken cancellationToken = context.CancellationToken;

            if (otherExpression.IsNumericLiteralExpression("0"))
            {
                if (SyntaxUtility.IsCompositeEnumValue(right, semanticModel, cancellationToken))
                {
                    return;
                }
            }
            else if (!CSharpFactory.AreEquivalent(right, otherExpression))
            {
                return;
            }

            IMethodSymbol methodSymbol = semanticModel.GetMethodSymbol(bitwiseAnd, cancellationToken);

            if (methodSymbol?.MethodKind != MethodKind.BuiltinOperator ||
                methodSymbol.Name != WellKnownMemberNames.BitwiseAndOperatorName ||
                methodSymbol.ContainingType?.TypeKind != TypeKind.Enum)
            {
                return;
            }

            ExpressionSyntax left = bitwiseAnd.Left.WalkDownParentheses();

            if (!IsSuitableAsExpressionOfHasFlag(left))
            {
                return;
            }

            if (!IsSuitableAsArgumentOfHasFlag(right))
            {
                return;
            }

            DiagnosticHelpers.ReportDiagnostic(
                context,
                DiagnosticRules.ReportOnly.ConvertBitwiseOperationToHasFlagCall,
                equalsOrNotEquals);

            bool IsSuitableAsExpressionOfHasFlag(ExpressionSyntax expression)
            {
                if (expression.IsKind(
                        SyntaxKind.IdentifierName,
                        SyntaxKind.SimpleMemberAccessExpression,
                        SyntaxKind.InvocationExpression,
                        SyntaxKind.ElementAccessExpression))
                {
                    return(semanticModel.GetTypeSymbol(expression, cancellationToken)?.TypeKind == TypeKind.Enum);
                }

                return(false);
            }

            bool IsSuitableAsArgumentOfHasFlag(ExpressionSyntax expression)
            {
                expression = expression.WalkDownParentheses();

                if (expression.IsKind(
                        SyntaxKind.BitwiseAndExpression,
                        SyntaxKind.BitwiseOrExpression,
                        SyntaxKind.SimpleMemberAccessExpression,
                        SyntaxKind.IdentifierName))
                {
                    return(semanticModel.GetTypeSymbol(expression, cancellationToken)?.TypeKind == TypeKind.Enum);
                }

                return(false);
            }
        }
Ejemplo n.º 2
0
        public static Task <Document> RefactorAsync(
            Document document,
            InvocationExpressionSyntax invocation,
            SemanticModel semanticModel,
            CancellationToken cancellationToken = default)
        {
            ExpressionSyntax expression = invocation.ArgumentList.Arguments[0].Expression;

            bool isComposite = SyntaxUtility.IsCompositeEnumValue(expression, semanticModel, cancellationToken);

            ParenthesizedExpressionSyntax parenthesizedExpression = ParenthesizedExpression(
                BitwiseAndExpression(
                    ((MemberAccessExpressionSyntax)invocation.Expression).Expression.Parenthesize(),
                    expression.Parenthesize())
                .Parenthesize());

            SyntaxKind binaryExpressionKind = (isComposite) ? SyntaxKind.EqualsExpression : SyntaxKind.NotEqualsExpression;

            SyntaxNode nodeToReplace = invocation;

            SyntaxNode parent = invocation.Parent;

            if (!parent.SpanContainsDirectives())
            {
                switch (parent.Kind())
                {
                case SyntaxKind.LogicalNotExpression:
                {
                    binaryExpressionKind = (isComposite) ? SyntaxKind.NotEqualsExpression : SyntaxKind.EqualsExpression;
                    nodeToReplace        = parent;
                    break;
                }

                case SyntaxKind.EqualsExpression:
                {
                    switch (((BinaryExpressionSyntax)parent).Right?.Kind())
                    {
                    case SyntaxKind.TrueLiteralExpression:
                    {
                        binaryExpressionKind = (isComposite) ? SyntaxKind.EqualsExpression : SyntaxKind.NotEqualsExpression;
                        nodeToReplace        = parent;
                        break;
                    }

                    case SyntaxKind.FalseLiteralExpression:
                    {
                        binaryExpressionKind = (isComposite) ? SyntaxKind.NotEqualsExpression : SyntaxKind.EqualsExpression;
                        nodeToReplace        = parent;
                        break;
                    }
                    }

                    break;
                }
                }
            }

            ExpressionSyntax right;

            if (isComposite)
            {
                right = expression.Parenthesize();
            }
            else
            {
                right = NumericLiteralExpression(0);
            }

            ParenthesizedExpressionSyntax newNode = BinaryExpression(binaryExpressionKind, parenthesizedExpression, right).WithTriviaFrom(nodeToReplace)
                                                    .Parenthesize()
                                                    .WithFormatterAnnotation();

            return(document.ReplaceNodeAsync(nodeToReplace, newNode, cancellationToken));
        }