Skip to content

Commit bed1479

Browse files
committed
Add additional value to suspensionOutcome enum and stop rethrowing
The new value indicates that the suspension failed because the executing thread already held a read lock to the suspension lock. This is an error state distinct from a failure due to an exception.
1 parent 6991bc8 commit bed1479

File tree

3 files changed

+57
-4
lines changed

3 files changed

+57
-4
lines changed

Rubberduck.Parsing/VBA/IParseManager.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ public enum SuspensionOutcome
6464
/// </summary>
6565
Canceled,
6666
/// <summary>
67+
/// We already hold a read lock to the suspension lock; this indicates a bug in code.
68+
/// </summary>
69+
ReadLockAlreadyHeld,
70+
/// <summary>
6771
/// An unexpected error; usually indicates a bug in code.
6872
/// </summary>
6973
UnexpectedError

Rubberduck.Parsing/VBA/ParseCoordinator.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ public void SuspendRequested(object sender, RubberduckStatusSuspendParserEventAr
116116
{
117117
if (ParsingSuspendLock.IsReadLockHeld)
118118
{
119-
e.Result = SuspensionOutcome.UnexpectedError;
119+
e.Result = SuspensionOutcome.ReadLockAlreadyHeld;
120120
const string errorMessage =
121121
"A suspension action was attempted while a read lock was held. This indicates a bug in the code logic as suspension should not be requested from same thread that has a read lock.";
122122
Logger.Error(errorMessage);
@@ -154,13 +154,11 @@ public void SuspendRequested(object sender, RubberduckStatusSuspendParserEventAr
154154
{
155155
e.Result = SuspensionOutcome.Canceled;
156156
e.EncounteredException = ex;
157-
throw;
158157
}
159158
catch (Exception ex)
160159
{
161160
e.Result = SuspensionOutcome.UnexpectedError;
162161
e.EncounteredException = ex;
163-
throw;
164162
}
165163
finally
166164
{

RubberduckTests/ParserState/ParserStateTests.cs

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,58 @@ public void Test_RPS_SuspendParser_Exception_Suspending_Inside_Parse()
116116
state.OnParseRequested(this);
117117
}
118118
Assert.IsFalse(wasSuspended);
119-
Assert.AreEqual(SuspensionOutcome.UnexpectedError, result);
119+
Assert.AreEqual(SuspensionOutcome.ReadLockAlreadyHeld, result);
120+
}
121+
122+
[Test]
123+
[Category("ParserState")]
124+
public void Test_RPS_SuspendParser_Exception()
125+
{
126+
SuspensionResult result;
127+
128+
var vbe = MockVbeBuilder.BuildFromSingleModule("", ComponentType.StandardModule, out var _);
129+
using (var state = MockParser.CreateAndParse(vbe.Object))
130+
{
131+
result = state.OnSuspendParser(this, AllowedRunStates, () => throw new NullReferenceException());
132+
}
133+
134+
Assert.IsNotNull(result.EncounteredException);
135+
Assert.AreEqual(typeof(NullReferenceException), result.EncounteredException.GetType());
136+
Assert.AreEqual(SuspensionOutcome.UnexpectedError, result.Outcome);
137+
}
138+
139+
[Test]
140+
[Category("ParserState")]
141+
public void Test_RPS_SuspendParser_Canceled()
142+
{
143+
SuspensionResult result;
144+
145+
var vbe = MockVbeBuilder.BuildFromSingleModule("", ComponentType.StandardModule, out var _);
146+
using (var state = MockParser.CreateAndParse(vbe.Object))
147+
{
148+
result = state.OnSuspendParser(this, AllowedRunStates, () => throw new OperationCanceledException());
149+
}
150+
151+
Assert.IsNotNull(result.EncounteredException);
152+
Assert.AreEqual(typeof(OperationCanceledException), result.EncounteredException.GetType());
153+
Assert.AreEqual(SuspensionOutcome.Canceled, result.Outcome);
154+
}
155+
156+
[Test]
157+
[Category("ParserState")]
158+
public void Test_RPS_SuspendParser_IncompatibleState()
159+
{
160+
var result = SuspensionOutcome.Pending;
161+
var wasRun = false;
162+
var wasSuspended = false;
163+
164+
var vbe = MockVbeBuilder.BuildFromSingleModule("", ComponentType.StandardModule, out var _);
165+
using (var state = MockParser.CreateAndParse(vbe.Object))
166+
{
167+
result = state.OnSuspendParser(this, new []{ParserState.Pending}, () => throw new OperationCanceledException()).Outcome;
168+
}
169+
Assert.IsFalse(wasSuspended);
170+
Assert.AreEqual(SuspensionOutcome.IncompatibleState, result);
120171
}
121172

122173
[Test]

0 commit comments

Comments
 (0)