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)); } }
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); } }