lsp-java icon indicating copy to clipboard operation
lsp-java copied to clipboard

xref-find-references fails with "Wrong type argument: hash-table-p, nil"

Open muirdm opened this issue 5 years ago • 21 comments

Describe the bug When running xref-find-references, I get a Wrong type argument: hash-table-p, nil error. The lsp function lsp-find-references seems to work properly, so it is something with the xref integration. For comparison, xref-find-references works properly with lsp-mode in rust-mode.

To Reproduce Put cursor over method definition, press <M-?> (default key binding for xref-find-references)

Expected behavior A list of users of method pops up.

muirdm avatar Apr 10 '19 17:04 muirdm

Can you include client server communication and error callstack after doing toggle-debug-on-error. Also, do you get the same results when using lsp-find-references?

yyoncho avatar Apr 10 '19 17:04 yyoncho

lsp-find-references works normally, as I mentioned.

Stack:

Debugger entered--Lisp error: (wrong-type-argument hash-table-p nil)
  gethash("uri" nil)
  lsp--location-to-td-position(nil)
  lsp--symbol-info-to-identifier(#<hash-table equal 6/65 0x4da831e5>)
  mapcar(lsp--symbol-info-to-identifier (#<hash-table equal 6/65 0x4da831e5> #<hash-table equal 7/65 0x418fcd5d>))
  #f(compiled-function (function sequence) #<bytecode 0x40aff1bf>)(lsp--symbol-info-to-identifier (#<hash-table equal 6/65 0x4da831e5> #<hash-table equal 7/65 0x418fcd5d>))
  apply(#f(compiled-function (function sequence) #<bytecode 0x40aff1bf>) lsp--symbol-info-to-identifier (#<hash-table equal 6/65 0x4da831e5> #<hash-table equal 7/65 0x418fcd5d>) nil)
  seq-map(lsp--symbol-info-to-identifier (#<hash-table equal 6/65 0x4da831e5> #<hash-table equal 7/65 0x418fcd5d>))
  #f(compiled-function (backend) #<bytecode 0x4366ade5>)(xref-lsp)
  apply(#f(compiled-function (backend) #<bytecode 0x4366ade5>) xref-lsp nil)
  xref-backend-identifier-completion-table(xref-lsp)
  xref--read-identifier("Find references of: ")
  byte-code("\300\301!C\207" [xref--read-identifier "Find references of: "] 2)
  call-interactively(xref-find-references nil nil)
  command-execute(xref-find-references)

Server communication:

{
  "jsonrpc": "2.0",
  "method": "textDocument/documentSymbol",
  "params": {
    "textDocument": {
      "uri": "file:///Users/muir/scratch/java/Foo.java"
    }
  },
  "id": 26
}

<<<< jdtls:7388
{
  "jsonrpc": "2.0",
  "method": "window/logMessage",
  "params": {
    "type": 3,
    "message": "Apr 10, 2019 10:27:19 AM >> document/documentSymbol"
  }
}
Apr 10, 2019 10:27:19 AM >> document/documentSymbol
<<<< jdtls:7388
{
  "jsonrpc": "2.0",
  "id": 26,
  "result": [
    {
      "name": "foo",
      "kind": 4,
      "range": {
        "start": {
          "line": 6,
          "character": 0
        },
        "end": {
          "line": 6,
          "character": 12
        }
      },
      "selectionRange": {
        "start": {
          "line": 6,
          "character": 0
        },
        "end": {
          "line": 6,
          "character": 12
        }
      },
      "detail": "",
      "deprecated": false
    },
    {
      "name": "Foo",
      "kind": 5,
      "range": {
        "start": {
          "line": 8,
          "character": 0
        },
        "end": {
          "line": 13,
          "character": 1
        }
      },
      "selectionRange": {
        "start": {
          "line": 8,
          "character": 13
        },
        "end": {
          "line": 8,
          "character": 16
        }
      },
      "detail": "",
      "deprecated": false,
      "children": [
        {
          "name": "foo()",
          "kind": 6,
          "range": {
            "start": {
              "line": 9,
              "character": 2
            },
            "end": {
              "line": 9,
              "character": 24
            }
          },
          "selectionRange": {
            "start": {
              "line": 9,
              "character": 15
            },
            "end": {
              "line": 9,
              "character": 18
            }
          },
          "detail": " : void",
          "deprecated": false,
          "children": []
        },
        {
          "name": "bar()",
          "kind": 6,
          "range": {
            "start": {
              "line": 10,
              "character": 2
            },
            "end": {
              "line": 12,
              "character": 3
            }
          },
          "selectionRange": {
            "start": {
              "line": 10,
              "character": 15
            },
            "end": {
              "line": 10,
              "character": 18
            }
          },
          "detail": " : void",
          "deprecated": false,
          "children": []
        }
      ]
    }
  ]
}

muirdm avatar Apr 10 '19 17:04 muirdm

lsp-find-references works normally, as I mentioned.

Ops, I misread your original comment.

yyoncho avatar Apr 10 '19 17:04 yyoncho

This was my test Foo.java file for your reference:

package foo;

public class Foo {
  private void foo() { }
  private void bar() {
    foo();
  }
}

muirdm avatar Apr 10 '19 17:04 muirdm

@muirrn can you include the call textDocument/references response which corresponds. I just want to make sure that I am fixing the correct thing.

yyoncho avatar Apr 10 '19 17:04 yyoncho

There was no "document/references" call when I did xref-find-references. It only called "document/documentSymbol" (or it crashed before getting to the "document/references" call). Below is the "document/references" call when I run lsp-find-references:

{
  "jsonrpc": "2.0",
  "method": "textDocument/references",
  "params": {
    "textDocument": {
      "uri": "file:///Users/muir/scratch/java/Foo.java"
    },
    "position": {
      "line": 9,
      "character": 17
    },
    "context": {
      "includeDeclaration": false
    }
  },
  "id": 382
}

<<<< jdtls:7388
{
  "jsonrpc": "2.0",
  "method": "window/logMessage",
  "params": {
    "type": 3,
    "message": "Apr 10, 2019 11:16:19 AM >> document/references"
  }
}
Apr 10, 2019 11:16:19 AM >> document/references
<<<< jdtls:7388
{
  "jsonrpc": "2.0",
  "id": 382,
  "result": [
    {
      "uri": "file:///Users/muir/scratch/java/Foo.java",
      "range": {
        "start": {
          "line": 13,
          "character": 4
        },
        "end": {
          "line": 13,
          "character": 9
        }
      }
    }
  ]
}

muirdm avatar Apr 10 '19 18:04 muirdm

I am able to reproduce this problem by doing C-u M-x xref-find-references which I think was impossible to support for some reason (mismatch of xref requirements/lsp spec) and that's why we introduced lsp-find-references .

yyoncho avatar Apr 10 '19 18:04 yyoncho

Ah, I see now. The problem is xref-find-references always prompts for the identifier, and the lsp supplied identifier list has no context, so all variables in your file named "foo" just show up as separate "foo" entries and there is no way to select the particular "foo" you want.

I was able to fix it by adding xref-find-references to the list of xref commands that will use point instead of prompting for identifier. With this change, xref-find-references works properly for me in lsp-mode.

(setq xref-prompt-for-identifier '(not xref-find-definitions
                                            xref-find-definitions-other-window
                                            xref-find-definitions-other-frame
                                            xref-find-references))

Perhaps we should include this setting in some lsp-mode documentation? Or maybe even do this automatically if the lsp-mode xref integration is enabled? xref-find-references is pretty useless w/ lsp-mode as is.

For reference: https://github.com/emacs-lsp/lsp-mode/issues/194 https://debbugs.gnu.org/cgi/bugreport.cgi?bug=29619 https://github.com/joaotavora/eglot/issues/147

muirdm avatar Apr 10 '19 19:04 muirdm

It is still worth noting that without my above workaround lsp-java behaves differently from other lsp-mode languages (e.g. rust). In rust, xref-find-references prompts for the identifier and works if you pick the correct identifier, but lsp-java immediately errors out.

muirdm avatar Apr 10 '19 19:04 muirdm

Yeah, on my machine xref-prompt-for-identifier is preconfigured(I am using spacemacs).

I think this is related to the fact that JDT LS does (not) support hierarchical document symbols which is breaking lsp--symbol-info-to-identifier. I am still struggling to figure out how it is supposed to work since I am not the author of that code. An alternative solution is to remap xref-find-references to lsp-find-references in lsp-mode map.

yyoncho avatar Apr 10 '19 19:04 yyoncho

Same here. I am setting xref-prompt-for-identifier to t.

Question, even if lsp cannot fetch all the available references for the completion, can it just provide simple prompt with no completion? This is how lookup works in CIDER (which doesn't rely on xref for M-.). Better than nothing.

vspinu avatar May 12 '19 11:05 vspinu

@vspinu the problem is that the lsp api works by file+position and cannot accept symbol. I am considering rebinding xref-find-definition to lsp-find-definition in lsp-mode-map.

yyoncho avatar May 12 '19 12:05 yyoncho

Oh, boy. That's a such a handicap. Then I guess you don't have a choice then.

vspinu avatar May 12 '19 12:05 vspinu

Wait a sec, which map do you mean? lsp-mode-map is empty. I have just spent an entire evening populating my own java-mode-map with lsp commands trying to figure out what is available. Would be nice to have a recommended map somewhere.

vspinu avatar May 12 '19 12:05 vspinu

You still need java-mode-map since a lot of the commands are java specific and it does not make sense to put them in lsp-mode-map unless you do not plan to use lsp-mode for other languages.

yyoncho avatar May 12 '19 12:05 yyoncho

Well, of course. My suggestion was to provide an example of a java-mode-map configuration with all the functionality currently available, even better a separate configuration or a function which would install those bindings in some meaningful way. Currently hunting all the available commands and trying to figure out what they do from the sparse docstring is a painful exercise.

vspinu avatar May 12 '19 13:05 vspinu

Well, of course. My suggestion was to provide an example of a java-mode-map configuration with all the functionality currently available, even better a separate configuration or a function which would install those bindings in some meaningful way. Currently hunting all the available commands and trying to figure out what they do from the sparse docstring is a painful exercise.

@vspinu we are planning to create packaging project which will be host this functionality (lsp-ide project) but we still cannot figure out the structure of that package.

yyoncho avatar May 13 '19 15:05 yyoncho

Hi @yyoncho, I have just tried out the newest version of LSP mode and it got a similar error. I have tried it on two of my pc and i still got the same error.

Here is the log i got: logs Here is my configuration: configuration

Can you please help check this out?

Note:

  • It is a simple Spring boot project only. It is gradle and spring version 2.3.0. My java version is openjdk version "1.8.0_252".

YumiSuki avatar Jul 03 '20 02:07 YumiSuki

@YumiSuki you are using boot integration as well, right?

yyoncho avatar Jul 03 '20 03:07 yyoncho

@YumiSuki you are using boot integration as well, right?

In the above configuration i uploaded on pastebin, I have something like below at the bottom of the file:

(require 'lsp-java-boot)
;; to enable the lenses
(add-hook 'lsp-mode-hook #'lsp-lens-mode)
(add-hook 'java-mode-hook #'lsp-java-boot-lens-mode)

YumiSuki avatar Jul 03 '20 03:07 YumiSuki

I'm using an internal language server for another language we created and am seeing the same issue. Using M-x lsp-find-references works, using M-x xref-find-references results in "lsp--position-to-point: Wrong type argument: hash-table-p, nil." when using lsp from Nov-25-2020, the 2645 commit https://github.com/emacs-lsp/lsp-mode/tree/d045920385bc337faf635ed87cb0dd164b798767

At some point, I believe this worked for us (the language server does work with VSCode). I thought it worked with a version of lsp-mode from June, but I just went back and checked and it's also broken with that.

Attached is the backtrace from toggle-debug-on-error. Any thoughts on where I could help find the issue?

backtrace.txt

One more item I noticed is the ':display-action' of lsp-find-references doesn't work, i.e.

(lsp-find-references nil :display-action 'frame)

won't pop up in another frame.

JohnC32 avatar Nov 26 '20 01:11 JohnC32