5
5
using System . Collections ;
6
6
using System . Collections . Generic ;
7
7
using System . ComponentModel . Composition ;
8
+ using System . Diagnostics ;
8
9
using System . Linq ;
9
10
using System . Threading ;
10
11
using System . Threading . Tasks ;
@@ -80,8 +81,8 @@ private SyntaxNode ProcessCore<TNode>(SyntaxNode syntaxRoot, TNode node) where T
80
81
return syntaxRoot ;
81
82
}
82
83
83
- SyntaxTriviaList newTriviaList ;
84
- if ( ! TryGetNewLeadingTrivia ( node , out newTriviaList ) )
84
+ var newTriviaList = GetNewLeadingTrivia ( node ) ;
85
+ if ( newTriviaList == node . GetLeadingTrivia ( ) )
85
86
{
86
87
return syntaxRoot ;
87
88
}
@@ -93,69 +94,104 @@ private SyntaxNode ProcessCore<TNode>(SyntaxNode syntaxRoot, TNode node) where T
93
94
/// Get the new leading trivia list that will add the double blank line that we are looking
94
95
/// for.
95
96
/// </summary>
96
- private bool TryGetNewLeadingTrivia ( SyntaxNode node , out SyntaxTriviaList newTriviaList )
97
+ private SyntaxTriviaList GetNewLeadingTrivia ( SyntaxNode node )
97
98
{
98
- var newLineTrivia = SyntaxUtil . GetBestNewLineTrivia ( node ) ;
99
99
var list = node . GetLeadingTrivia ( ) ;
100
- var index = list . Count - 1 ;
100
+ var searchIndex = 0 ;
101
+ var newLineTrivia = SyntaxUtil . GetBestNewLineTrivia ( node ) ;
102
+ var prev = node . FindPreviousNodeInParent ( ) ;
101
103
102
- MoveBackwardsPastWhitespace ( list , ref index ) ;
103
- if ( index < 0 || ! list [ index ] . IsAnyEndOfLine ( ) )
104
+ if ( prev == null )
104
105
{
105
- // There is no newline before the using at all. Add a double newline to
106
- // get the blank we are looking for
107
- newTriviaList = list . InsertRange ( index + 1 , new [ ] { newLineTrivia , newLineTrivia } ) ;
108
- return true ;
106
+ if ( node . Span . Start == 0 )
107
+ {
108
+ // First item in the file. Do nothing for this case.
109
+ return list ;
110
+ }
111
+ }
112
+ else
113
+ {
114
+ // If there is no new line in the trailing trivia of the previous node then need to add
115
+ // one to put this node on the next line.
116
+ if ( prev . GetTrailingTrivia ( ) . Count == 0 || ! prev . GetTrailingTrivia ( ) . Last ( ) . IsAnyEndOfLine ( ) )
117
+ {
118
+ list = list . Insert ( 0 , newLineTrivia ) ;
119
+ searchIndex = 1 ;
120
+ }
109
121
}
110
122
111
- var wasDirective = list [ index ] . IsDirective ;
112
- index -- ;
113
-
114
- // Move past any directives that are above the token. The newline needs to
115
- // be above them.
116
- while ( index >= 0 && list [ index ] . IsDirective )
123
+ // Ensure there are blank above #pragma directives here. This is an attempt to maintain compatibility
124
+ // with the original design of this rule which had special spacing rules for #pragma. No reason
125
+ // was given for the special casing, only tests.
126
+ if ( searchIndex < list . Count && list [ 0 ] . IsKind ( SyntaxKind . PragmaWarningDirectiveTrivia ) && list [ 0 ] . FullSpan . Start != 0 )
117
127
{
118
- index -- ;
128
+ list = list . Insert ( searchIndex , newLineTrivia ) ;
129
+ searchIndex ++ ;
119
130
}
120
131
121
- if ( wasDirective )
132
+ EnsureHasBlankLineAtEnd ( ref list , searchIndex , newLineTrivia ) ;
133
+
134
+ return list ;
135
+ }
136
+
137
+ /// <summary>
138
+ /// Ensure the trivia list has a blank line at the end. Both the second to last
139
+ /// and final line may contain spaces.
140
+ ///
141
+ /// Note: This function assumes the trivia token before <param name="startIndex" />
142
+ /// is an end of line trivia.
143
+ /// </summary>
144
+ private static void EnsureHasBlankLineAtEnd ( ref SyntaxTriviaList list , int startIndex , SyntaxTrivia newLineTrivia )
145
+ {
146
+ const int StateNone = 0 ;
147
+ const int StateEol = 1 ;
148
+ const int StateBlankLine = 2 ;
149
+
150
+ var state = StateEol ;
151
+ var index = startIndex ;
152
+ var eolIndex = startIndex - 1 ;
153
+
154
+ while ( index < list . Count )
122
155
{
123
- // There was a directive above the using and index now points directly before
124
- // that. This token must be a new line.
125
- if ( index < 0 || ! list [ index ] . IsKind ( SyntaxKind . EndOfLineTrivia ) )
156
+ var current = list [ index ] ;
157
+ if ( current . IsKind ( SyntaxKind . WhitespaceTrivia ) )
126
158
{
127
- newTriviaList = list . Insert ( index + 1 , newLineTrivia ) ;
128
- return true ;
159
+ index ++ ;
160
+ continue ;
129
161
}
130
162
131
- index -- ;
132
- }
133
-
134
- // In the logical line above the using. Need to see <blank><eol> in order for the
135
- // using to be correct
136
- var insertIndex = index + 1 ;
137
- MoveBackwardsPastWhitespace ( list , ref index ) ;
138
- if ( index < 0 || ! list [ index ] . IsAnyEndOfLine ( ) )
139
- {
140
- // If this is the first item in the file then there is no need for a double
141
- // blank line.
142
- if ( index >= 0 || node . FullSpan . Start != 0 )
163
+ var isStateAnyEol = ( state == StateEol || state == StateBlankLine ) ;
164
+ if ( isStateAnyEol && current . IsKind ( SyntaxKind . EndOfLineTrivia ) )
143
165
{
144
- newTriviaList = list . Insert ( insertIndex , newLineTrivia ) ;
145
- return true ;
166
+ state = StateBlankLine ;
167
+ }
168
+ else if ( current . IsAnyEndOfLine ( ) )
169
+ {
170
+ eolIndex = index ;
171
+ state = StateEol ;
172
+ }
173
+ else
174
+ {
175
+ state = StateNone ;
146
176
}
147
- }
148
177
149
- // The using is well formed so there is no work to be done.
150
- newTriviaList = SyntaxTriviaList . Empty ;
151
- return false ;
152
- }
178
+ index ++ ;
179
+ }
153
180
154
- private static void MoveBackwardsPastWhitespace ( SyntaxTriviaList list , ref int index )
155
- {
156
- while ( index >= 0 && list [ index ] . IsKind ( SyntaxKind . WhitespaceTrivia ) )
181
+ switch ( state )
157
182
{
158
- index -- ;
183
+ case StateNone :
184
+ list = list . InsertRange ( list . Count , new [ ] { newLineTrivia , newLineTrivia } ) ;
185
+ break ;
186
+ case StateEol :
187
+ list = list . Insert ( eolIndex + 1 , newLineTrivia ) ;
188
+ break ;
189
+ case StateBlankLine :
190
+ // Nothing to do.
191
+ break ;
192
+ default :
193
+ Debug . Assert ( false ) ;
194
+ break ;
159
195
}
160
196
}
161
197
}
0 commit comments