33
44namespace StyleCop . Analyzers . LayoutRules
55{
6+ using System ;
67 using System . Collections . Generic ;
78 using System . Collections . Immutable ;
89 using System . Composition ;
@@ -39,16 +40,44 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context)
3940
4041 foreach ( Diagnostic diagnostic in context . Diagnostics )
4142 {
43+ var insertBlankLine = DetermineCodeFixAction ( diagnostic ) ;
44+ if ( insertBlankLine == null )
45+ {
46+ continue ;
47+ }
48+
4249 context . RegisterCodeFix (
4350 CodeAction . Create (
44- LayoutResources . SA1516CodeFix ,
45- cancellationToken => GetTransformedDocumentAsync ( context . Document , syntaxRoot , diagnostic , context . CancellationToken ) ,
51+ insertBlankLine . Value ? LayoutResources . SA1516CodeFixInsert : LayoutResources . SA1516CodeFixRemove ,
52+ cancellationToken => GetTransformedDocumentAsync ( context . Document , syntaxRoot , diagnostic , insertBlankLine . Value , context . CancellationToken ) ,
4653 nameof ( SA1516CodeFixProvider ) ) ,
4754 diagnostic ) ;
4855 }
4956 }
5057
51- private static Task < Document > GetTransformedDocumentAsync ( Document document , SyntaxNode syntaxRoot , Diagnostic diagnostic , CancellationToken cancellationToken )
58+ private static bool ? DetermineCodeFixAction ( Diagnostic diagnostic )
59+ {
60+ string codeFixAction ;
61+
62+ if ( ! diagnostic . Properties . TryGetValue ( SA1516ElementsMustBeSeparatedByBlankLine . CodeFixActionKey , out codeFixAction ) )
63+ {
64+ return null ;
65+ }
66+
67+ switch ( codeFixAction )
68+ {
69+ case SA1516ElementsMustBeSeparatedByBlankLine . InsertBlankLineValue :
70+ return true ;
71+
72+ case SA1516ElementsMustBeSeparatedByBlankLine . RemoveBlankLinesValue :
73+ return false ;
74+
75+ default :
76+ return null ;
77+ }
78+ }
79+
80+ private static Task < Document > GetTransformedDocumentAsync ( Document document , SyntaxNode syntaxRoot , Diagnostic diagnostic , bool insertBlankLine , CancellationToken cancellationToken )
5281 {
5382 var node = syntaxRoot . FindNode ( diagnostic . Location . SourceSpan , getInnermostNodeForTie : true ) ;
5483 node = GetRelevantNode ( node ) ;
@@ -58,18 +87,30 @@ private static Task<Document> GetTransformedDocumentAsync(Document document, Syn
5887 return Task . FromResult ( document ) ;
5988 }
6089
61- var leadingTrivia = node . GetLeadingTrivia ( ) ;
62-
63- var newTriviaList = leadingTrivia ;
64- newTriviaList = newTriviaList . Insert ( 0 , SyntaxFactory . CarriageReturnLineFeed ) ;
65-
66- var newNode = node . WithLeadingTrivia ( newTriviaList ) ;
90+ SyntaxNode newNode = ProcessNode ( node , insertBlankLine ) ;
6791 var newSyntaxRoot = syntaxRoot . ReplaceNode ( node , newNode ) ;
6892 var newDocument = document . WithSyntaxRoot ( newSyntaxRoot ) ;
6993
7094 return Task . FromResult ( newDocument ) ;
7195 }
7296
97+ private static SyntaxNode ProcessNode ( SyntaxNode node , bool insertBlankLine )
98+ {
99+ var leadingTrivia = node . GetLeadingTrivia ( ) ;
100+ SyntaxTriviaList newLeadingTrivia ;
101+
102+ if ( insertBlankLine )
103+ {
104+ newLeadingTrivia = leadingTrivia . Insert ( 0 , SyntaxFactory . CarriageReturnLineFeed ) ;
105+ }
106+ else
107+ {
108+ newLeadingTrivia = leadingTrivia . WithoutBlankLines ( ) ;
109+ }
110+
111+ return node . WithLeadingTrivia ( newLeadingTrivia ) ;
112+ }
113+
73114 private static SyntaxNode GetRelevantNode ( SyntaxNode innerNode )
74115 {
75116 SyntaxNode currentNode = innerNode ;
@@ -112,7 +153,7 @@ private class FixAll : DocumentBasedFixAllProvider
112153 new FixAll ( ) ;
113154
114155 protected override string CodeActionTitle =>
115- LayoutResources . SA1516CodeFix ;
156+ LayoutResources . SA1516CodeFixAll ;
116157
117158 protected override async Task < SyntaxNode > FixAllInDocumentAsync ( FixAllContext fixAllContext , Document document , ImmutableArray < Diagnostic > diagnostics )
118159 {
@@ -123,26 +164,26 @@ protected override async Task<SyntaxNode> FixAllInDocumentAsync(FixAllContext fi
123164
124165 var syntaxRoot = await document . GetSyntaxRootAsync ( ) . ConfigureAwait ( false ) ;
125166
126- List < SyntaxNode > nodes = new List < SyntaxNode > ( ) ;
167+ Dictionary < SyntaxNode , SyntaxNode > replaceMap = new Dictionary < SyntaxNode , SyntaxNode > ( ) ;
127168
128169 foreach ( var diagnostic in diagnostics )
129170 {
171+ var insertBlankLine = DetermineCodeFixAction ( diagnostic ) ;
172+ if ( insertBlankLine == null )
173+ {
174+ continue ;
175+ }
176+
130177 var node = syntaxRoot . FindNode ( diagnostic . Location . SourceSpan , getInnermostNodeForTie : true ) ;
131178 node = GetRelevantNode ( node ) ;
132179
133180 if ( node != null )
134181 {
135- nodes . Add ( node ) ;
182+ replaceMap [ node ] = ProcessNode ( node , insertBlankLine . Value ) ;
136183 }
137184 }
138185
139- return syntaxRoot . ReplaceNodes ( nodes , ( oldNode , newNode ) =>
140- {
141- var newTriviaList = newNode . GetLeadingTrivia ( ) ;
142- newTriviaList = newTriviaList . Insert ( 0 , SyntaxFactory . CarriageReturnLineFeed ) ;
143-
144- return newNode . WithLeadingTrivia ( newTriviaList ) ;
145- } ) ;
186+ return syntaxRoot . ReplaceNodes ( replaceMap . Keys , ( original , rewritten ) => replaceMap [ original ] ) ;
146187 }
147188 }
148189 }
0 commit comments