hokein updated this revision to Diff 517948.
hokein added a comment.

rebase and polish the implementation.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D142967/new/

https://reviews.llvm.org/D142967

Files:
  clang-tools-extra/clangd/ClangdLSPServer.cpp
  clang-tools-extra/clangd/IncludeCleaner.cpp
  clang-tools-extra/clangd/IncludeCleaner.h
  clang-tools-extra/clangd/Protocol.cpp
  clang-tools-extra/clangd/Protocol.h
  clang-tools-extra/clangd/test/include-cleaner-batch-fix.test

Index: clang-tools-extra/clangd/test/include-cleaner-batch-fix.test
===================================================================
--- clang-tools-extra/clangd/test/include-cleaner-batch-fix.test
+++ clang-tools-extra/clangd/test/include-cleaner-batch-fix.test
@@ -112,7 +112,7 @@
 # CHECK-NEXT:     "version": 0
 # CHECK-NEXT:   }
 ---
-{"jsonrpc":"2.0","id":2,"method":"textDocument/codeAction","params":{"textDocument":{"uri":"test:///simple.cpp"},"range":{"start":{"line":2,"character":1},"end":{"line":2,"character":4}},"context":{"diagnostics":[{"range":{"start": {"line": 2, "character": 1}, "end": {"line": 2, "character": 4}},"severity":2,"message":"No header providing \"Foo\" is directly included (fixes available)", "code": "missing-includes", "source": "clangd"}]}}}
+{"jsonrpc":"2.0","id":2,"method":"textDocument/codeAction","params":{"textDocument":{"uri":"test:///simple.cpp"},"range":{"start":{"line":2,"character":1},"end":{"line":2,"character":4}},"context":{"only":["quickfix"], "diagnostics":[{"range":{"start": {"line": 2, "character": 1}, "end": {"line": 2, "character": 4}},"severity":2,"message":"No header providing \"Foo\" is directly included (fixes available)", "code": "missing-includes", "source": "clangd"}]}}}
 #      CHECK:  "id": 2,
 # CHECK-NEXT:  "jsonrpc": "2.0",
 # CHECK-NEXT:  "result": [
@@ -297,7 +297,7 @@
 # CHECK-NEXT:    }
 # CHECK-NEXT:  ]
 ---
-{"jsonrpc":"2.0","id":3,"method":"textDocument/codeAction","params":{"textDocument":{"uri":"test:///simple.cpp"},"range":{"start":{"line":0,"character":0},"end":{"line":0,"character":17}},"context":{"diagnostics":[{"range":{"start": {"line": 0, "character": 0}, "end": {"line": 0, "character": 17}},"severity":2,"message":"Included header all1.h is not used directly (fixes available)", "code": "unused-includes", "source": "clangd"}]}}}
+{"jsonrpc":"2.0","id":3,"method":"textDocument/codeAction","params":{"textDocument":{"uri":"test:///simple.cpp"},"range":{"start":{"line":0,"character":0},"end":{"line":0,"character":17}},"context":{"only":["quickfix"], "diagnostics":[{"range":{"start": {"line": 0, "character": 0}, "end": {"line": 0, "character": 17}},"severity":2,"message":"Included header all1.h is not used directly (fixes available)", "code": "unused-includes", "source": "clangd"}]}}}
 #      CHECK:  "id": 3,
 # CHECK-NEXT:  "jsonrpc": "2.0",
 # CHECK-NEXT:  "result": [
Index: clang-tools-extra/clangd/Protocol.h
===================================================================
--- clang-tools-extra/clangd/Protocol.h
+++ clang-tools-extra/clangd/Protocol.h
@@ -1076,6 +1076,7 @@
   const static llvm::StringLiteral QUICKFIX_KIND;
   const static llvm::StringLiteral REFACTOR_KIND;
   const static llvm::StringLiteral INFO_KIND;
+  const static llvm::StringLiteral SOURCE_ORGANIZE_IMPORT;
 
   /// The diagnostics that this code action resolves.
   std::optional<std::vector<Diagnostic>> diagnostics;
Index: clang-tools-extra/clangd/Protocol.cpp
===================================================================
--- clang-tools-extra/clangd/Protocol.cpp
+++ clang-tools-extra/clangd/Protocol.cpp
@@ -867,6 +867,7 @@
 const llvm::StringLiteral CodeAction::QUICKFIX_KIND = "quickfix";
 const llvm::StringLiteral CodeAction::REFACTOR_KIND = "refactor";
 const llvm::StringLiteral CodeAction::INFO_KIND = "info";
+const llvm::StringLiteral CodeAction::SOURCE_ORGANIZE_IMPORT = "source.organizeImports";
 
 llvm::json::Value toJSON(const CodeAction &CA) {
   auto CodeAction = llvm::json::Object{{"title", CA.title}};
Index: clang-tools-extra/clangd/IncludeCleaner.h
===================================================================
--- clang-tools-extra/clangd/IncludeCleaner.h
+++ clang-tools-extra/clangd/IncludeCleaner.h
@@ -23,6 +23,7 @@
 #include "clang-include-cleaner/Types.h"
 #include "clang/Tooling/Syntax/Tokens.h"
 #include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/StringRef.h"
 #include "llvm/ADT/StringSet.h"
 #include <tuple>
 #include <vector>
@@ -46,6 +47,11 @@
   std::vector<const Inclusion *> UnusedIncludes;
   std::vector<MissingIncludeDiagInfo> MissingIncludes;
 };
+inline constexpr llvm::StringLiteral RemoveAllUnusedMessage =
+    "remove all unused includes";
+inline constexpr llvm::StringLiteral AddAllMissingIncludesMessage =
+    "add all missing includes";
+inline constexpr llvm::StringLiteral FixAllIncludesMessage = "fix all includes";
 
 /// Retrieves headers that are referenced from the main file but not used.
 /// In unclear cases, headers are not marked as unused.
Index: clang-tools-extra/clangd/IncludeCleaner.cpp
===================================================================
--- clang-tools-extra/clangd/IncludeCleaner.cpp
+++ clang-tools-extra/clangd/IncludeCleaner.cpp
@@ -440,7 +440,7 @@
   assert(!UnusedIncludes.empty());
 
   Fix RemoveAll;
-  RemoveAll.Message = "remove all unused includes";
+  RemoveAll.Message = RemoveAllUnusedMessage;
   for (const auto &Diag : UnusedIncludes) {
     assert(Diag.Fixes.size() == 1 && "Expected exactly one fix.");
     RemoveAll.Edits.insert(RemoveAll.Edits.end(),
@@ -465,7 +465,7 @@
   assert(!MissingIncludeDiags.empty());
 
   Fix AddAllMissing;
-  AddAllMissing.Message = "add all missing includes";
+  AddAllMissing.Message = AddAllMissingIncludesMessage;
   // A map to deduplicate the edits with the same new text.
   // newText (#include "my_missing_header.h") -> TextEdit.
   llvm::StringMap<TextEdit> Edits;
@@ -493,7 +493,7 @@
 }
 Fix fixAll(const Fix& RemoveAllUnused, const Fix& AddAllMissing) {
   Fix FixAll;
-  FixAll.Message = "fix all includes";
+  FixAll.Message = FixAllIncludesMessage;
 
   for (const auto &F : RemoveAllUnused.Edits)
     FixAll.Edits.push_back(F);
Index: clang-tools-extra/clangd/ClangdLSPServer.cpp
===================================================================
--- clang-tools-extra/clangd/ClangdLSPServer.cpp
+++ clang-tools-extra/clangd/ClangdLSPServer.cpp
@@ -13,6 +13,7 @@
 #include "Diagnostics.h"
 #include "Feature.h"
 #include "GlobalCompilationDatabase.h"
+#include "IncludeCleaner.h"
 #include "LSPBinder.h"
 #include "Protocol.h"
 #include "SemanticHighlighting.h"
@@ -27,6 +28,7 @@
 #include "clang/Tooling/Core/Replacement.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/FunctionExtras.h"
+#include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/ScopeExit.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/ADT/Twine.h"
@@ -646,7 +648,8 @@
           ? llvm::json::Object{{"codeActionKinds",
                                 {CodeAction::QUICKFIX_KIND,
                                  CodeAction::REFACTOR_KIND,
-                                 CodeAction::INFO_KIND}}}
+                                 CodeAction::INFO_KIND,
+                                 CodeAction::SOURCE_ORGANIZE_IMPORT}}}
           : llvm::json::Value(true);
 
 
@@ -1029,6 +1032,48 @@
       }
     }
   }
+  if (KindAllowed(CodeAction::SOURCE_ORGANIZE_IMPORT)) {
+    std::lock_guard<std::mutex> Lock(FixItsMutex);
+    if (auto FileFixItsIter = FixItsMap.find(File.file());
+        FileFixItsIter != FixItsMap.end()) {
+      auto UnusedDiag =
+          llvm::find_if(FileFixItsIter->second, [](const auto &DiagFixes) {
+            return DiagFixes.first.code == "unused-includes";
+          });
+      auto MissingDiag =
+          llvm::find_if(FileFixItsIter->second, [](const auto &DiagFixes) {
+            return DiagFixes.first.code == "missing-include";
+          });
+      clang::clangd::CodeAction *RemoveAllUnused = nullptr;
+      clang::clangd::CodeAction *AddAllMissing = nullptr;
+      clang::clangd::CodeAction *FixAll = nullptr;
+      if (UnusedDiag != FileFixItsIter->second.end()) {
+        for (auto &Fix : UnusedDiag->second) {
+          if (Fix.title == RemoveAllUnusedMessage)
+            RemoveAllUnused = &Fix;
+          else if (Fix.title == FixAllIncludesMessage)
+            FixAll = &Fix;
+        }
+      }
+      if (MissingDiag != FileFixItsIter->second.end()) {
+        for (auto &Fix : MissingDiag->second) {
+          if (Fix.title == AddAllMissingIncludesMessage)
+            AddAllMissing = &Fix;
+          else if (Fix.title == FixAllIncludesMessage)
+            FixAll = &Fix;
+        }
+      }
+      auto AddFix = [&](const clang::clangd::CodeAction *Fix) {
+        if (!Fix)
+          return;
+        FixIts.push_back(*Fix);
+        FixIts.back().kind = CodeAction::SOURCE_ORGANIZE_IMPORT;
+      };
+      AddFix(RemoveAllUnused);
+      AddFix(AddAllMissing);
+      AddFix(FixAll);
+    }
+  }
 
   // Now enumerate the semantic code actions.
   auto ConsumeActions =
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to