[clang-tools-extra] [clangd] Make clangd-indexer respect .clangd configuration files (PR #214951)
via cfe-commits
cfe-commits at lists.llvm.org
Sat Aug 8 03:53:24 PDT 2026
https://github.com/Fil-Den created https://github.com/llvm/llvm-project/pull/214951
None
>From 92c6aef642d9cedbee379f0d71e4102c28a35af8 Mon Sep 17 00:00:00 2001
From: Fil-Den <ffil.denn at gmail.com>
Date: Sat, 11 Jul 2026 18:46:03 +0300
Subject: [PATCH] Clangd-indexer respects .clangd files
---
clang-tools-extra/clangd/ConfigProvider.cpp | 27 ++++++++++++++
clang-tools-extra/clangd/ConfigProvider.h | 10 +++++
.../clangd/indexer/IndexerMain.cpp | 37 ++++++++++++++++++-
.../clangd/test/indexer-clangd-config.test | 25 +++++++++++++
clang-tools-extra/clangd/tool/ClangdMain.cpp | 24 ++----------
5 files changed, 100 insertions(+), 23 deletions(-)
create mode 100644 clang-tools-extra/clangd/test/indexer-clangd-config.test
diff --git a/clang-tools-extra/clangd/ConfigProvider.cpp b/clang-tools-extra/clangd/ConfigProvider.cpp
index ac437ee8b6eb1..e26509d8b1c8b 100644
--- a/clang-tools-extra/clangd/ConfigProvider.cpp
+++ b/clang-tools-extra/clangd/ConfigProvider.cpp
@@ -10,10 +10,12 @@
#include "Config.h"
#include "ConfigFragment.h"
#include "support/FileCache.h"
+#include "support/Logger.h"
#include "support/Path.h"
#include "support/ThreadsafeFS.h"
#include "support/Trace.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Path.h"
@@ -166,6 +168,31 @@ Provider::combine(std::vector<const Provider *> Providers) {
return std::make_unique<CombinedProvider>(std::move(Providers));
}
+std::vector<std::unique_ptr<Provider>>
+Provider::createDefaultProviders(const ThreadsafeFS &TFS) {
+ std::vector<std::unique_ptr<Provider>> Providers;
+ Providers.push_back(fromAncestorRelativeYAMLFiles(".clangd", TFS));
+ llvm::SmallString<256> UserConfig;
+ if (llvm::sys::path::user_config_directory(UserConfig)) {
+ llvm::sys::path::append(UserConfig, "clangd", "config.yaml");
+ vlog("User config file is {0}", UserConfig);
+ Providers.push_back(
+ fromYAMLFile(UserConfig, /*Directory=*/"", TFS, /*Trusted=*/true));
+ } else {
+ elog("Couldn't determine user config file, not loading");
+ }
+ return Providers;
+}
+
+const char *const Provider::EnableConfigFlagDesc =
+ "Read user and project configuration from YAML files.\n"
+ "Project config is from a .clangd file in the project directory.\n"
+ "User config is from clangd/config.yaml in the following directories:\n"
+ "\tWindows: %USERPROFILE%\\AppData\\Local\n"
+ "\tMac OS: ~/Library/Preferences/\n"
+ "\tOthers: $XDG_CONFIG_HOME, usually ~/.config\n"
+ "Configuration is documented at https://clangd.llvm.org/config.html";
+
Config Provider::getConfig(const Params &P, DiagnosticCallback DC) const {
trace::Span Tracer("getConfig");
if (!P.Path.empty())
diff --git a/clang-tools-extra/clangd/ConfigProvider.h b/clang-tools-extra/clangd/ConfigProvider.h
index f268edb1df2a5..e1a52604e7de8 100644
--- a/clang-tools-extra/clangd/ConfigProvider.h
+++ b/clang-tools-extra/clangd/ConfigProvider.h
@@ -84,9 +84,19 @@ class Provider {
/// Order is preserved; later providers take precedence over earlier ones.
static std::unique_ptr<Provider> combine(std::vector<const Provider *>);
+ /// Returns providers for the configuration files that clangd tools read by
+ /// default: project config (ancestor `.clangd` files) and the user's
+ /// global config file.
+ static std::vector<std::unique_ptr<Provider>>
+ createDefaultProviders(const ThreadsafeFS &);
+
/// Build a config based on this provider.
Config getConfig(const Params &, DiagnosticCallback) const;
+ /// Help text for the --enable-config flag, shared by clangd tools that
+ /// expose createDefaultProviders() on the command line.
+ static const char *const EnableConfigFlagDesc;
+
private:
/// Provide fragments that may be relevant to the file.
/// The configuration provider is not responsible for testing conditions.
diff --git a/clang-tools-extra/clangd/indexer/IndexerMain.cpp b/clang-tools-extra/clangd/indexer/IndexerMain.cpp
index 94db860f0b9b5..c330be298a87a 100644
--- a/clang-tools-extra/clangd/indexer/IndexerMain.cpp
+++ b/clang-tools-extra/clangd/indexer/IndexerMain.cpp
@@ -10,21 +10,29 @@
//
//===----------------------------------------------------------------------===//
+#include "ClangdServer.h"
#include "CompileCommands.h"
#include "Compiler.h"
+#include "ConfigProvider.h"
#include "index/IndexAction.h"
#include "index/Merge.h"
#include "index/Ref.h"
#include "index/Serialization.h"
#include "index/Symbol.h"
#include "index/SymbolCollector.h"
+#include "support/Context.h"
#include "support/Logger.h"
+#include "support/ThreadsafeFS.h"
#include "clang/Tooling/ArgumentsAdjusters.h"
#include "clang/Tooling/Execution.h"
#include "clang/Tooling/Tooling.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Signals.h"
+#include <memory>
#include <utility>
+#include <vector>
namespace clang {
namespace clangd {
@@ -48,6 +56,12 @@ static llvm::cl::list<std::string> QueryDriverGlobs{
llvm::cl::CommaSeparated,
};
+static llvm::cl::opt<bool> EnableConfig{
+ "enable-config",
+ llvm::cl::desc(config::Provider::EnableConfigFlagDesc),
+ llvm::cl::init(true),
+};
+
class IndexActionFactory : public tooling::FrontendActionFactory {
public:
IndexActionFactory(IndexFileIn &Result) : Result(Result) {}
@@ -152,6 +166,20 @@ int main(int argc, const char **argv) {
return 1;
}
+ clang::clangd::RealThreadsafeFS TFS;
+ std::vector<std::unique_ptr<clang::clangd::config::Provider>> ProviderStack;
+ if (clang::clangd::EnableConfig)
+ ProviderStack =
+ clang::clangd::config::Provider::createDefaultProviders(TFS);
+ std::vector<const clang::clangd::config::Provider *> ProviderPointers;
+ for (const auto &P : ProviderStack)
+ ProviderPointers.push_back(P.get());
+ auto ConfigProvider =
+ clang::clangd::config::Provider::combine(std::move(ProviderPointers));
+ auto ContextProvider =
+ clang::clangd::ClangdServer::createConfiguredContextProvider(
+ ConfigProvider.get(), /*Callbacks=*/nullptr);
+
// Collect symbols found in each translation unit, merging as we go.
clang::clangd::IndexFileIn Data;
auto Mangler = std::make_shared<clang::clangd::CommandMangler>(
@@ -162,8 +190,13 @@ int main(int argc, const char **argv) {
auto Err = Executor->get()->execute(
std::make_unique<clang::clangd::IndexActionFactory>(Data),
clang::tooling::ArgumentsAdjuster(
- [Mangler = std::move(Mangler)](const std::vector<std::string> &Args,
- llvm::StringRef File) {
+ [Mangler = std::move(Mangler),
+ ContextProvider = std::move(ContextProvider)](
+ const std::vector<std::string> &Args, llvm::StringRef File) {
+ llvm::SmallString<256> AbsFile(File);
+ llvm::sys::fs::make_absolute(AbsFile);
+ clang::clangd::WithContext WithCfg(ContextProvider(AbsFile));
+
clang::tooling::CompileCommand Cmd;
Cmd.CommandLine = Args;
Mangler->operator()(Cmd, File);
diff --git a/clang-tools-extra/clangd/test/indexer-clangd-config.test b/clang-tools-extra/clangd/test/indexer-clangd-config.test
new file mode 100644
index 0000000000000..f99f2db410ee3
--- /dev/null
+++ b/clang-tools-extra/clangd/test/indexer-clangd-config.test
@@ -0,0 +1,25 @@
+# Test that clangd-indexer respects CompileFlags
+
+# RUN: rm -rf %t.dir && mkdir -p %t.dir
+# RUN: split-file %s %t.dir
+
+# By default config is enabled, so the .clangd file's CompileFlags.Add should
+# define FROM_CLANGD_FILE, and the #error below must not fire.
+# RUN: clangd-indexer %t.dir/test.cpp 2>&1 | FileCheck --check-prefix=ENABLED %s
+# ENABLED-NOT: error: "FROM_CLANGD_FILE not defined
+
+# With config disabled, the macro isn't defined by the .clangd file, so the
+# #error must fire.
+# RUN: clangd-indexer --enable-config=0 %t.dir/test.cpp 2>&1 \
+# RUN: | FileCheck --check-prefix=DISABLED %s
+# DISABLED: error: "FROM_CLANGD_FILE not defined - .clangd file was not applied"
+
+#--- .clangd
+CompileFlags:
+ Add: [-DFROM_CLANGD_FILE=1]
+
+#--- test.cpp
+#ifndef FROM_CLANGD_FILE
+#error "FROM_CLANGD_FILE not defined - .clangd file was not applied"
+#endif
+int foo() { return 0; }
diff --git a/clang-tools-extra/clangd/tool/ClangdMain.cpp b/clang-tools-extra/clangd/tool/ClangdMain.cpp
index 13fe4d3911731..f95e2dbf5eb38 100644
--- a/clang-tools-extra/clangd/tool/ClangdMain.cpp
+++ b/clang-tools-extra/clangd/tool/ClangdMain.cpp
@@ -489,14 +489,7 @@ opt<bool> PrettyPrint{
opt<bool> EnableConfig{
"enable-config",
cat(Misc),
- desc(
- "Read user and project configuration from YAML files.\n"
- "Project config is from a .clangd file in the project directory.\n"
- "User config is from clangd/config.yaml in the following directories:\n"
- "\tWindows: %USERPROFILE%\\AppData\\Local\n"
- "\tMac OS: ~/Library/Preferences/\n"
- "\tOthers: $XDG_CONFIG_HOME, usually ~/.config\n"
- "Configuration is documented at https://clangd.llvm.org/config.html"),
+ desc(config::Provider::EnableConfigFlagDesc),
init(true),
};
@@ -998,19 +991,8 @@ clangd accepts flags on the commandline, and in the CLANGD_FLAGS environment var
RealThreadsafeFS TFS;
std::vector<std::unique_ptr<config::Provider>> ProviderStack;
std::unique_ptr<config::Provider> Config;
- if (EnableConfig) {
- ProviderStack.push_back(
- config::Provider::fromAncestorRelativeYAMLFiles(".clangd", TFS));
- llvm::SmallString<256> UserConfig;
- if (llvm::sys::path::user_config_directory(UserConfig)) {
- llvm::sys::path::append(UserConfig, "clangd", "config.yaml");
- vlog("User config file is {0}", UserConfig);
- ProviderStack.push_back(config::Provider::fromYAMLFile(
- UserConfig, /*Directory=*/"", TFS, /*Trusted=*/true));
- } else {
- elog("Couldn't determine user config file, not loading");
- }
- }
+ if (EnableConfig)
+ ProviderStack = config::Provider::createDefaultProviders(TFS);
ProviderStack.push_back(std::make_unique<FlagsConfigProvider>());
std::vector<const config::Provider *> ProviderPointers;
for (const auto &P : ProviderStack)
More information about the cfe-commits
mailing list