Beispiel #1
0
            private int ValidateBreakpointLocationWorker(
                IVsTextBuffer pBuffer,
                int iLine,
                int iCol,
                VsTextSpan[] pCodeSpan,
                CancellationToken cancellationToken)
            {
                if (_breakpointService == null)
                {
                    return(VSConstants.E_FAIL);
                }

                var textBuffer = _languageService.EditorAdaptersFactoryService.GetDataBuffer(pBuffer);

                if (textBuffer != null)
                {
                    var      snapshot = textBuffer.CurrentSnapshot;
                    Document document = snapshot.AsText().GetDocumentWithFrozenPartialSemanticsAsync(cancellationToken).WaitAndGetResult(cancellationToken);
                    if (document != null)
                    {
                        var point  = snapshot.GetPoint(iLine, iCol);
                        var length = 0;
                        if (pCodeSpan != null && pCodeSpan.Length > 0)
                        {
                            // If we have a non-empty span then it means that the debugger is asking us to adjust an
                            // existing span.  In Everett we didn't do this so we had some good and some bad
                            // behavior.  For example if you had a breakpoint on: "int i;" and you changed it to "int
                            // i = 4;", then the breakpoint wouldn't adjust.  That was bad.  However, if you had the
                            // breakpoint on an open or close curly brace then it would always "stick" to that brace
                            // which was good.
                            //
                            // So we want to keep the best parts of both systems.  We want to appropriately "stick"
                            // to tokens and we also want to adjust spans intelligently.
                            //
                            // However, it turns out the latter is hard to do when there are parse errors in the
                            // code.  Things like missing name nodes cause a lot of havoc and make it difficult to
                            // track a closing curly brace.
                            //
                            // So the way we do this is that we default to not intelligently adjusting the spans
                            // while there are parse errors.  But when there are no parse errors then the span is
                            // adjusted.
                            var initialBreakpointSpan = snapshot.GetSpan(pCodeSpan[0]);
                            if (initialBreakpointSpan.Length > 0 && document.SupportsSyntaxTree)
                            {
                                var tree = document.GetSyntaxTreeAsync(cancellationToken).WaitAndGetResult(cancellationToken);
                                if (tree.GetDiagnostics(cancellationToken).Any(d => d.Severity == DiagnosticSeverity.Error))
                                {
                                    return(VSConstants.E_FAIL);
                                }
                            }

                            // If a span is provided, and the requested position falls in that span, then just
                            // move the requested position to the start of the span.
                            // Length will be used to determine if we need further analysis, which is only required when text spans multiple lines.
                            if (initialBreakpointSpan.Contains(point))
                            {
                                point  = initialBreakpointSpan.Start;
                                length = pCodeSpan[0].iEndLine > pCodeSpan[0].iStartLine ? initialBreakpointSpan.Length : 0;
                            }
                        }

                        // NOTE(cyrusn): we need to wait here because ValidateBreakpointLocation is
                        // synchronous.  In the future, it would be nice for the debugger to provide
                        // an async entry point for this.
                        var breakpoint = _breakpointService.ResolveBreakpointAsync(document, new CodeAnalysis.Text.TextSpan(point.Position, length), cancellationToken).WaitAndGetResult(cancellationToken);
                        if (breakpoint == null)
                        {
                            // There should *not* be a breakpoint here.  E_FAIL to let the debugger know
                            // that.
                            return(VSConstants.E_FAIL);
                        }

                        if (breakpoint.IsLineBreakpoint)
                        {
                            // Let the debugger take care of this. They'll put a line breakpoint
                            // here. This is useful for when the user does something like put a
                            // breakpoint in inactive code.  We want to allow this as they might
                            // just have different defines during editing versus debugging.

                            // TODO(cyrusn): Do we need to set the pCodeSpan in this case?
                            return(VSConstants.E_NOTIMPL);
                        }

                        // There should be a breakpoint at the location passed back.
                        if (pCodeSpan != null && pCodeSpan.Length > 0)
                        {
                            pCodeSpan[0] = breakpoint.TextSpan.ToSnapshotSpan(snapshot).ToVsTextSpan();
                        }

                        return(VSConstants.S_OK);
                    }
                }

                return(VSConstants.E_NOTIMPL);
            }