@@ -20,9 +20,7 @@ namespace Rubberduck.Parsing.VBA
20
20
public class RubberduckParser : IRubberduckParser
21
21
{
22
22
public RubberduckParserState State { get { return _state ; } }
23
-
24
- private CancellationTokenSource _central = new CancellationTokenSource ( ) ;
25
- private CancellationTokenSource _resolverTokenSource ; // linked to _central later
23
+
26
24
private readonly ConcurrentDictionary < VBComponent , Tuple < Task , CancellationTokenSource > > _currentTasks =
27
25
new ConcurrentDictionary < VBComponent , Tuple < Task , CancellationTokenSource > > ( ) ;
28
26
@@ -43,7 +41,6 @@ public RubberduckParser(
43
41
Func < IVBAPreprocessor > preprocessorFactory ,
44
42
IEnumerable < ICustomDeclarationLoader > customDeclarationLoaders )
45
43
{
46
- _resolverTokenSource = CancellationTokenSource . CreateLinkedTokenSource ( _central . Token ) ;
47
44
_vbe = vbe ;
48
45
_state = state ;
49
46
_attributeParser = attributeParser ;
@@ -53,12 +50,17 @@ public RubberduckParser(
53
50
state . ParseRequest += ReparseRequested ;
54
51
}
55
52
53
+ // Do not access this from anywhere but ReparseRequested.
54
+ // ReparseRequested needs to have a reference to all the cancellation tokens,
55
+ // but the cancelees need to use their own token.
56
+ private readonly List < CancellationTokenSource > _cancellationTokens = new List < CancellationTokenSource > { new CancellationTokenSource ( ) } ;
57
+
56
58
private void ReparseRequested ( object sender , ParseRequestEventArgs e )
57
59
{
58
60
if ( e . IsFullReparseRequest )
59
61
{
60
62
Cancel ( ) ;
61
- Task . Run ( ( ) => ParseAll ( ) ) ;
63
+ Task . Run ( ( ) => ParseAll ( _cancellationTokens [ 0 ] ) ) ;
62
64
}
63
65
else
64
66
{
@@ -70,14 +72,14 @@ private void ReparseRequested(object sender, ParseRequestEventArgs e)
70
72
SyncComReferences ( State . Projects ) ;
71
73
AddBuiltInDeclarations ( ) ;
72
74
73
- if ( _resolverTokenSource . IsCancellationRequested || _central . IsCancellationRequested )
75
+ if ( _cancellationTokens [ 0 ] . IsCancellationRequested )
74
76
{
75
77
return ;
76
78
}
77
79
78
- ParseAsync ( e . Component , CancellationToken . None ) . Wait ( ) ;
80
+ ParseAsync ( e . Component , _cancellationTokens [ 0 ] ) . Wait ( ) ;
79
81
80
- if ( _resolverTokenSource . IsCancellationRequested || _central . IsCancellationRequested )
82
+ if ( _cancellationTokens [ 0 ] . IsCancellationRequested )
81
83
{
82
84
return ;
83
85
}
@@ -93,7 +95,7 @@ private void ReparseRequested(object sender, ParseRequestEventArgs e)
93
95
if ( State . Status < ParserState . Error )
94
96
{
95
97
State . SetStatusAndFireStateChanged ( ParserState . ResolvedDeclarations ) ;
96
- ResolveReferencesAsync ( ) ;
98
+ ResolveReferencesAsync ( _cancellationTokens [ 0 ] . Token ) ;
97
99
}
98
100
} ) ;
99
101
}
@@ -102,7 +104,7 @@ private void ReparseRequested(object sender, ParseRequestEventArgs e)
102
104
/// <summary>
103
105
/// For the use of tests only
104
106
/// </summary>
105
- public void Parse ( )
107
+ public void Parse ( CancellationTokenSource token )
106
108
{
107
109
if ( State . Projects . Count == 0 )
108
110
{
@@ -153,9 +155,9 @@ public void Parse()
153
155
var index = i ;
154
156
parseTasks [ i ] = new Task ( ( ) =>
155
157
{
156
- ParseAsync ( components [ index ] , CancellationToken . None ) . Wait ( ) ;
158
+ ParseAsync ( components [ index ] , token ) . Wait ( token . Token ) ;
157
159
158
- if ( _resolverTokenSource . IsCancellationRequested || _central . IsCancellationRequested )
160
+ if ( token . IsCancellationRequested )
159
161
{
160
162
return ;
161
163
}
@@ -177,14 +179,14 @@ public void Parse()
177
179
if ( State . Status < ParserState . Error )
178
180
{
179
181
State . SetStatusAndFireStateChanged ( ParserState . ResolvedDeclarations ) ;
180
- Task . WaitAll ( ResolveReferencesAsync ( ) ) ;
182
+ Task . WaitAll ( ResolveReferencesAsync ( token . Token ) ) ;
181
183
}
182
184
}
183
185
184
186
/// <summary>
185
187
/// Starts parsing all components of all unprotected VBProjects associated with the VBE-Instance passed to the constructor of this parser instance.
186
188
/// </summary>
187
- private void ParseAll ( )
189
+ private void ParseAll ( CancellationTokenSource token )
188
190
{
189
191
if ( State . Projects . Count == 0 )
190
192
{
@@ -230,18 +232,13 @@ private void ParseAll()
230
232
}
231
233
232
234
var toParse = new List < VBComponent > ( ) ;
233
- var unchanged = new List < VBComponent > ( ) ;
234
235
235
236
foreach ( var component in components )
236
237
{
237
238
if ( State . IsNewOrModified ( component ) )
238
239
{
239
240
toParse . Add ( component ) ;
240
241
}
241
- else
242
- {
243
- unchanged . Add ( component ) ;
244
- }
245
242
}
246
243
247
244
if ( toParse . Count == 0 )
@@ -272,6 +269,11 @@ private void ParseAll()
272
269
}
273
270
}
274
271
272
+ if ( token . IsCancellationRequested )
273
+ {
274
+ return ;
275
+ }
276
+
275
277
_projectDeclarations . Clear ( ) ;
276
278
State . ClearBuiltInReferences ( ) ;
277
279
@@ -281,9 +283,9 @@ private void ParseAll()
281
283
var index = i ;
282
284
parseTasks [ i ] = new Task ( ( ) =>
283
285
{
284
- ParseAsync ( toParse [ index ] , CancellationToken . None ) . Wait ( ) ;
286
+ ParseAsync ( toParse [ index ] , token ) . Wait ( token . Token ) ;
285
287
286
- if ( _resolverTokenSource . IsCancellationRequested || _central . IsCancellationRequested )
288
+ if ( token . IsCancellationRequested )
287
289
{
288
290
return ;
289
291
}
@@ -301,16 +303,21 @@ private void ParseAll()
301
303
parseTasks [ i ] . Start ( ) ;
302
304
}
303
305
306
+ if ( token . IsCancellationRequested )
307
+ {
308
+ return ;
309
+ }
310
+
304
311
Task . WaitAll ( parseTasks ) ;
305
312
306
313
if ( State . Status < ParserState . Error )
307
314
{
308
315
State . SetStatusAndFireStateChanged ( ParserState . ResolvedDeclarations ) ;
309
- ResolveReferencesAsync ( ) ;
316
+ ResolveReferencesAsync ( token . Token ) ;
310
317
}
311
318
}
312
319
313
- private Task [ ] ResolveReferencesAsync ( )
320
+ private Task [ ] ResolveReferencesAsync ( CancellationToken token )
314
321
{
315
322
var finder = new DeclarationFinder ( State . AllDeclarations , State . AllComments , State . AllAnnotations ) ;
316
323
var passes = new List < ICompilationPass >
@@ -327,7 +334,7 @@ private Task[] ResolveReferencesAsync()
327
334
for ( var index = 0 ; index < State . ParseTrees . Count ; index ++ )
328
335
{
329
336
var kvp = State . ParseTrees [ index ] ;
330
- if ( _resolverTokenSource . IsCancellationRequested || _central . IsCancellationRequested )
337
+ if ( token . IsCancellationRequested )
331
338
{
332
339
return new Task [ 0 ] ;
333
340
}
@@ -337,7 +344,7 @@ private Task[] ResolveReferencesAsync()
337
344
State . SetModuleState ( kvp . Key . Component , ParserState . ResolvingReferences ) ;
338
345
339
346
ResolveReferences ( finder , kvp . Key . Component , kvp . Value ) ;
340
- } ) ;
347
+ } , token ) ;
341
348
}
342
349
343
350
return tasks ;
@@ -489,49 +496,44 @@ private void UnloadComReference(Reference reference, IReadOnlyList<VBProject> pr
489
496
}
490
497
}
491
498
492
- private Task ParseAsync ( VBComponent component , CancellationToken token , TokenStreamRewriter rewriter = null )
499
+ private Task ParseAsync ( VBComponent component , CancellationTokenSource token , TokenStreamRewriter rewriter = null )
493
500
{
494
501
State . ClearStateCache ( component ) ;
495
502
496
- var linkedTokenSource = CancellationTokenSource . CreateLinkedTokenSource ( _central . Token , token ) ;
497
-
498
- var task = new Task ( ( ) => ParseAsyncInternal ( component , linkedTokenSource . Token , rewriter ) ) ;
499
- _currentTasks . TryAdd ( component , Tuple . Create ( task , linkedTokenSource ) ) ;
503
+ var task = new Task ( ( ) => ParseAsyncInternal ( component , token . Token , rewriter ) ) ;
504
+ _currentTasks . TryAdd ( component , Tuple . Create ( task , token ) ) ;
500
505
501
506
Tuple < Task , CancellationTokenSource > removedTask ;
502
- task . ContinueWith ( t => _currentTasks . TryRemove ( component , out removedTask ) ) ; // default also executes on cancel
507
+ task . ContinueWith ( t => _currentTasks . TryRemove ( component , out removedTask ) , token . Token ) ; // default also executes on cancel
503
508
// See http://stackoverflow.com/questions/6800705/why-is-taskscheduler-current-the-default-taskscheduler
504
509
task . Start ( TaskScheduler . Default ) ;
505
510
return task ;
506
511
}
507
512
508
513
public void Cancel ( VBComponent component = null )
509
514
{
510
- lock ( _central )
511
- lock ( _resolverTokenSource )
515
+ lock ( _cancellationTokens [ 0 ] )
516
+ {
517
+ if ( component == null )
512
518
{
513
- if ( component == null )
514
- {
515
- _central . Cancel ( false ) ;
519
+ _cancellationTokens [ 0 ] . Cancel ( ) ;
516
520
517
- _central . Dispose ( ) ;
518
- _central = new CancellationTokenSource ( ) ;
519
- _resolverTokenSource = CancellationTokenSource . CreateLinkedTokenSource ( _central . Token ) ;
520
- }
521
- else
521
+ _cancellationTokens [ 0 ] . Dispose ( ) ;
522
+ _cancellationTokens . Add ( new CancellationTokenSource ( ) ) ;
523
+ _cancellationTokens . RemoveAt ( 0 ) ;
524
+ }
525
+ else
526
+ {
527
+ _cancellationTokens [ 0 ] . Cancel ( ) ;
528
+
529
+ Tuple < Task , CancellationTokenSource > result ;
530
+ if ( _currentTasks . TryGetValue ( component , out result ) )
522
531
{
523
- _resolverTokenSource . Cancel ( false ) ;
524
- _resolverTokenSource . Dispose ( ) ;
525
-
526
- _resolverTokenSource = CancellationTokenSource . CreateLinkedTokenSource ( _central . Token ) ;
527
- Tuple < Task , CancellationTokenSource > result ;
528
- if ( _currentTasks . TryGetValue ( component , out result ) )
529
- {
530
- result . Item2 . Cancel ( false ) ;
531
- result . Item2 . Dispose ( ) ;
532
- }
532
+ result . Item2 . Cancel ( ) ;
533
+ result . Item2 . Dispose ( ) ;
533
534
}
534
535
}
536
+ }
535
537
}
536
538
537
539
private void ParseAsyncInternal ( VBComponent component , CancellationToken token , TokenStreamRewriter rewriter = null )
@@ -569,6 +571,7 @@ private void ResolveDeclarations(VBComponent component, IParseTree tree)
569
571
570
572
var qualifiedModuleName = new QualifiedModuleName ( component ) ;
571
573
574
+ var stopwatch = Stopwatch . StartNew ( ) ;
572
575
try
573
576
{
574
577
var project = component . Collection . Parent ;
@@ -581,6 +584,7 @@ private void ResolveDeclarations(VBComponent component, IParseTree tree)
581
584
State . AddDeclaration ( projectDeclaration ) ;
582
585
}
583
586
Logger . Debug ( "Creating declarations for module {0}." , qualifiedModuleName . Name ) ;
587
+
584
588
var declarationsListener = new DeclarationSymbolsListener ( State , qualifiedModuleName , component . Type , State . GetModuleAnnotations ( component ) , State . GetModuleAttributes ( component ) , projectDeclaration ) ;
585
589
ParseTreeWalker . Default . Walk ( declarationsListener , tree ) ;
586
590
foreach ( var createdDeclaration in declarationsListener . CreatedDeclarations )
@@ -593,6 +597,8 @@ private void ResolveDeclarations(VBComponent component, IParseTree tree)
593
597
Logger . Error ( exception , "Exception thrown acquiring declarations for '{0}' (thread {1})." , component . Name , Thread . CurrentThread . ManagedThreadId ) ;
594
598
State . SetModuleState ( component , ParserState . ResolverError ) ;
595
599
}
600
+ stopwatch . Stop ( ) ;
601
+ Logger . Debug ( "{0}ms to resolve declarations for component {1}" , stopwatch . ElapsedMilliseconds , component . Name ) ;
596
602
}
597
603
598
604
private Declaration CreateProjectDeclaration ( QualifiedModuleName projectQualifiedName , VBProject project )
@@ -654,15 +660,10 @@ public void Dispose()
654
660
{
655
661
State . ParseRequest -= ReparseRequested ;
656
662
657
- if ( _central != null )
658
- {
659
- //_central.Cancel();
660
- _central . Dispose ( ) ;
661
- }
662
-
663
- if ( _resolverTokenSource != null )
663
+ if ( _cancellationTokens [ 0 ] != null )
664
664
{
665
- _resolverTokenSource . Dispose ( ) ;
665
+ _cancellationTokens [ 0 ] . Cancel ( ) ;
666
+ _cancellationTokens [ 0 ] . Dispose ( ) ;
666
667
}
667
668
}
668
669
}
0 commit comments