Skip to content

Commit 38b9fb5

Browse files
committed
[clangd] Add support for missing includes analysis.
Differential Revision: https://reviews.llvm.org/D143496
1 parent 723979e commit 38b9fb5

14 files changed

+537
-128
lines changed

Diff for: clang-tools-extra/clangd/Config.h

+7-5
Original file line numberDiff line numberDiff line change
@@ -88,11 +88,12 @@ struct Config {
8888
bool StandardLibrary = true;
8989
} Index;
9090

91-
enum class UnusedIncludesPolicy {
92-
/// Diagnose unused includes.
91+
enum class IncludesPolicy {
92+
/// Diagnose missing and unused includes.
9393
Strict,
9494
None,
95-
/// The same as Strict, but using the include-cleaner library.
95+
/// The same as Strict, but using the include-cleaner library for
96+
/// unused includes.
9697
Experiment,
9798
};
9899
/// Controls warnings and errors when parsing code.
@@ -107,11 +108,12 @@ struct Config {
107108
llvm::StringMap<std::string> CheckOptions;
108109
} ClangTidy;
109110

110-
UnusedIncludesPolicy UnusedIncludes = UnusedIncludesPolicy::None;
111-
112111
/// Enable emitting diagnostics using stale preambles.
113112
bool AllowStalePreamble = false;
114113

114+
IncludesPolicy UnusedIncludes = IncludesPolicy::None;
115+
IncludesPolicy MissingIncludes = IncludesPolicy::None;
116+
115117
/// IncludeCleaner will not diagnose usages of these headers matched by
116118
/// these regexes.
117119
struct {

Diff for: clang-tools-extra/clangd/ConfigCompile.cpp

+17-7
Original file line numberDiff line numberDiff line change
@@ -431,23 +431,33 @@ struct FragmentCompiler {
431431
});
432432

433433
if (F.UnusedIncludes)
434-
if (auto Val =
435-
compileEnum<Config::UnusedIncludesPolicy>("UnusedIncludes",
436-
**F.UnusedIncludes)
437-
.map("Strict", Config::UnusedIncludesPolicy::Strict)
438-
.map("Experiment", Config::UnusedIncludesPolicy::Experiment)
439-
.map("None", Config::UnusedIncludesPolicy::None)
440-
.value())
434+
if (auto Val = compileEnum<Config::IncludesPolicy>("UnusedIncludes",
435+
**F.UnusedIncludes)
436+
.map("Strict", Config::IncludesPolicy::Strict)
437+
.map("Experiment", Config::IncludesPolicy::Experiment)
438+
.map("None", Config::IncludesPolicy::None)
439+
.value())
441440
Out.Apply.push_back([Val](const Params &, Config &C) {
442441
C.Diagnostics.UnusedIncludes = *Val;
443442
});
443+
444444
if (F.AllowStalePreamble) {
445445
if (auto Val = F.AllowStalePreamble)
446446
Out.Apply.push_back([Val](const Params &, Config &C) {
447447
C.Diagnostics.AllowStalePreamble = **Val;
448448
});
449449
}
450450

451+
if (F.MissingIncludes)
452+
if (auto Val = compileEnum<Config::IncludesPolicy>("MissingIncludes",
453+
**F.MissingIncludes)
454+
.map("Strict", Config::IncludesPolicy::Strict)
455+
.map("None", Config::IncludesPolicy::None)
456+
.value())
457+
Out.Apply.push_back([Val](const Params &, Config &C) {
458+
C.Diagnostics.MissingIncludes = *Val;
459+
});
460+
451461
compile(std::move(F.Includes));
452462
compile(std::move(F.ClangTidy));
453463
}

Diff for: clang-tools-extra/clangd/ConfigFragment.h

+15-1
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ struct Fragment {
221221
/// This often has other advantages, such as skipping some analysis.
222222
std::vector<Located<std::string>> Suppress;
223223

224-
/// Controls how clangd will correct "unnecessary #include directives.
224+
/// Controls how clangd will correct "unnecessary" #include directives.
225225
/// clangd can warn if a header is `#include`d but not used, and suggest
226226
/// removing it.
227227
//
@@ -236,9 +236,23 @@ struct Fragment {
236236
/// - None
237237
std::optional<Located<std::string>> UnusedIncludes;
238238

239+
239240
/// Enable emitting diagnostics using stale preambles.
240241
std::optional<Located<bool>> AllowStalePreamble;
241242

243+
/// Controls if clangd should analyze missing #include directives.
244+
/// clangd will warn if no header providing a symbol is `#include`d
245+
/// (missing) directly, and suggest adding it.
246+
///
247+
/// Strict means a header providing a symbol is missing if it is not
248+
/// *directly #include'd. The file might still compile if the header is
249+
/// included transitively.
250+
///
251+
/// Valid values are:
252+
/// - Strict
253+
/// - None
254+
std::optional<Located<std::string>> MissingIncludes;
255+
242256
/// Controls IncludeCleaner diagnostics.
243257
struct IncludesBlock {
244258
/// Regexes that will be used to avoid diagnosing certain includes as

Diff for: clang-tools-extra/clangd/ConfigYAML.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,9 @@ class Parser {
128128
Dict.handle("UnusedIncludes", [&](Node &N) {
129129
F.UnusedIncludes = scalarValue(N, "UnusedIncludes");
130130
});
131+
Dict.handle("MissingIncludes", [&](Node &N) {
132+
F.MissingIncludes = scalarValue(N, "MissingIncludes");
133+
});
131134
Dict.handle("Includes", [&](Node &N) { parse(F.Includes, N); });
132135
Dict.handle("ClangTidy", [&](Node &N) { parse(F.ClangTidy, N); });
133136
Dict.handle("AllowStalePreamble", [&](Node &N) {

0 commit comments

Comments
 (0)