Skip to content

Commit b401bdf

Browse files
committed
Merge pull request #1855 from vweijsters/implement-SA1134
Implemented SA1134 (incl. tests + code fix)
2 parents 764eb9a + e7cd0d3 commit b401bdf

7 files changed

Lines changed: 616 additions & 4 deletions

File tree

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
2+
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
3+
4+
namespace StyleCop.Analyzers.ReadabilityRules
5+
{
6+
using System.Collections.Generic;
7+
using System.Collections.Immutable;
8+
using System.Composition;
9+
using System.Threading;
10+
using System.Threading.Tasks;
11+
using Helpers;
12+
using Microsoft.CodeAnalysis;
13+
using Microsoft.CodeAnalysis.CodeActions;
14+
using Microsoft.CodeAnalysis.CodeFixes;
15+
using Microsoft.CodeAnalysis.CSharp;
16+
using Microsoft.CodeAnalysis.CSharp.Syntax;
17+
18+
/// <summary>
19+
/// Implements a code fix for <see cref="SA1134AttributesMustNotShareLine"/>.
20+
/// </summary>
21+
[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(SA1134CodeFixProvider))]
22+
[Shared]
23+
internal class SA1134CodeFixProvider : CodeFixProvider
24+
{
25+
/// <inheritdoc/>
26+
public override ImmutableArray<string> FixableDiagnosticIds { get; } =
27+
ImmutableArray.Create(SA1134AttributesMustNotShareLine.DiagnosticId);
28+
29+
/// <inheritdoc/>
30+
public override FixAllProvider GetFixAllProvider()
31+
{
32+
return CustomFixAllProviders.BatchFixer;
33+
}
34+
35+
/// <inheritdoc/>
36+
public override Task RegisterCodeFixesAsync(CodeFixContext context)
37+
{
38+
foreach (var diagnostic in context.Diagnostics)
39+
{
40+
context.RegisterCodeFix(
41+
CodeAction.Create(
42+
ReadabilityResources.SA1134CodeFix,
43+
cancellationToken => GetTransformedDocumentAsync(context.Document, diagnostic, cancellationToken),
44+
nameof(SA1134CodeFixProvider)),
45+
diagnostic);
46+
}
47+
48+
return SpecializedTasks.CompletedTask;
49+
}
50+
51+
private static async Task<Document> GetTransformedDocumentAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken)
52+
{
53+
var syntaxRoot = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
54+
var indentationOptions = IndentationOptions.FromDocument(document);
55+
56+
var attributeListSyntax = (AttributeListSyntax)syntaxRoot.FindNode(diagnostic.Location.SourceSpan);
57+
58+
// use the containing type to determine the indentation level, anything else is less reliable.
59+
var containingType = attributeListSyntax.Parent?.Parent;
60+
var indentationSteps = (containingType != null) ? IndentationHelper.GetIndentationSteps(indentationOptions, containingType) + 1 : 0;
61+
var indentationTrivia = IndentationHelper.GenerateWhitespaceTrivia(indentationOptions, indentationSteps);
62+
63+
var tokensToReplace = new Dictionary<SyntaxToken, SyntaxToken>();
64+
65+
if (diagnostic.Properties.ContainsKey(SA1134AttributesMustNotShareLine.FixWithNewLineBeforeKey))
66+
{
67+
var token = attributeListSyntax.OpenBracketToken;
68+
var prevToken = token.GetPreviousToken();
69+
70+
tokensToReplace[prevToken] = prevToken.WithTrailingTrivia(prevToken.TrailingTrivia.WithoutTrailingWhitespace().Add(SyntaxFactory.CarriageReturnLineFeed));
71+
72+
var newLeadingTrivia = token.LeadingTrivia.Insert(0, indentationTrivia);
73+
tokensToReplace[token] = token.WithLeadingTrivia(newLeadingTrivia);
74+
}
75+
76+
if (diagnostic.Properties.ContainsKey(SA1134AttributesMustNotShareLine.FixWithNewLineAfterKey))
77+
{
78+
var token = attributeListSyntax.CloseBracketToken;
79+
var nextToken = token.GetNextToken();
80+
81+
tokensToReplace[token] = token.WithTrailingTrivia(token.TrailingTrivia.WithoutTrailingWhitespace().Add(SyntaxFactory.CarriageReturnLineFeed));
82+
83+
var newLeadingTrivia = nextToken.LeadingTrivia.Insert(0, indentationTrivia);
84+
tokensToReplace[nextToken] = nextToken.WithLeadingTrivia(newLeadingTrivia);
85+
}
86+
87+
var newSyntaxRoot = syntaxRoot.ReplaceTokens(tokensToReplace.Keys, (original, rewritten) => tokensToReplace[original]);
88+
var newDocument = document.WithSyntaxRoot(newSyntaxRoot.WithoutFormatting());
89+
90+
return newDocument;
91+
}
92+
}
93+
}

StyleCop.Analyzers/StyleCop.Analyzers.CodeFixes/StyleCop.Analyzers.CodeFixes.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@
128128
<Compile Include="ReadabilityRules\SA1131CodeFixProvider.cs" />
129129
<Compile Include="ReadabilityRules\SA1132CodeFixProvider.cs" />
130130
<Compile Include="ReadabilityRules\SA1133CodeFixProvider.cs" />
131+
<Compile Include="ReadabilityRules\SA1134CodeFixProvider.cs" />
131132
<Compile Include="ReadabilityRules\SX1101CodeFixProvider.cs" />
132133
<Compile Include="Settings\SettingsFileCodeFixProvider.cs" />
133134
<Compile Include="SpacingRules\SA1003CodeFixProvider.cs" />

0 commit comments

Comments
 (0)