Fix off-by-one errors in LanguageServer's GetRange (#7251)

LSP assumes lines are index 0 to n-1, but Carbon Locs are index from 1
to n. We had the logic for this correct for the start of range but not
for the end of range (inclusive range).

Before this was the diagnostic span we would produce:

```carbon
fn F() {
  return ();
  <~~~~~~~~>
}
<~~~~~~~~~~~>
```

after:

```carbon
fn F() {
  return ();
  <~~~~~~~~>
}
```
This commit is contained in:
DavidLoftus
2026-05-27 17:37:56 +00:00
committed by GitHub
parent 518704608e
commit de381bded1
3 changed files with 12 additions and 12 deletions
+2 -2
View File
@@ -77,8 +77,8 @@ class DiagnosticConsumer : public Diagnostics::Consumer {
auto GetRange(const Diagnostics::Loc& loc) -> clang::clangd::Range {
return {.start = {.line = loc.line_number - 1,
.character = loc.column_number - 1},
.end = {.line = loc.line_number,
.character = loc.column_number + loc.length}};
.end = {.line = loc.line_number - 1,
.character = loc.column_number + loc.length - 1}};
}
// Converts a diagnostic level to an LSP severity.
@@ -48,8 +48,8 @@
// CHECK:STDOUT: "message": "opening symbol without a corresponding closing symbol",
// CHECK:STDOUT: "range": {
// CHECK:STDOUT: "end": {
// CHECK:STDOUT: "character": 2,
// CHECK:STDOUT: "line": 1
// CHECK:STDOUT: "character": 1,
// CHECK:STDOUT: "line": 0
// CHECK:STDOUT: },
// CHECK:STDOUT: "start": {
// CHECK:STDOUT: "character": 0,
@@ -63,8 +63,8 @@
// CHECK:STDOUT: "message": "unrecognized declaration introducer",
// CHECK:STDOUT: "range": {
// CHECK:STDOUT: "end": {
// CHECK:STDOUT: "character": 2,
// CHECK:STDOUT: "line": 1
// CHECK:STDOUT: "character": 1,
// CHECK:STDOUT: "line": 0
// CHECK:STDOUT: },
// CHECK:STDOUT: "start": {
// CHECK:STDOUT: "character": 0,
@@ -78,8 +78,8 @@
// CHECK:STDOUT: "message": "semantics TODO: `handle invalid parse trees in `check``",
// CHECK:STDOUT: "range": {
// CHECK:STDOUT: "end": {
// CHECK:STDOUT: "character": 2,
// CHECK:STDOUT: "line": 1
// CHECK:STDOUT: "character": 1,
// CHECK:STDOUT: "line": 0
// CHECK:STDOUT: },
// CHECK:STDOUT: "start": {
// CHECK:STDOUT: "character": 0,
@@ -104,8 +104,8 @@
// CHECK:STDOUT: "message": "no return expression should be provided in this context",
// CHECK:STDOUT: "range": {
// CHECK:STDOUT: "end": {
// CHECK:STDOUT: "character": 20,
// CHECK:STDOUT: "line": 1
// CHECK:STDOUT: "character": 19,
// CHECK:STDOUT: "line": 0
// CHECK:STDOUT: },
// CHECK:STDOUT: "start": {
// CHECK:STDOUT: "character": 9,
@@ -44,8 +44,8 @@
// CHECK:STDOUT: "message": "'nonexistent.h' file not found",
// CHECK:STDOUT: "range": {
// CHECK:STDOUT: "end": {
// CHECK:STDOUT: "character": 11,
// CHECK:STDOUT: "line": 1
// CHECK:STDOUT: "character": 10,
// CHECK:STDOUT: "line": 0
// CHECK:STDOUT: },
// CHECK:STDOUT: "start": {
// CHECK:STDOUT: "character": 9,