diff --git a/clang-tools-extra/clangd/CompileCommands.cpp b/clang-tools-extra/clangd/CompileCommands.cpp --- a/clang-tools-extra/clangd/CompileCommands.cpp +++ b/clang-tools-extra/clangd/CompileCommands.cpp @@ -208,8 +208,13 @@ Cmd = tooling::getStripPluginsAdjuster()(Cmd, ""); Cmd = tooling::getClangSyntaxOnlyAdjuster()(Cmd, ""); - if (ResourceDir && !Has("-resource-dir")) - Cmd.push_back(("-resource-dir=" + *ResourceDir)); + if (!Has("-resource-dir")) { + // Prefer specified resource-dir over the one in config. + auto RDir = + ResourceDir ? *ResourceDir : Config::current().CompileFlags.ResourceDir; + if (!RDir.empty()) + Cmd.push_back(("-resource-dir=" + RDir)); + } // Don't set `-isysroot` if it is already set or if `--sysroot` is set. // `--sysroot` is a superset of the `-isysroot` argument. @@ -503,7 +508,6 @@ Args.resize(Write); } - std::string printArgv(llvm::ArrayRef Args) { std::string Buf; llvm::raw_string_ostream OS(Buf); diff --git a/clang-tools-extra/clangd/Config.h b/clang-tools-extra/clangd/Config.h --- a/clang-tools-extra/clangd/Config.h +++ b/clang-tools-extra/clangd/Config.h @@ -65,6 +65,8 @@ Edits; /// Where to search for compilation databases for this file's flags. CDBSearchSpec CDBSearch = {CDBSearchSpec::Ancestors, llvm::None}; + /// Directory to look for internal headers. + std::string ResourceDir; } CompileFlags; enum class BackgroundPolicy { Build, Skip }; 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 @@ -301,6 +301,16 @@ C.CompileFlags.CDBSearch = Spec; }); } + + if (F.ResourceDir) { + if (auto Path = makeAbsolute(*F.ResourceDir, "ResourceDir", + llvm::sys::path::Style::native)) { + Out.Apply.push_back( + [Path(std::move(*Path))](const Params &, Config &C) { + C.CompileFlags.ResourceDir = Path; + }); + } + } } void compile(Fragment::IndexBlock &&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 @@ -158,6 +158,11 @@ /// - Ancestors: search all parent directories (the default) /// - None: do not use a compilation database, just default flags. llvm::Optional> CompilationDatabase; + + /// Path to a directory on user's machine, that'll be used to search for + /// built-in headers. Relative paths may be used, if config fragment is + /// associated with a directory. + llvm::Optional> ResourceDir; }; CompileFlagsBlock CompileFlags; 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 @@ -98,6 +98,9 @@ Dict.handle("CompilationDatabase", [&](Node &N) { F.CompilationDatabase = scalarValue(N, "CompilationDatabase"); }); + Dict.handle("ResourceDir", [&](Node &N) { + F.ResourceDir = scalarValue(N, "ResourceDir"); + }); Dict.parse(N); } diff --git a/clang-tools-extra/clangd/unittests/CompileCommandsTests.cpp b/clang-tools-extra/clangd/unittests/CompileCommandsTests.cpp --- a/clang-tools-extra/clangd/unittests/CompileCommandsTests.cpp +++ b/clang-tools-extra/clangd/unittests/CompileCommandsTests.cpp @@ -52,10 +52,22 @@ TEST(CommandMangler, ResourceDir) { auto Mangler = CommandMangler::forTests(); - Mangler.ResourceDir = testPath("fake/resources"); + + // Check config works. + Config Cfg; + auto ResourceDir = testPath("config/resources"); + Cfg.CompileFlags.ResourceDir = ResourceDir; + WithContextValue WithConfig(Config::Key, std::move(Cfg)); std::vector Cmd = {"clang++", "foo.cc"}; Mangler.adjust(Cmd); - EXPECT_THAT(Cmd, Contains("-resource-dir=" + testPath("fake/resources"))); + EXPECT_THAT(Cmd, Contains("-resource-dir=" + ResourceDir)); + + // Check that explicit option overrides config. + ResourceDir = testPath("explicit/resources"); + Mangler.ResourceDir = ResourceDir; + Cmd = {"clang++", "foo.cc"}; + Mangler.adjust(Cmd); + EXPECT_THAT(Cmd, Contains("-resource-dir=" + ResourceDir)); } TEST(CommandMangler, Sysroot) { @@ -378,4 +390,3 @@ } // namespace } // namespace clangd } // namespace clang - 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 @@ -171,6 +171,22 @@ EXPECT_THAT(Diags.Diagnostics, IsEmpty()); } +TEST_F(ConfigCompileTests, ResourceDir) { + EXPECT_TRUE(compileAndApply()); + EXPECT_TRUE(Conf.CompileFlags.ResourceDir.empty()); + + auto ResourceDir = testPath("foo"); + Frag.CompileFlags.ResourceDir.emplace(ResourceDir); + EXPECT_TRUE(compileAndApply()); + EXPECT_EQ(Conf.CompileFlags.ResourceDir, ResourceDir); + + ResourceDir = "foo"; + Frag.Source.Directory = testRoot(); + Frag.CompileFlags.ResourceDir.emplace(ResourceDir); + EXPECT_TRUE(compileAndApply()); + EXPECT_EQ(Conf.CompileFlags.ResourceDir, testPath("foo")); +} + TEST_F(ConfigCompileTests, Index) { Frag.Index.Background.emplace("Skip"); EXPECT_TRUE(compileAndApply()); diff --git a/clang-tools-extra/clangd/unittests/ConfigYAMLTests.cpp b/clang-tools-extra/clangd/unittests/ConfigYAMLTests.cpp --- a/clang-tools-extra/clangd/unittests/ConfigYAMLTests.cpp +++ b/clang-tools-extra/clangd/unittests/ConfigYAMLTests.cpp @@ -14,6 +14,7 @@ #include "llvm/Support/SMLoc.h" #include "llvm/Support/ScopedPrinter.h" #include "llvm/Support/SourceMgr.h" +#include "llvm/Testing/Support/SupportHelpers.h" #include "gmock/gmock.h" #include "gtest/gtest.h" @@ -164,6 +165,17 @@ EXPECT_THAT(*Results[0].Index.External.getValue()->Server, Val("bar")); } +TEST(ParseYAML, ResourceDir) { + CapturedDiags Diags; + Annotations YAML(R"yaml( +CompileFlags: + ResourceDir: "foo")yaml"); + auto Results = + Fragment::parseYAML(YAML.code(), "config.yaml", Diags.callback()); + ASSERT_EQ(Results.size(), 1u); + ASSERT_THAT(Diags.Diagnostics, IsEmpty()); + EXPECT_THAT(Results[0].CompileFlags.ResourceDir, llvm::ValueIs(Val("foo"))); +} } // namespace } // namespace config } // namespace clangd