@@ -31,7 +31,6 @@ public class RubberduckParser : IRubberduckParser
31
31
private readonly IDictionary < VBComponent , IDictionary < Tuple < string , DeclarationType > , Attributes > > _componentAttributes
32
32
= new Dictionary < VBComponent , IDictionary < Tuple < string , DeclarationType > , Attributes > > ( ) ;
33
33
34
-
35
34
private readonly ReferencedDeclarationsCollector _comReflector ;
36
35
37
36
private readonly VBE _vbe ;
@@ -57,7 +56,6 @@ public RubberduckParser(
57
56
state . ParseRequest += ReparseRequested ;
58
57
}
59
58
60
-
61
59
private void ReparseRequested ( object sender , ParseRequestEventArgs e )
62
60
{
63
61
if ( e . IsFullReparseRequest )
@@ -72,10 +70,26 @@ private void ReparseRequested(object sender, ParseRequestEventArgs e)
72
70
{
73
71
ParseAsync ( e . Component , CancellationToken . None ) . Wait ( ) ;
74
72
75
- if ( _state . Status != ParserState . Error )
73
+ if ( _resolverTokenSource . IsCancellationRequested || _central . IsCancellationRequested )
74
+ {
75
+ return ;
76
+ }
77
+
78
+ if ( _state . Status == ParserState . Error ) { return ; }
79
+
80
+ var qualifiedName = new QualifiedModuleName ( e . Component ) ;
81
+ Logger . Debug ( "Module '{0}' {1}" , qualifiedName . ComponentName ,
82
+ _state . IsNewOrModified ( qualifiedName ) ? "was modified" : "was NOT modified" ) ;
83
+
84
+ _state . SetModuleState ( e . Component , ParserState . Resolving ) ;
85
+ ResolveDeclarations ( qualifiedName . Component ,
86
+ _state . ParseTrees . Find ( s => s . Key == qualifiedName ) . Value ) ;
87
+
88
+ _state . SetStatusAndFireStateChanged ( ParserState . ResolvedDeclarations ) ;
89
+
90
+ if ( _state . Status < ParserState . Error )
76
91
{
77
- Logger . Trace ( "Starting resolver task" ) ;
78
- Resolve ( _central . Token ) ;
92
+ ResolveReferencesAsync ( ) ;
79
93
}
80
94
} ) ;
81
95
}
@@ -103,6 +117,12 @@ public void Parse()
103
117
}
104
118
}
105
119
120
+ // tests do not fire events when components are removed--clear components
121
+ foreach ( var tree in _state . ParseTrees )
122
+ {
123
+ _state . ClearStateCache ( tree . Key . Component ) ;
124
+ }
125
+
106
126
SyncComReferences ( _state . Projects ) ;
107
127
108
128
foreach ( var component in components )
@@ -119,18 +139,42 @@ public void Parse()
119
139
}
120
140
}
121
141
142
+ _projectDeclarations . Clear ( ) ;
143
+ _state . ClearBuiltInReferences ( ) ;
144
+
122
145
var parseTasks = new Task [ components . Count ] ;
123
146
for ( var i = 0 ; i < components . Count ; i ++ )
124
147
{
125
- parseTasks [ i ] = ParseAsync ( components [ i ] , CancellationToken . None ) ;
148
+ var index = i ;
149
+ parseTasks [ i ] = new Task ( ( ) =>
150
+ {
151
+ ParseAsync ( components [ index ] , CancellationToken . None ) . Wait ( ) ;
152
+
153
+ if ( _resolverTokenSource . IsCancellationRequested || _central . IsCancellationRequested )
154
+ {
155
+ return ;
156
+ }
157
+
158
+ if ( _state . Status == ParserState . Error ) { return ; }
159
+
160
+ var qualifiedName = new QualifiedModuleName ( components [ index ] ) ;
161
+ Logger . Debug ( "Module '{0}' {1}" , qualifiedName . ComponentName ,
162
+ _state . IsNewOrModified ( qualifiedName ) ? "was modified" : "was NOT modified" ) ;
163
+
164
+ _state . SetModuleState ( components [ index ] , ParserState . Resolving ) ;
165
+ ResolveDeclarations ( qualifiedName . Component ,
166
+ _state . ParseTrees . Find ( s => s . Key == qualifiedName ) . Value ) ;
167
+ } ) ;
168
+
169
+ parseTasks [ i ] . Start ( ) ;
126
170
}
127
171
128
172
Task . WaitAll ( parseTasks ) ;
173
+ _state . SetStatusAndFireStateChanged ( ParserState . ResolvedDeclarations ) ;
129
174
130
- if ( _state . Status != ParserState . Error )
175
+ if ( _state . Status < ParserState . Error )
131
176
{
132
- Logger . Trace ( "Starting resolver task" ) ;
133
- Resolve ( _central . Token ) ; // Tests expect this to be synchronous
177
+ Task . WaitAll ( ResolveReferencesAsync ( ) ) ;
134
178
}
135
179
}
136
180
@@ -179,8 +223,7 @@ private void ParseAll()
179
223
State . SetStatusAndFireStateChanged ( _state . Status ) ;
180
224
return ;
181
225
}
182
-
183
-
226
+
184
227
lock ( _state ) // note, method is invoked from UI thread... really need the lock here?
185
228
{
186
229
foreach ( var component in toParse )
@@ -192,9 +235,6 @@ private void ParseAll()
192
235
// note: seting to 'Parsed' would include them in the resolver walk. 'Ready' excludes them.
193
236
_state . SetModuleState ( component , ParserState . Ready ) ;
194
237
}
195
-
196
- //Debug.Assert(unchanged.All(component => _state.GetModuleState(component) == ParserState.Ready));
197
- //Debug.Assert(toParse.All(component => _state.GetModuleState(component) == ParserState.Pending));
198
238
}
199
239
200
240
// invalidation cleanup should go into ParseAsync?
@@ -206,19 +246,71 @@ private void ParseAll()
206
246
}
207
247
}
208
248
209
- var parseTasks = new Task [ components . Count ] ;
210
- for ( var i = 0 ; i < components . Count ; i ++ )
249
+ _projectDeclarations . Clear ( ) ;
250
+ _state . ClearBuiltInReferences ( ) ;
251
+
252
+ var parseTasks = new Task [ toParse . Count ] ;
253
+ for ( var i = 0 ; i < toParse . Count ; i ++ )
211
254
{
212
- parseTasks [ i ] = ParseAsync ( components [ i ] , CancellationToken . None ) ;
255
+ var index = i ;
256
+ parseTasks [ i ] = new Task ( ( ) =>
257
+ {
258
+ ParseAsync ( toParse [ index ] , CancellationToken . None ) . Wait ( ) ;
259
+
260
+ if ( _resolverTokenSource . IsCancellationRequested || _central . IsCancellationRequested )
261
+ {
262
+ return ;
263
+ }
264
+
265
+ if ( _state . Status == ParserState . Error ) { return ; }
266
+
267
+ var qualifiedName = new QualifiedModuleName ( toParse [ index ] ) ;
268
+ Logger . Debug ( "Module '{0}' {1}" , qualifiedName . ComponentName ,
269
+ _state . IsNewOrModified ( qualifiedName ) ? "was modified" : "was NOT modified" ) ;
270
+
271
+ _state . SetModuleState ( toParse [ index ] , ParserState . Resolving ) ;
272
+ ResolveDeclarations ( qualifiedName . Component ,
273
+ _state . ParseTrees . Find ( s => s . Key == qualifiedName ) . Value ) ;
274
+ } ) ;
275
+
276
+ parseTasks [ i ] . Start ( ) ;
213
277
}
214
278
215
279
Task . WaitAll ( parseTasks ) ;
280
+ _state . SetStatusAndFireStateChanged ( ParserState . ResolvedDeclarations ) ;
281
+
282
+ if ( _state . Status < ParserState . Error )
283
+ {
284
+ ResolveReferencesAsync ( ) ;
285
+ }
286
+ }
287
+
288
+ private Task [ ] ResolveReferencesAsync ( )
289
+ {
290
+ var finder = new DeclarationFinder ( _state . AllDeclarations , _state . AllComments , _state . AllAnnotations ) ;
291
+ var passes = new List < ICompilationPass >
292
+ {
293
+ // This pass has to come first because the type binding resolution depends on it.
294
+ new ProjectReferencePass ( finder ) ,
295
+ new TypeHierarchyPass ( finder , new VBAExpressionParser ( ) ) ,
296
+ new TypeAnnotationPass ( finder , new VBAExpressionParser ( ) )
297
+ } ;
298
+ passes . ForEach ( p => p . Execute ( ) ) ;
299
+
300
+ var tasks = new Task [ _state . ParseTrees . Count ] ;
216
301
217
- if ( _state . Status != ParserState . Error )
302
+ for ( var index = 0 ; index < _state . ParseTrees . Count ; index ++ )
218
303
{
219
- Logger . Trace ( "Starting resolver task" ) ;
220
- Resolve ( _central . Token ) ;
304
+ var kvp = _state . ParseTrees [ index ] ;
305
+ if ( _resolverTokenSource . IsCancellationRequested || _central . IsCancellationRequested )
306
+ {
307
+ return new Task [ 0 ] ;
308
+ }
309
+
310
+ tasks [ index ] = Task . Run ( ( ) => ResolveReferences ( finder , kvp . Key . Component , kvp . Value ) ) ;
221
311
}
312
+
313
+ return tasks ;
222
314
}
223
315
224
316
private void AddBuiltInDeclarations ( IReadOnlyList < VBProject > projects )
@@ -375,7 +467,7 @@ private void UnloadComReference(Reference reference, IReadOnlyList<VBProject> pr
375
467
}
376
468
}
377
469
378
- public Task ParseAsync ( VBComponent component , CancellationToken token , TokenStreamRewriter rewriter = null )
470
+ private Task ParseAsync ( VBComponent component , CancellationToken token , TokenStreamRewriter rewriter = null )
379
471
{
380
472
lock ( _state )
381
473
lock ( component )
@@ -460,66 +552,7 @@ private void ParseAsyncInternal(VBComponent component, CancellationToken token,
460
552
parser . Start ( token ) ;
461
553
}
462
554
463
- private void Resolve ( CancellationToken token )
464
- {
465
- State . SetStatusAndFireStateChanged ( ParserState . Resolving ) ;
466
- var sharedTokenSource = CancellationTokenSource . CreateLinkedTokenSource ( _resolverTokenSource . Token , token ) ;
467
- // tests expect this to be synchronous :/
468
- //Task.Run(() => ResolveInternal(sharedTokenSource.Token));
469
- ResolveInternal ( sharedTokenSource . Token ) ;
470
- }
471
-
472
- private void ResolveInternal ( CancellationToken token )
473
- {
474
- var components = new List < VBComponent > ( ) ;
475
- foreach ( var project in _state . Projects )
476
- {
477
- if ( project . Protection == vbext_ProjectProtection . vbext_pp_locked )
478
- {
479
- continue ;
480
- }
481
-
482
- foreach ( VBComponent component in project . VBComponents )
483
- {
484
- components . Add ( component ) ;
485
- }
486
- }
487
-
488
- if ( ! _state . HasAllParseTrees ( components ) )
489
- {
490
- return ;
491
- }
492
- _projectDeclarations . Clear ( ) ;
493
- _state . ClearBuiltInReferences ( ) ;
494
- foreach ( var kvp in _state . ParseTrees )
495
- {
496
- var qualifiedName = kvp . Key ;
497
- Logger . Debug ( "Module '{0}' {1}" , qualifiedName . ComponentName , _state . IsNewOrModified ( qualifiedName ) ? "was modified" : "was NOT modified" ) ;
498
- // modified module; walk parse tree and re-acquire all declarations
499
- if ( token . IsCancellationRequested ) return ;
500
- ResolveDeclarations ( qualifiedName . Component , kvp . Value ) ;
501
- }
502
-
503
- _state . SetStatusAndFireStateChanged ( ParserState . ResolvedDeclarations ) ;
504
-
505
- // walk all parse trees (modified or not) for identifier references
506
- var finder = new DeclarationFinder ( _state . AllDeclarations , _state . AllComments , _state . AllAnnotations ) ;
507
- var passes = new List < ICompilationPass >
508
- {
509
- // This pass has to come first because the type binding resolution depends on it.
510
- new ProjectReferencePass ( finder ) ,
511
- new TypeHierarchyPass ( finder , new VBAExpressionParser ( ) ) ,
512
- new TypeAnnotationPass ( finder , new VBAExpressionParser ( ) )
513
- } ;
514
- passes . ForEach ( p => p . Execute ( ) ) ;
515
- foreach ( var kvp in _state . ParseTrees )
516
- {
517
- if ( token . IsCancellationRequested ) return ;
518
- ResolveReferences ( finder , kvp . Key . Component , kvp . Value ) ;
519
- }
520
- }
521
-
522
- private readonly Dictionary < string , Declaration > _projectDeclarations = new Dictionary < string , Declaration > ( ) ;
555
+ private readonly ConcurrentDictionary < string , Declaration > _projectDeclarations = new ConcurrentDictionary < string , Declaration > ( ) ;
523
556
private void ResolveDeclarations ( VBComponent component , IParseTree tree )
524
557
{
525
558
if ( component == null ) { return ; }
@@ -534,7 +567,7 @@ private void ResolveDeclarations(VBComponent component, IParseTree tree)
534
567
if ( ! _projectDeclarations . TryGetValue ( projectQualifiedName . ProjectId , out projectDeclaration ) )
535
568
{
536
569
projectDeclaration = CreateProjectDeclaration ( projectQualifiedName , project ) ;
537
- _projectDeclarations . Add ( projectQualifiedName . ProjectId , projectDeclaration ) ;
570
+ _projectDeclarations . AddOrUpdate ( projectQualifiedName . ProjectId , projectDeclaration , ( s , c ) => projectDeclaration ) ;
538
571
lock ( _state )
539
572
{
540
573
_state . AddDeclaration ( projectDeclaration ) ;
@@ -584,7 +617,7 @@ private Declaration CreateProjectDeclaration(QualifiedModuleName projectQualifie
584
617
private void ResolveReferences ( DeclarationFinder finder , VBComponent component , IParseTree tree )
585
618
{
586
619
var state = _state . GetModuleState ( component ) ;
587
- if ( _state . Status == ParserState . ResolverError || ( state != ParserState . Parsed ) )
620
+ if ( state != ParserState . Resolving )
588
621
{
589
622
return ;
590
623
}
0 commit comments