Confusing error message for invalid rangeLength in didChange request

While working on implementing proper UTF-16 support for a LSP client,
I received this very confusing error message:

stderr E[12:26:16.762] Failed to update
/home/bjorn/dev/neovim/src/nvim/ui.c: Change's rangeLength (24)
doesn't match the computed range length (24).

Note both lengths are the same. I think this is caused by the
following code in
https://github.com/llvm/llvm-project/blob/master/clang-tools-extra/clangd/DraftStore.cpp

    // EndIndex and StartIndex are in bytes, but Change.rangeLength is in UTF-16
    // code units.
    ssize_t ComputedRangeLength =
        lspLength(Contents.substr(*StartIndex, *EndIndex - *StartIndex));

     if (Change.rangeLength && ComputedRangeLength != *Change.rangeLength)
      return llvm::make_error<llvm::StringError>(
           llvm::formatv("Change's rangeLength ({0}) doesn't match the "
                         "computed range length ({1}).",
                        *Change.rangeLength, *EndIndex - *StartIndex),
          llvm::errc::invalid_argument);

The *EndIndex - *StartIndex should rather be ComputedRangeLength in
the error message I think.

Best,
Björn

Indeed, thanks! Fixed in https://reviews.llvm.org/rL367811

Since you’re looking at this, I’d mention that the only three places clangd deals with the encoding are:

  • encoding/decoding LSP Position objects
  • handling TextDocumentContentChangeEvent
  • producing ParameterInformation.labelOffsets as part of signature help (this one is easy to miss)
    I’d be interested if you know of any others we missed!

BTW clangd in particular supports -offset-encoding=utf-8, and encoding negotiated by LSP extensions[1], but that doesn’t help you if you need to handle arbitrary language servers.

1: https://clangd.github.io/extensions.html#utf-8-offsets