emacs-lsp / lsp-mode

Emacs client/library for the Language Server Protocol
https://emacs-lsp.github.io/lsp-mode
GNU General Public License v3.0
4.77k stars 883 forks source link

Diagnostics break after executing a code action #2901

Closed kuba-orlik closed 3 years ago

kuba-orlik commented 3 years ago

Thank you for the bug report

Bug description

After executing a code action with lsp-execute-code-action, the reported diagnostics stop making sense. They report issues that do not exist, or report critical syntax errors when there are none.

You can see the bug in action here:

https://asciinema.org/a/eYwnQDtlgyGpdbT5sM21bjfE9

Steps to reproduce

  1. Clone this repo: https://github.com/kuba-orlik/lsp-eslint-repro
  2. Open the index.ts file
  3. Run M-x lsp
  4. See the error about missing function return type being highlighted
  5. fix the error - see that the error highlight disappears
  6. Undo the change - the error highlight appears again
  7. Set the cursor on the function name and run M-x lsp-execute-code-action
  8. See that the error is fixed, but the error highlight remains

Expected behavior

The error highlight should work properly after executing a code action

Which Language Server did you use?

ts-ls, eslint

OS

Linux

Error callstack

No response

Anything else?

No response

yyoncho commented 3 years ago

@kuba-orlik I am not js/ts expert - do you know what might be the reason not to get the warning for missing return type in the first place?

kuba-orlik commented 3 years ago

I don't think there's any such thing. It looks like the lsp server receives something else than what the buffer shows. That would especially explain the error syntax that gets shown even though the code is exactly the same as it was a few edits ago.

The lsp-ts server log show the following error:

[Trace - 07:21:07 pm] Received response 'textDocument/documentSymbol - (105)' in 10ms.
Result: {
  "message": "Request textDocument/documentSymbol failed with message: Error processing request. Cannot read property 'charCount' of undefined\nTypeError: Cannot read property 'charCount' of undefined\n    at LineNode.walk (/home/kuba/.npm-global/lib/node_modules/typescript/lib/tsserver.js:155664:68)\n    at LineIndex.edit (/home/kuba/.npm-global/lib/node_modules/typescript/lib/tsserver.js:155545:31)\n    at ScriptVersionCache._getSnapshot (/home/kuba/.npm-global/lib/node_modules/typescript/lib/tsserver.js:155335:47)\n    at ScriptVersionCache.getSnapshot (/home/kuba/.npm-global/lib/node_modules/typescript/lib/tsserver.js:155328:82)\n    at TextStorage.getSnapshot (/home/kuba/.npm-global/lib/node_modules/typescript/lib/tsserver.js:146897:32)\n    at ScriptInfo.getSnapshot (/home/kuba/.npm-global/lib/node_modules/typescript/lib/tsserver.js:147059:41)\n    at InferredProject.Project.getScriptSnapshot (/home/kuba/.npm-global/lib/node_modules/typescript/lib/tsserver.js:147715:39)\n    at SyntaxTreeCache.getCurrentSourceFile (/home/kuba/.npm-global/lib/node_modules/typescript/lib/tsserver.js:143045:44)\n    at Object.getNavigationTree (/home/kuba/.npm-global/lib/node_modules/typescript/lib/tsserver.js:143704:71)\n    at IOSession.Session.getNavigationTree (/home/kuba/.npm-global/lib/node_modules/typescript/lib/tsserver.js:154516:44)\n    at Session.handlers.ts.Map.ts.getEntries._a.<computed> (/home/kuba/.npm-global/lib/node_modules/typescript/lib/tsserver.js:153310:61)\n    at /home/kuba/.npm-global/lib/node_modules/typescript/lib/tsserver.js:154962:88\n    at IOSession.Session.executeWithRequestId (/home/kuba/.npm-global/lib/node_modules/typescript/lib/tsserver.js:154953:28)\n    at IOSession.Session.executeCommand (/home/kuba/.npm-global/lib/node_modules/typescript/lib/tsserver.js:154962:33)\n    at IOSession.Session.onMessage (/home/kuba/.npm-global/lib/node_modules/typescript/lib/tsserver.js:154986:35)\n    at Interface.<anonymous> (/home/kuba/.npm-global/lib/node_modules/typescript/lib/tsserver.js:157202:27)\n    at Interface.emit (node:events:365:28)\n    at Interface._onLine (node:readline:452:10)\n    at Interface._normalWrite (node:readline:606:12)\n    at Socket.ondata (node:readline:252:10)\n    at Socket.emit (node:events:365:28)\n    at addChunk (node:internal/streams/readable:314:12)\n    at readableAddChunk (node:internal/streams/readable:289:9)\n    at Socket.Readable.push (node:internal/streams/readable:228:10)\n    at Pipe.onStreamRead (node:internal/stream_base_commons:190:23)",
  "code": -32603
}

But there are no errors in eslint server logs. Maybe I'm not doing enough to have them logged? I set up lsp-log-io to ;t

willnevillain commented 3 years ago

Hello, I'm also encountering this issue - eslint continues to report outdated diagnostic data after making a change via a code action.

I captured some log groups from with lsp-log-io and lsp-eslint-trace-server set to t. I don't see anything unusually besides the fact that an invalid diagnostic (in my case, one for an unused import that has already been removed from the source file via a code action) is still being reported.

Happy to provide any logs or additional details to help troubleshooting, not sure how code actions interact with the diagnostics of the running server(s).

kuba-orlik commented 3 years ago

My current fix is to run lsp every time I run lsp-execute-code-action:

(advice-add 'lsp-execute-code-action :after (lambda (r) (call-interactively 'lsp)))
sin-ack commented 3 years ago

Also seeing this issue. Correct me if I'm wrong, but I think what happens is that when the Typescript language server makes a change to the buffer via the code action, this change is not reflected back to the ESLint language server, and when you start entering code in the buffer, you will be entering invalid code for ESLint (which has the buffer state before the code action was executed), causing those syntax errors. Restarting the ESLint language server sends the entire buffer contents to it again, fixing the problems. I'm not quite sure about LSP internals, but is it possible to just make the other language servers re-read the updated buffer when a code action is executed? Or maybe there is a way to reflect the exact operations a code action performs on the buffer to other language servers.

yyoncho commented 3 years ago

@sin-ack this is not how it works - the changes are applied client-side and then sent to the server(s).

sin-ack commented 3 years ago

I see, then something else is the issue. I'll see whether I can dig further into it.

calbrecht commented 3 years ago

@sin-ack, your thoughts weren't that wrong, though.

With customized lsp-log-io . t, we are able to inspect the communication between lsp-mode and the language servers in the buffers *lsp-log: ts-ls:XXXXXXX* and *lsp-log: eslint:XXXXXXX*

There we can see, the action "Infer function return type" is a refactor code action provided by typescript-language-server, whereas the diagnostics stem from lsp-eslint.

When comparing the communication flow of lsp-mode with that from vscode, interestingly (but not surprisingly, because, i guess, the typescript language server is tsserver directly) there are some differences.

In vscode (several messages left out for brevity)

# Gui: move point to f_unction
<- eslint: textDocument/publishDiagnostics # Payload: diagnostics including warnings
# Gui: C-S-r
-> typescript: getApplicableRefactors # Payload: (point)
<- typescript: getApplicableRefactors # Payload: refactoring including "Infer type..."
# Gui: apply refactoring "Infer type..."
-> typescript: getEditsForRefactor # Payload (point)
<- typescript: getEditsForRefactor # Payload textChanges [...] ": number"
# Editor: applies textChanges
-> eslint: textDocument/didChange # Payload textChanges [...] ": number"
-> typescript: updateOpen # Payload textChanges
<- typescript: updateOpen # ACK
<- eslint: textDocument/publishDiagnostics # Payload diagnostics []

In lsp-mode (several messages left out for brevity)

# Gui: move point to f_unction
<- eslint: textDocument/publishDiagnostics # Payload: diagnostics including warnings
# Gui: <Prefix> a a
-> typescript: textDocument/codeAction # Payload: (point)
<- typescript: textDocument/codeAction # Payload: refactoring including "Infer type..."
-> eslint: textDocument/codeAction # Payload: (point)
<- eslint: textDocument/codeAction # Payload: quickfix "Disable rules..."
# Gui: apply refactoring "Infer type..."
?? -> typescript: textDocument/didChange # Payload contentChanges [...] ": number"
-> typescript: workspace/executeCommand # Payload: _typescript.applyRefactoring "Infer type.."
<- typescript: workspace/applyEdit # Payload: changes  [...] ": number"
-> eslint: workspace/executeCommand # Payload: _typescript.applyRefactoring "Infer type.."
<- eslint: workspace/executeCommand # Payload: {}
# Editor: applies textChanges
-> typescript: workspace/applyEdit # Payload: applied: true

As we see, the log entry textDocument/didChange is confusing.

It is logged out of order before the textDocument/applyEdit instructions are even received from typescript-language-server.

And it is in the wrong log file, namely that of ts-ls and does not occur in the eslint log.

My early conclusion, based on observations, would be that the textDocument/didChange is not send to eslint and therefore it does not know about the changes.

calbrecht commented 3 years ago

Here is a script to be run with emacs --load ./test-2901.el --visit index.ts for generating log files lsp-eslint.log and lsp-ts-ls.log.

lsp-ts-ls.log ```clojure [Trace - 05:54:03 PM] Sending request 'initialize - (1)'. Params: { "processId": null, "rootPath": "/ws/lsp-eslint-repro", "clientInfo": { "name": "emacs", "version": "GNU Emacs 28.0.50 (build 1, x86_64-pc-linux-gnu)" }, "rootUri": "file:///ws/lsp-eslint-repro", "capabilities": { "workspace": { "workspaceEdit": { "documentChanges": true, "resourceOperations": [ "create", "rename", "delete" ] }, "applyEdit": true, "symbol": { "symbolKind": { "valueSet": [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26 ] } }, "executeCommand": { "dynamicRegistration": false }, "didChangeWatchedFiles": { "dynamicRegistration": true }, "workspaceFolders": true, "configuration": true, "fileOperations": { "didCreate": false, "willCreate": false, "didRename": false, "willRename": false, "didDelete": false, "willDelete": false } }, "textDocument": { "declaration": { "linkSupport": true }, "definition": { "linkSupport": true }, "implementation": { "linkSupport": true }, "typeDefinition": { "linkSupport": true }, "synchronization": { "willSave": true, "didSave": true, "willSaveWaitUntil": true }, "documentSymbol": { "symbolKind": { "valueSet": [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26 ] }, "hierarchicalDocumentSymbolSupport": true }, "formatting": { "dynamicRegistration": true }, "rangeFormatting": { "dynamicRegistration": true }, "rename": { "dynamicRegistration": true, "prepareSupport": true }, "codeAction": { "dynamicRegistration": true, "isPreferredSupport": true, "codeActionLiteralSupport": { "codeActionKind": { "valueSet": [ "", "quickfix", "refactor", "refactor.extract", "refactor.inline", "refactor.rewrite", "source", "source.organizeImports" ] } }, "resolveSupport": { "properties": [ "edit", "command" ] }, "dataSupport": true }, "completion": { "completionItem": { "snippetSupport": true, "documentationFormat": [ "markdown", "plaintext" ], "resolveAdditionalTextEditsSupport": true, "insertReplaceSupport": true, "resolveSupport": { "properties": [ "documentation", "details", "additionalTextEdits", "command" ] }, "insertTextModeSupport": { "valueSet": [ 1, 2 ] } }, "contextSupport": true }, "signatureHelp": { "signatureInformation": { "parameterInformation": { "labelOffsetSupport": true } } }, "documentLink": { "dynamicRegistration": true, "tooltipSupport": true }, "hover": { "contentFormat": [ "markdown", "plaintext" ] }, "foldingRange": { "dynamicRegistration": true }, "callHierarchy": { "dynamicRegistration": false }, "publishDiagnostics": { "relatedInformation": true, "tagSupport": { "valueSet": [ 1, 2 ] }, "versionSupport": true }, "moniker": null, "linkedEditingRange": null }, "window": { "workDoneProgress": true, "showMessage": null, "showDocument": null } }, "initializationOptions": { "plugins": [], "logVerbosity": "info", "tsServerPath": "/nix/store/b7vhm7phhc51353n24zr71rvsi06ldi6-typescript-4.3.5/bin/tsserver" }, "workDoneToken": "1" } [Trace - 05:54:04 PM] Received response 'initialize - (1)' in 421ms. Result: { "capabilities": { "textDocumentSync": 2, "completionProvider": { "triggerCharacters": [ ".", "\"", "'", "/", "@", "<" ], "resolveProvider": true }, "codeActionProvider": true, "definitionProvider": true, "documentFormattingProvider": true, "documentRangeFormattingProvider": true, "documentHighlightProvider": true, "documentSymbolProvider": true, "executeCommandProvider": { "commands": [ "_typescript.applyWorkspaceEdit", "_typescript.applyCodeAction", "_typescript.applyRefactoring", "_typescript.organizeImports", "_typescript.applyRenameFile" ] }, "hoverProvider": true, "renameProvider": true, "referencesProvider": true, "signatureHelpProvider": { "triggerCharacters": [ "(", ",", "<" ] }, "workspaceSymbolProvider": true, "implementationProvider": true, "typeDefinitionProvider": true, "foldingRangeProvider": true, "callsProvider": true }, "logFileUri": "file:///ws/lsp-eslint-repro/.log/tsserver.log" } [Trace - 05:54:04 PM] Sending notification 'initialized'. Params: {} [Trace - 05:54:04 PM] Sending notification 'textDocument/didOpen'. Params: { "textDocument": { "uri": "file:///ws/lsp-eslint-repro/index.ts", "languageId": "typescript", "version": 0, "text": "export function test() {\n return 2;\n}\n" } } [Trace - 05:54:04 PM] Sending request 'textDocument/codeAction - (3)'. Params: { "textDocument": { "uri": "file:///ws/lsp-eslint-repro/index.ts" }, "range": { "start": { "line": 0, "character": 8 }, "end": { "line": 0, "character": 8 } }, "context": { "diagnostics": [] } } [Trace - 05:54:04 PM] Sending request 'textDocument/documentHighlight - (4)'. Params: { "textDocument": { "uri": "file:///ws/lsp-eslint-repro/index.ts" }, "position": { "line": 0, "character": 8 } } [Trace - 05:54:04 PM] Sending notification '$/cancelRequest'. Params: { "id": 3 } [Trace - 05:54:04 PM] Sending request 'textDocument/codeAction - (5)'. Params: { "textDocument": { "uri": "file:///ws/lsp-eslint-repro/index.ts" }, "range": { "start": { "line": 0, "character": 8 }, "end": { "line": 0, "character": 8 } }, "context": { "diagnostics": [] } } [Trace - 05:54:04 PM] Sending notification '$/cancelRequest'. Params: { "id": 4 } [Trace - 05:54:04 PM] Sending request 'textDocument/documentHighlight - (6)'. Params: { "textDocument": { "uri": "file:///ws/lsp-eslint-repro/index.ts" }, "position": { "line": 0, "character": 8 } } [Trace - 05:54:04 PM] Sending notification '$/cancelRequest'. Params: { "id": 5 } [Trace - 05:54:04 PM] Sending request 'textDocument/codeAction - (7)'. Params: { "textDocument": { "uri": "file:///ws/lsp-eslint-repro/index.ts" }, "range": { "start": { "line": 0, "character": 8 }, "end": { "line": 0, "character": 8 } }, "context": { "diagnostics": [] } } [Trace - 05:54:04 PM] Sending notification '$/cancelRequest'. Params: { "id": 6 } [Trace - 05:54:04 PM] Sending request 'textDocument/documentHighlight - (8)'. Params: { "textDocument": { "uri": "file:///ws/lsp-eslint-repro/index.ts" }, "position": { "line": 0, "character": 8 } } [Trace - 05:54:04 PM] Received response 'nil - (4)' in 0ms. Result: [ { "kind": 2, "range": { "start": { "line": 0, "character": 16 }, "end": { "line": 0, "character": 20 } } } ] [Trace - 05:54:04 PM] Received response 'nil - (6)' in 0ms. Result: [ { "kind": 2, "range": { "start": { "line": 0, "character": 16 }, "end": { "line": 0, "character": 20 } } } ] [Trace - 05:54:04 PM] Received response 'textDocument/documentHighlight - (8)' in 304ms. Result: [ { "kind": 2, "range": { "start": { "line": 0, "character": 16 }, "end": { "line": 0, "character": 20 } } } ] [Trace - 05:54:04 PM] Received response 'nil - (3)' in 0ms. Result: [ { "title": "Infer function return type", "command": { "title": "Infer function return type", "command": "_typescript.applyRefactoring", "arguments": [ { "file": "/ws/lsp-eslint-repro/index.ts", "startLine": 1, "startOffset": 9, "endLine": 1, "endOffset": 9, "refactor": "Infer function return type", "action": "Infer function return type" } ] }, "kind": "refactor" } ] [Trace - 05:54:04 PM] Received response 'nil - (5)' in 0ms. Result: [ { "title": "Infer function return type", "command": { "title": "Infer function return type", "command": "_typescript.applyRefactoring", "arguments": [ { "file": "/ws/lsp-eslint-repro/index.ts", "startLine": 1, "startOffset": 9, "endLine": 1, "endOffset": 9, "refactor": "Infer function return type", "action": "Infer function return type" } ] }, "kind": "refactor" } ] [Trace - 05:54:04 PM] Received response 'textDocument/codeAction - (7)' in 304ms. Result: [ { "title": "Infer function return type", "command": { "title": "Infer function return type", "command": "_typescript.applyRefactoring", "arguments": [ { "file": "/ws/lsp-eslint-repro/index.ts", "startLine": 1, "startOffset": 9, "endLine": 1, "endOffset": 9, "refactor": "Infer function return type", "action": "Infer function return type" } ] }, "kind": "refactor" } ] [Trace - 05:54:04 PM] Received notification 'textDocument/publishDiagnostics'. Params: { "uri": "file:///ws/lsp-eslint-repro/index.ts", "diagnostics": [] } [Trace - 05:54:04 PM] Sending request 'textDocument/codeAction - (9)'. Params: { "textDocument": { "uri": "file:///ws/lsp-eslint-repro/index.ts" }, "range": { "start": { "line": 0, "character": 8 }, "end": { "line": 0, "character": 8 } }, "context": { "diagnostics": [] } } [Trace - 05:54:05 PM] Received response 'textDocument/codeAction - (9)' in 149ms. Result: [ { "title": "Infer function return type", "command": { "title": "Infer function return type", "command": "_typescript.applyRefactoring", "arguments": [ { "file": "/ws/lsp-eslint-repro/index.ts", "startLine": 1, "startOffset": 9, "endLine": 1, "endOffset": 9, "refactor": "Infer function return type", "action": "Infer function return type" } ] }, "kind": "refactor" } ] [Trace - 05:54:05 PM] Sending request 'textDocument/codeAction - (10)'. Params: { "textDocument": { "uri": "file:///ws/lsp-eslint-repro/index.ts" }, "range": { "start": { "line": 0, "character": 8 }, "end": { "line": 0, "character": 8 } }, "context": { "diagnostics": [ { "message": "Missing return type on function.", "severity": 2, "source": "eslint", "range": { "start": { "line": 0, "character": 7 }, "end": { "line": 0, "character": 22 } }, "code": "@typescript-eslint/explicit-module-boundary-types", "codeDescription": { "href": "https://github.com/typescript-eslint/typescript-eslint/blob/v4.24.0/packages/eslint-plugin/docs/rules/explicit-module-boundary-types.md" } } ], "only": [ "refactor" ] } } [Trace - 05:54:05 PM] Received response 'textDocument/codeAction - (10)' in 2ms. Result: [ { "title": "Infer function return type", "command": { "title": "Infer function return type", "command": "_typescript.applyRefactoring", "arguments": [ { "file": "/ws/lsp-eslint-repro/index.ts", "startLine": 1, "startOffset": 9, "endLine": 1, "endOffset": 9, "refactor": "Infer function return type", "action": "Infer function return type" } ] }, "kind": "refactor" } ] [Trace - 05:54:05 PM] Sending request 'workspace/executeCommand - (11)'. Params: { "command": "_typescript.applyRefactoring", "arguments": [ { "file": "/ws/lsp-eslint-repro/index.ts", "startLine": 1, "startOffset": 9, "endLine": 1, "endOffset": 9, "refactor": "Infer function return type", "action": "Infer function return type" } ] } [Trace - 05:54:05 PM] Sending notification 'textDocument/didChange'. Params: { "textDocument": { "uri": "file:///ws/lsp-eslint-repro/index.ts", "version": 1 }, "contentChanges": [ { "range": { "start": { "line": 0, "character": 22 }, "end": { "line": 0, "character": 22 } }, "rangeLength": 0, "text": ": number" } ] } [Trace - 05:54:05 PM] Received request 'workspace/applyEdit - (0). Params: { "edit": { "changes": { "file:///ws/lsp-eslint-repro/index.ts": [ { "range": { "start": { "line": 0, "character": 22 }, "end": { "line": 0, "character": 22 } }, "newText": ": number" } ] } } } [Trace - 05:54:05 PM] Sending response 'workspace/applyEdit - (0)'. Processing request took 2ms Params: { "jsonrpc": "2.0", "id": 0, "result": { "applied": true } } [Trace - 05:54:05 PM] Sending request 'textDocument/codeAction - (12)'. Params: { "textDocument": { "uri": "file:///ws/lsp-eslint-repro/index.ts" }, "range": { "start": { "line": 0, "character": 8 }, "end": { "line": 0, "character": 8 } }, "context": { "diagnostics": [ { "message": "Missing return type on function.", "severity": 2, "source": "eslint", "range": { "start": { "line": 0, "character": 7 }, "end": { "line": 0, "character": 22 } }, "code": "@typescript-eslint/explicit-module-boundary-types", "codeDescription": { "href": "https://github.com/typescript-eslint/typescript-eslint/blob/v4.24.0/packages/eslint-plugin/docs/rules/explicit-module-boundary-types.md" } } ] } } [Trace - 05:54:05 PM] Received response 'workspace/executeCommand - (11)' in 17ms. Result: null [Trace - 05:54:05 PM] Sending notification '$/cancelRequest'. Params: { "id": 12 } [Trace - 05:54:05 PM] Sending request 'textDocument/codeAction - (13)'. Params: { "textDocument": { "uri": "file:///ws/lsp-eslint-repro/index.ts" }, "range": { "start": { "line": 0, "character": 8 }, "end": { "line": 0, "character": 8 } }, "context": { "diagnostics": [ { "message": "Missing return type on function.", "severity": 2, "source": "eslint", "range": { "start": { "line": 0, "character": 7 }, "end": { "line": 0, "character": 22 } }, "code": "@typescript-eslint/explicit-module-boundary-types", "codeDescription": { "href": "https://github.com/typescript-eslint/typescript-eslint/blob/v4.24.0/packages/eslint-plugin/docs/rules/explicit-module-boundary-types.md" } } ] } } [Trace - 05:54:05 PM] Received response 'nil - (12)' in 0ms. Result: [] [Trace - 05:54:05 PM] Received response 'textDocument/codeAction - (13)' in 30ms. Result: [] [Trace - 05:54:05 PM] Sending notification 'textDocument/didChange'. Params: { "textDocument": { "uri": "file:///ws/lsp-eslint-repro/index.ts", "version": 2 }, "contentChanges": [ { "range": { "start": { "line": 0, "character": 22 }, "end": { "line": 0, "character": 30 } }, "rangeLength": 8, "text": "" } ] } [Trace - 05:54:05 PM] Sending request 'textDocument/codeAction - (14)'. Params: { "textDocument": { "uri": "file:///ws/lsp-eslint-repro/index.ts" }, "range": { "start": { "line": 0, "character": 22 }, "end": { "line": 0, "character": 22 } }, "context": { "diagnostics": [ { "message": "Missing return type on function.", "severity": 2, "source": "eslint", "range": { "start": { "line": 0, "character": 7 }, "end": { "line": 0, "character": 22 } }, "code": "@typescript-eslint/explicit-module-boundary-types", "codeDescription": { "href": "https://github.com/typescript-eslint/typescript-eslint/blob/v4.24.0/packages/eslint-plugin/docs/rules/explicit-module-boundary-types.md" } } ] } } ```
lsp-eslint.log ```clojure [Trace - 05:54:03 PM] Sending request 'initialize - (2)'. Params: { "processId": null, "rootPath": "/ws/lsp-eslint-repro", "clientInfo": { "name": "emacs", "version": "GNU Emacs 28.0.50 (build 1, x86_64-pc-linux-gnu)" }, "rootUri": "file:///ws/lsp-eslint-repro", "capabilities": { "workspace": { "workspaceEdit": { "documentChanges": true, "resourceOperations": [ "create", "rename", "delete" ] }, "applyEdit": true, "symbol": { "symbolKind": { "valueSet": [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26 ] } }, "executeCommand": { "dynamicRegistration": false }, "didChangeWatchedFiles": { "dynamicRegistration": true }, "workspaceFolders": true, "configuration": true, "fileOperations": { "didCreate": false, "willCreate": false, "didRename": false, "willRename": false, "didDelete": false, "willDelete": false } }, "textDocument": { "declaration": { "linkSupport": true }, "definition": { "linkSupport": true }, "implementation": { "linkSupport": true }, "typeDefinition": { "linkSupport": true }, "synchronization": { "willSave": true, "didSave": true, "willSaveWaitUntil": true }, "documentSymbol": { "symbolKind": { "valueSet": [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26 ] }, "hierarchicalDocumentSymbolSupport": true }, "formatting": { "dynamicRegistration": true }, "rangeFormatting": { "dynamicRegistration": true }, "rename": { "dynamicRegistration": true, "prepareSupport": true }, "codeAction": { "dynamicRegistration": true, "isPreferredSupport": true, "codeActionLiteralSupport": { "codeActionKind": { "valueSet": [ "", "quickfix", "refactor", "refactor.extract", "refactor.inline", "refactor.rewrite", "source", "source.organizeImports" ] } }, "resolveSupport": { "properties": [ "edit", "command" ] }, "dataSupport": true }, "completion": { "completionItem": { "snippetSupport": true, "documentationFormat": [ "markdown", "plaintext" ], "resolveAdditionalTextEditsSupport": true, "insertReplaceSupport": true, "resolveSupport": { "properties": [ "documentation", "details", "additionalTextEdits", "command" ] }, "insertTextModeSupport": { "valueSet": [ 1, 2 ] } }, "contextSupport": true }, "signatureHelp": { "signatureInformation": { "parameterInformation": { "labelOffsetSupport": true } } }, "documentLink": { "dynamicRegistration": true, "tooltipSupport": true }, "hover": { "contentFormat": [ "markdown", "plaintext" ] }, "foldingRange": { "dynamicRegistration": true }, "callHierarchy": { "dynamicRegistration": false }, "publishDiagnostics": { "relatedInformation": true, "tagSupport": { "valueSet": [ 1, 2 ] }, "versionSupport": true }, "moniker": null, "linkedEditingRange": null }, "window": { "workDoneProgress": true, "showMessage": null, "showDocument": null } }, "initializationOptions": null, "workDoneToken": "1", "workspaceFolders": [ { "uri": "file:///ws/lsp-eslint-repro", "name": "lsp-eslint-repro" }, { "uri": "file:///ws/customerce/e2e-test", "name": "e2e-test" }, { "uri": "file:///ws/customerce/shop-frontend", "name": "shop-frontend" } ] } [Trace - 05:54:04 PM] Received notification 'window/logMessage'. Params: { "type": 3, "message": "ESLint server running in node v16.5.0" } [Trace - 05:54:04 PM] Received notification '$/progress'. Params: { "token": "1", "value": { "kind": "begin", "title": "Initializing ESLint Server" } } [Trace - 05:54:04 PM] Received notification '$/progress'. Params: { "token": "1", "value": { "kind": "end" } } [Trace - 05:54:04 PM] Received response 'initialize - (2)' in 583ms. Result: { "capabilities": { "textDocumentSync": { "openClose": true, "change": 2, "willSaveWaitUntil": null, "save": { "includeText": null } }, "workspace": { "workspaceFolders": { "supported": true } }, "codeActionProvider": { "codeActionKinds": [ "quickfix", "source.fixAll.eslint" ] }, "executeCommandProvider": { "commands": [ "eslint.applySingleFix", "eslint.applySuggestion", "eslint.applySameFixes", "eslint.applyAllFixes", "eslint.applyDisableLine", "eslint.applyDisableFile", "eslint.openRuleDoc" ] } } } [Trace - 05:54:04 PM] Sending notification 'initialized'. Params: {} [Trace - 05:54:04 PM] Sending notification 'textDocument/didOpen'. Params: { "textDocument": { "uri": "file:///ws/lsp-eslint-repro/index.ts", "languageId": "typescript", "version": 0, "text": "export function test() {\n return 2;\n}\n" } } [Trace - 05:54:04 PM] Sending request 'textDocument/codeAction - (5)'. Params: { "textDocument": { "uri": "file:///ws/lsp-eslint-repro/index.ts" }, "range": { "start": { "line": 0, "character": 8 }, "end": { "line": 0, "character": 8 } }, "context": { "diagnostics": [] } } [Trace - 05:54:04 PM] Received request 'client/registerCapability - (0). Params: { "registrations": [ { "id": "4d4e4a66-e024-444d-9b98-33e92220b6bc", "method": "workspace/didChangeConfiguration", "registerOptions": {} } ] } [Trace - 05:54:04 PM] Sending response 'client/registerCapability - (0)'. Processing request took 18ms Params: { "jsonrpc": "2.0", "id": 0, "result": null } [Trace - 05:54:04 PM] Received request 'client/registerCapability - (1). Params: { "registrations": [ { "id": "183d5119-0632-4f3d-a8ad-35dd350c2caa", "method": "workspace/didChangeWorkspaceFolders", "registerOptions": {} } ] } [Trace - 05:54:04 PM] Sending response 'client/registerCapability - (1)'. Processing request took 17ms Params: { "jsonrpc": "2.0", "id": 1, "result": null } [Trace - 05:54:04 PM] Received request 'workspace/configuration - (2). Params: { "items": [ { "scopeUri": "file:///ws/lsp-eslint-repro/index.ts", "section": "" } ] } [Trace - 05:54:04 PM] Sending response 'workspace/configuration - (2)'. Processing request took 5ms Params: { "jsonrpc": "2.0", "id": 2, "result": [ { "validate": "on", "packageManager": "npm", "codeAction": { "disableRuleComment": { "enable": true, "location": "separateLine" }, "showDocumentation": { "enable": true } }, "codeActionOnSave": { "enable": true, "mode": "all" }, "format": true, "quiet": false, "onIgnoredFiles": "off", "options": {}, "rulesCustomizations": [], "run": "onType", "nodePath": null, "workspaceFolder": { "uri": "file:///ws/lsp-eslint-repro", "name": "lsp-eslint-repro" } } ] } [Trace - 05:54:04 PM] Sending notification '$/cancelRequest'. Params: { "id": 5 } [Trace - 05:54:04 PM] Sending request 'textDocument/codeAction - (7)'. Params: { "textDocument": { "uri": "file:///ws/lsp-eslint-repro/index.ts" }, "range": { "start": { "line": 0, "character": 8 }, "end": { "line": 0, "character": 8 } }, "context": { "diagnostics": [] } } [Trace - 05:54:04 PM] Sending request 'textDocument/codeAction - (9)'. Params: { "textDocument": { "uri": "file:///ws/lsp-eslint-repro/index.ts" }, "range": { "start": { "line": 0, "character": 8 }, "end": { "line": 0, "character": 8 } }, "context": { "diagnostics": [] } } [Trace - 05:54:05 PM] Received notification 'window/logMessage'. Params: { "type": 3, "message": "ESLint library loaded from: /ws/lsp-eslint-repro/node_modules/eslint/lib/api.js" } [Trace - 05:54:05 PM] Received request 'client/registerCapability - (3). Params: { "registrations": [ { "id": "e4f442b9-41e8-4a24-a752-cc2a97d9a6c6", "method": "textDocument/formatting", "registerOptions": { "documentSelector": [ { "scheme": "file", "pattern": "/ws/lsp-eslint-repro/index.ts" } ] } } ] } [Trace - 05:54:05 PM] Sending response 'client/registerCapability - (3)'. Processing request took 10ms Params: { "jsonrpc": "2.0", "id": 3, "result": null } [Trace - 05:54:05 PM] Received response 'nil - (5)' in 0ms. Result: [] [Trace - 05:54:05 PM] Received response 'textDocument/codeAction - (7)' in 913ms. Result: [] [Trace - 05:54:05 PM] Received notification 'textDocument/publishDiagnostics'. Params: { "uri": "file:///ws/lsp-eslint-repro/index.ts", "diagnostics": [ { "message": "Missing return type on function.", "severity": 2, "source": "eslint", "range": { "start": { "line": 0, "character": 7 }, "end": { "line": 0, "character": 22 } }, "code": "@typescript-eslint/explicit-module-boundary-types", "codeDescription": { "href": "https://github.com/typescript-eslint/typescript-eslint/blob/v4.24.0/packages/eslint-plugin/docs/rules/explicit-module-boundary-types.md" } } ] } [Trace - 05:54:05 PM] Received notification 'eslint/status'. Params: { "uri": "file:///ws/lsp-eslint-repro/index.ts", "state": 1 } [Trace - 05:54:05 PM] Received response 'textDocument/codeAction - (9)' in 560ms. Result: [] [Trace - 05:54:05 PM] Sending request 'textDocument/codeAction - (10)'. Params: { "textDocument": { "uri": "file:///ws/lsp-eslint-repro/index.ts" }, "range": { "start": { "line": 0, "character": 8 }, "end": { "line": 0, "character": 8 } }, "context": { "diagnostics": [ { "message": "Missing return type on function.", "severity": 2, "source": "eslint", "range": { "start": { "line": 0, "character": 7 }, "end": { "line": 0, "character": 22 } }, "code": "@typescript-eslint/explicit-module-boundary-types", "codeDescription": { "href": "https://github.com/typescript-eslint/typescript-eslint/blob/v4.24.0/packages/eslint-plugin/docs/rules/explicit-module-boundary-types.md" } } ], "only": [ "refactor" ] } } [Trace - 05:54:05 PM] Received response 'textDocument/codeAction - (10)' in 2ms. Result: [ { "title": "Disable @typescript-eslint/explicit-module-boundary-types for this line", "command": { "title": "Disable @typescript-eslint/explicit-module-boundary-types for this line", "command": "eslint.applyDisableLine", "arguments": [ { "uri": "file:///ws/lsp-eslint-repro/index.ts", "version": 0, "ruleId": "@typescript-eslint/explicit-module-boundary-types" } ] }, "kind": "refactor" }, { "title": "Disable @typescript-eslint/explicit-module-boundary-types for the entire file", "command": { "title": "Disable @typescript-eslint/explicit-module-boundary-types for the entire file", "command": "eslint.applyDisableFile", "arguments": [ { "uri": "file:///ws/lsp-eslint-repro/index.ts", "version": 0, "ruleId": "@typescript-eslint/explicit-module-boundary-types" } ] }, "kind": "refactor" }, { "title": "Show documentation for @typescript-eslint/explicit-module-boundary-types", "command": { "title": "Show documentation for @typescript-eslint/explicit-module-boundary-types", "command": "eslint.openRuleDoc", "arguments": [ { "uri": "file:///ws/lsp-eslint-repro/index.ts", "version": 0, "ruleId": "@typescript-eslint/explicit-module-boundary-types" } ] }, "kind": "refactor" } ] [Trace - 05:54:05 PM] Sending request 'workspace/executeCommand - (11)'. Params: { "command": "_typescript.applyRefactoring", "arguments": [ { "file": "/ws/lsp-eslint-repro/index.ts", "startLine": 1, "startOffset": 9, "endLine": 1, "endOffset": 9, "refactor": "Infer function return type", "action": "Infer function return type" } ] } [Trace - 05:54:05 PM] Received response 'workspace/executeCommand - (11)' in 13ms. Result: {} [Trace - 05:54:05 PM] Sending request 'textDocument/codeAction - (12)'. Params: { "textDocument": { "uri": "file:///ws/lsp-eslint-repro/index.ts" }, "range": { "start": { "line": 0, "character": 8 }, "end": { "line": 0, "character": 8 } }, "context": { "diagnostics": [ { "message": "Missing return type on function.", "severity": 2, "source": "eslint", "range": { "start": { "line": 0, "character": 7 }, "end": { "line": 0, "character": 22 } }, "code": "@typescript-eslint/explicit-module-boundary-types", "codeDescription": { "href": "https://github.com/typescript-eslint/typescript-eslint/blob/v4.24.0/packages/eslint-plugin/docs/rules/explicit-module-boundary-types.md" } } ] } } [Trace - 05:54:05 PM] Sending notification '$/cancelRequest'. Params: { "id": 12 } [Trace - 05:54:05 PM] Sending request 'textDocument/codeAction - (13)'. Params: { "textDocument": { "uri": "file:///ws/lsp-eslint-repro/index.ts" }, "range": { "start": { "line": 0, "character": 8 }, "end": { "line": 0, "character": 8 } }, "context": { "diagnostics": [ { "message": "Missing return type on function.", "severity": 2, "source": "eslint", "range": { "start": { "line": 0, "character": 7 }, "end": { "line": 0, "character": 22 } }, "code": "@typescript-eslint/explicit-module-boundary-types", "codeDescription": { "href": "https://github.com/typescript-eslint/typescript-eslint/blob/v4.24.0/packages/eslint-plugin/docs/rules/explicit-module-boundary-types.md" } } ] } } [Trace - 05:54:05 PM] Received response 'nil - (12)' in 0ms. Result: [ { "title": "Disable @typescript-eslint/explicit-module-boundary-types for this line", "command": { "title": "Disable @typescript-eslint/explicit-module-boundary-types for this line", "command": "eslint.applyDisableLine", "arguments": [ { "uri": "file:///ws/lsp-eslint-repro/index.ts", "version": 0, "ruleId": "@typescript-eslint/explicit-module-boundary-types" } ] }, "kind": "quickfix" }, { "title": "Disable @typescript-eslint/explicit-module-boundary-types for the entire file", "command": { "title": "Disable @typescript-eslint/explicit-module-boundary-types for the entire file", "command": "eslint.applyDisableFile", "arguments": [ { "uri": "file:///ws/lsp-eslint-repro/index.ts", "version": 0, "ruleId": "@typescript-eslint/explicit-module-boundary-types" } ] }, "kind": "quickfix" }, { "title": "Show documentation for @typescript-eslint/explicit-module-boundary-types", "command": { "title": "Show documentation for @typescript-eslint/explicit-module-boundary-types", "command": "eslint.openRuleDoc", "arguments": [ { "uri": "file:///ws/lsp-eslint-repro/index.ts", "version": 0, "ruleId": "@typescript-eslint/explicit-module-boundary-types" } ] }, "kind": "quickfix" } ] [Trace - 05:54:05 PM] Received response 'textDocument/codeAction - (13)' in 2ms. Result: [ { "title": "Disable @typescript-eslint/explicit-module-boundary-types for this line", "command": { "title": "Disable @typescript-eslint/explicit-module-boundary-types for this line", "command": "eslint.applyDisableLine", "arguments": [ { "uri": "file:///ws/lsp-eslint-repro/index.ts", "version": 0, "ruleId": "@typescript-eslint/explicit-module-boundary-types" } ] }, "kind": "quickfix" }, { "title": "Disable @typescript-eslint/explicit-module-boundary-types for the entire file", "command": { "title": "Disable @typescript-eslint/explicit-module-boundary-types for the entire file", "command": "eslint.applyDisableFile", "arguments": [ { "uri": "file:///ws/lsp-eslint-repro/index.ts", "version": 0, "ruleId": "@typescript-eslint/explicit-module-boundary-types" } ] }, "kind": "quickfix" }, { "title": "Show documentation for @typescript-eslint/explicit-module-boundary-types", "command": { "title": "Show documentation for @typescript-eslint/explicit-module-boundary-types", "command": "eslint.openRuleDoc", "arguments": [ { "uri": "file:///ws/lsp-eslint-repro/index.ts", "version": 0, "ruleId": "@typescript-eslint/explicit-module-boundary-types" } ] }, "kind": "quickfix" } ] [Trace - 05:54:05 PM] Sending notification 'textDocument/didChange'. Params: { "textDocument": { "uri": "file:///ws/lsp-eslint-repro/index.ts", "version": 2 }, "contentChanges": [ { "range": { "start": { "line": 0, "character": 22 }, "end": { "line": 0, "character": 30 } }, "rangeLength": 8, "text": "" } ] } [Trace - 05:54:05 PM] Sending request 'textDocument/codeAction - (14)'. Params: { "textDocument": { "uri": "file:///ws/lsp-eslint-repro/index.ts" }, "range": { "start": { "line": 0, "character": 22 }, "end": { "line": 0, "character": 22 } }, "context": { "diagnostics": [ { "message": "Missing return type on function.", "severity": 2, "source": "eslint", "range": { "start": { "line": 0, "character": 7 }, "end": { "line": 0, "character": 22 } }, "code": "@typescript-eslint/explicit-module-boundary-types", "codeDescription": { "href": "https://github.com/typescript-eslint/typescript-eslint/blob/v4.24.0/packages/eslint-plugin/docs/rules/explicit-module-boundary-types.md" } } ] } } [Trace - 05:54:05 PM] Received notification 'textDocument/publishDiagnostics'. Params: { "uri": "file:///ws/lsp-eslint-repro/index.ts", "diagnostics": [ { "message": "Parsing error: '{' or ';' expected.", "severity": 1, "source": "eslint", "range": { "start": { "line": 0, "character": 23 }, "end": { "line": 0, "character": 23 } } } ] } ```
;;; package --- Log generator for #2901
;;; Commentary:
;;;
;;; Run with "emacs --load ./test-2901.el --visit index.ts", after
;;; cloning the reproduction repository and running "npm install".
;;;
;;; This script will *kill* Emacs at the end *without* confirmation
;;; and *without* asking to save buffers.
;;;
;;; Find logs generated in "./lsp-ts-ls.log" and "./lsp-eslint.log"
;;;
;;; Code:

(eval-when-compile
  (require 'lsp-mode))

(with-current-buffer (switch-to-buffer (find-file-noselect "index.ts"))
  (goto-char 9)
  (defun on-invalid-error (err)
    (remove-hook 'flycheck-process-error-functions #'on-invalid-error t)
    (mapcar
     (lambda (buffer)
       (when (string-match-p "lsp-log: ts-ls" (buffer-name buffer))
         (with-current-buffer buffer (write-file "lsp-ts-ls.log") (save-buffer 0)))
       (when (string-match-p "lsp-log: eslint" (buffer-name buffer))
         (with-current-buffer buffer (write-file "lsp-eslint.log") (save-buffer 0)))
       nil)
     (buffer-list))
    (setq kill-emacs-hook nil)
    (kill-emacs 0)
    nil)
  (defun on-outdated-error (err)
    (remove-hook 'flycheck-process-error-functions #'on-outdated-error t)
    (ignore-errors (undo))
    (add-hook 'flycheck-process-error-functions #'on-invalid-error nil t)
    nil)
  (defun on-valid-error (err)
    (remove-hook 'flycheck-process-error-functions #'on-valid-error t)
    (lsp-execute-code-action
     (lsp-seq-first
      (seq-filter
       (lambda (action)
         (equal "Infer function return type" (gethash "title" action)))
       (lsp-code-actions-at-point "refactor"))))
    (add-hook 'flycheck-process-error-functions #'on-outdated-error nil t)
    nil)
  (add-hook 'flycheck-process-error-functions #'on-valid-error nil t)
  nil)

(provide 'test-2901)
;;; test-2901.el ends here
JordanAnthonyKing commented 3 years ago

Has there been any progress on this issue? It's been driving me up the wall :L

yyoncho commented 3 years ago

I am testing with the provided repo using lsp-gitpod and it seems like the provided steps work fine.

https://gitpod.io/#ORG=kuba-orlik,PROJECT=lsp-eslint-repro,PROFILE=vanilla/https://github.com/yyoncho/lsp-gitpod

Can someone provide other steps and eventually test with lsp-gitpod?

JordanAnthonyKing commented 3 years ago

Thanks for responding. I have set up this repro for reproduction: https://github.com/JordanAnthonyKing/lsp-eslint-test

This is a basic angular project set up with ng new [project name]. All I have added are some configs for eslint and prettier. You can see these changes in the .prettierrc, .prettierignore, .eslintrc.json, .eslintignore, and then the new packages added to package.json that contain eslint in their name compared to a default project.

To reproduce:

In order to restore the buffer to a working state lsp-workspace-restart must be executed for the eslint language server: image Note: You should be able to fix these errors without issue. My initial assumption was just that since these fixes do not shift lines they don't cause any problem, however I have had this bug when converting concatenated strings to interpolated strings, despite this not shifting the lines at all.

Thanks, and please let me know if you need further info or any help reproducing this.