diff --git a/clang-tools-extra/clangd/ConfigCompile.cpp b/clang-tools-extra/clangd/ConfigCompile.cpp --- a/clang-tools-extra/clangd/ConfigCompile.cpp +++ b/clang-tools-extra/clangd/ConfigCompile.cpp @@ -103,6 +103,22 @@ }); }); } + + auto PathExclude = std::make_unique>(); + for (auto &Entry : F.PathExclude) { + if (auto RE = compileRegex(Entry)) + PathExclude->push_back(std::move(*RE)); + } + if (!PathExclude->empty()) { + Out.Conditions.push_back( + [PathExclude(std::move(PathExclude))](const Params &P) { + if (P.Path.empty()) + return false; + return llvm::none_of(*PathExclude, [&](const llvm::Regex &RE) { + return RE.match(P.Path); + }); + }); + } } void compile(Fragment::CompileFlagsBlock &&F) { diff --git a/clang-tools-extra/clangd/ConfigFragment.h b/clang-tools-extra/clangd/ConfigFragment.h --- a/clang-tools-extra/clangd/ConfigFragment.h +++ b/clang-tools-extra/clangd/ConfigFragment.h @@ -108,6 +108,9 @@ struct IfBlock { /// The file being processed must fully match a regular expression. std::vector> PathMatch; + /// The file being processed must *not* fully match a regular expression. + std::vector> PathExclude; + /// An unrecognized key was found while parsing the condition. /// The condition will evaluate to false. bool HasUnrecognizedCondition = false; diff --git a/clang-tools-extra/clangd/ConfigYAML.cpp b/clang-tools-extra/clangd/ConfigYAML.cpp --- a/clang-tools-extra/clangd/ConfigYAML.cpp +++ b/clang-tools-extra/clangd/ConfigYAML.cpp @@ -50,6 +50,10 @@ if (auto Values = scalarValues(N)) F.PathMatch = std::move(*Values); }); + Dict.handle("PathExclude", [&](Node &N) { + if (auto Values = scalarValues(N)) + F.PathExclude = std::move(*Values); + }); Dict.parse(N); } diff --git a/clang-tools-extra/clangd/unittests/ConfigCompileTests.cpp b/clang-tools-extra/clangd/unittests/ConfigCompileTests.cpp --- a/clang-tools-extra/clangd/unittests/ConfigCompileTests.cpp +++ b/clang-tools-extra/clangd/unittests/ConfigCompileTests.cpp @@ -67,6 +67,13 @@ EXPECT_TRUE(compileAndApply()); EXPECT_THAT(Diags.Diagnostics, IsEmpty()); + // Excluded regex. + Frag = {}; + Frag.If.PathMatch.emplace_back("b.*"); + Frag.If.PathExclude.emplace_back(".*r"); + EXPECT_FALSE(compileAndApply()); + EXPECT_THAT(Diags.Diagnostics, IsEmpty()); + // Invalid regex. Frag = {}; Frag.If.PathMatch.emplace_back("**]@theu");