public override async Task RegisterCodeFixesAsync(CodeFixContext context) { SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false); if (!TryFindFirstAncestorOrSelf(root, context.Span, out SyntaxNode node, predicate: f => f.IsKind(SyntaxKind.CastExpression, SyntaxKind.InvocationExpression))) { return; } switch (node.Kind()) { case SyntaxKind.CastExpression: { CodeAction codeAction = CodeAction.Create( "Remove redundant cast", cancellationToken => RemoveRedundantCastRefactoring.RefactorAsync(context.Document, (CastExpressionSyntax)node, cancellationToken), GetEquivalenceKey(DiagnosticIdentifiers.RemoveRedundantCast)); context.RegisterCodeFix(codeAction, context.Diagnostics); break; } case SyntaxKind.InvocationExpression: { CodeAction codeAction = CodeAction.Create( "Remove redundant cast", cancellationToken => RemoveRedundantCastRefactoring.RefactorAsync(context.Document, (InvocationExpressionSyntax)node, cancellationToken), GetEquivalenceKey(DiagnosticIdentifiers.RemoveRedundantCast)); context.RegisterCodeFix(codeAction, context.Diagnostics); break; } } }
public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false); SyntaxNode node = root .FindNode(context.Span, getInnermostNodeForTie: true)? .FirstAncestorOrSelf(f => f.IsKind(SyntaxKind.CastExpression, SyntaxKind.InvocationExpression)); Debug.Assert(node != null, $"{nameof(node)} is null"); if (node == null) { return; } switch (node.Kind()) { case SyntaxKind.CastExpression: { CodeAction codeAction = CodeAction.Create( "Remove redundant cast", cancellationToken => RemoveRedundantCastRefactoring.RefactorAsync(context.Document, (CastExpressionSyntax)node, cancellationToken), DiagnosticIdentifiers.RemoveRedundantCast + EquivalenceKeySuffix); context.RegisterCodeFix(codeAction, context.Diagnostics); break; } case SyntaxKind.InvocationExpression: { CodeAction codeAction = CodeAction.Create( "Remove redundant cast", cancellationToken => RemoveRedundantCastRefactoring.RefactorAsync(context.Document, (InvocationExpressionSyntax)node, cancellationToken), DiagnosticIdentifiers.RemoveRedundantCast + EquivalenceKeySuffix); context.RegisterCodeFix(codeAction, context.Diagnostics); break; } } }
private void AnalyzeInvocationExpression(SyntaxNodeAnalysisContext context) { var invocation = (InvocationExpressionSyntax)context.Node; ExpressionSyntax expression = invocation.Expression; if (expression?.IsKind(SyntaxKind.SimpleMemberAccessExpression) == true) { var memberAccess = (MemberAccessExpressionSyntax)expression; ArgumentListSyntax argumentList = invocation.ArgumentList; if (argumentList?.IsMissing == false) { int argumentCount = argumentList.Arguments.Count; string methodName = memberAccess.Name?.Identifier.ValueText; if (argumentCount == 0) { switch (methodName) { case "Any": { SimplifyLinqMethodChainRefactoring.Analyze(context, invocation, memberAccess, methodName); break; } case "Cast": { CallOfTypeInsteadOfWhereAndCastRefactoring.Analyze(context, invocation); break; } case "Count": case "First": case "FirstOrDefault": case "Last": case "LastOrDefault": case "LongCount": case "Single": case "SingleOrDefault": { SimplifyLinqMethodChainRefactoring.Analyze(context, invocation, memberAccess, methodName); break; } } } else if (argumentCount == 1) { switch (methodName) { case "FirstOrDefault": { CallFindInsteadOfFirstOrDefaultRefactoring.Analyze(context, invocation, memberAccess); break; } case "Where": { CombineEnumerableWhereMethodChainRefactoring.Analyze(context, invocation, memberAccess); break; } } } } } if (UseBitwiseOperationInsteadOfCallingHasFlagRefactoring.CanRefactor(invocation, context.SemanticModel, context.CancellationToken) && !invocation.SpanContainsDirectives()) { context.ReportDiagnostic(DiagnosticDescriptors.UseBitwiseOperationInsteadOfCallingHasFlag, invocation); } RemoveRedundantStringToCharArrayCallRefactoring.Analyze(context, invocation); CombineEnumerableWhereAndAnyRefactoring.AnalyzeInvocationExpression(context); if (!invocation.ContainsDiagnostics) { if (!invocation.SpanContainsDirectives()) { CallExtensionMethodAsInstanceMethodAnalysis analysis = CallExtensionMethodAsInstanceMethodRefactoring.Analyze(invocation, context.SemanticModel, allowAnyExpression: false, cancellationToken: context.CancellationToken); if (analysis.Success && context.SemanticModel .GetEnclosingNamedType(analysis.InvocationExpression.SpanStart, context.CancellationToken)? .Equals(analysis.MethodSymbol.ContainingType) == false) { context.ReportDiagnostic(DiagnosticDescriptors.CallExtensionMethodAsInstanceMethod, invocation); } } MemberInvocationExpressionInfo invocationInfo = SyntaxInfo.MemberInvocationExpressionInfo(invocation); if (invocationInfo.Success) { if (!invocation.SpanContainsDirectives()) { UseRegexInstanceInsteadOfStaticMethodRefactoring.Analyze(context, invocationInfo); } string methodName = invocationInfo.NameText; AvoidNullReferenceExceptionRefactoring.Analyze(context, invocationInfo); int argumentCount = invocationInfo.Arguments.Count; switch (argumentCount) { case 0: { switch (methodName) { case "Any": { UseCountOrLengthPropertyInsteadOfAnyMethodRefactoring.Analyze(context, invocationInfo); break; } case "Cast": { RemoveRedundantCastRefactoring.Analyze(context, invocationInfo); break; } case "Count": { UseInsteadOfCountMethodRefactoring.Analyze(context, invocationInfo); break; } case "First": { if (!invocationInfo.Expression.IsKind(SyntaxKind.InvocationExpression) && UseElementAccessInsteadOfFirstRefactoring.CanRefactor(invocationInfo, context.SemanticModel, context.CancellationToken)) { context.ReportDiagnostic(DiagnosticDescriptors.UseElementAccessInsteadOfFirst, invocationInfo.Name); } break; } case "ToString": { RemoveRedundantToStringCallRefactoring.Analyze(context, invocationInfo); UseNameOfOperatorRefactoring.Analyze(context, invocationInfo); break; } case "ToLower": case "ToLowerInvariant": case "ToUpper": case "ToUpperInvariant": { UseStringComparisonRefactoring.Analyze(context, invocationInfo); break; } } break; } case 1: { switch (methodName) { case "All": case "Any": { SimplifyLogicalNegationRefactoring.Analyze(context, invocationInfo); break; } case "ElementAt": { if (!invocationInfo.Expression.IsKind(SyntaxKind.InvocationExpression) && UseElementAccessInsteadOfElementAtRefactoring.CanRefactor(invocationInfo, context.SemanticModel, context.CancellationToken)) { context.ReportDiagnostic(DiagnosticDescriptors.UseElementAccessInsteadOfElementAt, invocationInfo.Name); } break; } } break; } } switch (methodName) { case "Append": case "AppendLine": case "AppendFormat": case "Insert": { OptimizeStringBuilderAppendCallRefactoring.Analyze(context, invocationInfo); break; } case "Select": { if (argumentCount == 1 || argumentCount == 2) { CallCastInsteadOfSelectRefactoring.Analyze(context, invocationInfo); } break; } case "OrderBy": case "OrderByDescending": { if (argumentCount == 1 || argumentCount == 2 || argumentCount == 3) { CallThenByInsteadOfOrderByRefactoring.Analyze(context, invocationInfo); } break; } } if (UseMethodChainingRefactoring.IsFixable(invocationInfo, context.SemanticModel, context.CancellationToken)) { context.ReportDiagnostic(DiagnosticDescriptors.UseMethodChaining, invocationInfo.InvocationExpression); } } } }