@@ -28,6 +28,7 @@ public class ParseCoordinator : IParseCoordinator
28
28
public RubberduckParserState State { get { return _state ; } }
29
29
30
30
private const int _maxDegreeOfParserParallelism = - 1 ;
31
+ private const int _maxDegreeOfModuleStateChangeParallelism = - 1 ;
31
32
32
33
private readonly IDictionary < IVBComponent , IDictionary < Tuple < string , DeclarationType > , Attributes > > _componentAttributes
33
34
= new Dictionary < IVBComponent , IDictionary < Tuple < string , DeclarationType > , Attributes > > ( ) ;
@@ -79,7 +80,8 @@ private void ReparseRequested(object sender, EventArgs e)
79
80
}
80
81
else
81
82
{
82
- Parse ( _cancellationTokens [ 0 ] ) ;
83
+ Cancel ( ) ;
84
+ ParseInternal ( _cancellationTokens [ 0 ] ) ;
83
85
}
84
86
}
85
87
@@ -100,7 +102,28 @@ private void Cancel(bool createNewTokenSource = true)
100
102
/// <summary>
101
103
/// For the use of tests only
102
104
/// </summary>
105
+ ///
103
106
public void Parse ( CancellationTokenSource token )
107
+ {
108
+ SetSavedCancellationTokenSource ( token ) ;
109
+ ParseInternal ( token ) ;
110
+ }
111
+
112
+ private void SetSavedCancellationTokenSource ( CancellationTokenSource token )
113
+ {
114
+ if ( _cancellationTokens . Any ( ) )
115
+ {
116
+ _cancellationTokens [ 0 ] . Cancel ( ) ;
117
+ _cancellationTokens [ 0 ] . Dispose ( ) ;
118
+ _cancellationTokens [ 0 ] = token ;
119
+ }
120
+ else
121
+ {
122
+ _cancellationTokens . Add ( token ) ;
123
+ }
124
+ }
125
+
126
+ private void ParseInternal ( CancellationTokenSource token )
104
127
{
105
128
State . RefreshProjects ( _vbe ) ;
106
129
@@ -163,10 +186,12 @@ private void RefreshDeclarationFinder()
163
186
164
187
private void SetModuleStates ( List < IVBComponent > components , ParserState parserState )
165
188
{
166
- foreach ( var component in components )
167
- {
168
- State . SetModuleState ( component , parserState ) ;
169
- }
189
+ var options = new ParallelOptions ( ) ;
190
+ options . MaxDegreeOfParallelism = _maxDegreeOfModuleStateChangeParallelism ;
191
+
192
+ Parallel . ForEach ( components , options , component => State . SetModuleState ( component , parserState , null , false ) ) ;
193
+
194
+ State . EvaluateParserState ( ) ;
170
195
}
171
196
172
197
private void CleanUpComponentAttributes ( List < IVBComponent > components )
@@ -190,20 +215,34 @@ private void ClearComponentStateCacheForTests()
190
215
191
216
private void ParseComponents ( List < IVBComponent > components , CancellationToken token )
192
217
{
218
+ SetModuleStates ( components , ParserState . Parsing ) ;
219
+
193
220
var options = new ParallelOptions ( ) ;
194
221
options . CancellationToken = token ;
195
222
options . MaxDegreeOfParallelism = _maxDegreeOfParserParallelism ;
196
223
197
- Parallel . ForEach ( components ,
198
- options ,
199
- component =>
224
+ try
225
+ {
226
+ Parallel . ForEach ( components ,
227
+ options ,
228
+ component =>
229
+ {
230
+ State . ClearStateCache ( component ) ;
231
+ var finishedParseTask = FinishedParseComponentTask ( component , token ) ;
232
+ ProcessComponentParseResults ( component , finishedParseTask ) ;
233
+ }
234
+ ) ;
235
+ }
236
+ catch ( AggregateException exception )
237
+ {
238
+ if ( exception . Flatten ( ) . InnerExceptions . All ( ex => ex is OperationCanceledException ) )
200
239
{
201
- State . SetModuleState ( component , ParserState . Parsing ) ;
202
- State . ClearStateCache ( component ) ;
203
- var finishedParseTask = FinishedParseComponentTask ( component , token ) ;
204
- ProcessComponentParseResults ( component , finishedParseTask ) ;
240
+ return ;
205
241
}
206
- ) ;
242
+ throw ;
243
+ }
244
+
245
+ State . EvaluateParserState ( ) ;
207
246
}
208
247
209
248
private Task < ComponentParseTask . ParseCompletionArgs > FinishedParseComponentTask ( IVBComponent component , CancellationToken token , TokenStreamRewriter rewriter = null )
@@ -215,7 +254,14 @@ private void ParseComponents(List<IVBComponent> components, CancellationToken to
215
254
216
255
parser . ParseFailure += ( sender , e ) =>
217
256
{
218
- tcs . SetException ( e . Cause ) ;
257
+ if ( e . Cause is OperationCanceledException )
258
+ {
259
+ tcs . SetCanceled ( ) ;
260
+ }
261
+ else
262
+ {
263
+ tcs . SetException ( e . Cause ) ;
264
+ }
219
265
} ;
220
266
parser . ParseCompleted += ( sender , e ) =>
221
267
{
@@ -230,9 +276,9 @@ private void ParseComponents(List<IVBComponent> components, CancellationToken to
230
276
231
277
private void ProcessComponentParseResults ( IVBComponent component , Task < ComponentParseTask . ParseCompletionArgs > finishedParseTask )
232
278
{
233
- finishedParseTask . Wait ( ) ;
234
279
if ( finishedParseTask . IsFaulted )
235
280
{
281
+ //In contrast to the situation in the success scenario, the overall parser state is reevaluated immediately.
236
282
State . SetModuleState ( component , ParserState . Error , finishedParseTask . Exception . InnerException as SyntaxErrorException ) ;
237
283
}
238
284
else if ( finishedParseTask . IsCompleted )
@@ -249,7 +295,9 @@ private void ProcessComponentParseResults(IVBComponent component, Task<Component
249
295
State . SetModuleAnnotations ( component , result . Annotations ) ;
250
296
251
297
// This really needs to go last
252
- State . SetModuleState ( component , ParserState . Parsed ) ;
298
+ //It does not reevaluate the overall parer state to avoid concurrent evaluation of all module states and for performance reasons.
299
+ //The evaluation has to be triggered manually in the calling procedure.
300
+ State . SetModuleState ( component , ParserState . Parsed , null , false ) ;
253
301
}
254
302
}
255
303
}
@@ -258,26 +306,48 @@ private void ProcessComponentParseResults(IVBComponent component, Task<Component
258
306
259
307
private void ResolveAllDeclarations ( List < IVBComponent > components , CancellationToken token )
260
308
{
309
+ SetModuleStates ( components , ParserState . ResolvingDeclarations ) ;
310
+
261
311
var options = new ParallelOptions ( ) ;
262
312
options . CancellationToken = token ;
263
313
options . MaxDegreeOfParallelism = _maxDegreeOfParserParallelism ;
264
-
265
- Parallel . ForEach ( components ,
266
- options ,
267
- component =>
314
+ try
315
+ {
316
+ Parallel . ForEach ( components ,
317
+ options ,
318
+ component =>
319
+ {
320
+ var qualifiedName = new QualifiedModuleName ( component ) ;
321
+ ResolveDeclarations ( qualifiedName . Component ,
322
+ State . ParseTrees . Find ( s => s . Key == qualifiedName ) . Value ) ;
323
+ }
324
+ ) ;
325
+ }
326
+ catch ( AggregateException exception )
327
+ {
328
+ if ( exception . Flatten ( ) . InnerExceptions . All ( ex => ex is OperationCanceledException ) )
268
329
{
269
- var qualifiedName = new QualifiedModuleName ( component ) ;
270
- State . SetModuleState ( component , ParserState . ResolvingDeclarations ) ;
271
- ResolveDeclarations ( qualifiedName . Component ,
272
- State . ParseTrees . Find ( s => s . Key == qualifiedName ) . Value ) ;
330
+ return ;
273
331
}
274
- ) ;
332
+ throw ;
333
+ }
275
334
}
276
335
277
336
278
337
private void ResolveReferences ( CancellationToken token )
279
338
{
280
- Task . WaitAll ( ResolveReferencesAsync ( token ) ) ;
339
+ try
340
+ {
341
+ Task . WaitAll ( ResolveReferencesAsync ( token ) ) ;
342
+ }
343
+ catch ( AggregateException exception )
344
+ {
345
+ if ( exception . Flatten ( ) . InnerExceptions . All ( ex => ex is OperationCanceledException ) )
346
+ {
347
+ return ;
348
+ }
349
+ throw ;
350
+ }
281
351
}
282
352
283
353
0 commit comments