private async Task UpdateCategory()

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);
                        }
                    }
                }
                
            }
        }