Skip to content

Commit f3ee17b

Browse files
Update 'hide base' fixer to use modern fix all pattern. (#79174)
2 parents 8f3fb8d + 57941dd commit f3ee17b

File tree

2 files changed

+69
-44
lines changed

2 files changed

+69
-44
lines changed

src/Analyzers/CSharp/CodeFixes/HideBase/HideBaseCodeFixProvider.AddNewKeywordAction.cs

Lines changed: 23 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2,64 +2,53 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33
// See the LICENSE file in the project root for more information.
44

5+
using System.Collections.Generic;
56
using System.Linq;
67
using System.Threading;
78
using System.Threading.Tasks;
8-
using Microsoft.CodeAnalysis.CodeActions;
99
using Microsoft.CodeAnalysis.CSharp.CodeStyle;
1010
using Microsoft.CodeAnalysis.CSharp.LanguageService;
1111
using Microsoft.CodeAnalysis.CSharp.OrderModifiers;
1212
using Microsoft.CodeAnalysis.Options;
1313
using Microsoft.CodeAnalysis.OrderModifiers;
1414
using Microsoft.CodeAnalysis.Shared.Extensions;
15-
using Roslyn.Utilities;
1615

1716
namespace Microsoft.CodeAnalysis.CSharp.CodeFixes.HideBase;
1817

1918
using static CSharpSyntaxTokens;
2019

2120
internal sealed partial class HideBaseCodeFixProvider
2221
{
23-
private sealed class AddNewKeywordAction(Document document, SyntaxNode node) : CodeAction
22+
private static async Task<Document> GetChangedDocumentAsync(
23+
Document document, SyntaxNode node, CancellationToken cancellationToken)
2424
{
25-
private readonly Document _document = document;
26-
private readonly SyntaxNode _node = node;
25+
var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
26+
var modifierOrder = await GetModifierOrderAsync(document, cancellationToken).ConfigureAwait(false);
2727

28-
public override string Title => CSharpCodeFixesResources.Hide_base_member;
29-
30-
protected override async Task<Document> GetChangedDocumentAsync(CancellationToken cancellationToken)
31-
{
32-
var root = await _document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
33-
var configOptions = await _document.GetHostAnalyzerConfigOptionsAsync(cancellationToken).ConfigureAwait(false);
34-
35-
var newNode = GetNewNode(_node, configOptions.GetOption(CSharpCodeStyleOptions.PreferredModifierOrder).Value);
36-
var newRoot = root.ReplaceNode(_node, newNode);
28+
return document.WithSyntaxRoot(root.ReplaceNode(node, GetNewNode(node, modifierOrder)));
29+
}
3730

38-
return _document.WithSyntaxRoot(newRoot);
39-
}
31+
private static SyntaxNode GetNewNode(SyntaxNode node, Dictionary<int, int>? preferredOrder)
32+
{
33+
var syntaxFacts = CSharpSyntaxFacts.Instance;
34+
var modifiers = syntaxFacts.GetModifiers(node);
35+
var newModifiers = modifiers.Add(NewKeyword);
4036

41-
private static SyntaxNode GetNewNode(SyntaxNode node, string preferredModifierOrder)
37+
if (preferredOrder is null ||
38+
!AbstractOrderModifiersHelpers.IsOrdered(preferredOrder, modifiers))
4239
{
43-
var syntaxFacts = CSharpSyntaxFacts.Instance;
44-
var modifiers = syntaxFacts.GetModifiers(node);
45-
var newModifiers = modifiers.Add(NewKeyword);
46-
47-
if (!CSharpOrderModifiersHelper.Instance.TryGetOrComputePreferredOrder(preferredModifierOrder, out var preferredOrder) ||
48-
!AbstractOrderModifiersHelpers.IsOrdered(preferredOrder, modifiers))
49-
{
50-
return syntaxFacts.WithModifiers(node, newModifiers);
51-
}
40+
return syntaxFacts.WithModifiers(node, newModifiers);
41+
}
5242

53-
var orderedModifiers = new SyntaxTokenList(
54-
newModifiers.OrderBy(CompareModifiers));
43+
var orderedModifiers = new SyntaxTokenList(
44+
newModifiers.OrderBy(CompareModifiers));
5545

56-
return syntaxFacts.WithModifiers(node, orderedModifiers);
46+
return syntaxFacts.WithModifiers(node, orderedModifiers);
5747

58-
int CompareModifiers(SyntaxToken left, SyntaxToken right)
59-
=> GetOrder(left) - GetOrder(right);
48+
int CompareModifiers(SyntaxToken left, SyntaxToken right)
49+
=> GetOrder(left) - GetOrder(right);
6050

61-
int GetOrder(SyntaxToken token)
62-
=> preferredOrder.TryGetValue(token.RawKind, out var value) ? value : int.MaxValue;
63-
}
51+
int GetOrder(SyntaxToken token)
52+
=> preferredOrder.TryGetValue(token.RawKind, out var value) ? value : int.MaxValue;
6453
}
6554
}

src/Analyzers/CSharp/CodeFixes/HideBase/HideBaseCodeFixProvider.cs

Lines changed: 46 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,45 +2,81 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33
// See the LICENSE file in the project root for more information.
44

5+
using System.Collections.Generic;
56
using System.Collections.Immutable;
67
using System.Composition;
78
using System.Diagnostics.CodeAnalysis;
89
using System.Linq;
10+
using System.Threading;
911
using System.Threading.Tasks;
12+
using Microsoft.CodeAnalysis.CodeActions;
1013
using Microsoft.CodeAnalysis.CodeFixes;
14+
using Microsoft.CodeAnalysis.CSharp.CodeStyle;
15+
using Microsoft.CodeAnalysis.CSharp.OrderModifiers;
1116
using Microsoft.CodeAnalysis.CSharp.Syntax;
17+
using Microsoft.CodeAnalysis.Editing;
18+
using Microsoft.CodeAnalysis.Options;
1219
using Microsoft.CodeAnalysis.Shared.Extensions;
1320

1421
namespace Microsoft.CodeAnalysis.CSharp.CodeFixes.HideBase;
1522

1623
[ExportCodeFixProvider(LanguageNames.CSharp, Name = PredefinedCodeFixProviderNames.AddNew), Shared]
1724
[method: ImportingConstructor]
1825
[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
2027
{
2128
internal const string CS0108 = nameof(CS0108); // 'SomeClass.SomeMember' hides inherited member 'SomeClass.SomeMember'. Use the new keyword if hiding was intended.
2229

2330
public override ImmutableArray<string> FixableDiagnosticIds => [CS0108];
2431

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)
2933
{
30-
var root = await context.Document.GetRequiredSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
31-
32-
var diagnostic = context.Diagnostics.First();
3334
var diagnosticSpan = diagnostic.Location.SourceSpan;
34-
3535
var token = root.FindToken(diagnosticSpan.Start);
3636

3737
var originalNode = token.GetAncestor<PropertyDeclarationSyntax>() ??
3838
token.GetAncestor<MethodDeclarationSyntax>() ??
3939
(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);
4046

47+
var originalNode = GetOriginalNode(root, context.Diagnostics.First());
4148
if (originalNode == null)
4249
return;
4350

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;
4581
}
4682
}

0 commit comments

Comments
 (0)