This is an archive of the discontinued LLVM Phabricator instance.

[clangd] transfer the fixits with the notes instead of adding them to the main diagnostic if request by the client
Needs ReviewPublic

Authored by arphaman on Aug 15 2018, 3:17 PM.

Details

Summary

This patch extends Clangd to allow the clients to specify the preference for how it wants to consume the fixes on the notes. If AllowNotesWithFixes is true in the DiagnosticOptions, then Clangd will keep the notes with the fixes instead of converting to fixes in the main diagnostic. This extension can be enabled by the client using the "clangdNotesWithFixSupport" capability.

Diff Detail

Event Timeline

arphaman created this revision.Aug 15 2018, 3:17 PM

Why do we want an alternative mode for transferring fix-its and notes? Any reason why our current model is bad?
One thing that comes to mind is inconsistency between clang and our model, but I wonder where would it affect the user experience in a bad way?

Our client has a presentation layer with a Clang-based hierarchical model for diagnostics, so we need the original notes. This is a hard requirement in that sense.

Just to make sure I fully understand the use-case: could you elaborate a little more? Do you need to get exactly the same set of notes that clang provides?
Our current model seems to follow the clang's model, but it removes some notes and shows them as fix-its for the main diagnostic instead.
(We think it should provide a better user experience, because those notes do look like a way to present a fix-it to the user when you have only text-based output and they seem redundant when one has an editor-based UI with fix-its).

Not opposed to changing the model to meet other needs, but want to make sure what we're currently doing in clangd makes sense and understand your use-case better.

Just to make sure I fully understand the use-case: could you elaborate a little more? Do you need to get exactly the same set of notes that clang provides?

Yep. We are replacing libclang in a client that currently consumes diagnostics as provided by clang. We'd like to avoid regressions in the client, so we are looking to match the diagnostics provided by clangd, at least for now.
It might be possible to recreate the original hierarchy using the diagnostics that are currently provided by clangd using some heroics on the client-side. However, we'd like to avoid them for now and get the data from Clangd directly :)

Our current model seems to follow the clang's model, but it removes some notes and shows them as fix-its for the main diagnostic instead.
(We think it should provide a better user experience, because those notes do look like a way to present a fix-it to the user when you have only text-based output and they seem redundant when one has an editor-based UI with fix-its).

The current Clangd model certainly works well for newer clients who are built with LSP in mind from the get go. Sending diagnostics in a format similar to Clang's originals diagnostics would be helpful to clients that are transitioning though :)

Not opposed to changing the model to meet other needs, but want to make sure what we're currently doing in clangd makes sense and understand your use-case better.

Sorry for the delayed response. It seems we absolutely need this if mirroring libclang is an absolute requirement.
We seem to have multiple implementation options:

Which classes to use for representing diagnostics? We can:

  1. Reuse existing hierarchy for diagnostics. (current option)
  2. Have separate hierarchies for "flat" (fixits with notes) and "grouped" (fix-its are always attached to main diag). "flat" diagnostics can be stored exactly as they come from clang, with notes and main diags in the same vector, main diag should lack the "notes" field. I.e. if we choose to go with "raw" clang mode, we can as well avoid grouping the notes altogether instead of having code that does something in between the classical libclang and new clangd approach.

I think the added separation is worth it for code clarity, but also realize it's a bunch of boilerplate, so others may disagree. WDYT?

Another alternative that we might explore is always producing fix-its attached to notes at the lowest level (in Diagnostics.cpp) and reconstructing the current diagnostics hierarchy somewhere higher up the chain, e.g. at the LSPServer level.
This would allow to keep the option at the LSPServer level and would only require extracting a (seemingly simple) conversion function that can be called at the LSP Server level.
Having the option handled at the top-level seems like a win, since most of the code does not need to care about this option.

+@sammccall, who wanted to take a look at this issue.

Sorry for the delayed response. It seems we absolutely need this if mirroring libclang is an absolute requirement.
We seem to have multiple implementation options:

Which classes to use for representing diagnostics? We can:

  1. Reuse existing hierarchy for diagnostics. (current option)
  2. Have separate hierarchies for "flat" (fixits with notes) and "grouped" (fix-its are always attached to main diag). "flat" diagnostics can be stored exactly as they come from clang, with notes and main diags in the same vector, main diag should lack the "notes" field. I.e. if we choose to go with "raw" clang mode, we can as well avoid grouping the notes altogether instead of having code that does something in between the classical libclang and new clangd approach.

I think the added separation is worth it for code clarity, but also realize it's a bunch of boilerplate, so others may disagree. WDYT?

I think having separate hierarchies would be more confusing and harder to test well. I'd prefer to use one hierarchy.

Another alternative that we might explore is always producing fix-its attached to notes at the lowest level (in Diagnostics.cpp) and reconstructing the current diagnostics hierarchy somewhere higher up the chain, e.g. at the LSPServer level.
This would allow to keep the option at the LSPServer level and would only require extracting a (seemingly simple) conversion function that can be called at the LSP Server level.
Having the option handled at the top-level seems like a win, since most of the code does not need to care about this option.\

That would be my personal preference. I will work on an updated patch that does that.

+@sammccall, who wanted to take a look at this issue.

jkorous resigned from this revision.Jan 21 2022, 3:52 PM