[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(RefitRouteCodeFixProvider)), Shared] public class RefitRouteCodeFixProvider : CodeFixProvider { private const string CodeFixTitle = "Fix routes"; public sealed override ImmutableArray FixableDiagnosticIds { get { return ImmutableArray.Create(RefitRouteAnalyzer.DiagnosticId); } } public sealed override FixAllProvider GetFixAllProvider() { return WellKnownFixAllProviders.BatchFixer; } public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); var diagnostic = context.Diagnostics.First(); if (diagnostic.AdditionalLocations.Count > 0) { var properties = diagnostic.Properties; var locations = diagnostic.AdditionalLocations; // Register a code action that will invoke the fix. var codeAction = CodeAction.Create( title: CodeFixTitle, createChangedDocument: ct => FixeRoutesAsync(context.Document, root, locations, properties, ct), equivalenceKey: CodeFixTitle); context.RegisterCodeFix(codeAction, diagnostic); } } private async Task FixeRoutesAsync(Document doc, SyntaxNode root, IReadOnlyList locations, IImmutableDictionary properties, CancellationToken cancellationToken) { var editor = await DocumentEditor.CreateAsync(doc, cancellationToken).ConfigureAwait(false); for (int i = 0; i < locations.Count; i++) { var location = locations[i]; var validRoute = properties[(i + 1).ToString()]; if (root.FindToken(location.SourceSpan.Start).Parent is LiteralExpressionSyntax oldLiteral) { var newliteral = SyntaxFactory.LiteralExpression(SyntaxKind.StringLiteralExpression, SyntaxFactory.Literal(validRoute)); editor.ReplaceNode(oldLiteral, newliteral); } } return editor.GetChangedDocument(); } }