[clangd] Provide a way to disable external index

Users can reset any external index set by previous fragments by
putting a `None` for the external block, e.g:

```
Index:
  External: None
```

Differential Revision: https://reviews.llvm.org/D100106
This commit is contained in:
Kadir Cetinkaya 2021-04-08 15:50:50 +02:00
parent 4cbaaf4a24
commit 63bc9e4435
No known key found for this signature in database
GPG Key ID: E39E36B8D2057ED6
6 changed files with 82 additions and 20 deletions

View File

@ -70,7 +70,7 @@ struct Config {
enum class BackgroundPolicy { Build, Skip };
/// Describes an external index configuration.
struct ExternalIndexSpec {
enum { File, Server } Kind;
enum { None, File, Server } Kind;
/// This is one of:
/// - Address of a clangd-index-server, in the form of "ip:port".
/// - Absolute path to an index produced by clangd-indexer.

View File

@ -329,10 +329,11 @@ struct FragmentCompiler {
}
#endif
// Make sure exactly one of the Sources is set.
unsigned SourceCount =
External.File.hasValue() + External.Server.hasValue();
unsigned SourceCount = External.File.hasValue() +
External.Server.hasValue() + *External.IsNone;
if (SourceCount != 1) {
diag(Error, "Exactly one of File or Server must be set.", BlockRange);
diag(Error, "Exactly one of File, Server or None must be set.",
BlockRange);
return;
}
Config::ExternalIndexSpec Spec;
@ -346,7 +347,11 @@ struct FragmentCompiler {
if (!AbsPath)
return;
Spec.Location = std::move(*AbsPath);
} else {
assert(*External.IsNone);
Spec.Kind = Config::ExternalIndexSpec::None;
}
if (Spec.Kind != Config::ExternalIndexSpec::None) {
// Make sure MountPoint is an absolute path with forward slashes.
if (!External.MountPoint)
External.MountPoint.emplace(FragmentDirectory);
@ -359,7 +364,12 @@ struct FragmentCompiler {
if (!AbsPath)
return;
Spec.MountPoint = std::move(*AbsPath);
}
Out.Apply.push_back([Spec(std::move(Spec))](const Params &P, Config &C) {
if (Spec.Kind == Config::ExternalIndexSpec::None) {
C.Index.External.reset();
return;
}
if (P.Path.empty() || !pathStartsWith(Spec.MountPoint, P.Path,
llvm::sys::path::Style::posix))
return;

View File

@ -173,6 +173,9 @@ struct Fragment {
/// usually prepared using clangd-indexer.
/// Exactly one source (File/Server) should be configured.
struct ExternalBlock {
/// Whether the block is explicitly set to `None`. Can be used to clear
/// any external index specified before.
Located<bool> IsNone = false;
/// Path to an index file generated by clangd-indexer. Relative paths may
/// be used, if config fragment is associated with a directory.
llvm::Optional<Located<std::string>> File;

View File

@ -12,6 +12,7 @@
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/YAMLParser.h"
#include <string>
#include <system_error>
namespace clang {
@ -149,13 +150,34 @@ private:
[&](Node &N) { F.Background = scalarValue(N, "Background"); });
Dict.handle("External", [&](Node &N) {
Fragment::IndexBlock::ExternalBlock External;
// External block can either be a mapping or a scalar value. Dispatch
// accordingly.
if (N.getType() == Node::NK_Mapping) {
parse(External, N);
} else if (N.getType() == Node::NK_Scalar ||
N.getType() == Node::NK_BlockScalar) {
parse(External, scalarValue(N, "External").getValue());
} else {
error("External must be either a scalar or a mapping.", N);
return;
}
F.External.emplace(std::move(External));
F.External->Range = N.getSourceRange();
});
Dict.parse(N);
}
void parse(Fragment::IndexBlock::ExternalBlock &F,
Located<std::string> ExternalVal) {
if (!llvm::StringRef(*ExternalVal).equals_lower("none")) {
error("Only scalar value supported for External is 'None'",
ExternalVal.Range);
return;
}
F.IsNone = true;
F.IsNone.Range = ExternalVal.Range;
}
void parse(Fragment::IndexBlock::ExternalBlock &F, Node &N) {
DictParser Dict("External", this);
Dict.handle("File", [&](Node &N) { F.File = scalarValue(N, "File"); });

View File

@ -327,7 +327,8 @@ TEST_F(ConfigCompileTests, ExternalBlockWarnOnMultipleSource) {
#ifdef CLANGD_ENABLE_REMOTE
EXPECT_THAT(
Diags.Diagnostics,
Contains(AllOf(DiagMessage("Exactly one of File or Server must be set."),
Contains(
AllOf(DiagMessage("Exactly one of File, Server or None must be set."),
DiagKind(llvm::SourceMgr::DK_Error))));
#else
ASSERT_TRUE(Conf.Index.External.hasValue());
@ -335,12 +336,21 @@ TEST_F(ConfigCompileTests, ExternalBlockWarnOnMultipleSource) {
#endif
}
TEST_F(ConfigCompileTests, ExternalBlockDisableWithNone) {
Fragment::IndexBlock::ExternalBlock External;
External.IsNone = true;
Frag.Index.External = std::move(External);
compileAndApply();
EXPECT_FALSE(Conf.Index.External.hasValue());
}
TEST_F(ConfigCompileTests, ExternalBlockErrOnNoSource) {
Frag.Index.External.emplace(Fragment::IndexBlock::ExternalBlock{});
compileAndApply();
EXPECT_THAT(
Diags.Diagnostics,
Contains(AllOf(DiagMessage("Exactly one of File or Server must be set."),
Contains(
AllOf(DiagMessage("Exactly one of File, Server or None must be set."),
DiagKind(llvm::SourceMgr::DK_Error))));
}

View File

@ -147,6 +147,23 @@ horrible
ASSERT_THAT(Results, IsEmpty());
}
TEST(ParseYAML, ExternalBlockNone) {
CapturedDiags Diags;
Annotations YAML(R"yaml(
Index:
External: None
)yaml");
auto Results =
Fragment::parseYAML(YAML.code(), "config.yaml", Diags.callback());
ASSERT_THAT(Diags.Diagnostics, IsEmpty());
ASSERT_EQ(Results.size(), 1u);
ASSERT_TRUE(Results[0].Index.External);
EXPECT_FALSE(Results[0].Index.External.getValue()->File.hasValue());
EXPECT_FALSE(Results[0].Index.External.getValue()->MountPoint.hasValue());
EXPECT_FALSE(Results[0].Index.External.getValue()->Server.hasValue());
EXPECT_THAT(*Results[0].Index.External.getValue()->IsNone, testing::Eq(true));
}
TEST(ParseYAML, ExternalBlock) {
CapturedDiags Diags;
Annotations YAML(R"yaml(