kadircet created this revision.
Herald added subscribers: usaxena95, arphaman.
kadircet requested review of this revision.
Herald added subscribers: cfe-commits, MaskRay, ilya-biryukov.
Herald added a project: clang.

Fixes only allow modifications to local file containing the diagnostics,
with CodeActions we'll be able to provide changes that can fix the issue
outside of the local file (e.g. build file/header modificiations).

As an implementation detail, we now covert all the fixes to codeactions
directly at publish time, rather than onCodeAction requests. So this
implies some extra copies on each diag release.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D96245

Files:
  clang-tools-extra/clangd/ClangdLSPServer.cpp
  clang-tools-extra/clangd/ClangdLSPServer.h
  clang-tools-extra/clangd/Diagnostics.cpp
  clang-tools-extra/clangd/Diagnostics.h
  clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp

Index: clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp
===================================================================
--- clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp
+++ clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp
@@ -693,7 +693,8 @@
   // Transform diagnostics and check the results.
   std::vector<std::pair<clangd::Diagnostic, std::vector<clangd::Fix>>> LSPDiags;
   toLSPDiags(D, MainFile, Opts,
-             [&](clangd::Diagnostic LSPDiag, ArrayRef<clangd::Fix> Fixes) {
+             [&](clangd::Diagnostic LSPDiag, ArrayRef<clangd::Fix> Fixes,
+                 ArrayRef<CodeAction>) {
                LSPDiags.push_back(
                    {std::move(LSPDiag),
                     std::vector<clangd::Fix>(Fixes.begin(), Fixes.end())});
@@ -712,7 +713,8 @@
   LSPDiags.clear();
   Opts.EmitRelatedLocations = true;
   toLSPDiags(D, MainFile, Opts,
-             [&](clangd::Diagnostic LSPDiag, ArrayRef<clangd::Fix> Fixes) {
+             [&](clangd::Diagnostic LSPDiag, ArrayRef<clangd::Fix> Fixes,
+                 ArrayRef<CodeAction>) {
                LSPDiags.push_back(
                    {std::move(LSPDiag),
                     std::vector<clangd::Fix>(Fixes.begin(), Fixes.end())});
@@ -1334,16 +1336,14 @@
   D.InsideMainFile = true;
   N.InsideMainFile = false;
   toLSPDiags(D, {}, Opts,
-             [&](clangd::Diagnostic LSPDiag, ArrayRef<clangd::Fix>) {
-               EXPECT_EQ(LSPDiag.range, D.Range);
-             });
+             [&](clangd::Diagnostic LSPDiag, ArrayRef<clangd::Fix>,
+                 ArrayRef<CodeAction>) { EXPECT_EQ(LSPDiag.range, D.Range); });
 
   D.InsideMainFile = false;
   N.InsideMainFile = true;
   toLSPDiags(D, {}, Opts,
-             [&](clangd::Diagnostic LSPDiag, ArrayRef<clangd::Fix>) {
-               EXPECT_EQ(LSPDiag.range, N.Range);
-             });
+             [&](clangd::Diagnostic LSPDiag, ArrayRef<clangd::Fix>,
+                 ArrayRef<CodeAction>) { EXPECT_EQ(LSPDiag.range, N.Range); });
 }
 
 } // namespace
Index: clang-tools-extra/clangd/Diagnostics.h
===================================================================
--- clang-tools-extra/clangd/Diagnostics.h
+++ clang-tools-extra/clangd/Diagnostics.h
@@ -97,6 +97,7 @@
   std::vector<Note> Notes;
   /// *Alternative* fixes for this diagnostic, one should be chosen.
   std::vector<Fix> Fixes;
+  std::vector<CodeAction> Actions;
 };
 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Diag &D);
 
@@ -107,9 +108,11 @@
 /// separate diagnostics with their corresponding fixits. Notes outside main
 /// file do not have a corresponding LSP diagnostic, but can still be included
 /// as part of their main diagnostic's message.
-void toLSPDiags(
-    const Diag &D, const URIForFile &File, const ClangdDiagnosticOptions &Opts,
-    llvm::function_ref<void(clangd::Diagnostic, llvm::ArrayRef<Fix>)> OutFn);
+void toLSPDiags(const Diag &D, const URIForFile &File,
+                const ClangdDiagnosticOptions &Opts,
+                llvm::function_ref<void(clangd::Diagnostic, llvm::ArrayRef<Fix>,
+                                        llvm::ArrayRef<CodeAction>)>
+                    OutFn);
 
 /// Convert from Fix to LSP CodeAction.
 CodeAction toCodeAction(const Fix &D, const URIForFile &File);
Index: clang-tools-extra/clangd/Diagnostics.cpp
===================================================================
--- clang-tools-extra/clangd/Diagnostics.cpp
+++ clang-tools-extra/clangd/Diagnostics.cpp
@@ -9,6 +9,7 @@
 #include "Diagnostics.h"
 #include "../clang-tidy/ClangTidyDiagnosticConsumer.h"
 #include "Compiler.h"
+#include "Plugin.h"
 #include "Protocol.h"
 #include "SourceCode.h"
 #include "support/Logger.h"
@@ -403,9 +404,11 @@
   return Result;
 }
 
-void toLSPDiags(
-    const Diag &D, const URIForFile &File, const ClangdDiagnosticOptions &Opts,
-    llvm::function_ref<void(clangd::Diagnostic, llvm::ArrayRef<Fix>)> OutFn) {
+void toLSPDiags(const Diag &D, const URIForFile &File,
+                const ClangdDiagnosticOptions &Opts,
+                llvm::function_ref<void(clangd::Diagnostic, llvm::ArrayRef<Fix>,
+                                        llvm::ArrayRef<CodeAction>)>
+                    OutFn) {
   clangd::Diagnostic Main;
   Main.severity = getSeverity(D.Severity);
 
@@ -437,7 +440,7 @@
     break;
   }
   if (Opts.EmbedFixesInDiagnostics) {
-    Main.codeActions.emplace();
+    Main.codeActions = D.Actions;
     for (const auto &Fix : D.Fixes)
       Main.codeActions->push_back(toCodeAction(Fix, File));
     if (Main.codeActions->size() == 1)
@@ -462,7 +465,7 @@
       Main.relatedInformation->push_back(std::move(RelInfo));
     }
   }
-  OutFn(std::move(Main), D.Fixes);
+  OutFn(std::move(Main), D.Fixes, D.Actions);
 
   // If we didn't emit the notes as relatedLocations, emit separate diagnostics
   // so the user can find the locations easily.
@@ -474,7 +477,7 @@
       Res.severity = getSeverity(Note.Severity);
       Res.range = Note.Range;
       Res.message = noteMessage(D, Note, Opts);
-      OutFn(std::move(Res), llvm::ArrayRef<Fix>());
+      OutFn(std::move(Res), {}, {});
     }
 }
 
@@ -744,6 +747,8 @@
       LastDiag->Fixes.insert(LastDiag->Fixes.end(), ExtraFixes.begin(),
                              ExtraFixes.end());
     }
+    llvm::append_range(LastDiag->Actions,
+                       Plugin::collectFixes(DiagLevel, Info));
   } else {
     // Handle a note to an existing diagnostic.
 
Index: clang-tools-extra/clangd/ClangdLSPServer.h
===================================================================
--- clang-tools-extra/clangd/ClangdLSPServer.h
+++ clang-tools-extra/clangd/ClangdLSPServer.h
@@ -163,7 +163,7 @@
   /// hierarchy.
   void onMemoryUsage(Callback<MemoryTree>);
 
-  std::vector<Fix> getFixes(StringRef File, const clangd::Diagnostic &D);
+  std::vector<CodeAction> getFixes(StringRef File, const clangd::Diagnostic &D);
 
   /// Checks if completion request should be ignored. We need this due to the
   /// limitation of the LSP. Per LSP, a client sends requests for all "trigger
@@ -210,7 +210,8 @@
   std::atomic<bool> IsBeingDestroyed = {false};
 
   std::mutex FixItsMutex;
-  typedef std::map<clangd::Diagnostic, std::vector<Fix>, LSPDiagnosticCompare>
+  typedef std::map<clangd::Diagnostic, std::vector<CodeAction>,
+                   LSPDiagnosticCompare>
       DiagnosticToReplacementMap;
   /// Caches FixIts per file and diagnostics
   llvm::StringMap<DiagnosticToReplacementMap> FixItsMap;
Index: clang-tools-extra/clangd/ClangdLSPServer.cpp
===================================================================
--- clang-tools-extra/clangd/ClangdLSPServer.cpp
+++ clang-tools-extra/clangd/ClangdLSPServer.cpp
@@ -27,6 +27,7 @@
 #include "clang/Tooling/Core/Replacement.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/Optional.h"
+#include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/ScopeExit.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/ADT/iterator_range.h"
@@ -1050,7 +1051,7 @@
   if (KindAllowed(CodeAction::QUICKFIX_KIND)) {
     for (const Diagnostic &D : Params.context.diagnostics) {
       for (auto &F : getFixes(File.file(), D)) {
-        FixIts.push_back(toCodeAction(F, Params.textDocument.uri));
+        FixIts.emplace_back(std::move(F));
         FixIts.back().diagnostics = {D};
       }
     }
@@ -1580,8 +1581,8 @@
     Server->profile(MT.child("clangd_server"));
 }
 
-std::vector<Fix> ClangdLSPServer::getFixes(llvm::StringRef File,
-                                           const clangd::Diagnostic &D) {
+std::vector<CodeAction> ClangdLSPServer::getFixes(llvm::StringRef File,
+                                                  const clangd::Diagnostic &D) {
   std::lock_guard<std::mutex> Lock(FixItsMutex);
   auto DiagToFixItsIter = FixItsMap.find(File);
   if (DiagToFixItsIter == FixItsMap.end())
@@ -1647,9 +1648,14 @@
   DiagnosticToReplacementMap LocalFixIts; // Temporary storage
   for (auto &Diag : Diagnostics) {
     toLSPDiags(Diag, Notification.uri, DiagOpts,
-               [&](clangd::Diagnostic Diag, llvm::ArrayRef<Fix> Fixes) {
+               [&](clangd::Diagnostic Diag, llvm::ArrayRef<Fix> Fixes,
+                   llvm::ArrayRef<CodeAction> Actions) {
                  auto &FixItsForDiagnostic = LocalFixIts[Diag];
-                 llvm::copy(Fixes, std::back_inserter(FixItsForDiagnostic));
+                 llvm::copy(Actions, std::back_inserter(FixItsForDiagnostic));
+                 for (const auto &Fix : Fixes) {
+                   FixItsForDiagnostic.emplace_back(
+                       toCodeAction(Fix, Notification.uri));
+                 }
                  Notification.diagnostics.push_back(std::move(Diag));
                });
   }
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to