Skip to content

Commit f31b56b

Browse files
committed
Collect parse results into a ConcurrentBag and add to parser state later
This removes the need for the lock on the parser state, which we used previously.
1 parent a2aa50e commit f31b56b

File tree

4 files changed

+61
-35
lines changed

4 files changed

+61
-35
lines changed

Rubberduck.Parsing/VBA/Parsing/IModuleParser.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
using Antlr4.Runtime;
44
using Antlr4.Runtime.Tree;
55
using Rubberduck.Parsing.Annotations;
6-
using Rubberduck.Parsing.Rewriter;
76
using Rubberduck.Parsing.Symbols;
87
using Rubberduck.VBEditor;
98

Rubberduck.Parsing/VBA/Parsing/ParseRunner.cs

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Collections.Concurrent;
23
using System.Collections.Generic;
34
using System.Linq;
45
using System.Threading;
@@ -21,26 +22,30 @@ public ParseRunner(
2122
parser)
2223
{ }
2324

24-
public override void ParseModules(IReadOnlyCollection<QualifiedModuleName> modules, CancellationToken token)
25+
protected override IReadOnlyCollection<(QualifiedModuleName module, ModuleParseResults results)> ModulePareResults(IReadOnlyCollection<QualifiedModuleName> modules, CancellationToken token)
2526
{
2627
if (!modules.Any())
2728
{
28-
return;
29+
return new List<(QualifiedModuleName module, ModuleParseResults results)>();
2930
}
3031

3132
token.ThrowIfCancellationRequested();
3233

3334
var parsingStageTimer = ParsingStageTimer.StartNew();
3435

35-
var options = new ParallelOptions();
36-
options.CancellationToken = token;
37-
options.MaxDegreeOfParallelism = _maxDegreeOfParserParallelism;
36+
var results = new ConcurrentBag<(QualifiedModuleName module, ModuleParseResults results)>();
37+
38+
var options = new ParallelOptions
39+
{
40+
CancellationToken = token,
41+
MaxDegreeOfParallelism = _maxDegreeOfParserParallelism
42+
};
3843

3944
try
4045
{
4146
Parallel.ForEach(modules,
4247
options,
43-
module => ParseModule(module, token)
48+
module => results.Add((module, ModuleParseResults(module, token)))
4449
);
4550
}
4651
catch (AggregateException exception)
@@ -55,6 +60,8 @@ public override void ParseModules(IReadOnlyCollection<QualifiedModuleName> modul
5560

5661
parsingStageTimer.Stop();
5762
parsingStageTimer.Log("Parsed user modules in {0}ms.");
63+
64+
return results;
5865
}
5966
}
6067
}

Rubberduck.Parsing/VBA/Parsing/ParseRunnerBase.cs

Lines changed: 41 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
using System;
2+
using System.Collections.Concurrent;
23
using System.Collections.Generic;
4+
using System.Linq;
35
using System.Threading;
46
using Rubberduck.Parsing.VBA.Parsing.ParsingExceptions;
57
using Rubberduck.VBEditor;
@@ -36,23 +38,27 @@ protected ParseRunnerBase(
3638
_parser = parser;
3739
}
3840

41+
public void ParseModules(IReadOnlyCollection<QualifiedModuleName> modules, CancellationToken token)
42+
{
43+
var parseResults = ModulePareResults(modules, token);
44+
SaveModuleParseResultsOnState(parseResults, token);
45+
}
3946

40-
public abstract void ParseModules(IReadOnlyCollection<QualifiedModuleName> modules, CancellationToken token);
41-
47+
protected abstract IReadOnlyCollection<(QualifiedModuleName module, ModuleParseResults results)> ModulePareResults(IReadOnlyCollection<QualifiedModuleName> modules, CancellationToken token);
4248

43-
protected void ParseModule(QualifiedModuleName module, CancellationToken token)
49+
protected ModuleParseResults ModuleParseResults(QualifiedModuleName module, CancellationToken token)
4450
{
4551
_state.ClearStateCache(module);
4652
try
4753
{
48-
var parseResults = _parser.Parse(module, token);
49-
SaveModuleParseResultsOnState(module, parseResults, token);
54+
return _parser.Parse(module, token);
5055
}
5156
catch (SyntaxErrorException syntaxErrorException)
5257
{
5358
//In contrast to the situation in the success scenario, the overall parser state is reevaluated immediately.
54-
//This sets the state directly on the state because it is the sole instance where we have to pass the SyntaxErorException.
59+
//This sets the state directly on the state because it is the sole instance where we have to pass the SyntaxErrorException.
5560
_state.SetModuleState(module, ParserState.Error, token, syntaxErrorException);
61+
return default;
5662
}
5763
catch (Exception exception)
5864
{
@@ -61,30 +67,40 @@ protected void ParseModule(QualifiedModuleName module, CancellationToken token)
6167
}
6268
}
6369

64-
private void SaveModuleParseResultsOnState(QualifiedModuleName module, ModuleParseResults results, CancellationToken token)
70+
private void SaveModuleParseResultsOnState(IReadOnlyCollection<(QualifiedModuleName module, ModuleParseResults results)> parseResults, CancellationToken token)
6571
{
66-
lock (_state)
72+
foreach (var (module, result) in parseResults)
6773
{
68-
token.ThrowIfCancellationRequested();
74+
if (result.CodePaneParseTree == null)
75+
{
76+
continue;
77+
}
6978

70-
//This has to come first because it creates the module state if not present.
71-
_state.AddModuleStateIfNotPresent(module);
79+
SaveModuleParseResultsOnState(module, result, token);
80+
}
81+
}
7282

73-
_state.SaveContentHash(module);
74-
_state.AddParseTree(module, results.CodePaneParseTree);
75-
_state.AddParseTree(module, results.AttributesParseTree, CodeKind.AttributesCode);
76-
_state.SetModuleComments(module, results.Comments);
77-
_state.SetModuleAnnotations(module, results.Annotations);
78-
_state.SetModuleAttributes(module, results.Attributes);
79-
_state.SetMembersAllowingAttributes(module, results.MembersAllowingAttributes);
80-
_state.SetCodePaneTokenStream(module, results.CodePaneTokenStream);
81-
_state.SetAttributesTokenStream(module, results.AttributesTokenStream);
83+
private void SaveModuleParseResultsOnState(QualifiedModuleName module, ModuleParseResults results, CancellationToken token)
84+
{
85+
token.ThrowIfCancellationRequested();
8286

83-
// This really needs to go last
84-
//It does not reevaluate the overall parer state to avoid concurrent evaluation of all module states and for performance reasons.
85-
//The evaluation has to be triggered manually in the calling procedure.
86-
StateManager.SetModuleState(module, ParserState.Parsed, token, false); //Note that this is ok because locks allow re-entrancy.
87-
}
87+
//This has to come first because it creates the module state if not present.
88+
_state.AddModuleStateIfNotPresent(module);
89+
90+
_state.SaveContentHash(module);
91+
_state.AddParseTree(module, results.CodePaneParseTree);
92+
_state.AddParseTree(module, results.AttributesParseTree, CodeKind.AttributesCode);
93+
_state.SetModuleComments(module, results.Comments);
94+
_state.SetModuleAnnotations(module, results.Annotations);
95+
_state.SetModuleAttributes(module, results.Attributes);
96+
_state.SetMembersAllowingAttributes(module, results.MembersAllowingAttributes);
97+
_state.SetCodePaneTokenStream(module, results.CodePaneTokenStream);
98+
_state.SetAttributesTokenStream(module, results.AttributesTokenStream);
99+
100+
// This really needs to go last
101+
//It does not reevaluate the overall parer state to avoid concurrent evaluation of all module states and for performance reasons.
102+
//The evaluation has to be triggered manually in the calling procedure.
103+
StateManager.SetModuleState(module, ParserState.Parsed, token,false); //Note that this is ok because locks allow re-entrancy.
88104
}
89105
}
90106
}

Rubberduck.Parsing/VBA/Parsing/SynchronousParseRunner.cs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,20 +18,22 @@ public SynchronousParseRunner(
1818
{ }
1919

2020

21-
public override void ParseModules(IReadOnlyCollection<QualifiedModuleName> modules, CancellationToken token)
21+
protected override IReadOnlyCollection<(QualifiedModuleName module, ModuleParseResults results)> ModulePareResults(IReadOnlyCollection<QualifiedModuleName> modules, CancellationToken token)
2222
{
2323
if (!modules.Any())
2424
{
25-
return;
25+
return new List<(QualifiedModuleName module, ModuleParseResults results)>();
2626
}
2727

2828
token.ThrowIfCancellationRequested();
2929

30+
var results = new List<(QualifiedModuleName module, ModuleParseResults results)>();
31+
3032
try
3133
{
3234
foreach (var module in modules)
3335
{
34-
ParseModule(module, token);
36+
results.Add((module, ModuleParseResults(module, token)));
3537
}
3638
}
3739
catch (OperationCanceledException)
@@ -43,6 +45,8 @@ public override void ParseModules(IReadOnlyCollection<QualifiedModuleName> modul
4345
StateManager.SetStatusAndFireStateChanged(this, ParserState.Error, token);
4446
throw;
4547
}
48+
49+
return results;
4650
}
4751
}
4852
}

0 commit comments

Comments
 (0)