Skip to content

Commit 84e1ff4

Browse files
authored
Merge branch 'next' into next
2 parents 932637f + 265b67e commit 84e1ff4

File tree

4 files changed

+117
-34
lines changed

4 files changed

+117
-34
lines changed

RetailCoder.VBE/Refactorings/ExtractInterface/ExtractInterfaceRefactoring.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,6 @@ public void Refactor()
6565
pane.Selection = oldSelection.Value.Selection;
6666
}
6767
}
68-
69-
_state.OnParseRequested(this);
7068
}
7169

7270
public void Refactor(QualifiedSelection target)

Rubberduck.Parsing/VBA/ComponentParseTask.cs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,9 +101,15 @@ public void Start(CancellationToken token)
101101
Cause = exception
102102
});
103103
}
104-
catch (OperationCanceledException)
104+
catch (OperationCanceledException exception)
105105
{
106-
// no results to be used, so no results "returned"
106+
//We return this, so that the calling code knows that the operation actually has been cancelled.
107+
var failedHandler = ParseFailure;
108+
if (failedHandler != null)
109+
failedHandler.Invoke(this, new ParseFailureArgs
110+
{
111+
Cause = exception
112+
});
107113
}
108114
}
109115

Rubberduck.Parsing/VBA/ParseCoordinator.cs

Lines changed: 96 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ public class ParseCoordinator : IParseCoordinator
2828
public RubberduckParserState State { get { return _state; } }
2929

3030
private const int _maxDegreeOfParserParallelism = -1;
31+
private const int _maxDegreeOfModuleStateChangeParallelism = -1;
3132

3233
private readonly IDictionary<IVBComponent, IDictionary<Tuple<string, DeclarationType>, Attributes>> _componentAttributes
3334
= new Dictionary<IVBComponent, IDictionary<Tuple<string, DeclarationType>, Attributes>>();
@@ -79,7 +80,8 @@ private void ReparseRequested(object sender, EventArgs e)
7980
}
8081
else
8182
{
82-
Parse(_cancellationTokens[0]);
83+
Cancel();
84+
ParseInternal(_cancellationTokens[0]);
8385
}
8486
}
8587

@@ -100,7 +102,28 @@ private void Cancel(bool createNewTokenSource = true)
100102
/// <summary>
101103
/// For the use of tests only
102104
/// </summary>
105+
///
103106
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)
104127
{
105128
State.RefreshProjects(_vbe);
106129

@@ -163,10 +186,12 @@ private void RefreshDeclarationFinder()
163186

164187
private void SetModuleStates(List<IVBComponent> components, ParserState parserState)
165188
{
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();
170195
}
171196

172197
private void CleanUpComponentAttributes(List<IVBComponent> components)
@@ -190,20 +215,34 @@ private void ClearComponentStateCacheForTests()
190215

191216
private void ParseComponents(List<IVBComponent> components, CancellationToken token)
192217
{
218+
SetModuleStates(components, ParserState.Parsing);
219+
193220
var options = new ParallelOptions();
194221
options.CancellationToken = token;
195222
options.MaxDegreeOfParallelism = _maxDegreeOfParserParallelism;
196223

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))
200239
{
201-
State.SetModuleState(component, ParserState.Parsing);
202-
State.ClearStateCache(component);
203-
var finishedParseTask = FinishedParseComponentTask(component, token);
204-
ProcessComponentParseResults(component, finishedParseTask);
240+
return;
205241
}
206-
);
242+
throw;
243+
}
244+
245+
State.EvaluateParserState();
207246
}
208247

209248
private Task<ComponentParseTask.ParseCompletionArgs> FinishedParseComponentTask(IVBComponent component, CancellationToken token, TokenStreamRewriter rewriter = null)
@@ -215,7 +254,14 @@ private void ParseComponents(List<IVBComponent> components, CancellationToken to
215254

216255
parser.ParseFailure += (sender, e) =>
217256
{
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+
}
219265
};
220266
parser.ParseCompleted += (sender, e) =>
221267
{
@@ -230,9 +276,9 @@ private void ParseComponents(List<IVBComponent> components, CancellationToken to
230276

231277
private void ProcessComponentParseResults(IVBComponent component, Task<ComponentParseTask.ParseCompletionArgs> finishedParseTask)
232278
{
233-
finishedParseTask.Wait();
234279
if (finishedParseTask.IsFaulted)
235280
{
281+
//In contrast to the situation in the success scenario, the overall parser state is reevaluated immediately.
236282
State.SetModuleState(component, ParserState.Error, finishedParseTask.Exception.InnerException as SyntaxErrorException);
237283
}
238284
else if (finishedParseTask.IsCompleted)
@@ -249,7 +295,9 @@ private void ProcessComponentParseResults(IVBComponent component, Task<Component
249295
State.SetModuleAnnotations(component, result.Annotations);
250296

251297
// 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);
253301
}
254302
}
255303
}
@@ -258,26 +306,48 @@ private void ProcessComponentParseResults(IVBComponent component, Task<Component
258306

259307
private void ResolveAllDeclarations(List<IVBComponent> components, CancellationToken token)
260308
{
309+
SetModuleStates(components, ParserState.ResolvingDeclarations);
310+
261311
var options = new ParallelOptions();
262312
options.CancellationToken = token;
263313
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))
268329
{
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;
273331
}
274-
);
332+
throw;
333+
}
275334
}
276335

277336

278337
private void ResolveReferences(CancellationToken token)
279338
{
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+
}
281351
}
282352

283353

Rubberduck.Parsing/VBA/RubberduckParserState.cs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,7 @@ private void OnModuleStateChanged(IVBComponent component, ParserState state, Par
311311
}
312312
}
313313

314-
public void SetModuleState(IVBComponent component, ParserState state, SyntaxErrorException parserError = null)
314+
public void SetModuleState(IVBComponent component, ParserState state, SyntaxErrorException parserError = null, bool evaluateOverallState = true)
315315
{
316316
if (AllUserDeclarations.Count > 0)
317317
{
@@ -339,7 +339,7 @@ public void SetModuleState(IVBComponent component, ParserState state, SyntaxErro
339339
{
340340
// ghost component shouldn't even exist
341341
ClearStateCache(component);
342-
Status = EvaluateParserState();
342+
EvaluateParserState();
343343
return;
344344
}
345345
}
@@ -351,10 +351,18 @@ public void SetModuleState(IVBComponent component, ParserState state, SyntaxErro
351351
_moduleStates.AddOrUpdate(key, new ModuleState(parserError), (c, e) => e.SetModuleException(parserError));
352352
Logger.Debug("Module '{0}' state is changing to '{1}' (thread {2})", key.ComponentName, state, Thread.CurrentThread.ManagedThreadId);
353353
OnModuleStateChanged(component, state, oldState);
354-
Status = EvaluateParserState();
354+
if (evaluateOverallState)
355+
{
356+
EvaluateParserState();
357+
}
358+
}
359+
360+
public void EvaluateParserState()
361+
{
362+
lock (_statusLockObject) Status = OverallParserStateFromModuleStates();
355363
}
356364

357-
private ParserState EvaluateParserState()
365+
private ParserState OverallParserStateFromModuleStates()
358366
{
359367
if (_moduleStates.IsEmpty)
360368
{
@@ -497,6 +505,7 @@ public ParserState GetModuleState(IVBComponent component)
497505
return _moduleStates.GetOrAdd(new QualifiedModuleName(component), new ModuleState(ParserState.Pending)).State;
498506
}
499507

508+
private readonly object _statusLockObject = new object();
500509
private ParserState _status;
501510
public ParserState Status
502511
{

0 commit comments

Comments
 (0)