eclipse.jdt.ls icon indicating copy to clipboard operation
eclipse.jdt.ls copied to clipboard

signatureHelp returns activeParameter = -1

Open mikehaertl opened this issue 2 years ago • 10 comments

System.out.println( |);

Response from LS:

{
  activeParameter = -1,
  activeSignature = 0,
  signatures = { {
      label = "println() : void",
      parameters = {}
    }, {
      label = "println(Object x) : void",
      parameters = { {
          label = "Object x"
        } }
    }, {
      label = "println(String x) : void",
      parameters = { {
          label = "String x"
        } }
    },
   [ ... ]
}

This breaks signature help with neovim (0.8.2) and cmp-nvim-lsp. For context: I also use nvim-jdtls, mason.nvim, mason-lspconfig.nvim and nvim-cmp.

I use eclipse.jdt.ls 1.19.0.

mikehaertl avatar Feb 03 '23 09:02 mikehaertl

This issue can probably be fixed in cmp-nvim-lsp (see PR above).

I'm still interested in feedback if this behavior is expected. The LSP specs are a bit unclear to me in this regard:

The active parameter of the active signature. If omitted or the value lies outside the range of signatures[activeSignature].parameters defaults to 0 if the active signature has parameters. If the active signature has no parameters it is ignored. In future version of the protocol this property might become mandatory to better express the active parameter if the active signature does have any.

I don't quite get the 2nd sentence. How can it be omitted/outside the range and at the same time default to 0?

mikehaertl avatar Feb 03 '23 09:02 mikehaertl

If you look at the protocol spec, you'll see activeParameter?: uinteger; . The question mark implies property is optional, and so it's perfectly valid to provide SignatureHelp response that doesn't contain it. However, you're absolutely right that uinteger rules out negative values.

rgrunber avatar Feb 03 '23 20:02 rgrunber

https://github.com/eclipse/eclipse.jdt.ls/blob/fecf51c318e766dc81acc414a1544ccd79ef4604/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/SignatureHelpUtils.java#L195 :neutral_face:

rgrunber avatar Feb 03 '23 21:02 rgrunber

See the discussion here: https://github.com/microsoft/vscode/issues/145851.

If we set it to 0, it could cause another problem: when the cursor is out of the range of the brackets, the first parameter will still be highlighted. (This is what I've observed when I implemented this feature, not sure if this is still true now).

There is a contribution that allows null active parameters to the spec, which is exactly what we want.

I'm okay to follow the spec - return 0 instead of -1 now. - The tradeoff is that we lose some correctness.

jdneo avatar Feb 08 '23 00:02 jdneo

You're right. If activeParameter is not defined it seems to imply it treats it as the 1st (0) parameter being the active one. We definitely don't want to break this in clients, assuming they would want a way to avoid having a parameter as active when out of the invocation range.

I guess we depend on the spec being updated to properly support this.

rgrunber avatar Feb 08 '23 13:02 rgrunber

Doesn't the specs already include that case (outside range...)? But TBH I still struggle to parse this sentence:

If omitted or the value lies outside the range of signatures[activeSignature].parameters defaults to 0 if the active signature has parameters

To me this reads like:

if value==nil or value==(outside range) then value==0

which makes no sense. This sentence looks like it's missing a part in the middle or something.

mikehaertl avatar Feb 08 '23 13:02 mikehaertl

FYI, looks like this PR is close to be merged. We can adopt the new spec once it's ready.

https://github.com/microsoft/language-server-protocol/pull/1597

jdneo avatar Feb 09 '23 01:02 jdneo

If omitted or the value lies outside the range of signatures[activeSignature].parameters defaults to 0 if the active signature has parameters

Looking back, it is confusing. I just intepreted the final if as a condition that must be satisfied for the entire initial "if" to apply.

if (
     ( 
       (value == null/undefined) || value < 0 || value > signatures[activeSignature].parameters)
     ) && signatures[activeSignature].parameters > 0
   ) => 0

Here's what the behaviour looks like. We'd lose the ability to have the signature help popup shown with no active parameter if we stopped returning -1. The new capability introduced should support the new behaviour while respecting the spec.

current behaviour activeParameter-with-negative

return null where we would return -1 activeParameter-with-empty

I think the problem is you've joined different phrases together, while in the documentation, the whitespace was used to separate the different conditions :

rgrunber avatar Feb 10 '23 01:02 rgrunber

The upstream PR is merged in the next spec version. We can consider adopting it sooner.

jdneo avatar Dec 06 '23 00:12 jdneo