https://github.com/ArcsinX updated 
https://github.com/llvm/llvm-project/pull/154836

>From 27b44cefdc1ea4b373f8e990bc1fea05fc278701 Mon Sep 17 00:00:00 2001
From: Aleksandr Platonov <platonov.aleksa...@huawei.com>
Date: Thu, 21 Aug 2025 22:51:41 +0300
Subject: [PATCH 1/2] [clangd] Introduce feature modules registry This patch
 adds feature modules registry, which allows to discover registered feature
 modules and add them into the clangd's feature module set

---
 clang-tools-extra/clangd/FeatureModule.cpp   | 15 +++++++++++++++
 clang-tools-extra/clangd/FeatureModule.h     | 17 ++++++++++++++---
 clang-tools-extra/clangd/tool/ClangdMain.cpp |  5 +++++
 3 files changed, 34 insertions(+), 3 deletions(-)

diff --git a/clang-tools-extra/clangd/FeatureModule.cpp 
b/clang-tools-extra/clangd/FeatureModule.cpp
index 872cea1443789..38461e3db4e6b 100644
--- a/clang-tools-extra/clangd/FeatureModule.cpp
+++ b/clang-tools-extra/clangd/FeatureModule.cpp
@@ -22,6 +22,10 @@ FeatureModule::Facilities &FeatureModule::facilities() {
   return *Fac;
 }
 
+void FeatureModuleSet::add(std::unique_ptr<FeatureModule> M) {
+  Modules.push_back(std::move(M));
+}
+
 bool FeatureModuleSet::addImpl(void *Key, std::unique_ptr<FeatureModule> M,
                                const char *Source) {
   if (!Map.try_emplace(Key, M.get()).second) {
@@ -33,5 +37,16 @@ bool FeatureModuleSet::addImpl(void *Key, 
std::unique_ptr<FeatureModule> M,
   return true;
 }
 
+FeatureModuleSet FeatureModuleSet::fromRegistry() {
+  FeatureModuleSet ModuleSet;
+  for (FeatureModuleRegistry::entry E : FeatureModuleRegistry::entries()) {
+    vlog("Adding feature module '{0}' ({1})", E.getName(), E.getDesc());
+    ModuleSet.add(E.instantiate());
+  }
+  return ModuleSet;
+}
+
 } // namespace clangd
 } // namespace clang
+
+LLVM_INSTANTIATE_REGISTRY(clang::clangd::FeatureModuleRegistry)
diff --git a/clang-tools-extra/clangd/FeatureModule.h 
b/clang-tools-extra/clangd/FeatureModule.h
index 7b6883507be3f..ee65aa8a59ed2 100644
--- a/clang-tools-extra/clangd/FeatureModule.h
+++ b/clang-tools-extra/clangd/FeatureModule.h
@@ -15,6 +15,7 @@
 #include "llvm/ADT/FunctionExtras.h"
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/JSON.h"
+#include "llvm/Support/Registry.h"
 #include <memory>
 #include <optional>
 #include <type_traits>
@@ -143,9 +144,14 @@ class FeatureModule {
 
 /// A FeatureModuleSet is a collection of feature modules installed in clangd.
 ///
-/// Modules can be looked up by type, or used via the FeatureModule interface.
-/// This allows individual modules to expose a public API.
-/// For this reason, there can be only one feature module of each type.
+/// Modules added with explicit type specification can be looked up by type, or
+/// used via the FeatureModule interface. This allows individual modules to
+/// expose a public API. For this reason, there can be only one feature module
+/// of each type.
+///
+/// Modules added using a base class pointer can be used only via the
+/// FeatureModule interface and can't be looked up by type, thus custom public
+/// API (if provided by the module) can't be used.
 ///
 /// The set owns the modules. It is itself owned by main, not ClangdServer.
 class FeatureModuleSet {
@@ -164,6 +170,8 @@ class FeatureModuleSet {
 public:
   FeatureModuleSet() = default;
 
+  static FeatureModuleSet fromRegistry();
+
   using iterator = llvm::pointee_iterator<decltype(Modules)::iterator>;
   using const_iterator =
       llvm::pointee_iterator<decltype(Modules)::const_iterator>;
@@ -172,6 +180,7 @@ class FeatureModuleSet {
   const_iterator begin() const { return const_iterator(Modules.begin()); }
   const_iterator end() const { return const_iterator(Modules.end()); }
 
+  void add(std::unique_ptr<FeatureModule> M);
   template <typename Mod> bool add(std::unique_ptr<Mod> M) {
     return addImpl(&ID<Mod>::Key, std::move(M), LLVM_PRETTY_FUNCTION);
   }
@@ -185,6 +194,8 @@ class FeatureModuleSet {
 
 template <typename Mod> int FeatureModuleSet::ID<Mod>::Key;
 
+using FeatureModuleRegistry = llvm::Registry<FeatureModule>;
+
 } // namespace clangd
 } // namespace clang
 #endif
diff --git a/clang-tools-extra/clangd/tool/ClangdMain.cpp 
b/clang-tools-extra/clangd/tool/ClangdMain.cpp
index f287439f10cab..1856d4f47ffc5 100644
--- a/clang-tools-extra/clangd/tool/ClangdMain.cpp
+++ b/clang-tools-extra/clangd/tool/ClangdMain.cpp
@@ -13,6 +13,7 @@
 #include "Config.h"
 #include "ConfigProvider.h"
 #include "Feature.h"
+#include "FeatureModule.h"
 #include "IncludeCleaner.h"
 #include "PathMapping.h"
 #include "Protocol.h"
@@ -1017,6 +1018,10 @@ clangd accepts flags on the commandline, and in the 
CLANGD_FLAGS environment var
                : static_cast<int>(ErrorResultCode::CheckFailed);
   }
 
+  FeatureModuleSet ModuleSet = FeatureModuleSet::fromRegistry();
+  if (ModuleSet.begin() != ModuleSet.end())
+    Opts.FeatureModules = &ModuleSet;
+
   // Initialize and run ClangdLSPServer.
   // Change stdin to binary to not lose \r\n on windows.
   llvm::sys::ChangeStdinToBinary();

>From c0961a4094a355539989fc4ed54bdfda1fb3047c Mon Sep 17 00:00:00 2001
From: Aleksandr Platonov <platonov.aleksa...@huawei.com>
Date: Wed, 27 Aug 2025 23:23:06 +0300
Subject: [PATCH 2/2] Add feature modules registry test

---
 clang-tools-extra/clangd/FeatureModule.h      |  5 ++
 .../clangd/unittests/CMakeLists.txt           |  5 ++
 .../unittests/FeatureModulesRegistryTests.cpp | 66 +++++++++++++++++++
 .../unittests/feature-modules/CMakeLists.txt  |  2 +
 .../unittests/feature-modules/ForceLinker.h   | 20 ++++++
 .../feature-modules/dummy/CMakeLists.txt      |  2 +
 .../dummy/DummyFeatureModule.cpp              | 41 ++++++++++++
 7 files changed, 141 insertions(+)
 create mode 100644 
clang-tools-extra/clangd/unittests/FeatureModulesRegistryTests.cpp
 create mode 100644 
clang-tools-extra/clangd/unittests/feature-modules/CMakeLists.txt
 create mode 100644 
clang-tools-extra/clangd/unittests/feature-modules/ForceLinker.h
 create mode 100644 
clang-tools-extra/clangd/unittests/feature-modules/dummy/CMakeLists.txt
 create mode 100644 
clang-tools-extra/clangd/unittests/feature-modules/dummy/DummyFeatureModule.cpp

diff --git a/clang-tools-extra/clangd/FeatureModule.h 
b/clang-tools-extra/clangd/FeatureModule.h
index ee65aa8a59ed2..55ca908a6ec51 100644
--- a/clang-tools-extra/clangd/FeatureModule.h
+++ b/clang-tools-extra/clangd/FeatureModule.h
@@ -198,4 +198,9 @@ using FeatureModuleRegistry = llvm::Registry<FeatureModule>;
 
 } // namespace clangd
 } // namespace clang
+
+namespace llvm {
+extern template class Registry<clang::clangd::FeatureModule>;
+} // namespace llvm
+
 #endif
diff --git a/clang-tools-extra/clangd/unittests/CMakeLists.txt 
b/clang-tools-extra/clangd/unittests/CMakeLists.txt
index 9656eeaeb37ce..9dd5f8b3b9204 100644
--- a/clang-tools-extra/clangd/unittests/CMakeLists.txt
+++ b/clang-tools-extra/clangd/unittests/CMakeLists.txt
@@ -54,6 +54,7 @@ add_unittest(ClangdUnitTests ClangdTests
   DumpASTTests.cpp
   ExpectedTypeTest.cpp
   FeatureModulesTests.cpp
+  FeatureModulesRegistryTests.cpp
   FileDistanceTests.cpp
   FileIndexTests.cpp
   FindSymbolsTests.cpp
@@ -154,6 +155,8 @@ target_include_directories(ClangdTests PUBLIC
   $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>
 )
 
+add_subdirectory(feature-modules)
+
 clang_target_link_libraries(ClangdTests
   PRIVATE
   clangAST
@@ -183,6 +186,8 @@ target_link_libraries(ClangdTests
   clangTidy
   clangTidyUtils
   clangdSupport
+
+  ${FEATURE_MODULES}
   )
 
 if (CLANGD_ENABLE_REMOTE)
diff --git a/clang-tools-extra/clangd/unittests/FeatureModulesRegistryTests.cpp 
b/clang-tools-extra/clangd/unittests/FeatureModulesRegistryTests.cpp
new file mode 100644
index 0000000000000..0495897a8079f
--- /dev/null
+++ b/clang-tools-extra/clangd/unittests/FeatureModulesRegistryTests.cpp
@@ -0,0 +1,66 @@
+//===--- FeatureModulesRegistryTests.cpp  
---------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "FeatureModule.h"
+#include "feature-modules/ForceLinker.h" // IWYU pragma: keep
+#include "refactor/Tweak.h"
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+using testing::ElementsAre;
+
+namespace llvm {
+raw_ostream &operator<<(raw_ostream &OS,
+                        const clang::clangd::FeatureModuleRegistry::entry &E) {
+  OS << "(name = " << E.getName() << ", description = '" << E.getDesc() << 
"')";
+  return OS;
+}
+
+raw_ostream &operator<<(
+    raw_ostream &OS,
+    const iterator_range<Registry<clang::clangd::FeatureModule>::iterator>
+        &Rng) {
+  OS << "{ ";
+  bool First = true;
+  for (clang::clangd::FeatureModuleRegistry::entry E : Rng) {
+    if (First)
+      First = false;
+    else
+      OS << ", ";
+    OS << E;
+  }
+  OS << " }";
+  return OS;
+}
+
+raw_ostream &operator<<(raw_ostream &OS, const clang::clangd::Tweak &T) {
+  OS << "(id = " << T.id() << ", "
+     << "title = " << T.title() << ")";
+  return OS;
+}
+} // namespace llvm
+
+namespace clang::clangd {
+namespace {
+
+MATCHER_P(moduleName, Name, "") { return arg.getName() == Name; }
+MATCHER_P(tweakID, ID, "") { return arg->id() == ID; }
+
+TEST(FeatureModulesRegistryTest, DummyModule) {
+  EXPECT_THAT(FeatureModuleRegistry::entries(),
+              ElementsAre(moduleName("dummy")));
+  FeatureModuleSet Set = FeatureModuleSet::fromRegistry();
+  ASSERT_EQ(Set.end() - Set.begin(), 1u);
+  std::vector<std::unique_ptr<Tweak>> Tweaks;
+  Set.begin()->contributeTweaks(Tweaks);
+  EXPECT_THAT(Tweaks, ElementsAre(tweakID("DummyTweak")));
+}
+
+} // namespace
+} // namespace clang::clangd
diff --git a/clang-tools-extra/clangd/unittests/feature-modules/CMakeLists.txt 
b/clang-tools-extra/clangd/unittests/feature-modules/CMakeLists.txt
new file mode 100644
index 0000000000000..e7a3757d56447
--- /dev/null
+++ b/clang-tools-extra/clangd/unittests/feature-modules/CMakeLists.txt
@@ -0,0 +1,2 @@
+add_subdirectory(dummy)
+set(FEATURE_MODULES ${FEATURE_MODULES} PARENT_SCOPE)
diff --git a/clang-tools-extra/clangd/unittests/feature-modules/ForceLinker.h 
b/clang-tools-extra/clangd/unittests/feature-modules/ForceLinker.h
new file mode 100644
index 0000000000000..85bc0b7638a37
--- /dev/null
+++ b/clang-tools-extra/clangd/unittests/feature-modules/ForceLinker.h
@@ -0,0 +1,20 @@
+//===- ForceLinker.h 
----------------------------------------------*-C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_UNITTEST_FEATURE_MODULES_FORCE_LINKER_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_UNITTEST_FEATURE_MODULES_FORCE_LINKER_H
+
+#include "llvm/Support/Compiler.h"
+
+namespace clang::clangd {
+extern volatile int DummyFeatureModuleAnchorSource;
+static int LLVM_ATTRIBUTE_UNUSED DummyFeatureModuleAnchorDestination =
+    DummyFeatureModuleAnchorSource;
+} // namespace clang::clangd
+
+#endif
diff --git 
a/clang-tools-extra/clangd/unittests/feature-modules/dummy/CMakeLists.txt 
b/clang-tools-extra/clangd/unittests/feature-modules/dummy/CMakeLists.txt
new file mode 100644
index 0000000000000..7a4a8de44bca7
--- /dev/null
+++ b/clang-tools-extra/clangd/unittests/feature-modules/dummy/CMakeLists.txt
@@ -0,0 +1,2 @@
+add_llvm_library(dummyFeatureModule DummyFeatureModule.cpp)
+set(FEATURE_MODULES ${FEATURE_MODULES} dummyFeatureModule PARENT_SCOPE)
diff --git 
a/clang-tools-extra/clangd/unittests/feature-modules/dummy/DummyFeatureModule.cpp
 
b/clang-tools-extra/clangd/unittests/feature-modules/dummy/DummyFeatureModule.cpp
new file mode 100644
index 0000000000000..f1e65f46d0bac
--- /dev/null
+++ 
b/clang-tools-extra/clangd/unittests/feature-modules/dummy/DummyFeatureModule.cpp
@@ -0,0 +1,41 @@
+//===--- DummyFeatureModule.cpp 
-------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "FeatureModule.h"
+#include "refactor/Tweak.h"
+#include "support/Logger.h"
+
+namespace clang::clangd {
+
+class Dummy final : public FeatureModule {
+  static constexpr const char *TweakID = "DummyTweak";
+  struct DummyTweak final : public Tweak {
+    const char *id() const override { return TweakID; }
+    bool prepare(const Selection &) override { return true; }
+    Expected<Effect> apply(const Selection &) override {
+      return error("not implemented");
+    }
+    std::string title() const override { return id(); }
+    llvm::StringLiteral kind() const override {
+      return llvm::StringLiteral("");
+    };
+  };
+
+  void contributeTweaks(std::vector<std::unique_ptr<Tweak>> &Out) override {
+    Out.emplace_back(new DummyTweak);
+  }
+};
+
+static FeatureModuleRegistry::Add<Dummy>
+    X("dummy", "Dummy feature module with dummy tweak");
+
+// This anchor is used to force the linker to link in the generated object file
+// and thus register the Dummy feature module.
+volatile int DummyFeatureModuleAnchorSource = 0;
+
+} // namespace clang::clangd

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to