in src/MIDebugEngine/Engine.Impl/ExceptionManager.cs [490:626]
private async Task UpdateCategory(Guid categoryId, ExceptionCategorySettings categorySettings, SettingsUpdates updates)
{
// Update the category
if (updates.NewCategoryState.HasValue && (
updates.NewCategoryState.Value != ExceptionBreakpointStates.None || // send down a rule if the category isn't in the default state
categorySettings.CurrentRules.Count != 0)) // Or if we have other rules for the category that we need to blow away
{
ExceptionBreakpointStates newCategoryState = updates.NewCategoryState.Value;
categorySettings.CategoryState = newCategoryState;
// remove exception breakpoints before categorySettings.CurrentRules is cleared
await _commandFactory.RemoveExceptionBreakpoint(categoryId, categorySettings.CurrentRules.Values);
lock (categorySettings.CurrentRules)
{
categorySettings.CurrentRules.Clear();
}
// only do a generic catch throw if C++ exceptions category is checked
if (newCategoryState != ExceptionBreakpointStates.None)
{
try
{
IEnumerable<ulong> breakpointIds = await _commandFactory.SetExceptionBreakpoints(categoryId, null, newCategoryState);
ulong breakpointId = breakpointIds.Single();
lock (categorySettings.CurrentRules)
{
categorySettings.CurrentRules.Add("*", breakpointId);
}
}
catch (NotSupportedException)
{
_canProcessExceptions = false;
_callback.OnOutputMessage(new OutputMessage(ResourceStrings.Warning_ExceptionsNotSupported, enum_MESSAGETYPE.MT_OUTPUTSTRING, OutputMessage.Severity.Warning));
return;
}
}
}
// Process any removes
if (updates.RulesToRemove.Count > 0)
{
// Detach these exceptions from 'CurrentRules'
List<ulong> breakpointsToRemove = new List<ulong>();
lock (categorySettings.CurrentRules)
{
foreach (string exceptionToRemove in updates.RulesToRemove)
{
ulong breakpointId;
if (!categorySettings.CurrentRules.TryGetValue(exceptionToRemove, out breakpointId))
continue;
categorySettings.CurrentRules.Remove(exceptionToRemove);
breakpointsToRemove.Add(breakpointId);
}
}
if (breakpointsToRemove.Count > 0)
{
await _commandFactory.RemoveExceptionBreakpoint(categoryId, breakpointsToRemove);
}
}
// process any adds
foreach (IGrouping<ExceptionBreakpointStates, string> grouping in updates.RulesToAdd.GroupBy((pair) => pair.Value, (pair) => pair.Key))
{
IEnumerable<string> exceptionNames = grouping;
if (grouping.Key == categorySettings.CategoryState)
{
// A request to set an exception to the same state as the category is redundant unless we have previously changed the state of that exception to something else
lock (categorySettings.CurrentRules)
{
exceptionNames = exceptionNames.Intersect(categorySettings.CurrentRules.Keys);
}
if (!exceptionNames.Any())
{
continue; // no exceptions left, so ignore this group
}
}
bool isBreakThrown = grouping.Key.HasFlag(ExceptionBreakpointStates.BreakThrown);
if (!categorySettings.CategoryState.HasFlag(ExceptionBreakpointStates.BreakThrown) && isBreakThrown)
{
try
{
IEnumerable<ulong> breakpointIds = await _commandFactory.SetExceptionBreakpoints(categoryId, exceptionNames, grouping.Key);
lock (categorySettings.CurrentRules)
{
int count = exceptionNames.Zip(breakpointIds, (exceptionName, breakpointId) =>
{
// remove old breakpoint if exceptionName is in categorySettings.CurrentRules.Keys
if (categorySettings.CurrentRules.ContainsKey(exceptionName))
{
_commandFactory.RemoveExceptionBreakpoint(categoryId, new ulong[] { categorySettings.CurrentRules[exceptionName] });
}
categorySettings.CurrentRules[exceptionName] = breakpointId;
return 1;
}).Sum();
#if DEBUG
Debug.Assert(count == exceptionNames.Count());
#endif
}
}
catch (NotSupportedException)
{
_canProcessExceptions = false;
_callback.OnOutputMessage(new OutputMessage(ResourceStrings.Warning_ExceptionsNotSupported, enum_MESSAGETYPE.MT_OUTPUTSTRING, OutputMessage.Severity.Warning));
return;
}
}
else if (grouping.Key != categorySettings.CategoryState && !isBreakThrown)
{
// Send warning when there are unchecked exceptions in a checked exceptions category
_callback.OnOutputMessage(new OutputMessage(ResourceStrings.Warning_UncheckedExceptionsInCheckedCategory, enum_MESSAGETYPE.MT_OUTPUTSTRING, OutputMessage.Severity.Warning));
}
if (!isBreakThrown)
{
ulong breakpointId;
lock (categorySettings.CurrentRules)
{
foreach (string exceptionName in exceptionNames)
{
if (!categorySettings.CurrentRules.TryGetValue(exceptionName, out breakpointId))
continue;
_commandFactory.RemoveExceptionBreakpoint(categoryId, new ulong[] { breakpointId });
categorySettings.CurrentRules.Remove(exceptionName);
}
}
}
}
}