[clangd] Add BuiltinHeaders config option (#129459)

This option, under `CompileFlags`, governs whether clangd uses its own
built-in headers (`Clangd` option value) or the built-in headers of the driver
in the file's compile command (`QueryDriver` option value, applicable to
cases where `--query-driver` is used to instruct clangd to ask the driver
for its system include paths).

The default value is `Clangd`, preserving clangd's current defaut behaviour.

Fixes clangd/clangd#2074
This commit is contained in:
Khalil Estell 2025-03-08 16:16:37 -08:00 committed by GitHub
parent a892a5dc5e
commit 85d60a441a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 58 additions and 17 deletions

View File

@ -59,6 +59,7 @@ struct Config {
std::optional<std::string> FixedCDBPath;
};
enum class BuiltinHeaderPolicy { Clangd, QueryDriver };
/// Controls how the compile command for the current file is determined.
struct {
/// Edits to apply to the compile command, in sequence.
@ -66,6 +67,10 @@ struct Config {
Edits;
/// Where to search for compilation databases for this file's flags.
CDBSearchSpec CDBSearch = {CDBSearchSpec::Ancestors, std::nullopt};
/// Whether to use clangd's own builtin headers, or ones from the system
/// include extractor, if available.
BuiltinHeaderPolicy BuiltinHeaders = BuiltinHeaderPolicy::Clangd;
} CompileFlags;
enum class BackgroundPolicy { Build, Skip };

View File

@ -290,6 +290,18 @@ struct FragmentCompiler {
});
}
if (F.BuiltinHeaders) {
if (auto Val =
compileEnum<Config::BuiltinHeaderPolicy>("BuiltinHeaders",
*F.BuiltinHeaders)
.map("Clangd", Config::BuiltinHeaderPolicy::Clangd)
.map("QueryDriver", Config::BuiltinHeaderPolicy::QueryDriver)
.value())
Out.Apply.push_back([Val](const Params &, Config &C) {
C.CompileFlags.BuiltinHeaders = *Val;
});
}
if (F.CompilationDatabase) {
std::optional<Config::CDBSearchSpec> Spec;
if (**F.CompilationDatabase == "Ancestors") {

View File

@ -170,6 +170,14 @@ struct Fragment {
/// - Ancestors: search all parent directories (the default)
/// - std::nullopt: do not use a compilation database, just default flags.
std::optional<Located<std::string>> CompilationDatabase;
/// Controls whether Clangd should use its own built-in system headers (like
/// stddef.h), or use the system headers from the query driver. Use the
/// option value 'Clangd' (default) to indicate Clangd's headers, and use
/// 'QueryDriver' to indicate QueryDriver's headers. `Clangd` is the
/// fallback if no query driver is supplied or if the query driver regex
/// string fails to match the compiler used in the CDB.
std::optional<Located<std::string>> BuiltinHeaders;
};
CompileFlagsBlock CompileFlags;

View File

@ -104,6 +104,10 @@ private:
if (auto Values = scalarValues(N))
F.Remove = std::move(*Values);
});
Dict.handle("BuiltinHeaders", [&](Node &N) {
if (auto BuiltinHeaders = scalarValue(N, "BuiltinHeaders"))
F.BuiltinHeaders = *BuiltinHeaders;
});
Dict.handle("CompilationDatabase", [&](Node &N) {
F.CompilationDatabase = scalarValue(N, "CompilationDatabase");
});

View File

@ -30,6 +30,7 @@
// in the paths that are explicitly included by the user.
#include "CompileCommands.h"
#include "Config.h"
#include "GlobalCompilationDatabase.h"
#include "support/Logger.h"
#include "support/Threading.h"
@ -401,22 +402,30 @@ extractSystemIncludesAndTarget(const DriverArgs &InputArgs,
if (!Info)
return std::nullopt;
// The built-in headers are tightly coupled to parser builtins.
// (These are clang's "resource dir", GCC's GCC_INCLUDE_DIR.)
// We should keep using clangd's versions, so exclude the queried builtins.
// They're not specially marked in the -v output, but we can get the path
// with `$DRIVER -print-file-name=include`.
if (auto BuiltinHeaders =
run({Driver, "-print-file-name=include"}, /*OutputIsStderr=*/false)) {
auto Path = llvm::StringRef(*BuiltinHeaders).trim();
if (!Path.empty() && llvm::sys::path::is_absolute(Path)) {
auto Size = Info->SystemIncludes.size();
llvm::erase(Info->SystemIncludes, Path);
vlog("System includes extractor: builtin headers {0} {1}", Path,
(Info->SystemIncludes.size() != Size)
? "excluded"
: "not found in driver's response");
switch (Config::current().CompileFlags.BuiltinHeaders) {
case Config::BuiltinHeaderPolicy::Clangd: {
// The built-in headers are tightly coupled to parser builtins.
// (These are clang's "resource dir", GCC's GCC_INCLUDE_DIR.)
// We should keep using clangd's versions, so exclude the queried
// builtins. They're not specially marked in the -v output, but we can
// get the path with `$DRIVER -print-file-name=include`.
if (auto BuiltinHeaders = run({Driver, "-print-file-name=include"},
/*OutputIsStderr=*/false)) {
auto Path = llvm::StringRef(*BuiltinHeaders).trim();
if (!Path.empty() && llvm::sys::path::is_absolute(Path)) {
auto Size = Info->SystemIncludes.size();
llvm::erase(Info->SystemIncludes, Path);
vlog("System includes extractor: builtin headers {0} {1}", Path,
(Info->SystemIncludes.size() != Size)
? "excluded"
: "not found in driver's response");
}
}
break;
}
case Config::BuiltinHeaderPolicy::QueryDriver:
vlog("System includes extractor: Using builtin headers from query driver.");
break;
}
log("System includes extractor: successfully executed {0}\n\tgot includes: "

View File

@ -58,6 +58,9 @@ Semantic Highlighting
Compile flags
^^^^^^^^^^^^^
- Added `BuiltinHeaders` config key which controls whether clangd's built-in
headers are used or ones extracted from the driver.
Hover
^^^^^
@ -112,7 +115,7 @@ Changes in existing checks
<clang-tidy/checks/bugprone/unchecked-optional-access>` fixing false
positives from smart pointer accessors repeated in checking ``has_value``
and accessing ``value``. The option `IgnoreSmartPointerDereference` should
no longer be needed and will be removed. Also fixing false positive from
no longer be needed and will be removed. Also fixing false positive from
const reference accessors to objects containing optional member.
- Improved :doc:`bugprone-unsafe-functions
@ -135,7 +138,7 @@ Changes in existing checks
- Improved :doc:`performance/unnecessary-value-param
<clang-tidy/checks/performance/unnecessary-value-param>` check performance by
tolerating fix-it breaking compilation when functions is used as pointers
tolerating fix-it breaking compilation when functions is used as pointers
to avoid matching usage of functions within the current compilation unit.
- Improved :doc:`performance-move-const-arg