protected override void HandleSetBreakpointsRequestAsync()

in src/OpenDebugAD7/AD7DebugSession.cs [2167:2381]


        protected override void HandleSetBreakpointsRequestAsync(IRequestResponder<SetBreakpointsArguments, SetBreakpointsResponse> responder)
        {
            SetBreakpointsResponse response = new SetBreakpointsResponse();

            string path = null;
            string name = null;

            if (responder.Arguments.Source != null)
            {
                string p = responder.Arguments.Source.Path;
                if (p != null && p.Trim().Length > 0)
                {
                    path = p;
                }
                string nm = responder.Arguments.Source.Name;
                if (nm != null && nm.Trim().Length > 0)
                {
                    name = nm;
                }
            }

            var source = new Source()
            {
                Name = name,
                Path = path,
                SourceReference = 0
            };

            List<SourceBreakpoint> breakpoints = responder.Arguments.Breakpoints;

            bool sourceModified = responder.Arguments.SourceModified.GetValueOrDefault(false);

            // we do not support other sources than 'path'
            if (source.Path != null)
            {
                ErrorBuilder eb = new ErrorBuilder(() => AD7Resources.Error_UnableToSetBreakpoint);

                try
                {
                    string convertedPath = m_pathConverter.ConvertClientPathToDebugger(source.Path);

                    if (Utilities.IsWindows() && convertedPath.Length > 2)
                    {
                        // vscode may send drive letters with inconsistent casing which will mess up the key
                        // in the dictionary.  see https://github.com/Microsoft/vscode/issues/6268
                        // Normalize the drive letter casing. Note that drive letters
                        // are not localized so invariant is safe here.
                        string drive = convertedPath.Substring(0, 2);
                        if (char.IsLower(drive[0]) && drive.EndsWith(":", StringComparison.Ordinal))
                        {
                            convertedPath = String.Concat(drive.ToUpperInvariant(), convertedPath.Substring(2));
                        }
                    }

                    HashSet<int> lines = new HashSet<int>(breakpoints.Select((b) => b.Line));

                    Dictionary<int, IDebugPendingBreakpoint2> dict = null;
                    if (m_breakpoints.ContainsKey(convertedPath))
                    {
                        dict = m_breakpoints[convertedPath];
                        var keys = new int[dict.Keys.Count];
                        dict.Keys.CopyTo(keys, 0);
                        foreach (var l in keys)
                        {
                            // Delete all breakpoints that are no longer listed.
                            // In the case of modified source, delete everything.
                            if (!lines.Contains(l) || sourceModified)
                            {
                                var bp = dict[l];
                                bp.Delete();
                                dict.Remove(l);
                            }
                        }
                    }
                    else
                    {
                        dict = new Dictionary<int, IDebugPendingBreakpoint2>();
                        m_breakpoints[convertedPath] = dict;
                    }

                    var resBreakpoints = new List<Breakpoint>();
                    foreach (var bp in breakpoints)
                    {
                        if (dict.ContainsKey(bp.Line))
                        {
                            // already created
                            IDebugBreakpointRequest2 breakpointRequest;
                            if (dict[bp.Line].GetBreakpointRequest(out breakpointRequest) == 0 && 
                                breakpointRequest is AD7BreakPointRequest ad7BPRequest)
                            {
                                // Check to see if this breakpoint has a condition that has changed.
                                if (!StringComparer.Ordinal.Equals(ad7BPRequest.Condition, bp.Condition))
                                {
                                    // Condition has been modified. Delete breakpoint so it will be recreated with the updated condition.
                                    var toRemove = dict[bp.Line];
                                    toRemove.Delete();
                                    dict.Remove(bp.Line);
                                }
                                // Check to see if tracepoint changed
                                else if (!StringComparer.Ordinal.Equals(ad7BPRequest.LogMessage, bp.LogMessage))
                                {
                                    ad7BPRequest.ClearTracepoint();
                                    var toRemove = dict[bp.Line];
                                    toRemove.Delete();
                                    dict.Remove(bp.Line);
                                }
                                else
                                {
                                    if (ad7BPRequest.BindResult != null)
                                    {
                                        // use the breakpoint created from IDebugBreakpointErrorEvent2 or IDebugBreakpointBoundEvent2
                                        resBreakpoints.Add(ad7BPRequest.BindResult);
                                    }
                                    else
                                    {
                                        resBreakpoints.Add(new Breakpoint()
                                        {
                                            Id = (int)ad7BPRequest.Id,
                                            Verified = true,
                                            Line = bp.Line
                                        });
                                    }
                                    continue;
                                }
                            }
                        }


                        // Create a new breakpoint
                        if (!dict.ContainsKey(bp.Line))
                        {
                            IDebugPendingBreakpoint2 pendingBp;
                            AD7BreakPointRequest pBPRequest = new AD7BreakPointRequest(m_sessionConfig, convertedPath, m_pathConverter.ConvertClientLineToDebugger(bp.Line), bp.Condition);

                            try
                            {
                                bool verified = true;
                                if (!string.IsNullOrEmpty(bp.LogMessage))
                                {
                                    // Make sure tracepoint is valid.
                                    verified = pBPRequest.SetLogMessage(bp.LogMessage);
                                }

                                if (verified)
                                {
                                    eb.CheckHR(m_engine.CreatePendingBreakpoint(pBPRequest, out pendingBp));
                                    eb.CheckHR(pendingBp.Bind());

                                    dict[bp.Line] = pendingBp;

                                    resBreakpoints.Add(new Breakpoint()
                                    {
                                        Id = (int)pBPRequest.Id,
                                        Verified = verified,
                                        Line = bp.Line
                                    });
                                }
                                else
                                {
                                    resBreakpoints.Add(new Breakpoint()
                                    {
                                        Id = (int)pBPRequest.Id,
                                        Verified = verified,
                                        Line = bp.Line,
                                        Message = string.Format(CultureInfo.CurrentCulture, AD7Resources.Error_UnableToParseLogMessage)
                                    });
                                }
                            }
                            catch (Exception e)
                            {
                                e = Utilities.GetInnerMost(e);
                                if (Utilities.IsCorruptingException(e))
                                {
                                    Utilities.ReportException(e);
                                }

                                resBreakpoints.Add(new Breakpoint()
                                {
                                    Id = (int)pBPRequest.Id,
                                    Verified = false,
                                    Line = bp.Line,
                                    Message = eb.GetMessageForException(e)
                                });
                            }
                        }
                    }

                    response.Breakpoints = resBreakpoints;
                }
                catch (Exception e)
                {
                    // If setBreakpoints returns an error vscode aborts launch, so we never want to return an error,
                    // so convert this to failure results

                    e = Utilities.GetInnerMost(e);
                    if (Utilities.IsCorruptingException(e))
                    {
                        Utilities.ReportException(e);
                    }

                    string message = eb.GetMessageForException(e);
                    List<Breakpoint> resBreakpoints = breakpoints.Select(bp => new Breakpoint()
                    {
                        Id = (int)AD7BreakPointRequest.GetNextBreakpointId(),
                        Verified = false,
                        Line = bp.Line,
                        Message = message
                    }).ToList();

                    response.Breakpoints = resBreakpoints;
                }
            }

            responder.SetResponse(response);
        }