clangd icon indicating copy to clipboard operation
clangd copied to clipboard

Wrong hover info on Windows platform

Open timxx opened this issue 2 years ago • 4 comments

When using clang-cl mode on Windows, hover on STDAPI function always displays the nothrow document

image

It's strange after changing the cl.exe to clang++.exe in compile_commands.json, it work as expected.

Logs

Please attach the clangd stderr log if you can. (Usually available from the editor) If possible, run with --log=verbose - note that the logs will include the contents of open files! If this is a crash, try to put llvm-symbolizer on your PATH per the troubleshooting instructions.

System information

Output of clangd --version: 17.0.6

Editor/LSP plugin: VS Code

Operating system: Windows

The attachment is a basic reproducible demo (You may have to change the directory in compile_comands.json) bug.zip

timxx avatar Dec 01 '23 03:12 timxx

Confirmed. Note that we have an extra attribute nothrow on the function Decl:

image

(I still couldn't get a code + invocation arguments combo for debugging at the moment, so forgive me for posting screenshots directly.)

If the cl.exe gets replaced with clang++.exe, that node disappears (and then we'll see ordinary function signatures):

image

zyn0217 avatar Dec 04 '23 06:12 zyn0217

Confirmed. Note that we have an extra attribute nothrow on the function Decl:

image

(I still couldn't get a code + invocation arguments combo for debugging at the moment, so forgive me for posting screenshots directly.)

If the cl.exe gets replaced with clang++.exe, that node disappears (and then we'll see ordinary function signatures):

image

After debugging the hover, I found that when creating the selection tree, the commonAncestor returns the nothrow attr as selected

const Node *SelectionTree::commonAncestor() const {
  const Node *Ancestor = Root;
  while (Ancestor->Children.size() == 1 && !Ancestor->Selected)
    Ancestor = Ancestor->Children.front();
  // Returning nullptr here is a bit unprincipled, but it makes the API safer:
  // the TranslationUnitDecl contains all of the preamble, so traversing it is a
  // performance cliff. Callers can check for null and use root() if they want.
  return Ancestor != Root ? Ancestor : nullptr;
}

timxx avatar Dec 08 '23 01:12 timxx

SelectionTree returns nodes of the associated AST under specified lines, so I think the crux of the issue is that clang somehow builds up a slightly abnormal FunctionDecl followed by a NoThrow attribute if being invoked with (part of) your compile commands. The NoThrow declaration is then mishit by SelectionTree and presented anyway.

Regarding the fix, I think we shall first reduce the code to make it replicable on clang. It would be better if we can inspect the node differences on e.g. godbolt. Then, we could decide if this is a clang bug, or we shall refine our SelectionTree logic.

zyn0217 avatar Dec 08 '23 02:12 zyn0217

NoThrow attribute has the same sourceRange (the location ID) as the test identifier (in Selection.cpp getSourceRange), and it's hitted.

I'm not familiar with clang, don't known if this is a bug of clang or clangd

timxx avatar Dec 08 '23 02:12 timxx