Skip to content

Commit d545b84

Browse files
committed
Implement custom SA1121 fix all provider
1 parent 98b446f commit d545b84

1 file changed

Lines changed: 68 additions & 34 deletions

File tree

StyleCop.Analyzers/StyleCop.Analyzers/ReadabilityRules/SA1121CodeFixProvider.cs

Lines changed: 68 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
namespace StyleCop.Analyzers.ReadabilityRules
55
{
6+
using System;
67
using System.Collections.Generic;
78
using System.Collections.Immutable;
89
using System.Composition;
@@ -27,23 +28,23 @@ namespace StyleCop.Analyzers.ReadabilityRules
2728
[Shared]
2829
internal class SA1121CodeFixProvider : CodeFixProvider
2930
{
30-
private static readonly Dictionary<SpecialType, SyntaxKind> PredefinedSpecialTypes = new Dictionary<SpecialType, SyntaxKind>
31+
private static readonly Dictionary<SpecialType, PredefinedTypeSyntax> PredefinedSpecialTypes = new Dictionary<SpecialType, PredefinedTypeSyntax>
3132
{
32-
[SpecialType.System_Boolean] = SyntaxKind.BoolKeyword,
33-
[SpecialType.System_Byte] = SyntaxKind.ByteKeyword,
34-
[SpecialType.System_Char] = SyntaxKind.CharKeyword,
35-
[SpecialType.System_Decimal] = SyntaxKind.DecimalKeyword,
36-
[SpecialType.System_Double] = SyntaxKind.DoubleKeyword,
37-
[SpecialType.System_Int16] = SyntaxKind.ShortKeyword,
38-
[SpecialType.System_Int32] = SyntaxKind.IntKeyword,
39-
[SpecialType.System_Int64] = SyntaxKind.LongKeyword,
40-
[SpecialType.System_Object] = SyntaxKind.ObjectKeyword,
41-
[SpecialType.System_SByte] = SyntaxKind.SByteKeyword,
42-
[SpecialType.System_Single] = SyntaxKind.FloatKeyword,
43-
[SpecialType.System_String] = SyntaxKind.StringKeyword,
44-
[SpecialType.System_UInt16] = SyntaxKind.UShortKeyword,
45-
[SpecialType.System_UInt32] = SyntaxKind.UIntKeyword,
46-
[SpecialType.System_UInt64] = SyntaxKind.ULongKeyword
33+
[SpecialType.System_Boolean] = SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.BoolKeyword)),
34+
[SpecialType.System_Byte] = SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.ByteKeyword)),
35+
[SpecialType.System_Char] = SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.CharKeyword)),
36+
[SpecialType.System_Decimal] = SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.DecimalKeyword)),
37+
[SpecialType.System_Double] = SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.DoubleKeyword)),
38+
[SpecialType.System_Int16] = SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.ShortKeyword)),
39+
[SpecialType.System_Int32] = SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.IntKeyword)),
40+
[SpecialType.System_Int64] = SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.LongKeyword)),
41+
[SpecialType.System_Object] = SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.ObjectKeyword)),
42+
[SpecialType.System_SByte] = SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.SByteKeyword)),
43+
[SpecialType.System_Single] = SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.FloatKeyword)),
44+
[SpecialType.System_String] = SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.StringKeyword)),
45+
[SpecialType.System_UInt16] = SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.UShortKeyword)),
46+
[SpecialType.System_UInt32] = SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.UIntKeyword)),
47+
[SpecialType.System_UInt64] = SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.ULongKeyword))
4748
};
4849

4950
private static readonly ImmutableArray<string> FixableDiagnostics =
@@ -55,7 +56,7 @@ internal class SA1121CodeFixProvider : CodeFixProvider
5556
/// <inheritdoc/>
5657
public override FixAllProvider GetFixAllProvider()
5758
{
58-
return CustomFixAllProviders.BatchFixer;
59+
return FixAll.Instance;
5960
}
6061

6162
/// <inheritdoc/>
@@ -74,17 +75,8 @@ public override Task RegisterCodeFixesAsync(CodeFixContext context)
7475
return SpecializedTasks.CompletedTask;
7576
}
7677

77-
private static async Task<Document> GetTransformedDocumentAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken)
78+
private static SyntaxNode ComputeReplacement(SemanticModel semanticModel, SyntaxNode node, CancellationToken cancellationToken)
7879
{
79-
var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
80-
var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
81-
if (semanticModel == null)
82-
{
83-
return document;
84-
}
85-
86-
var node = root.FindNode(diagnostic.Location.SourceSpan, findInsideTrivia: true, getInnermostNodeForTie: true);
87-
8880
var memberAccess = node.Parent as MemberAccessExpressionSyntax;
8981
if (memberAccess != null)
9082
{
@@ -96,14 +88,13 @@ private static async Task<Document> GetTransformedDocumentAsync(Document documen
9688

9789
var type = semanticModel.GetSymbolInfo(node, cancellationToken).Symbol as INamedTypeSymbol;
9890

99-
SyntaxKind specialKind;
100-
if (!PredefinedSpecialTypes.TryGetValue(type.SpecialType, out specialKind))
91+
PredefinedTypeSyntax typeSyntax;
92+
if (!PredefinedSpecialTypes.TryGetValue(type.SpecialType, out typeSyntax))
10193
{
102-
return document;
94+
return node;
10395
}
10496

10597
SyntaxNode newNode;
106-
PredefinedTypeSyntax typeSyntax = SyntaxFactory.PredefinedType(SyntaxFactory.Token(specialKind));
10798
if (node is CrefSyntax)
10899
{
109100
newNode = SyntaxFactory.TypeCref(typeSyntax);
@@ -113,12 +104,55 @@ private static async Task<Document> GetTransformedDocumentAsync(Document documen
113104
newNode = typeSyntax;
114105
}
115106

116-
newNode = newNode
117-
.WithTriviaFrom(node)
118-
.WithoutFormatting();
107+
return newNode.WithTriviaFrom(node).WithoutFormatting();
108+
}
109+
110+
private static async Task<Document> GetTransformedDocumentAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken)
111+
{
112+
var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
113+
var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
114+
if (semanticModel == null)
115+
{
116+
return document;
117+
}
118+
119+
var node = root.FindNode(diagnostic.Location.SourceSpan, findInsideTrivia: true, getInnermostNodeForTie: true);
120+
121+
var newNode = ComputeReplacement(semanticModel, node, cancellationToken);
119122

120123
var newRoot = root.ReplaceNode(node, newNode);
121124
return document.WithSyntaxRoot(newRoot);
122125
}
126+
127+
private class FixAll : DocumentBasedFixAllProvider
128+
{
129+
public static FixAllProvider Instance { get; }
130+
= new FixAll();
131+
132+
protected override string CodeActionTitle
133+
=> ReadabilityResources.SA1121CodeFix;
134+
135+
protected override async Task<SyntaxNode> FixAllInDocumentAsync(FixAllContext fixAllContext, Document document)
136+
{
137+
var diagnostics = await fixAllContext.GetDocumentDiagnosticsAsync(document).ConfigureAwait(false);
138+
if (diagnostics.IsEmpty)
139+
{
140+
return null;
141+
}
142+
143+
var syntaxRoot = await document.GetSyntaxRootAsync().ConfigureAwait(false);
144+
var semanticModel = await document.GetSemanticModelAsync(fixAllContext.CancellationToken).ConfigureAwait(false);
145+
146+
List<SyntaxNode> nodesToReplace = new List<SyntaxNode>(diagnostics.Length);
147+
foreach (var diagnostic in diagnostics)
148+
{
149+
var node = syntaxRoot.FindNode(diagnostic.Location.SourceSpan, findInsideTrivia: true, getInnermostNodeForTie: true);
150+
151+
nodesToReplace.Add(node);
152+
}
153+
154+
return syntaxRoot.ReplaceNodes(nodesToReplace, (originalNode, rewrittenNode) => ComputeReplacement(semanticModel, originalNode, fixAllContext.CancellationToken));
155+
}
156+
}
123157
}
124158
}

0 commit comments

Comments
 (0)