| File: Microsoft.NetCore.Analyzers\Performance\PreferIsEmptyOverCount.Fixer.cs | Web Access |
| Project: src\sdk\src\Microsoft.CodeAnalysis.NetAnalyzers\src\Microsoft.CodeAnalysis.NetAnalyzers\Microsoft.CodeAnalysis.NetAnalyzers.csproj (Microsoft.CodeAnalysis.NetAnalyzers) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Immutable; using System.Threading.Tasks; using Analyzer.Utilities; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.Editing; namespace Microsoft.NetCore.Analyzers.Performance { /// <summary> /// CA1836: Prefer IsEmpty over Count when available. /// </summary> public abstract class PreferIsEmptyOverCountFixer : CodeFixProvider { public sealed override ImmutableArray<string> FixableDiagnosticIds { get; } = ImmutableArray.Create(UseCountProperlyAnalyzer.CA1836); public sealed override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer; public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { SyntaxNode root = await context.Document.GetRequiredSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); SyntaxNode node = root.FindNode(context.Span, getInnermostNodeForTie: true); if (node == null) { return; } ImmutableDictionary<string, string?> properties = context.Diagnostics[0].Properties; if (properties == null) { return; } // Indicates whether the Count method or property is on the Right or Left side of a binary expression // OR if it is the argument or the instance of an Equals invocation. string operationKey = properties[UseCountProperlyAnalyzer.OperationKey]!; // Indicates if the replacing IsEmpty node should be negated. (!IsEmpty). bool shouldNegate = properties.ContainsKey(UseCountProperlyAnalyzer.ShouldNegateKey); context.RegisterCodeFix(CodeAction.Create( title: MicrosoftNetCoreAnalyzersResources.PreferIsEmptyOverCountTitle, createChangedDocument: async cancellationToken => { DocumentEditor editor = await DocumentEditor.CreateAsync(context.Document, cancellationToken).ConfigureAwait(false); SyntaxGenerator generator = editor.Generator; // The object that the Count property belongs to OR null if countAccessor is not a MemberAccessExpressionSyntax. SyntaxNode? objectExpression = GetObjectExpressionFromOperation(node, operationKey); // The IsEmpty property meant to replace the binary expression. SyntaxNode isEmptyNode = objectExpression is null ? generator.IdentifierName(UseCountProperlyAnalyzer.IsEmpty) : generator.MemberAccessExpression(objectExpression, UseCountProperlyAnalyzer.IsEmpty); if (shouldNegate) { isEmptyNode = generator.LogicalNotExpression(isEmptyNode); } editor.ReplaceNode(node, isEmptyNode.WithTriviaFrom(node)); return editor.GetChangedDocument(); }, equivalenceKey: MicrosoftNetCoreAnalyzersResources.PreferIsEmptyOverCountMessage), context.Diagnostics); } /// <summary> /// The object that the Count method or property belongs to OR null if the Count method or property is not a MemberAccessExpressionSyntax. /// </summary> protected abstract SyntaxNode? GetObjectExpressionFromOperation(SyntaxNode node, string operationKey); } }