[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:
		
							parent
							
								
									4cbaaf4a24
								
							
						
					
					
						commit
						63bc9e4435
					
				| 
						 | 
					@ -70,7 +70,7 @@ struct Config {
 | 
				
			||||||
  enum class BackgroundPolicy { Build, Skip };
 | 
					  enum class BackgroundPolicy { Build, Skip };
 | 
				
			||||||
  /// Describes an external index configuration.
 | 
					  /// Describes an external index configuration.
 | 
				
			||||||
  struct ExternalIndexSpec {
 | 
					  struct ExternalIndexSpec {
 | 
				
			||||||
    enum { File, Server } Kind;
 | 
					    enum { None, File, Server } Kind;
 | 
				
			||||||
    /// This is one of:
 | 
					    /// This is one of:
 | 
				
			||||||
    /// - Address of a clangd-index-server, in the form of "ip:port".
 | 
					    /// - Address of a clangd-index-server, in the form of "ip:port".
 | 
				
			||||||
    /// - Absolute path to an index produced by clangd-indexer.
 | 
					    /// - Absolute path to an index produced by clangd-indexer.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -329,10 +329,11 @@ struct FragmentCompiler {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
    // Make sure exactly one of the Sources is set.
 | 
					    // Make sure exactly one of the Sources is set.
 | 
				
			||||||
    unsigned SourceCount =
 | 
					    unsigned SourceCount = External.File.hasValue() +
 | 
				
			||||||
        External.File.hasValue() + External.Server.hasValue();
 | 
					                           External.Server.hasValue() + *External.IsNone;
 | 
				
			||||||
    if (SourceCount != 1) {
 | 
					    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;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    Config::ExternalIndexSpec Spec;
 | 
					    Config::ExternalIndexSpec Spec;
 | 
				
			||||||
| 
						 | 
					@ -346,20 +347,29 @@ struct FragmentCompiler {
 | 
				
			||||||
      if (!AbsPath)
 | 
					      if (!AbsPath)
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
      Spec.Location = std::move(*AbsPath);
 | 
					      Spec.Location = std::move(*AbsPath);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      assert(*External.IsNone);
 | 
				
			||||||
 | 
					      Spec.Kind = Config::ExternalIndexSpec::None;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    // Make sure MountPoint is an absolute path with forward slashes.
 | 
					    if (Spec.Kind != Config::ExternalIndexSpec::None) {
 | 
				
			||||||
    if (!External.MountPoint)
 | 
					      // Make sure MountPoint is an absolute path with forward slashes.
 | 
				
			||||||
      External.MountPoint.emplace(FragmentDirectory);
 | 
					      if (!External.MountPoint)
 | 
				
			||||||
    if ((**External.MountPoint).empty()) {
 | 
					        External.MountPoint.emplace(FragmentDirectory);
 | 
				
			||||||
      diag(Error, "A mountpoint is required.", BlockRange);
 | 
					      if ((**External.MountPoint).empty()) {
 | 
				
			||||||
      return;
 | 
					        diag(Error, "A mountpoint is required.", BlockRange);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      auto AbsPath = makeAbsolute(std::move(*External.MountPoint), "MountPoint",
 | 
				
			||||||
 | 
					                                  llvm::sys::path::Style::posix);
 | 
				
			||||||
 | 
					      if (!AbsPath)
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					      Spec.MountPoint = std::move(*AbsPath);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    auto AbsPath = makeAbsolute(std::move(*External.MountPoint), "MountPoint",
 | 
					 | 
				
			||||||
                                llvm::sys::path::Style::posix);
 | 
					 | 
				
			||||||
    if (!AbsPath)
 | 
					 | 
				
			||||||
      return;
 | 
					 | 
				
			||||||
    Spec.MountPoint = std::move(*AbsPath);
 | 
					 | 
				
			||||||
    Out.Apply.push_back([Spec(std::move(Spec))](const Params &P, Config &C) {
 | 
					    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,
 | 
					      if (P.Path.empty() || !pathStartsWith(Spec.MountPoint, P.Path,
 | 
				
			||||||
                                            llvm::sys::path::Style::posix))
 | 
					                                            llvm::sys::path::Style::posix))
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -173,6 +173,9 @@ struct Fragment {
 | 
				
			||||||
    /// usually prepared using clangd-indexer.
 | 
					    /// usually prepared using clangd-indexer.
 | 
				
			||||||
    /// Exactly one source (File/Server) should be configured.
 | 
					    /// Exactly one source (File/Server) should be configured.
 | 
				
			||||||
    struct ExternalBlock {
 | 
					    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
 | 
					      /// Path to an index file generated by clangd-indexer. Relative paths may
 | 
				
			||||||
      /// be used, if config fragment is associated with a directory.
 | 
					      /// be used, if config fragment is associated with a directory.
 | 
				
			||||||
      llvm::Optional<Located<std::string>> File;
 | 
					      llvm::Optional<Located<std::string>> File;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,6 +12,7 @@
 | 
				
			||||||
#include "llvm/Support/MemoryBuffer.h"
 | 
					#include "llvm/Support/MemoryBuffer.h"
 | 
				
			||||||
#include "llvm/Support/SourceMgr.h"
 | 
					#include "llvm/Support/SourceMgr.h"
 | 
				
			||||||
#include "llvm/Support/YAMLParser.h"
 | 
					#include "llvm/Support/YAMLParser.h"
 | 
				
			||||||
 | 
					#include <string>
 | 
				
			||||||
#include <system_error>
 | 
					#include <system_error>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace clang {
 | 
					namespace clang {
 | 
				
			||||||
| 
						 | 
					@ -149,13 +150,34 @@ private:
 | 
				
			||||||
                [&](Node &N) { F.Background = scalarValue(N, "Background"); });
 | 
					                [&](Node &N) { F.Background = scalarValue(N, "Background"); });
 | 
				
			||||||
    Dict.handle("External", [&](Node &N) {
 | 
					    Dict.handle("External", [&](Node &N) {
 | 
				
			||||||
      Fragment::IndexBlock::ExternalBlock External;
 | 
					      Fragment::IndexBlock::ExternalBlock External;
 | 
				
			||||||
      parse(External, N);
 | 
					      // 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.emplace(std::move(External));
 | 
				
			||||||
      F.External->Range = N.getSourceRange();
 | 
					      F.External->Range = N.getSourceRange();
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    Dict.parse(N);
 | 
					    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) {
 | 
					  void parse(Fragment::IndexBlock::ExternalBlock &F, Node &N) {
 | 
				
			||||||
    DictParser Dict("External", this);
 | 
					    DictParser Dict("External", this);
 | 
				
			||||||
    Dict.handle("File", [&](Node &N) { F.File = scalarValue(N, "File"); });
 | 
					    Dict.handle("File", [&](Node &N) { F.File = scalarValue(N, "File"); });
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -327,21 +327,31 @@ TEST_F(ConfigCompileTests, ExternalBlockWarnOnMultipleSource) {
 | 
				
			||||||
#ifdef CLANGD_ENABLE_REMOTE
 | 
					#ifdef CLANGD_ENABLE_REMOTE
 | 
				
			||||||
  EXPECT_THAT(
 | 
					  EXPECT_THAT(
 | 
				
			||||||
      Diags.Diagnostics,
 | 
					      Diags.Diagnostics,
 | 
				
			||||||
      Contains(AllOf(DiagMessage("Exactly one of File or Server must be set."),
 | 
					      Contains(
 | 
				
			||||||
                     DiagKind(llvm::SourceMgr::DK_Error))));
 | 
					          AllOf(DiagMessage("Exactly one of File, Server or None must be set."),
 | 
				
			||||||
 | 
					                DiagKind(llvm::SourceMgr::DK_Error))));
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
  ASSERT_TRUE(Conf.Index.External.hasValue());
 | 
					  ASSERT_TRUE(Conf.Index.External.hasValue());
 | 
				
			||||||
  EXPECT_EQ(Conf.Index.External->Kind, Config::ExternalIndexSpec::File);
 | 
					  EXPECT_EQ(Conf.Index.External->Kind, Config::ExternalIndexSpec::File);
 | 
				
			||||||
#endif
 | 
					#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) {
 | 
					TEST_F(ConfigCompileTests, ExternalBlockErrOnNoSource) {
 | 
				
			||||||
  Frag.Index.External.emplace(Fragment::IndexBlock::ExternalBlock{});
 | 
					  Frag.Index.External.emplace(Fragment::IndexBlock::ExternalBlock{});
 | 
				
			||||||
  compileAndApply();
 | 
					  compileAndApply();
 | 
				
			||||||
  EXPECT_THAT(
 | 
					  EXPECT_THAT(
 | 
				
			||||||
      Diags.Diagnostics,
 | 
					      Diags.Diagnostics,
 | 
				
			||||||
      Contains(AllOf(DiagMessage("Exactly one of File or Server must be set."),
 | 
					      Contains(
 | 
				
			||||||
                     DiagKind(llvm::SourceMgr::DK_Error))));
 | 
					          AllOf(DiagMessage("Exactly one of File, Server or None must be set."),
 | 
				
			||||||
 | 
					                DiagKind(llvm::SourceMgr::DK_Error))));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
TEST_F(ConfigCompileTests, ExternalBlockDisablesBackgroundIndex) {
 | 
					TEST_F(ConfigCompileTests, ExternalBlockDisablesBackgroundIndex) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -147,6 +147,23 @@ horrible
 | 
				
			||||||
  ASSERT_THAT(Results, IsEmpty());
 | 
					  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) {
 | 
					TEST(ParseYAML, ExternalBlock) {
 | 
				
			||||||
  CapturedDiags Diags;
 | 
					  CapturedDiags Diags;
 | 
				
			||||||
  Annotations YAML(R"yaml(
 | 
					  Annotations YAML(R"yaml(
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue