Diagnostics use a stale parse_result when the request is read before its didChange is applied
I maintainer di solito rispondono entro 1 giorno
Valutazione
- Difficoltà
- 4/5
- Tempo stimato
- 3-5 giorni
- Idoneità per principianti
- 52/100
Direzione di ricerca
Start with BaseServer#start, the worker's push_edits path, and the diagnostic request handling; compare when needs_parsing is set with when document.parse_result is refreshed. Check the RuboCop add-on's RuntimeAdapter#prism_result and Requests::Diagnostics for both reported effects. Done means diagnostics and syntax warnings use a parse result matching the updated document source in the reproduction.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
Ruby LSP Information
- ruby-lsp 0.26.11 (code in question is unchanged on
main) - rubocop 1.87.0 (also checked 1.88.0
RuntimeAdapter#prism_result, unchanged), prism 1.9.0 - Ruby 4.0.6 via rbenv, Linux
- Neovim 0.11.6, built-in LSP client (pull diagnostics)
initializationOptions: { linters: ["rubocop"] }(RuboCop's own add-on)
Description
Diagnostics are intermittently computed with a parse_result from the previous document version while document.source is already the new version. With RuboCop's add-on, which reuses document.parse_result as prism_result, this produces wrong offenses that stay until the next edit. Syntax warnings from Requests::Diagnostics read the same stale tree.
Order of events, as I read it:
- Client sends
didChangeand immediatelytextDocument/diagnostic(Neovim pulls diagnostics on everydidChange). - The main thread (
BaseServer#start) only callsdocument.parse!for non-did*messages and queuesdidChangewithout applying it. When the diagnostic request arrives, the edit isn't applied yet,needs_parsingisfalse, so nothing is parsed. - The worker applies the edits (
push_editssetsneeds_parsing = true), then handles the diagnostic request without parsing.
Server-side log from a stale run (a small workspace add-on that logs at enqueue, worker start and in RuntimeAdapter#run_diagnostic):
reader enqueue textDocument/didChange doc v0 needs_parsing=false tree=current
worker start textDocument/didChange doc v0 needs_parsing=false tree=current
reader enqueue textDocument/diagnostic doc v0 needs_parsing=false tree=current
worker push_edits v15 start
worker push_edits v15 done src="# frozen_string_literal: true\n\ndef foo\n y = \"abc\"\n x = 1\n x\nend\n"
worker start textDocument/diagnostic doc v15 needs_parsing=true tree=STALE
adapter run_diagnostic v15 source==parsed_source? false
source: "# frozen_string_literal: true\n\ndef foo\n y = \"abc\"\n x = 1\n x\nend\n"
parse_result: "# frozen_string_literal: true\n\ndef foo\n x = 1\n x\nend\n"
Resulting diagnostics vs. rubocop --stdin on the same text:
client: 4:3 Style/RedundantAssignment | 4:9 Layout/ExtraSpacing
rubocop: 4:3 Lint/UselessAssignment | 4:7 Style/StringLiterals | 5:3 Style/RedundantAssignment
In a later stale run the parser warning assigned but unused variable - y remained after y had been deleted, so this isn't specific to the RuboCop add-on.
Reproduction steps
Project: Gemfile with gem "rubocop", a .rubocop.yml with AllCops: { NewCops: enable }, and app.rb:
# frozen_string_literal: true
def foo
x = 1
x
end
Minimal Neovim config (nvim --clean -u init.lua app.rb):
vim.lsp.config("ruby_lsp", {
cmd = { "rbenv", "exec", "ruby-lsp" },
filetypes = { "ruby" },
root_markers = { "Gemfile" },
init_options = { linters = { "rubocop" } },
})
vim.lsp.enable("ruby_lsp")
- Open
app.rband wait for diagnostics. - Insert a new line
y = "abc"afterdef foo. I typed it vianvim_buf_set_textone character at a time, 40ms apart; the client sends it as a singledidChange. - See diagnostics that don't match the buffer.
Results (headless, 6 runs each):
| setting | stale runs |
|---|---|
linters: ["rubocop"] |
6/6 |
linters: ["rubocop_internal"] |
0/6 |
no linters (detects rubocop_internal) |
0/6 |
["rubocop"] in my full config, with a 300ms delay before sending the diagnostic request |
0/5 (vs 2/5 without the delay in that batch) |
rubocop_internal is unaffected because RuboCopRunner#run doesn't pass prism_result through (the assignment is commented out) and RuboCop parses contents itself.
Possible fix direction: call document.parse! in the worker before handling a request, or parse after push_edits, so a request never sees a tree older than its source. I haven't checked whether VS Code hits this; its pull timing may hide it.
- Lingua principale
- Ruby
- Stelle
- 2k
- Fork
- 286
- Merge medio
- 8h 37m
- PR unite (30g)
- 12
Preparare l'ambiente
Avvia il container di sviluppo del progetto nel browser, con il tuo account GitHub.
- Nessun Dockerfile né file Docker Compose
- Ha un modello di pull request
- Leggi la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di Shopify/ruby-lsp
-
Dependencies view: `getParent` loops forever on untitled documents, extension host runs out of memoryForse già presa @efegokdemir l’ha presa 13 giorni fa. Apertabug
Difficoltà 2/5 1-3 ore Idoneità per principianti 70/100
I maintainer di solito rispondono entro 1 giorno
-
Linux file system with square brackets in the directory/filename are failing to be indexedForse già presa @andriytyurnikov l’ha presa 218 giorni fa. Apertabug help-wanted pinned
Difficoltà 2/5 1-3 ore Idoneità per principianti 68/100
Shopify/ruby-lsp#3503 · 8 commenti · 1 reazione ·
I maintainer di solito rispondono entro 1 giorno
-
rbenv activation leaks RBENV_VERSION and RBENV_DIR into process.env of the extension hostForse già presa @efegokdemir l’ha presa 8 giorni fa. Apertabug
Difficoltà 3/5 Mezza giornata Idoneità per principianti 45/100
I maintainer di solito rispondono entro 1 giorno
-
Rename of a class moves its file and leaves require_relative on the old pathForse già presa @efegokdemir l’ha presa 15 giorni fa. Aperta
Difficoltà 4/5 3-5 giorni Idoneità per principianti 22/100
I maintainer di solito rispondono entro 1 giorno
-
Paths need to be escapedForse già presa @Vraiment l’ha presa 19 giorni fa. Apertabug
Difficoltà 2/5 1-3 ore Idoneità per principianti 25/100
I maintainer di solito rispondono entro 1 giorno
Tutte le issue di Shopify/ruby-lsp
Issue simili
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 74/100
I maintainer di solito rispondono entro 1 giorno
-
[Bug] Chatwoot v4.19.0 – Super Admin returns 500 due to missing superadmin.scss Vite manifest entryApertaBug
Difficoltà 2/5 1-3 ore Idoneità per principianti 76/100
I maintainer di solito rispondono entro 2 giorni
-
PRM baseline System 1 and 2 fans run continuously in unoccupied hours (low priority)Forse già presa @anchapin l’ha presa oggi. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 70/100
NatLabRockies/openstudio-standards#2167 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 76/100
18F/identity-idp#13734 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
Ubuntu 26.04: gems linking OpenSSL statically (e.g. rugged) fail to build – libjitterentropy3-dev missingForse già presa @BattleAurora l’ha presa oggi. ApertaArea: Ruby bug report needs triage OS: Ubuntu
Difficoltà 2/5 1-3 ore Idoneità per principianti 68/100
actions/runner-images#15068 · 1 commento ·
I maintainer di solito rispondono entro 3 giorni