Beispiel #1
0
        private static void AnalyzeSimpleMemberAccessExpression(SyntaxNodeAnalysisContext context)
        {
            var memberAccessExpression = (MemberAccessExpressionSyntax)context.Node;

            SimpleNameSyntax name = memberAccessExpression.Name;

            switch (name)
            {
            case IdentifierNameSyntax identifierName:
            {
                switch (identifierName.Identifier.ValueText)
                {
                case "Start":
                {
                    ExpressionSyntax expression = memberAccessExpression.Expression;

                    if (!expression.IsKind(SyntaxKind.SimpleMemberAccessExpression))
                    {
                        break;
                    }

                    ISymbol symbol = context.SemanticModel.GetSymbol(memberAccessExpression, context.CancellationToken);

                    if (symbol == null)
                    {
                        break;
                    }

                    if (!symbol.ContainingType.HasMetadataName(RoslynMetadataNames.Microsoft_CodeAnalysis_Text_TextSpan))
                    {
                        break;
                    }

                    var memberAccess2 = (MemberAccessExpressionSyntax)expression;

                    SimpleNameSyntax name2 = memberAccess2.Name;

                    if (!(name2 is IdentifierNameSyntax identifierName2))
                    {
                        break;
                    }

                    if (!string.Equals(identifierName2.Identifier.ValueText, "Span", StringComparison.Ordinal))
                    {
                        break;
                    }

                    ISymbol symbol2 = context.SemanticModel.GetSymbol(expression, context.CancellationToken);

                    if (symbol2 == null)
                    {
                        break;
                    }

                    if (!symbol2.ContainingType.HasMetadataName(RoslynMetadataNames.Microsoft_CodeAnalysis_SyntaxNode))
                    {
                        break;
                    }

                    DiagnosticHelpers.ReportDiagnostic(context, DiagnosticRules.UsePropertySyntaxNodeSpanStart, memberAccessExpression);
                    break;
                }

                case "Count":
                {
                    CallAnyInsteadOfUsingCount();
                    break;
                }
                }

                break;
            }
            }

            void CallAnyInsteadOfUsingCount()
            {
                SyntaxNode expression = memberAccessExpression.WalkUpParentheses();

                SyntaxNode parent = expression.Parent;

                if (!parent.IsKind(SyntaxKind.EqualsExpression, SyntaxKind.NotEqualsExpression, SyntaxKind.GreaterThanExpression))
                {
                    return;
                }

                BinaryExpressionInfo binaryExpressionInfo = SyntaxInfo.BinaryExpressionInfo((BinaryExpressionSyntax)parent);

                if (!binaryExpressionInfo.Success)
                {
                    return;
                }

                ExpressionSyntax otherExpression = (expression == binaryExpressionInfo.Left)
                    ? binaryExpressionInfo.Right
                    : binaryExpressionInfo.Left;

                if (!otherExpression.IsKind(SyntaxKind.NumericLiteralExpression))
                {
                    return;
                }

                var numericLiteralExpression = (LiteralExpressionSyntax)otherExpression;

                if (numericLiteralExpression.Token.ValueText != "0")
                {
                    return;
                }

                ISymbol symbol = context.SemanticModel.GetSymbol(memberAccessExpression, context.CancellationToken);

                if (symbol?.Kind != SymbolKind.Property ||
                    symbol.IsStatic ||
                    symbol.DeclaredAccessibility != Accessibility.Public ||
                    !RoslynSymbolUtility.IsList(symbol.ContainingType.OriginalDefinition))
                {
                    return;
                }

                TextSpan span = (memberAccessExpression == binaryExpressionInfo.Left)
                    ? TextSpan.FromBounds(name.SpanStart, numericLiteralExpression.Span.End)
                    : TextSpan.FromBounds(numericLiteralExpression.SpanStart, name.Span.End);

                DiagnosticHelpers.ReportDiagnostic(context, DiagnosticRules.CallAnyInsteadOfAccessingCount, Location.Create(memberAccessExpression.SyntaxTree, span));
            }
        }
Beispiel #2
0
        private static void AnalyzeElementAccessExpression(SyntaxNodeAnalysisContext context)
        {
            var elementAccessExpression = (ElementAccessExpressionSyntax)context.Node;

            ExpressionSyntax expression = elementAccessExpression
                                          .ArgumentList
                                          .Arguments
                                          .SingleOrDefault(shouldThrow: false)?
                                          .Expression
                                          .WalkDownParentheses();

            if (expression == null)
            {
                return;
            }

            if (!expression.IsKind(SyntaxKind.SubtractExpression))
            {
                return;
            }

            BinaryExpressionInfo subtractExpressionInfo = SyntaxInfo.BinaryExpressionInfo((BinaryExpressionSyntax)expression);

            if (!subtractExpressionInfo.Right.IsNumericLiteralExpression("1"))
            {
                return;
            }

            if (!subtractExpressionInfo.Left.IsKind(SyntaxKind.SimpleMemberAccessExpression))
            {
                return;
            }

            var memberAccessExpression = (MemberAccessExpressionSyntax)subtractExpressionInfo.Left;

            if (!(memberAccessExpression.Name is IdentifierNameSyntax identifierName))
            {
                return;
            }

            if (identifierName.Identifier.ValueText != "Count")
            {
                return;
            }

            if (!CSharpFactory.AreEquivalent(elementAccessExpression.Expression, memberAccessExpression.Expression))
            {
                return;
            }

            ISymbol symbol = context.SemanticModel.GetSymbol(elementAccessExpression, context.CancellationToken);

            if (symbol?.Kind != SymbolKind.Property ||
                symbol.IsStatic ||
                symbol.DeclaredAccessibility != Accessibility.Public ||
                !RoslynSymbolUtility.IsList(symbol.ContainingType.OriginalDefinition))
            {
                return;
            }

            context.ReportDiagnostic(DiagnosticDescriptors.CallLastInsteadOfUsingElementAccess, elementAccessExpression.ArgumentList);
        }
        private static void AnalyzeInvocationExpression(SyntaxNodeAnalysisContext context)
        {
            var invocationExpression = (InvocationExpressionSyntax)context.Node;

            if (invocationExpression.ContainsDiagnostics)
            {
                return;
            }

            SimpleMemberInvocationExpressionInfo invocationInfo = SyntaxInfo.SimpleMemberInvocationExpressionInfo(invocationExpression);

            if (!invocationInfo.Success)
            {
                return;
            }

            ISymbol symbol = null;

            string methodName = invocationInfo.NameText;

            switch (invocationInfo.Arguments.Count)
            {
            case 0:
            {
                switch (methodName)
                {
                case "First":
                {
                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.UseElementAccess))
                    {
                        UseElementAccessInsteadOfCallingFirst();
                    }

                    break;
                }
                }

                break;
            }

            case 1:
            {
                switch (methodName)
                {
                case "ElementAt":
                {
                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.UseElementAccess))
                    {
                        UseElementAccessInsteadOfCallingElementAt();
                    }

                    break;
                }

                case "IsKind":
                {
                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.UnnecessaryNullCheck))
                    {
                        AnalyzeUnnecessaryNullCheck();
                    }

                    break;
                }
                }

                break;
            }
            }

            if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.UseReturnValue) &&
                invocationExpression.IsParentKind(SyntaxKind.ExpressionStatement))
            {
                UseReturnValue();
            }

            void AnalyzeUnnecessaryNullCheck()
            {
                ExpressionSyntax expression = invocationInfo.InvocationExpression.WalkUpParentheses();

                SyntaxNode parent = expression.Parent;

                if (!parent.IsKind(SyntaxKind.LogicalAndExpression))
                {
                    return;
                }

                var binaryExpression = (BinaryExpressionSyntax)parent;

                if (expression != binaryExpression.Right)
                {
                    return;
                }

                if (binaryExpression.Left.ContainsDirectives)
                {
                    return;
                }

                if (binaryExpression.OperatorToken.ContainsDirectives)
                {
                    return;
                }

                NullCheckExpressionInfo nullCheckInfo = SyntaxInfo.NullCheckExpressionInfo(binaryExpression.Left, NullCheckStyles.CheckingNotNull & ~NullCheckStyles.HasValue);

                if (!nullCheckInfo.Success)
                {
                    return;
                }

                if (!CSharpFactory.AreEquivalent(invocationInfo.Expression, nullCheckInfo.Expression))
                {
                    return;
                }

                if (!CSharpSymbolUtility.IsIsKindExtensionMethod(invocationExpression, context.SemanticModel, context.CancellationToken))
                {
                    return;
                }

                TextSpan span = TextSpan.FromBounds(binaryExpression.Left.SpanStart, binaryExpression.OperatorToken.Span.End);

                DiagnosticHelpers.ReportDiagnostic(
                    context,
                    DiagnosticDescriptors.UnnecessaryNullCheck,
                    Location.Create(invocationInfo.InvocationExpression.SyntaxTree, span));
            }

            void UseElementAccessInsteadOfCallingFirst()
            {
                if (!invocationInfo.Expression.GetTrailingTrivia().IsEmptyOrWhitespace())
                {
                    return;
                }

                symbol = context.SemanticModel.GetSymbol(invocationExpression, context.CancellationToken);

                if (symbol?.Kind != SymbolKind.Method ||
                    symbol.IsStatic ||
                    symbol.DeclaredAccessibility != Accessibility.Public ||
                    !RoslynSymbolUtility.IsList(symbol.ContainingType.OriginalDefinition))
                {
                    return;
                }

                TextSpan span = TextSpan.FromBounds(invocationInfo.Name.SpanStart, invocationExpression.Span.End);

                DiagnosticHelpers.ReportDiagnostic(
                    context,
                    DiagnosticDescriptors.UseElementAccess,
                    Location.Create(invocationExpression.SyntaxTree, span));
            }

            void UseElementAccessInsteadOfCallingElementAt()
            {
                if (!invocationInfo.Expression.GetTrailingTrivia().IsEmptyOrWhitespace())
                {
                    return;
                }

                symbol = context.SemanticModel.GetSymbol(invocationExpression, context.CancellationToken);

                if (symbol?.Kind != SymbolKind.Method ||
                    symbol.IsStatic ||
                    symbol.DeclaredAccessibility != Accessibility.Public ||
                    !symbol.ContainingType.OriginalDefinition.HasMetadataName(RoslynMetadataNames.Microsoft_CodeAnalysis_SyntaxTriviaList))
                {
                    return;
                }

                TextSpan span = TextSpan.FromBounds(invocationInfo.Name.SpanStart, invocationExpression.Span.End);

                DiagnosticHelpers.ReportDiagnostic(
                    context,
                    DiagnosticDescriptors.UseElementAccess,
                    Location.Create(invocationExpression.SyntaxTree, span));
            }

            void UseReturnValue()
            {
                if (symbol == null)
                {
                    symbol = context.SemanticModel.GetSymbol(invocationExpression, context.CancellationToken);
                }

                if (symbol?.Kind != SymbolKind.Method)
                {
                    return;
                }

                if (!RoslynSymbolUtility.IsRoslynType(symbol.ContainingType))
                {
                    return;
                }

                var methodSymbol = (IMethodSymbol)symbol;

                if (!RoslynSymbolUtility.IsRoslynType(methodSymbol.ReturnType))
                {
                    return;
                }

                DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.UseReturnValue, invocationExpression);
            }
        }