| File: Kestrel\ListenOnIPv6AnyFixer.cs | Web Access |
| Project: src\aspnetcore\src\Framework\AspNetCoreAnalyzers\src\CodeFixes\Microsoft.AspNetCore.App.CodeFixes.csproj (Microsoft.AspNetCore.App.CodeFixes) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Composition; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis; using System.Collections.Immutable; using System.Threading.Tasks; using Microsoft.AspNetCore.Analyzers; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp; namespace Microsoft.AspNetCore.Fixers.Kestrel; [ExportCodeFixProvider(LanguageNames.CSharp), Shared] public class ListenOnIPv6AnyFixer : CodeFixProvider { public override ImmutableArray<string> FixableDiagnosticIds => [ DiagnosticDescriptors.KestrelShouldListenOnIPv6AnyInsteadOfIpAny.Id ]; public sealed override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer; public override Task RegisterCodeFixesAsync(CodeFixContext context) { foreach (var diagnostic in context.Diagnostics) { context.RegisterCodeFix( CodeAction.Create( "Consider using IPAddress.IPv6Any instead of IPAddress.Any", async cancellationToken => { var editor = await DocumentEditor.CreateAsync(context.Document, cancellationToken).ConfigureAwait(false); var root = await context.Document.GetSyntaxRootAsync(cancellationToken); if (root is null) { return context.Document; } var argumentSyntax = root.FindNode(diagnostic.Location.SourceSpan).FirstAncestorOrSelf<ArgumentSyntax>(); if (argumentSyntax is null) { return context.Document; } // get to the `Listen(IPAddress.Any, ...)` invocation if (argumentSyntax.Parent?.Parent is not InvocationExpressionSyntax { ArgumentList.Arguments.Count: > 1 } invocationExpressionSyntax) { return context.Document; } if (invocationExpressionSyntax.Expression is not MemberAccessExpressionSyntax memberAccessExpressionSyntax) { return context.Document; } var instanceVariableInvoked = memberAccessExpressionSyntax.Expression; var adjustedArgumentList = invocationExpressionSyntax.ArgumentList.RemoveNode(invocationExpressionSyntax.ArgumentList.Arguments.First(), SyntaxRemoveOptions.KeepLeadingTrivia); if (adjustedArgumentList is null || adjustedArgumentList.Arguments.Count == 0) { return context.Document; } // changing invocation from `<variable>.Listen(IPAddress.Any, ...)` to `<variable>.ListenAnyIP(...)` editor.ReplaceNode( invocationExpressionSyntax, invocationExpressionSyntax .WithExpression(SyntaxFactory.ParseExpression($"{instanceVariableInvoked.ToString()}.ListenAnyIP")) .WithArgumentList(adjustedArgumentList!) .WithLeadingTrivia(invocationExpressionSyntax.GetLeadingTrivia()) ); return editor.GetChangedDocument(); }, equivalenceKey: DiagnosticDescriptors.KestrelShouldListenOnIPv6AnyInsteadOfIpAny.Id), diagnostic); } return Task.CompletedTask; } }