[clang-tools-extra] [clangd] Add dynamic plugins support (PR #226995)
Aleksandr Platonov via cfe-commits
cfe-commits at lists.llvm.org
Tue Sep 29 05:33:21 PDT 2026
https://github.com/ArcsinX updated https://github.com/llvm/llvm-project/pull/226995
>From e535c83df43ab3da72246f96a3fc6c2a7ce23cfa Mon Sep 17 00:00:00 2001
From: Aleksandr Platonov <arcsinx45 at gmail.com>
Date: Thu, 24 Sep 2026 23:33:25 +0300
Subject: [PATCH 1/7] [clangd][FeatureModule] Allow dynamic loading
---
clang-tools-extra/clangd/CMakeLists.txt | 5 +
clang-tools-extra/clangd/FeatureModule.cpp | 13 +++
clang-tools-extra/clangd/FeatureModule.h | 7 ++
.../clangd/examples/CMakeLists.txt | 1 +
.../SampleFeatureModule/CMakeLists.txt | 34 ++++++
.../examples/SampleFeatureModule/README.md | 78 ++++++++++++++
.../SampleFeatureModule.cpp | 100 ++++++++++++++++++
clang-tools-extra/clangd/test/CMakeLists.txt | 22 ++++
.../clangd/test/FeatureModuleExample.cpp | 42 ++++++++
.../clangd/test/feature-module.test | 14 +++
clang-tools-extra/clangd/test/lit.cfg.py | 5 +
.../clangd/test/lit.site.cfg.py.in | 2 +
clang-tools-extra/clangd/tool/CMakeLists.txt | 10 ++
clang-tools-extra/clangd/tool/ClangdMain.cpp | 16 ++-
.../unittests/FeatureModulesRegistryTests.cpp | 13 ++-
15 files changed, 354 insertions(+), 8 deletions(-)
create mode 100644 clang-tools-extra/clangd/examples/CMakeLists.txt
create mode 100644 clang-tools-extra/clangd/examples/SampleFeatureModule/CMakeLists.txt
create mode 100644 clang-tools-extra/clangd/examples/SampleFeatureModule/README.md
create mode 100644 clang-tools-extra/clangd/examples/SampleFeatureModule/SampleFeatureModule.cpp
create mode 100644 clang-tools-extra/clangd/test/FeatureModuleExample.cpp
create mode 100644 clang-tools-extra/clangd/test/feature-module.test
diff --git a/clang-tools-extra/clangd/CMakeLists.txt b/clang-tools-extra/clangd/CMakeLists.txt
index 3aa1b7bddb994e..e2da91b8968e5c 100644
--- a/clang-tools-extra/clangd/CMakeLists.txt
+++ b/clang-tools-extra/clangd/CMakeLists.txt
@@ -233,3 +233,8 @@ add_subdirectory(index/remote)
if(CLANGD_BUILD_DEXP)
add_subdirectory(index/dex/dexp)
endif()
+
+option(CLANGD_BUILD_EXAMPLES "Build clangd examples" OFF)
+if(CLANGD_BUILD_EXAMPLES)
+ add_subdirectory(examples)
+endif()
diff --git a/clang-tools-extra/clangd/FeatureModule.cpp b/clang-tools-extra/clangd/FeatureModule.cpp
index 38461e3db4e6bd..dd72a6dd6c6cbe 100644
--- a/clang-tools-extra/clangd/FeatureModule.cpp
+++ b/clang-tools-extra/clangd/FeatureModule.cpp
@@ -8,6 +8,8 @@
#include "FeatureModule.h"
#include "support/Logger.h"
+#include "llvm/Support/DynamicLibrary.h"
+#include "llvm/Support/Error.h"
namespace clang {
namespace clangd {
@@ -46,6 +48,17 @@ FeatureModuleSet FeatureModuleSet::fromRegistry() {
return ModuleSet;
}
+llvm::Error loadFeatureModule(llvm::StringRef SharedLibraryPath) {
+ std::string Err;
+ if (llvm::sys::DynamicLibrary::LoadLibraryPermanently(
+ SharedLibraryPath.str().c_str(), &Err))
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "Failed to load feature module '%s': %s",
+ SharedLibraryPath.str().c_str(),
+ Err.c_str());
+ return llvm::Error::success();
+}
+
} // namespace clangd
} // namespace clang
diff --git a/clang-tools-extra/clangd/FeatureModule.h b/clang-tools-extra/clangd/FeatureModule.h
index 90714fe9101a83..0b3ba894ae3871 100644
--- a/clang-tools-extra/clangd/FeatureModule.h
+++ b/clang-tools-extra/clangd/FeatureModule.h
@@ -14,6 +14,7 @@
#include "clang/Basic/Diagnostic.h"
#include "llvm/ADT/FunctionExtras.h"
#include "llvm/Support/Compiler.h"
+#include "llvm/Support/Error.h"
#include "llvm/Support/JSON.h"
#include "llvm/Support/Registry.h"
#include <memory>
@@ -215,6 +216,12 @@ template <typename Mod> int FeatureModuleSet::ID<Mod>::Key;
using FeatureModuleRegistry = llvm::Registry<FeatureModule>;
+/// Dynamically load a feature module from a shared library.
+/// The shared library is expected to register one or more FeatureModules
+/// via FeatureModuleRegistry.
+/// Returns an Error if the library could not be loaded.
+llvm::Error loadFeatureModule(llvm::StringRef SharedLibraryPath);
+
} // namespace clangd
} // namespace clang
diff --git a/clang-tools-extra/clangd/examples/CMakeLists.txt b/clang-tools-extra/clangd/examples/CMakeLists.txt
new file mode 100644
index 00000000000000..42c3c05d146087
--- /dev/null
+++ b/clang-tools-extra/clangd/examples/CMakeLists.txt
@@ -0,0 +1 @@
+add_subdirectory(SampleFeatureModule)
diff --git a/clang-tools-extra/clangd/examples/SampleFeatureModule/CMakeLists.txt b/clang-tools-extra/clangd/examples/SampleFeatureModule/CMakeLists.txt
new file mode 100644
index 00000000000000..eaee5d017d3400
--- /dev/null
+++ b/clang-tools-extra/clangd/examples/SampleFeatureModule/CMakeLists.txt
@@ -0,0 +1,34 @@
+if(NOT DEFINED LLVM_MAIN_SRC_DIR)
+ cmake_minimum_required(VERSION 3.20)
+ project(SampleFeatureModule)
+
+ find_package(LLVM REQUIRED CONFIG)
+ find_package(Clang REQUIRED CONFIG)
+
+ list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_DIR}")
+ include(AddLLVM)
+
+ include_directories(${LLVM_INCLUDE_DIRS} ${CLANG_INCLUDE_DIRS})
+ link_directories(${LLVM_LIBDIR_SUFFIX})
+
+ add_llvm_library(SampleFeatureModule MODULE
+ SampleFeatureModule.cpp
+ PLUGIN_TOOL clangd
+ )
+else()
+ add_llvm_library(SampleFeatureModule MODULE
+ SampleFeatureModule.cpp
+ PLUGIN_TOOL clangd
+ )
+
+ target_include_directories(SampleFeatureModule PRIVATE
+ "${CMAKE_CURRENT_SOURCE_DIR}/../../"
+ "${CMAKE_CURRENT_BINARY_DIR}/../../"
+ )
+
+ if(WIN32 OR CYGWIN)
+ set(LLVM_LINK_COMPONENTS
+ Support
+ )
+ endif()
+endif()
diff --git a/clang-tools-extra/clangd/examples/SampleFeatureModule/README.md b/clang-tools-extra/clangd/examples/SampleFeatureModule/README.md
new file mode 100644
index 00000000000000..ac8c180d49afbf
--- /dev/null
+++ b/clang-tools-extra/clangd/examples/SampleFeatureModule/README.md
@@ -0,0 +1,78 @@
+# Sample Dynamic FeatureModule for Clangd
+
+This example demonstrates how to implement, build, and load a **dynamic `FeatureModule`** plugin into `clangd`.
+
+## Background
+
+Clangd supports vertical extensions via `FeatureModule`s. Previously, `FeatureModule`s could only be linked statically into the `clangd` binary. With dynamic loading support, feature modules can be compiled into independent shared libraries (`.so` / `.dylib` / `.dll`) and loaded at runtime into `clangd` via the standard LLVM `-load` command-line option.
+
+When a plugin shared library is loaded:
+1. Static initializers in the shared library run.
+2. `FeatureModuleRegistry::Add<MyModule> X("name", "description")` registers the module with `FeatureModuleRegistry`.
+3. Clangd queries `FeatureModuleSet::fromRegistry()`, which instantiates all registered feature modules and integrates them into the LSP server.
+
+## Features demonstrated in this example
+
+- **Tweaks (Code Actions)**: Contributes a custom code action tweak (`SampleModuleTweak`) that appears in editors.
+- **AST Listeners**: Observes AST building lifecycle events (`beforeExecute`, `afterExecute`) and diagnostics (`sawDiagnostic`).
+- **LSP Bindings**: Demonstrates how to register custom LSP methods, notifications, or commands via `LSPBinder` and modify server capabilities in `initializeLSP`.
+
+## How to Build
+
+### In-tree Build
+
+To build this example as part of LLVM / Clang:
+
+1. Configure LLVM with examples enabled:
+ ```bash
+ cmake -B build -S llvm -DCLANGD_BUILD_EXAMPLES=ON [other options...]
+ ```
+2. Build the plugin:
+ ```bash
+ ninja -C build SampleFeatureModule
+ ```
+ The shared library will be built in `build/lib/SampleFeatureModule.so` (or `.dylib` on macOS).
+
+### Out-of-tree Build
+
+You can also build feature modules against an installed LLVM / Clang toolchain:
+
+```bash
+mkdir build && cd build
+cmake -DCMAKE_PREFIX_PATH=/path/to/llvm/installation ..
+cmake --build .
+```
+
+## How to Use with Clangd
+
+### Check Mode
+
+You can test that your module is loaded and functioning using `clangd --check`:
+
+```bash
+clangd -check=test.cpp -load=/path/to/SampleFeatureModule.so -log=verbose
+```
+
+Output will show:
+```
+Loaded plugin: /path/to/SampleFeatureModule.so
+Adding feature module 'sample-feature-module' (Example feature module demonstrating dynamic loading into clangd)
+...
+ tweak: SampleModuleTweak
+```
+
+### Editor Integration
+
+Pass `-load=/path/to/SampleFeatureModule.so` to the `clangd` arguments in your editor configuration:
+
+- **VS Code** (`settings.json`):
+ ```json
+ "clangd.arguments": [
+ "--load=/path/to/SampleFeatureModule.so"
+ ]
+ ```
+- **Environment Variable**:
+ You can also pass arguments via the `CLANGD_FLAGS` environment variable:
+ ```bash
+ export CLANGD_FLAGS="--load=/path/to/SampleFeatureModule.so"
+ ```
diff --git a/clang-tools-extra/clangd/examples/SampleFeatureModule/SampleFeatureModule.cpp b/clang-tools-extra/clangd/examples/SampleFeatureModule/SampleFeatureModule.cpp
new file mode 100644
index 00000000000000..6ae690a14eb15b
--- /dev/null
+++ b/clang-tools-extra/clangd/examples/SampleFeatureModule/SampleFeatureModule.cpp
@@ -0,0 +1,100 @@
+//===--- SampleFeatureModule.cpp - Example Clangd Feature Module ----------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements an example FeatureModule for clangd that can be
+// dynamically loaded into clangd at runtime via the `-load` option:
+//
+// clangd -load=/path/to/SampleFeatureModule.so
+//
+// When loaded, the module registers itself with clangd's FeatureModuleRegistry
+// and demonstrates:
+// 1. Contributing custom code action tweaks (Tweak).
+// 2. Observing AST builds and diagnostics via ASTListener.
+// 3. Registering custom LSP method/command handlers via LSPBinder.
+//
+//===----------------------------------------------------------------------===//
+
+#include "FeatureModule.h"
+#include "LSPBinder.h"
+#include "refactor/Tweak.h"
+#include "support/Logger.h"
+
+namespace clang::clangd {
+namespace {
+
+/// An example code action tweak contributed by the feature module.
+class SampleTweak final : public Tweak {
+public:
+ const char *id() const override { return "SampleModuleTweak"; }
+
+ bool prepare(const Selection &Sel) override {
+ // This tweak is available anywhere in the file.
+ return true;
+ }
+
+ Expected<Effect> apply(const Selection &Sel) override {
+ return Effect::showMessage("Sample FeatureModule tweak executed!");
+ }
+
+ std::string title() const override {
+ return "Execute Sample FeatureModule action";
+ }
+
+ llvm::StringLiteral kind() const override {
+ return llvm::StringLiteral("quickfix");
+ }
+};
+
+/// An example AST listener that observes AST construction events.
+class SampleASTListener final : public FeatureModule::ASTListener {
+public:
+ void beforeExecute(CompilerInstance &CI) override {
+ vlog("SampleFeatureModule: before AST execution");
+ }
+
+ void afterExecute(CompilerInstance &CI) override {
+ vlog("SampleFeatureModule: after AST execution");
+ }
+
+ void sawDiagnostic(const clang::Diagnostic &Diag, clangd::Diag &D) override {
+ vlog("SampleFeatureModule: observed diagnostic '{0}'", D.Message);
+ }
+};
+
+/// The main feature module class.
+class SampleFeatureModule final : public FeatureModule {
+public:
+ /// Contribute custom tweaks to clangd's code action list.
+ void contributeTweaks(std::vector<std::unique_ptr<Tweak>> &Out) override {
+ Out.emplace_back(new SampleTweak);
+ }
+
+ /// Hook into AST creation to observe AST events and diagnostics.
+ std::unique_ptr<ASTListener> astListeners() override {
+ return std::make_unique<SampleASTListener>();
+ }
+
+ /// Register custom LSP endpoints or update server capabilities.
+ void initializeLSP(LSPBinder &Bind,
+ const llvm::json::Object &ClientCaps,
+ llvm::json::Object &ServerCaps) override {
+ vlog("SampleFeatureModule: initializeLSP called");
+ // Example: Bind a custom LSP method or notification if needed:
+ // Bind.method("sample/customMethod", this, &SampleFeatureModule::onCustomMethod);
+ }
+};
+
+// Register the module with clangd's FeatureModuleRegistry.
+// When clangd loads this shared library via -load, this static initializer
+// will run and add the module to clangd's registry.
+static FeatureModuleRegistry::Add<SampleFeatureModule>
+ X("sample-feature-module",
+ "Example feature module demonstrating dynamic loading into clangd");
+
+} // namespace
+} // namespace clang::clangd
diff --git a/clang-tools-extra/clangd/test/CMakeLists.txt b/clang-tools-extra/clangd/test/CMakeLists.txt
index 608835cab2fc5e..17f95f8abc005e 100644
--- a/clang-tools-extra/clangd/test/CMakeLists.txt
+++ b/clang-tools-extra/clangd/test/CMakeLists.txt
@@ -30,6 +30,28 @@ foreach(dep FileCheck count not llvm-config)
endif()
endforeach()
+if (NOT WIN32 OR NOT LLVM_LINK_LLVM_DYLIB)
+ llvm_add_library(
+ ClangdFeatureModuleExample
+ MODULE FeatureModuleExample.cpp
+ PLUGIN_TOOL clangd)
+endif()
+
+if(TARGET ClangdFeatureModuleExample)
+ list(APPEND CLANGD_TEST_DEPS ClangdFeatureModuleExample)
+ target_include_directories(ClangdFeatureModuleExample PUBLIC BEFORE
+ "${CLANG_TOOLS_SOURCE_DIR}/clangd"
+ "${CMAKE_CURRENT_BINARY_DIR}/.."
+ )
+ if(CLANG_PLUGIN_SUPPORT AND (WIN32 OR CYGWIN))
+ set(LLVM_LINK_COMPONENTS
+ Support
+ )
+ endif()
+endif()
+
+llvm_canonicalize_cmake_booleans(CLANG_PLUGIN_SUPPORT)
+
configure_lit_site_cfg(
${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.py.in
${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg.py
diff --git a/clang-tools-extra/clangd/test/FeatureModuleExample.cpp b/clang-tools-extra/clangd/test/FeatureModuleExample.cpp
new file mode 100644
index 00000000000000..e1e86678f30f53
--- /dev/null
+++ b/clang-tools-extra/clangd/test/FeatureModuleExample.cpp
@@ -0,0 +1,42 @@
+//===--- FeatureModuleExample.cpp - Example dynamic FeatureModule ---------===//
+//
+// 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 {
+namespace {
+
+/// An example tweak contributed by the dynamic feature module.
+class ExampleModuleTweak final : public Tweak {
+public:
+ const char *id() const override { return "ExampleModuleTweak"; }
+ bool prepare(const Selection &) override { return true; }
+ Expected<Effect> apply(const Selection &) override {
+ return Effect::showMessage("Example module tweak executed");
+ }
+ std::string title() const override { return "Execute example module action"; }
+ llvm::StringLiteral kind() const override {
+ return llvm::StringLiteral("quickfix");
+ }
+};
+
+/// An example FeatureModule loaded dynamically into clangd.
+class ExampleFeatureModule final : public FeatureModule {
+public:
+ void contributeTweaks(std::vector<std::unique_ptr<Tweak>> &Out) override {
+ Out.emplace_back(new ExampleModuleTweak);
+ }
+};
+
+static FeatureModuleRegistry::Add<ExampleFeatureModule>
+ X("example-feature-module", "Example clangd feature module");
+
+} // namespace
+} // namespace clang::clangd
diff --git a/clang-tools-extra/clangd/test/feature-module.test b/clang-tools-extra/clangd/test/feature-module.test
new file mode 100644
index 00000000000000..e25cf8933f6ff8
--- /dev/null
+++ b/clang-tools-extra/clangd/test/feature-module.test
@@ -0,0 +1,14 @@
+// REQUIRES: plugins
+// RUN: clangd --help | FileCheck --check-prefix=CHECK-HELP %s
+// CHECK-HELP: --load=<pluginfilename> - Load the specified plugin
+
+// RUN: cp %s %t.cpp
+// RUN: clangd -enable-config=0 -log=verbose -check=%t.cpp -load=%llvmshlibdir/ClangdFeatureModuleExample%pluginext 2>&1 | FileCheck -strict-whitespace %s
+
+// CHECK: Loaded plugin: {{.*}}ClangdFeatureModuleExample{{.*}}
+// CHECK: Adding feature module 'example-feature-module' (Example clangd feature module)
+// CHECK: Testing features at each token
+// CHECK-DAG: tweak: ExampleModuleTweak
+// CHECK: All checks completed, 0 errors
+
+int x = 42;
diff --git a/clang-tools-extra/clangd/test/lit.cfg.py b/clang-tools-extra/clangd/test/lit.cfg.py
index aac3a938353e8c..f56a73b56a9113 100644
--- a/clang-tools-extra/clangd/test/lit.cfg.py
+++ b/clang-tools-extra/clangd/test/lit.cfg.py
@@ -43,6 +43,11 @@ def calculate_arch_features(arch_string):
if lit.util.pythonize_bool(config.have_benchmarks):
config.available_features.add("have-benchmarks")
+# Plugins (loadable modules)
+if config.has_plugins and config.llvm_plugin_ext:
+ config.available_features.add("plugins")
+ config.substitutions.append(("%pluginext", config.llvm_plugin_ext))
+
# It is not realistically possible to account for all options that could
# possibly be present in system and user configuration files, so disable
# default configs for the test runs.
diff --git a/clang-tools-extra/clangd/test/lit.site.cfg.py.in b/clang-tools-extra/clangd/test/lit.site.cfg.py.in
index f5ae3eb1f0743d..650006b8b72f57 100644
--- a/clang-tools-extra/clangd/test/lit.site.cfg.py.in
+++ b/clang-tools-extra/clangd/test/lit.site.cfg.py.in
@@ -20,6 +20,8 @@ config.clangd_enable_remote = @CLANGD_ENABLE_REMOTE@
config.clangd_tidy_checks = @CLANGD_TIDY_CHECKS@
config.have_zlib = @LLVM_ENABLE_ZLIB@
config.have_benchmarks = "@LLVM_INCLUDE_BENCHMARKS@"
+config.has_plugins = @CLANG_PLUGIN_SUPPORT@
+config.llvm_plugin_ext = "@LLVM_PLUGIN_EXT@"
# Delegate logic to lit.cfg.py.
lit_config.load_config(config, "@CMAKE_CURRENT_SOURCE_DIR@/lit.cfg.py")
diff --git a/clang-tools-extra/clangd/tool/CMakeLists.txt b/clang-tools-extra/clangd/tool/CMakeLists.txt
index 1bd6a1f864dd3b..bae511341219f0 100644
--- a/clang-tools-extra/clangd/tool/CMakeLists.txt
+++ b/clang-tools-extra/clangd/tool/CMakeLists.txt
@@ -9,9 +9,15 @@ add_clang_library(clangdMain STATIC
DISABLE_PCH_REUSE
)
+# Support plugins.
+if(CLANG_PLUGIN_SUPPORT)
+ set(support_plugins SUPPORT_PLUGINS)
+endif()
+
add_clang_tool(clangd
ClangdToolMain.cpp
$<TARGET_OBJECTS:obj.clangDaemonTweaks>
+ ${support_plugins}
)
set(LLVM_LINK_COMPONENTS
@@ -61,3 +67,7 @@ target_link_libraries(clangd
clangDaemon
clangdSupport
)
+
+if(CLANG_PLUGIN_SUPPORT)
+ export_executable_symbols_for_plugins(clangd)
+endif()
diff --git a/clang-tools-extra/clangd/tool/ClangdMain.cpp b/clang-tools-extra/clangd/tool/ClangdMain.cpp
index 13fe4d3911731d..dc0e1be1e69461 100644
--- a/clang-tools-extra/clangd/tool/ClangdMain.cpp
+++ b/clang-tools-extra/clangd/tool/ClangdMain.cpp
@@ -38,6 +38,7 @@
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/InitLLVM.h"
#include "llvm/Support/Path.h"
+#include "llvm/Support/PluginLoader.h" // IWYU pragma: keep
#include "llvm/Support/Process.h"
#include "llvm/Support/Program.h"
#include "llvm/Support/Signals.h"
@@ -795,6 +796,11 @@ It should be used via an editor plugin rather than invoked directly. For more in
clangd accepts flags on the commandline, and in the CLANGD_FLAGS environment variable.
)";
+ // Enable help for -load option, if plugins are enabled.
+ if (llvm::cl::Option *LoadOpt =
+ llvm::cl::getRegisteredOptions().lookup("load"))
+ LoadOpt->addCategory(Features);
+
llvm::cl::HideUnrelatedOptions(ClangdCategories);
llvm::cl::ParseCommandLineOptions(argc, argv, Overview, /*Errs=*/nullptr,
/*VFS=*/nullptr, FlagsEnvVar);
@@ -910,6 +916,8 @@ clangd accepts flags on the commandline, and in the CLANGD_FLAGS environment var
}
for (int I = 0; I < argc; ++I)
log("argv[{0}]: {1}", I, argv[I]);
+ for (unsigned I = 0, E = llvm::PluginLoader::getNumPlugins(); I < E; ++I)
+ log("Loaded plugin: {0}", llvm::PluginLoader::getPlugin(I));
if (auto EnvFlags = llvm::sys::Process::GetEnv(FlagsEnvVar))
log("{0}: {1}", FlagsEnvVar, *EnvFlags);
// Log environment variables that influence how clangd finds system headers.
@@ -1047,6 +1055,10 @@ clangd accepts flags on the commandline, and in the CLANGD_FLAGS environment var
if (ForceOffsetEncoding != OffsetEncoding::UnsupportedEncoding)
Opts.Encoding = ForceOffsetEncoding;
+ FeatureModuleSet ModuleSet = FeatureModuleSet::fromRegistry();
+ if (ModuleSet.begin() != ModuleSet.end())
+ Opts.FeatureModules = &ModuleSet;
+
if (CheckFile.getNumOccurrences()) {
llvm::SmallString<256> Path;
if (auto Error =
@@ -1060,10 +1072,6 @@ 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();
diff --git a/clang-tools-extra/clangd/unittests/FeatureModulesRegistryTests.cpp b/clang-tools-extra/clangd/unittests/FeatureModulesRegistryTests.cpp
index b8941cdb4b1783..936070220c0aa5 100644
--- a/clang-tools-extra/clangd/unittests/FeatureModulesRegistryTests.cpp
+++ b/clang-tools-extra/clangd/unittests/FeatureModulesRegistryTests.cpp
@@ -74,10 +74,9 @@ static FeatureModuleRegistry::Add<Dummy>
MATCHER_P(moduleName, Name, "") { return arg.getName() == Name; }
MATCHER_P(tweakID, ID, "") { return arg->id() == llvm::StringRef(ID); }
-// In this test, it is assumed that for unittests executable, all feature
-// modules are added to the registry only here (in this file). To implement
-// modules for clangd tool, one need to link them directly to the clangd
-// executable in clangd/tool/CMakeLists.txt.
+// Feature modules can be added statically via FeatureModuleRegistry::Add,
+// or loaded dynamically at runtime via the -load command-line option or
+// loadFeatureModule().
TEST(FeatureModulesRegistryTest, DummyModule) {
EXPECT_THAT(FeatureModuleRegistry::entries(),
ElementsAre(moduleName("dummy")));
@@ -88,5 +87,11 @@ TEST(FeatureModulesRegistryTest, DummyModule) {
EXPECT_THAT(Tweaks, ElementsAre(tweakID("DummyTweak")));
}
+TEST(FeatureModulesRegistryTest, LoadNonexistentModule) {
+ llvm::Error Err = loadFeatureModule("nonexistent_module.so");
+ EXPECT_TRUE(bool(Err));
+ llvm::consumeError(std::move(Err));
+}
+
} // namespace
} // namespace clang::clangd
>From eebf8d4c0dc6b65a180ebe7385e8417136780d88 Mon Sep 17 00:00:00 2001
From: Aleksandr Platonov <arcsinx45 at gmail.com>
Date: Thu, 24 Sep 2026 23:48:25 +0300
Subject: [PATCH 2/7] Remove examples dir
---
clang-tools-extra/clangd/CMakeLists.txt | 5 -
.../clangd/examples/CMakeLists.txt | 1 -
.../SampleFeatureModule/CMakeLists.txt | 34 ------
.../examples/SampleFeatureModule/README.md | 78 --------------
.../SampleFeatureModule.cpp | 100 ------------------
5 files changed, 218 deletions(-)
delete mode 100644 clang-tools-extra/clangd/examples/CMakeLists.txt
delete mode 100644 clang-tools-extra/clangd/examples/SampleFeatureModule/CMakeLists.txt
delete mode 100644 clang-tools-extra/clangd/examples/SampleFeatureModule/README.md
delete mode 100644 clang-tools-extra/clangd/examples/SampleFeatureModule/SampleFeatureModule.cpp
diff --git a/clang-tools-extra/clangd/CMakeLists.txt b/clang-tools-extra/clangd/CMakeLists.txt
index e2da91b8968e5c..3aa1b7bddb994e 100644
--- a/clang-tools-extra/clangd/CMakeLists.txt
+++ b/clang-tools-extra/clangd/CMakeLists.txt
@@ -233,8 +233,3 @@ add_subdirectory(index/remote)
if(CLANGD_BUILD_DEXP)
add_subdirectory(index/dex/dexp)
endif()
-
-option(CLANGD_BUILD_EXAMPLES "Build clangd examples" OFF)
-if(CLANGD_BUILD_EXAMPLES)
- add_subdirectory(examples)
-endif()
diff --git a/clang-tools-extra/clangd/examples/CMakeLists.txt b/clang-tools-extra/clangd/examples/CMakeLists.txt
deleted file mode 100644
index 42c3c05d146087..00000000000000
--- a/clang-tools-extra/clangd/examples/CMakeLists.txt
+++ /dev/null
@@ -1 +0,0 @@
-add_subdirectory(SampleFeatureModule)
diff --git a/clang-tools-extra/clangd/examples/SampleFeatureModule/CMakeLists.txt b/clang-tools-extra/clangd/examples/SampleFeatureModule/CMakeLists.txt
deleted file mode 100644
index eaee5d017d3400..00000000000000
--- a/clang-tools-extra/clangd/examples/SampleFeatureModule/CMakeLists.txt
+++ /dev/null
@@ -1,34 +0,0 @@
-if(NOT DEFINED LLVM_MAIN_SRC_DIR)
- cmake_minimum_required(VERSION 3.20)
- project(SampleFeatureModule)
-
- find_package(LLVM REQUIRED CONFIG)
- find_package(Clang REQUIRED CONFIG)
-
- list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_DIR}")
- include(AddLLVM)
-
- include_directories(${LLVM_INCLUDE_DIRS} ${CLANG_INCLUDE_DIRS})
- link_directories(${LLVM_LIBDIR_SUFFIX})
-
- add_llvm_library(SampleFeatureModule MODULE
- SampleFeatureModule.cpp
- PLUGIN_TOOL clangd
- )
-else()
- add_llvm_library(SampleFeatureModule MODULE
- SampleFeatureModule.cpp
- PLUGIN_TOOL clangd
- )
-
- target_include_directories(SampleFeatureModule PRIVATE
- "${CMAKE_CURRENT_SOURCE_DIR}/../../"
- "${CMAKE_CURRENT_BINARY_DIR}/../../"
- )
-
- if(WIN32 OR CYGWIN)
- set(LLVM_LINK_COMPONENTS
- Support
- )
- endif()
-endif()
diff --git a/clang-tools-extra/clangd/examples/SampleFeatureModule/README.md b/clang-tools-extra/clangd/examples/SampleFeatureModule/README.md
deleted file mode 100644
index ac8c180d49afbf..00000000000000
--- a/clang-tools-extra/clangd/examples/SampleFeatureModule/README.md
+++ /dev/null
@@ -1,78 +0,0 @@
-# Sample Dynamic FeatureModule for Clangd
-
-This example demonstrates how to implement, build, and load a **dynamic `FeatureModule`** plugin into `clangd`.
-
-## Background
-
-Clangd supports vertical extensions via `FeatureModule`s. Previously, `FeatureModule`s could only be linked statically into the `clangd` binary. With dynamic loading support, feature modules can be compiled into independent shared libraries (`.so` / `.dylib` / `.dll`) and loaded at runtime into `clangd` via the standard LLVM `-load` command-line option.
-
-When a plugin shared library is loaded:
-1. Static initializers in the shared library run.
-2. `FeatureModuleRegistry::Add<MyModule> X("name", "description")` registers the module with `FeatureModuleRegistry`.
-3. Clangd queries `FeatureModuleSet::fromRegistry()`, which instantiates all registered feature modules and integrates them into the LSP server.
-
-## Features demonstrated in this example
-
-- **Tweaks (Code Actions)**: Contributes a custom code action tweak (`SampleModuleTweak`) that appears in editors.
-- **AST Listeners**: Observes AST building lifecycle events (`beforeExecute`, `afterExecute`) and diagnostics (`sawDiagnostic`).
-- **LSP Bindings**: Demonstrates how to register custom LSP methods, notifications, or commands via `LSPBinder` and modify server capabilities in `initializeLSP`.
-
-## How to Build
-
-### In-tree Build
-
-To build this example as part of LLVM / Clang:
-
-1. Configure LLVM with examples enabled:
- ```bash
- cmake -B build -S llvm -DCLANGD_BUILD_EXAMPLES=ON [other options...]
- ```
-2. Build the plugin:
- ```bash
- ninja -C build SampleFeatureModule
- ```
- The shared library will be built in `build/lib/SampleFeatureModule.so` (or `.dylib` on macOS).
-
-### Out-of-tree Build
-
-You can also build feature modules against an installed LLVM / Clang toolchain:
-
-```bash
-mkdir build && cd build
-cmake -DCMAKE_PREFIX_PATH=/path/to/llvm/installation ..
-cmake --build .
-```
-
-## How to Use with Clangd
-
-### Check Mode
-
-You can test that your module is loaded and functioning using `clangd --check`:
-
-```bash
-clangd -check=test.cpp -load=/path/to/SampleFeatureModule.so -log=verbose
-```
-
-Output will show:
-```
-Loaded plugin: /path/to/SampleFeatureModule.so
-Adding feature module 'sample-feature-module' (Example feature module demonstrating dynamic loading into clangd)
-...
- tweak: SampleModuleTweak
-```
-
-### Editor Integration
-
-Pass `-load=/path/to/SampleFeatureModule.so` to the `clangd` arguments in your editor configuration:
-
-- **VS Code** (`settings.json`):
- ```json
- "clangd.arguments": [
- "--load=/path/to/SampleFeatureModule.so"
- ]
- ```
-- **Environment Variable**:
- You can also pass arguments via the `CLANGD_FLAGS` environment variable:
- ```bash
- export CLANGD_FLAGS="--load=/path/to/SampleFeatureModule.so"
- ```
diff --git a/clang-tools-extra/clangd/examples/SampleFeatureModule/SampleFeatureModule.cpp b/clang-tools-extra/clangd/examples/SampleFeatureModule/SampleFeatureModule.cpp
deleted file mode 100644
index 6ae690a14eb15b..00000000000000
--- a/clang-tools-extra/clangd/examples/SampleFeatureModule/SampleFeatureModule.cpp
+++ /dev/null
@@ -1,100 +0,0 @@
-//===--- SampleFeatureModule.cpp - Example Clangd Feature Module ----------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-//
-// This file implements an example FeatureModule for clangd that can be
-// dynamically loaded into clangd at runtime via the `-load` option:
-//
-// clangd -load=/path/to/SampleFeatureModule.so
-//
-// When loaded, the module registers itself with clangd's FeatureModuleRegistry
-// and demonstrates:
-// 1. Contributing custom code action tweaks (Tweak).
-// 2. Observing AST builds and diagnostics via ASTListener.
-// 3. Registering custom LSP method/command handlers via LSPBinder.
-//
-//===----------------------------------------------------------------------===//
-
-#include "FeatureModule.h"
-#include "LSPBinder.h"
-#include "refactor/Tweak.h"
-#include "support/Logger.h"
-
-namespace clang::clangd {
-namespace {
-
-/// An example code action tweak contributed by the feature module.
-class SampleTweak final : public Tweak {
-public:
- const char *id() const override { return "SampleModuleTweak"; }
-
- bool prepare(const Selection &Sel) override {
- // This tweak is available anywhere in the file.
- return true;
- }
-
- Expected<Effect> apply(const Selection &Sel) override {
- return Effect::showMessage("Sample FeatureModule tweak executed!");
- }
-
- std::string title() const override {
- return "Execute Sample FeatureModule action";
- }
-
- llvm::StringLiteral kind() const override {
- return llvm::StringLiteral("quickfix");
- }
-};
-
-/// An example AST listener that observes AST construction events.
-class SampleASTListener final : public FeatureModule::ASTListener {
-public:
- void beforeExecute(CompilerInstance &CI) override {
- vlog("SampleFeatureModule: before AST execution");
- }
-
- void afterExecute(CompilerInstance &CI) override {
- vlog("SampleFeatureModule: after AST execution");
- }
-
- void sawDiagnostic(const clang::Diagnostic &Diag, clangd::Diag &D) override {
- vlog("SampleFeatureModule: observed diagnostic '{0}'", D.Message);
- }
-};
-
-/// The main feature module class.
-class SampleFeatureModule final : public FeatureModule {
-public:
- /// Contribute custom tweaks to clangd's code action list.
- void contributeTweaks(std::vector<std::unique_ptr<Tweak>> &Out) override {
- Out.emplace_back(new SampleTweak);
- }
-
- /// Hook into AST creation to observe AST events and diagnostics.
- std::unique_ptr<ASTListener> astListeners() override {
- return std::make_unique<SampleASTListener>();
- }
-
- /// Register custom LSP endpoints or update server capabilities.
- void initializeLSP(LSPBinder &Bind,
- const llvm::json::Object &ClientCaps,
- llvm::json::Object &ServerCaps) override {
- vlog("SampleFeatureModule: initializeLSP called");
- // Example: Bind a custom LSP method or notification if needed:
- // Bind.method("sample/customMethod", this, &SampleFeatureModule::onCustomMethod);
- }
-};
-
-// Register the module with clangd's FeatureModuleRegistry.
-// When clangd loads this shared library via -load, this static initializer
-// will run and add the module to clangd's registry.
-static FeatureModuleRegistry::Add<SampleFeatureModule>
- X("sample-feature-module",
- "Example feature module demonstrating dynamic loading into clangd");
-
-} // namespace
-} // namespace clang::clangd
>From b605be6b81b287499dd4bb941e61910868deaf63 Mon Sep 17 00:00:00 2001
From: Aleksandr Platonov <arcsinx45 at gmail.com>
Date: Fri, 25 Sep 2026 10:08:34 +0300
Subject: [PATCH 3/7] Added tweak example
---
clang-tools-extra/clangd/test/CMakeLists.txt | 30 +++++++++++-------
.../clangd/test/StandaloneTweakExample.cpp | 31 +++++++++++++++++++
.../clangd/test/standalone-tweak.test | 10 ++++++
3 files changed, 60 insertions(+), 11 deletions(-)
create mode 100644 clang-tools-extra/clangd/test/StandaloneTweakExample.cpp
create mode 100644 clang-tools-extra/clangd/test/standalone-tweak.test
diff --git a/clang-tools-extra/clangd/test/CMakeLists.txt b/clang-tools-extra/clangd/test/CMakeLists.txt
index 17f95f8abc005e..401d3a8b156db7 100644
--- a/clang-tools-extra/clangd/test/CMakeLists.txt
+++ b/clang-tools-extra/clangd/test/CMakeLists.txt
@@ -34,21 +34,29 @@ if (NOT WIN32 OR NOT LLVM_LINK_LLVM_DYLIB)
llvm_add_library(
ClangdFeatureModuleExample
MODULE FeatureModuleExample.cpp
- PLUGIN_TOOL clangd)
+ PLUGIN_TOOL clangd
+ PARTIAL_SOURCES_INTENDED)
+ llvm_add_library(
+ ClangdStandaloneTweakExample
+ MODULE StandaloneTweakExample.cpp
+ PLUGIN_TOOL clangd
+ PARTIAL_SOURCES_INTENDED)
endif()
-if(TARGET ClangdFeatureModuleExample)
- list(APPEND CLANGD_TEST_DEPS ClangdFeatureModuleExample)
- target_include_directories(ClangdFeatureModuleExample PUBLIC BEFORE
- "${CLANG_TOOLS_SOURCE_DIR}/clangd"
- "${CMAKE_CURRENT_BINARY_DIR}/.."
- )
- if(CLANG_PLUGIN_SUPPORT AND (WIN32 OR CYGWIN))
- set(LLVM_LINK_COMPONENTS
- Support
+foreach(target ClangdFeatureModuleExample ClangdStandaloneTweakExample)
+ if(TARGET ${target})
+ list(APPEND CLANGD_TEST_DEPS ${target})
+ target_include_directories(${target} PUBLIC BEFORE
+ "${CLANG_TOOLS_SOURCE_DIR}/clangd"
+ "${CMAKE_CURRENT_BINARY_DIR}/.."
)
+ if(CLANG_PLUGIN_SUPPORT AND (WIN32 OR CYGWIN))
+ set(LLVM_LINK_COMPONENTS
+ Support
+ )
+ endif()
endif()
-endif()
+endforeach()
llvm_canonicalize_cmake_booleans(CLANG_PLUGIN_SUPPORT)
diff --git a/clang-tools-extra/clangd/test/StandaloneTweakExample.cpp b/clang-tools-extra/clangd/test/StandaloneTweakExample.cpp
new file mode 100644
index 00000000000000..4a472b15ec74b1
--- /dev/null
+++ b/clang-tools-extra/clangd/test/StandaloneTweakExample.cpp
@@ -0,0 +1,31 @@
+//===--- StandaloneTweakExample.cpp - Example standalone dynamic Tweak ----===//
+//
+// 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 "refactor/Tweak.h"
+
+namespace clang::clangd {
+namespace {
+
+/// A standalone tweak registered directly via REGISTER_TWEAK without a FeatureModule.
+class StandaloneTweak final : public Tweak {
+public:
+ const char *id() const override;
+ bool prepare(const Selection &) override { return true; }
+ Expected<Effect> apply(const Selection &) override {
+ return Effect::showMessage("Standalone tweak executed");
+ }
+ std::string title() const override { return "Execute standalone action"; }
+ llvm::StringLiteral kind() const override {
+ return llvm::StringLiteral("quickfix");
+ }
+};
+
+REGISTER_TWEAK(StandaloneTweak)
+
+} // namespace
+} // namespace clang::clangd
diff --git a/clang-tools-extra/clangd/test/standalone-tweak.test b/clang-tools-extra/clangd/test/standalone-tweak.test
new file mode 100644
index 00000000000000..c74e81a4a68b3c
--- /dev/null
+++ b/clang-tools-extra/clangd/test/standalone-tweak.test
@@ -0,0 +1,10 @@
+// REQUIRES: plugins
+// RUN: cp %s %t.cpp
+// RUN: clangd -enable-config=0 -log=verbose -check=%t.cpp -load=%llvmshlibdir/ClangdStandaloneTweakExample%pluginext 2>&1 | FileCheck -strict-whitespace %s
+
+// CHECK: Loaded plugin: {{.*}}ClangdStandaloneTweakExample{{.*}}
+// CHECK: Testing features at each token
+// CHECK-DAG: tweak: StandaloneTweak
+// CHECK: All checks completed, 0 errors
+
+int x = 42;
>From a335b0634538ee7a66aca4f163f699bc4f202bad Mon Sep 17 00:00:00 2001
From: Aleksandr Platonov <arcsinx45 at gmail.com>
Date: Mon, 28 Sep 2026 16:19:12 +0300
Subject: [PATCH 4/7] Remove loadFeatureModule()
---
clang-tools-extra/clangd/FeatureModule.cpp | 13 -------------
clang-tools-extra/clangd/FeatureModule.h | 7 -------
.../unittests/FeatureModulesRegistryTests.cpp | 13 ++++---------
3 files changed, 4 insertions(+), 29 deletions(-)
diff --git a/clang-tools-extra/clangd/FeatureModule.cpp b/clang-tools-extra/clangd/FeatureModule.cpp
index dd72a6dd6c6cbe..38461e3db4e6bd 100644
--- a/clang-tools-extra/clangd/FeatureModule.cpp
+++ b/clang-tools-extra/clangd/FeatureModule.cpp
@@ -8,8 +8,6 @@
#include "FeatureModule.h"
#include "support/Logger.h"
-#include "llvm/Support/DynamicLibrary.h"
-#include "llvm/Support/Error.h"
namespace clang {
namespace clangd {
@@ -48,17 +46,6 @@ FeatureModuleSet FeatureModuleSet::fromRegistry() {
return ModuleSet;
}
-llvm::Error loadFeatureModule(llvm::StringRef SharedLibraryPath) {
- std::string Err;
- if (llvm::sys::DynamicLibrary::LoadLibraryPermanently(
- SharedLibraryPath.str().c_str(), &Err))
- return llvm::createStringError(llvm::inconvertibleErrorCode(),
- "Failed to load feature module '%s': %s",
- SharedLibraryPath.str().c_str(),
- Err.c_str());
- return llvm::Error::success();
-}
-
} // namespace clangd
} // namespace clang
diff --git a/clang-tools-extra/clangd/FeatureModule.h b/clang-tools-extra/clangd/FeatureModule.h
index 0b3ba894ae3871..90714fe9101a83 100644
--- a/clang-tools-extra/clangd/FeatureModule.h
+++ b/clang-tools-extra/clangd/FeatureModule.h
@@ -14,7 +14,6 @@
#include "clang/Basic/Diagnostic.h"
#include "llvm/ADT/FunctionExtras.h"
#include "llvm/Support/Compiler.h"
-#include "llvm/Support/Error.h"
#include "llvm/Support/JSON.h"
#include "llvm/Support/Registry.h"
#include <memory>
@@ -216,12 +215,6 @@ template <typename Mod> int FeatureModuleSet::ID<Mod>::Key;
using FeatureModuleRegistry = llvm::Registry<FeatureModule>;
-/// Dynamically load a feature module from a shared library.
-/// The shared library is expected to register one or more FeatureModules
-/// via FeatureModuleRegistry.
-/// Returns an Error if the library could not be loaded.
-llvm::Error loadFeatureModule(llvm::StringRef SharedLibraryPath);
-
} // namespace clangd
} // namespace clang
diff --git a/clang-tools-extra/clangd/unittests/FeatureModulesRegistryTests.cpp b/clang-tools-extra/clangd/unittests/FeatureModulesRegistryTests.cpp
index 936070220c0aa5..b8941cdb4b1783 100644
--- a/clang-tools-extra/clangd/unittests/FeatureModulesRegistryTests.cpp
+++ b/clang-tools-extra/clangd/unittests/FeatureModulesRegistryTests.cpp
@@ -74,9 +74,10 @@ static FeatureModuleRegistry::Add<Dummy>
MATCHER_P(moduleName, Name, "") { return arg.getName() == Name; }
MATCHER_P(tweakID, ID, "") { return arg->id() == llvm::StringRef(ID); }
-// Feature modules can be added statically via FeatureModuleRegistry::Add,
-// or loaded dynamically at runtime via the -load command-line option or
-// loadFeatureModule().
+// In this test, it is assumed that for unittests executable, all feature
+// modules are added to the registry only here (in this file). To implement
+// modules for clangd tool, one need to link them directly to the clangd
+// executable in clangd/tool/CMakeLists.txt.
TEST(FeatureModulesRegistryTest, DummyModule) {
EXPECT_THAT(FeatureModuleRegistry::entries(),
ElementsAre(moduleName("dummy")));
@@ -87,11 +88,5 @@ TEST(FeatureModulesRegistryTest, DummyModule) {
EXPECT_THAT(Tweaks, ElementsAre(tweakID("DummyTweak")));
}
-TEST(FeatureModulesRegistryTest, LoadNonexistentModule) {
- llvm::Error Err = loadFeatureModule("nonexistent_module.so");
- EXPECT_TRUE(bool(Err));
- llvm::consumeError(std::move(Err));
-}
-
} // namespace
} // namespace clang::clangd
>From 036de1a5df808326ef664909c36a27b6281bf401 Mon Sep 17 00:00:00 2001
From: Aleksandr Platonov <arcsinx45 at gmail.com>
Date: Mon, 28 Sep 2026 16:39:52 +0300
Subject: [PATCH 5/7] Removed IWYU comment
---
clang-tools-extra/clangd/tool/ClangdMain.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang-tools-extra/clangd/tool/ClangdMain.cpp b/clang-tools-extra/clangd/tool/ClangdMain.cpp
index dc0e1be1e69461..6f3451232db04f 100644
--- a/clang-tools-extra/clangd/tool/ClangdMain.cpp
+++ b/clang-tools-extra/clangd/tool/ClangdMain.cpp
@@ -38,7 +38,7 @@
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/InitLLVM.h"
#include "llvm/Support/Path.h"
-#include "llvm/Support/PluginLoader.h" // IWYU pragma: keep
+#include "llvm/Support/PluginLoader.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/Program.h"
#include "llvm/Support/Signals.h"
>From 2805916ac0afe8c423edd5100417fb5114dd1afd Mon Sep 17 00:00:00 2001
From: Aleksandr Platonov <arcsinx45 at gmail.com>
Date: Mon, 28 Sep 2026 17:52:26 +0300
Subject: [PATCH 6/7] fix format
---
clang-tools-extra/clangd/test/StandaloneTweakExample.cpp | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/clang-tools-extra/clangd/test/StandaloneTweakExample.cpp b/clang-tools-extra/clangd/test/StandaloneTweakExample.cpp
index 4a472b15ec74b1..3afe027fd7ab64 100644
--- a/clang-tools-extra/clangd/test/StandaloneTweakExample.cpp
+++ b/clang-tools-extra/clangd/test/StandaloneTweakExample.cpp
@@ -11,7 +11,8 @@
namespace clang::clangd {
namespace {
-/// A standalone tweak registered directly via REGISTER_TWEAK without a FeatureModule.
+/// A standalone tweak registered directly via REGISTER_TWEAK without a
+/// FeatureModule.
class StandaloneTweak final : public Tweak {
public:
const char *id() const override;
>From 0523da70748b4994b8cf2e2cea70654720c81541 Mon Sep 17 00:00:00 2001
From: Aleksandr Platonov <arcsinx45 at gmail.com>
Date: Tue, 29 Sep 2026 15:32:50 +0300
Subject: [PATCH 7/7] update release notes
---
clang-tools-extra/docs/ReleaseNotes.md | 3 +++
1 file changed, 3 insertions(+)
diff --git a/clang-tools-extra/docs/ReleaseNotes.md b/clang-tools-extra/docs/ReleaseNotes.md
index 833638a47abc63..92342c4818a738 100644
--- a/clang-tools-extra/docs/ReleaseNotes.md
+++ b/clang-tools-extra/docs/ReleaseNotes.md
@@ -112,6 +112,9 @@ infrastructure are described first, followed by tool-specific sections.
C++20 concepts.
([#206875](https://github.com/llvm/llvm-project/issues/206875))
+- Added support for loading dynamic plugins via the `-load` command-line
+ option.
+
### Improvements to clang-doc
### Improvements to clang-query
More information about the cfe-commits
mailing list