This is an archive of the discontinued LLVM Phabricator instance.

[clangd] Refine the workflow for diagnostic Fixits.
ClosedPublic

Authored by hokein on Jul 13 2023, 3:53 AM.

Details

Summary
  • No longer store the diagnostic fixits in the clangdLSPServer
  • When propagating the fixit via the code action, we use the Diag information stored in the ParsedAST (in clangdServer.cpp)

Diff Detail

Event Timeline

hokein created this revision.Jul 13 2023, 3:53 AM
Herald added a project: Restricted Project. · View Herald TranscriptJul 13 2023, 3:53 AM
Herald added a subscriber: arphaman. · View Herald Transcript
hokein requested review of this revision.Jul 13 2023, 3:53 AM
Herald added a project: Restricted Project. · View Herald TranscriptJul 13 2023, 3:53 AM
kadircet added inline comments.Jul 14 2023, 2:55 AM
clang-tools-extra/clangd/ClangdServer.cpp
675

this is tricky indeed and conceptually really hard to achieve inside ClangdServer layer.

what about keeping the cache in ClangdLSPServer, but changing the format? Similar to TweakRef, we now have a DiagRef, which is ClangdServer-native. So we can keep a cache from (FilePath, clangd::Diagnostic) to clangd::DiagRef, and pass those DiagRefs to ClangdServer and make sure we're doing the search for sure on the right domain here?

this also gives us the flexibility to change the definition of a DiagRef in the future.

687

we can have quick fix kind tweaks too (e.g. populate switch)

709–710

can you also move this counter to global scope and use it in ::codeAction too?

clang-tools-extra/clangd/ClangdServer.h
384

maybe a more structured output can be useful here:

struct CodeActionResult {
  std::string Version; // Version of content results belong to.
  struct QuickFix {
      DiagRef D; // Diagnostic being addressed by the fix.
      Fix F;
  };
  std::vector<QuickFix> QuickFixes;
  std::vector<TweakRef> TweakRefs;
};
hokein updated this revision to Diff 541009.Jul 17 2023, 7:02 AM
hokein marked an inline comment as done.

address review comments.

clang-tools-extra/clangd/ClangdServer.cpp
675

I'm not a fan of keeping a cache in ClangdLSPServer, I'd like to remove it entirely.

What do you think about this alternative?

  • pull out and exposed the mainMessage API from the toLSPDiags
  • we add the ClangdDiagnosticOptions to the CodeActionInputs.
  • when searching a diagnostic in ClangdServer.cpp, we check the equality by checking mainMessage(ClangdServerDiagnostic.message, Inputs.DiagOpts) == DiagRef.Message

The downside here is that we have to pay O(N * cost of mainMessage) to find a matched diagnostic.

687

oops, I weren't aware of that, removed.

709–710

I added a similar local counter in codeAction method, since this method is being deprecated, and removed eventually (it doesn't seem too make much sense to use a shared counter)

clang-tools-extra/clangd/ClangdServer.h
384

good idea, also keep symmetry with the CodeActionInputs

hokein updated this revision to Diff 541129.Jul 17 2023, 10:32 AM

Use the mainMessage to find the corresponding ClangdServer diagnostics.

clang-tools-extra/clangd/ClangdServer.cpp
675

I updated the patch with the mainMessage approach, please take a look.

kadircet added inline comments.Jul 18 2023, 12:01 AM
clang-tools-extra/clangd/ClangdServer.cpp
675

i believe this still runs into the same conceptual problems. we're trying to imitate the logic done by clangdlspserver when converting a clangd-native diagnostic into an lsp-diagnostic and all of this will break as soon as there's a change in that logic. so if we want to go down that path, the best option would be to call toLSPDiagevery time here and make sure we imitate that logic properly (e.g. right now we're relying on the ranges not being remapped because we only store fixes for the main file diagnostics).

but i feel like this is unnecessary cost both at runtime but also as code-complexity wise. this is ~the same as the data/args we publish with commands. it's just unfortunate that data field in diagnostic didn't exist pre LSP 3.16, hence we can't rely on it without breaking compatibility with some old clients (hopefully we can do that one day), hence instead of clients keeping this identifier around, I am merely suggesting to keep this alive on the server side. as conceptually this is the only layer that can do the mapping back and forth.

709–710

sorry i am confused. the counter has nothing to do with how we generated a tweak. it's merely counting number of times a tweak was returned. hence we don't need a new one (if a code action Bar was made available either through a call to ::enumerateTweaks or ::codeAction we should increment the same counter. clients won't be invoking both at the same time, they'll be using one or the other).

hokein updated this revision to Diff 541389.Jul 18 2023, 1:18 AM
hokein marked 2 inline comments as done.

add LSPServer cache back and repurpose for lsp <=> naive diagnostic mapping, per offline discussion.

kadircet added inline comments.Jul 18 2023, 4:46 AM
clang-tools-extra/clangd/ClangdLSPServer.cpp
1013–1015

we're already making a copy of Params.context.diagnostics when creating the CB.

so you might as well have a std::map<ClangdServer::DiagRef, clangd::Diagnostic> RefsToDiags; and get rid of the extra index conversions.

clang-tools-extra/clangd/ClangdLSPServer.h
239

instead of storing clangd::Diagnostic as the key, can we have a DiagnosticKey struct here (we can have a helper diagKey(const clangd::Diagnostic&) -> DiagnosticKey)? to make sure we don't get into trouble if there are too many "big" diagnostics :)

that way we can also get rid of the custom comparator.

hokein updated this revision to Diff 541480.Jul 18 2023, 5:46 AM
hokein marked an inline comment as done.

address comments

  • introduce DiagKey for the caching map
  • get rid of extra index conversion
hokein updated this revision to Diff 541481.Jul 18 2023, 5:47 AM

more cleanup

kadircet accepted this revision.Jul 18 2023, 7:09 AM

thanks!

clang-tools-extra/clangd/ClangdLSPServer.cpp
1063

no need for LSPDiags anymore, you can just use ToLSPDiags.begin()

clang-tools-extra/clangd/ClangdServer.cpp
671

nit: you can return an llvm::ArrayRef<Fix> here and get rid of one extra layer of nesting down below

This revision is now accepted and ready to land.Jul 18 2023, 7:09 AM
hokein updated this revision to Diff 541546.Jul 18 2023, 8:22 AM
hokein marked 2 inline comments as done.

address comments

hokein edited the summary of this revision. (Show Details)Jul 18 2023, 8:24 AM
This revision was landed with ongoing or failed builds.Jul 18 2023, 8:25 AM
This revision was automatically updated to reflect the committed changes.