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

First patch to enable diagnostic fix generation through modules. The
workflow will look like:

- ASTWorker letting modules know about diagnostics while building AST,

modules can read clang::Diagnostic and mutate clangd::Diagnostic through
that hook.

- Modules can implement and expose tweaks to fix diagnostics or act as

general refactorings.

- Tweak::Selection will contain information about the diagnostic

associated with the codeAction request to enable modules to fail their
diagnostic fixing tweakson prepare if need be.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D98498

Files:
  clang-tools-extra/clangd/ClangdServer.cpp
  clang-tools-extra/clangd/FeatureModule.h
  clang-tools-extra/clangd/refactor/Tweak.cpp
  clang-tools-extra/clangd/refactor/Tweak.h
  clang-tools-extra/clangd/tool/Check.cpp
  clang-tools-extra/clangd/unittests/tweaks/TweakTesting.cpp

Index: clang-tools-extra/clangd/unittests/tweaks/TweakTesting.cpp
===================================================================
--- clang-tools-extra/clangd/unittests/tweaks/TweakTesting.cpp
+++ clang-tools-extra/clangd/unittests/tweaks/TweakTesting.cpp
@@ -75,7 +75,7 @@
                             Range.second, [&](SelectionTree ST) {
                               Tweak::Selection S(Index, AST, Range.first,
                                                  Range.second, std::move(ST));
-                              if (auto T = prepareTweak(TweakID, S)) {
+                              if (auto T = prepareTweak(TweakID, S, nullptr)) {
                                 Result = (*T)->apply(S);
                                 return true;
                               } else {
Index: clang-tools-extra/clangd/tool/Check.cpp
===================================================================
--- clang-tools-extra/clangd/tool/Check.cpp
+++ clang-tools-extra/clangd/tool/Check.cpp
@@ -206,7 +206,8 @@
       auto Tree = SelectionTree::createRight(AST->getASTContext(),
                                              AST->getTokens(), Start, End);
       Tweak::Selection Selection(&Index, *AST, Start, End, std::move(Tree));
-      for (const auto &T : prepareTweaks(Selection, Opts.TweakFilter)) {
+      for (const auto &T :
+           prepareTweaks(Opts.FeatureModules, Selection, Opts.TweakFilter)) {
         auto Result = T->apply(Selection);
         if (!Result) {
           elog("    tweak: {0} ==> FAIL: {1}", T->id(), Result.takeError());
Index: clang-tools-extra/clangd/refactor/Tweak.h
===================================================================
--- clang-tools-extra/clangd/refactor/Tweak.h
+++ clang-tools-extra/clangd/refactor/Tweak.h
@@ -127,14 +127,15 @@
 /// Calls prepare() on all tweaks that satisfy the filter, returning those that
 /// can run on the selection.
 std::vector<std::unique_ptr<Tweak>>
-prepareTweaks(const Tweak::Selection &S,
+prepareTweaks(const class FeatureModuleSet *Modules, const Tweak::Selection &S,
               llvm::function_ref<bool(const Tweak &)> Filter);
 
 // Calls prepare() on the tweak with a given ID.
 // If prepare() returns false, returns an error.
 // If prepare() returns true, returns the corresponding tweak.
-llvm::Expected<std::unique_ptr<Tweak>> prepareTweak(StringRef TweakID,
-                                                    const Tweak::Selection &S);
+llvm::Expected<std::unique_ptr<Tweak>>
+prepareTweak(StringRef ID, const Tweak::Selection &S,
+             const class FeatureModuleSet *Modules);
 } // namespace clangd
 } // namespace clang
 
Index: clang-tools-extra/clangd/refactor/Tweak.cpp
===================================================================
--- clang-tools-extra/clangd/refactor/Tweak.cpp
+++ clang-tools-extra/clangd/refactor/Tweak.cpp
@@ -6,6 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 #include "Tweak.h"
+#include "FeatureModule.h"
 #include "SourceCode.h"
 #include "index/Index.h"
 #include "support/Logger.h"
@@ -20,6 +21,7 @@
 #include <functional>
 #include <memory>
 #include <utility>
+#include <vector>
 
 LLVM_INSTANTIATE_REGISTRY(llvm::Registry<clang::clangd::Tweak>)
 
@@ -43,6 +45,18 @@
   }
 #endif
 }
+
+std::vector<std::unique_ptr<Tweak>>
+getAllTweaks(const FeatureModuleSet *Modules) {
+  std::vector<std::unique_ptr<Tweak>> All;
+  for (const auto &E : TweakRegistry::entries())
+    All.emplace_back(E.instantiate());
+  if (!Modules)
+    return All;
+  for (auto &M : *Modules)
+    M.contributeTweaks(All);
+  return All;
+}
 } // namespace
 
 Tweak::Selection::Selection(const SymbolIndex *Index, ParsedAST &AST,
@@ -56,13 +70,12 @@
 }
 
 std::vector<std::unique_ptr<Tweak>>
-prepareTweaks(const Tweak::Selection &S,
+prepareTweaks(const FeatureModuleSet *Modules, const Tweak::Selection &S,
               llvm::function_ref<bool(const Tweak &)> Filter) {
   validateRegistry();
 
   std::vector<std::unique_ptr<Tweak>> Available;
-  for (const auto &E : TweakRegistry::entries()) {
-    std::unique_ptr<Tweak> T = E.instantiate();
+  for (auto &T : getAllTweaks(Modules)) {
     if (!Filter(*T) || !T->prepare(S))
       continue;
     Available.push_back(std::move(T));
@@ -74,17 +87,17 @@
   return Available;
 }
 
-llvm::Expected<std::unique_ptr<Tweak>> prepareTweak(StringRef ID,
-                                                    const Tweak::Selection &S) {
-  auto It = llvm::find_if(
-      TweakRegistry::entries(),
-      [ID](const TweakRegistry::entry &E) { return E.getName() == ID; });
-  if (It == TweakRegistry::end())
-    return error("tweak ID {0} is invalid", ID);
-  std::unique_ptr<Tweak> T = It->instantiate();
-  if (!T->prepare(S))
-    return error("failed to prepare() tweak {0}", ID);
-  return std::move(T);
+llvm::Expected<std::unique_ptr<Tweak>>
+prepareTweak(StringRef ID, const Tweak::Selection &S,
+             const FeatureModuleSet *Modules) {
+  for (auto &T : getAllTweaks(Modules)) {
+    if (T->id() != ID)
+      continue;
+    if (!T->prepare(S))
+      return error("failed to prepare() tweak {0}", ID);
+    return std::move(T);
+  }
+  return error("tweak ID {0} is invalid", ID);
 }
 
 llvm::Expected<std::pair<Path, Edit>>
Index: clang-tools-extra/clangd/FeatureModule.h
===================================================================
--- clang-tools-extra/clangd/FeatureModule.h
+++ clang-tools-extra/clangd/FeatureModule.h
@@ -91,6 +91,11 @@
   /// Called by the server when shutting down, and also by tests.
   virtual bool blockUntilIdle(Deadline) { return true; }
 
+  /// Tweaks implemented by this module. Can be called asynchronously when
+  /// enumerating or applying code actions.
+  virtual void
+  contributeTweaks(std::vector<std::unique_ptr<class Tweak>> &Out) {}
+
 protected:
   /// Accessors for modules to access shared server facilities they depend on.
   Facilities &facilities();
Index: clang-tools-extra/clangd/ClangdServer.cpp
===================================================================
--- clang-tools-extra/clangd/ClangdServer.cpp
+++ clang-tools-extra/clangd/ClangdServer.cpp
@@ -568,8 +568,9 @@
   static constexpr trace::Metric TweakAvailable(
       "tweak_available", trace::Metric::Counter, "tweak_id");
   auto Action = [File = File.str(), Sel, CB = std::move(CB),
-                 Filter =
-                     std::move(Filter)](Expected<InputsAndAST> InpAST) mutable {
+                 Filter = std::move(Filter),
+                 FeatureModules(this->FeatureModules)](
+                    Expected<InputsAndAST> InpAST) mutable {
     if (!InpAST)
       return CB(InpAST.takeError());
     auto Selections = tweakSelection(Sel, *InpAST);
@@ -582,7 +583,7 @@
       return Filter(T) && !PreparedTweaks.count(T.id());
     };
     for (const auto &Sel : *Selections) {
-      for (auto &T : prepareTweaks(*Sel, DeduplicatingFilter)) {
+      for (auto &T : prepareTweaks(FeatureModules, *Sel, DeduplicatingFilter)) {
         Res.push_back({T->id(), T->title(), T->kind()});
         PreparedTweaks.insert(T->id());
         TweakAvailable.record(1, T->id());
@@ -617,7 +618,7 @@
     // Try each selection, take the first one that prepare()s.
     // If they all fail, Effect will hold get the last error.
     for (const auto &Selection : *Selections) {
-      auto T = prepareTweak(TweakID, *Selection);
+      auto T = prepareTweak(TweakID, *Selection, FeatureModules);
       if (T) {
         Effect = (*T)->apply(*Selection);
         break;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to