|
2 | 2 | // The .NET Foundation licenses this file to you under the MIT license.
|
3 | 3 | // See the LICENSE file in the project root for more information.
|
4 | 4 |
|
| 5 | +using System.Collections.Generic; |
5 | 6 | using System.Collections.Immutable;
|
6 | 7 | using System.Composition;
|
7 | 8 | using System.Diagnostics.CodeAnalysis;
|
8 | 9 | using System.Linq;
|
| 10 | +using System.Threading; |
9 | 11 | using System.Threading.Tasks;
|
| 12 | +using Microsoft.CodeAnalysis.CodeActions; |
10 | 13 | using Microsoft.CodeAnalysis.CodeFixes;
|
| 14 | +using Microsoft.CodeAnalysis.CSharp.CodeStyle; |
| 15 | +using Microsoft.CodeAnalysis.CSharp.OrderModifiers; |
11 | 16 | using Microsoft.CodeAnalysis.CSharp.Syntax;
|
| 17 | +using Microsoft.CodeAnalysis.Editing; |
| 18 | +using Microsoft.CodeAnalysis.Options; |
12 | 19 | using Microsoft.CodeAnalysis.Shared.Extensions;
|
13 | 20 |
|
14 | 21 | namespace Microsoft.CodeAnalysis.CSharp.CodeFixes.HideBase;
|
15 | 22 |
|
16 | 23 | [ExportCodeFixProvider(LanguageNames.CSharp, Name = PredefinedCodeFixProviderNames.AddNew), Shared]
|
17 | 24 | [method: ImportingConstructor]
|
18 | 25 | [method: SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")]
|
19 |
| -internal sealed partial class HideBaseCodeFixProvider() : CodeFixProvider |
| 26 | +internal sealed partial class HideBaseCodeFixProvider() : SyntaxEditorBasedCodeFixProvider |
20 | 27 | {
|
21 | 28 | internal const string CS0108 = nameof(CS0108); // 'SomeClass.SomeMember' hides inherited member 'SomeClass.SomeMember'. Use the new keyword if hiding was intended.
|
22 | 29 |
|
23 | 30 | public override ImmutableArray<string> FixableDiagnosticIds => [CS0108];
|
24 | 31 |
|
25 |
| - public override FixAllProvider GetFixAllProvider() |
26 |
| - => WellKnownFixAllProviders.BatchFixer; |
27 |
| - |
28 |
| - public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) |
| 32 | + private static SyntaxNode? GetOriginalNode(SyntaxNode root, Diagnostic diagnostic) |
29 | 33 | {
|
30 |
| - var root = await context.Document.GetRequiredSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); |
31 |
| - |
32 |
| - var diagnostic = context.Diagnostics.First(); |
33 | 34 | var diagnosticSpan = diagnostic.Location.SourceSpan;
|
34 |
| - |
35 | 35 | var token = root.FindToken(diagnosticSpan.Start);
|
36 | 36 |
|
37 | 37 | var originalNode = token.GetAncestor<PropertyDeclarationSyntax>() ??
|
38 | 38 | token.GetAncestor<MethodDeclarationSyntax>() ??
|
39 | 39 | (SyntaxNode?)token.GetAncestor<FieldDeclarationSyntax>();
|
| 40 | + return originalNode; |
| 41 | + } |
| 42 | + |
| 43 | + public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) |
| 44 | + { |
| 45 | + var root = await context.Document.GetRequiredSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); |
40 | 46 |
|
| 47 | + var originalNode = GetOriginalNode(root, context.Diagnostics.First()); |
41 | 48 | if (originalNode == null)
|
42 | 49 | return;
|
43 | 50 |
|
44 |
| - context.RegisterCodeFix(new AddNewKeywordAction(context.Document, originalNode), context.Diagnostics); |
| 51 | + context.RegisterCodeFix(CodeAction.Create( |
| 52 | + CSharpCodeFixesResources.Hide_base_member, |
| 53 | + cancellationToken => GetChangedDocumentAsync(context.Document, originalNode, cancellationToken), |
| 54 | + nameof(CSharpCodeFixesResources.Hide_base_member)), |
| 55 | + context.Diagnostics); |
| 56 | + } |
| 57 | + |
| 58 | + protected override async Task FixAllAsync( |
| 59 | + Document document, ImmutableArray<Diagnostic> diagnostics, SyntaxEditor editor, CancellationToken cancellationToken) |
| 60 | + { |
| 61 | + var modifierOrder = await GetModifierOrderAsync(document, cancellationToken).ConfigureAwait(false); |
| 62 | + |
| 63 | + var root = editor.OriginalRoot; |
| 64 | + foreach (var diagnostic in diagnostics) |
| 65 | + { |
| 66 | + var originalNode = GetOriginalNode(root, diagnostic); |
| 67 | + if (originalNode == null) |
| 68 | + continue; |
| 69 | + |
| 70 | + var newNode = GetNewNode(originalNode, modifierOrder); |
| 71 | + editor.ReplaceNode(originalNode, newNode); |
| 72 | + } |
| 73 | + } |
| 74 | + |
| 75 | + private static async Task<Dictionary<int, int>?> GetModifierOrderAsync(Document document, CancellationToken cancellationToken) |
| 76 | + { |
| 77 | + var configOptions = await document.GetHostAnalyzerConfigOptionsAsync(cancellationToken).ConfigureAwait(false); |
| 78 | + var modifierOrder = configOptions.GetOption(CSharpCodeStyleOptions.PreferredModifierOrder).Value; |
| 79 | + CSharpOrderModifiersHelper.Instance.TryGetOrComputePreferredOrder(modifierOrder, out var preferredOrder); |
| 80 | + return preferredOrder; |
45 | 81 | }
|
46 | 82 | }
|
0 commit comments