diff --git a/clang-tools-extra/clangd/tool/ClangdMain.cpp b/clang-tools-extra/clangd/tool/ClangdMain.cpp --- a/clang-tools-extra/clangd/tool/ClangdMain.cpp +++ b/clang-tools-extra/clangd/tool/ClangdMain.cpp @@ -892,12 +892,16 @@ if (EnableConfig) { ProviderStack.push_back( config::Provider::fromAncestorRelativeYAMLFiles(".clangd", TFS)); - llvm::SmallString<256> UserConfig; - if (llvm::sys::path::user_config_directory(UserConfig)) { - llvm::sys::path::append(UserConfig, "clangd", "config.yaml"); - vlog("User config file is {0}", UserConfig); - ProviderStack.push_back(config::Provider::fromYAMLFile( - UserConfig, /*Directory=*/"", TFS, /*Trusted=*/true)); + std::vector UserConfigs; + if (llvm::sys::path::user_config_directories(UserConfigs)) { + for (auto ConfigRoot : UserConfigs) { + llvm::SmallString<128> UserConfig; + UserConfig.assign(ConfigRoot); + llvm::sys::path::append(UserConfig, "clangd", "config.yaml"); + vlog("User config file is {0}", UserConfig); + ProviderStack.push_back(config::Provider::fromYAMLFile( + UserConfig, /*Directory=*/"", TFS, /*Trusted=*/true)); + } } else { elog("Couldn't determine user config file, not loading"); } diff --git a/llvm/include/llvm/Support/Path.h b/llvm/include/llvm/Support/Path.h --- a/llvm/include/llvm/Support/Path.h +++ b/llvm/include/llvm/Support/Path.h @@ -419,12 +419,12 @@ /// @result True if a home directory is set, false otherwise. bool home_directory(SmallVectorImpl &result); -/// Get the directory where packages should read user-specific configurations. -/// e.g. $XDG_CONFIG_HOME. +/// Get the directories where packages should read user-specific +/// configurations. e.g. $XDG_CONFIG_HOME. /// -/// @param result Holds the resulting path name. +/// @param result Holds the resulting paths. /// @result True if the appropriate path was determined, it need not exist. -bool user_config_directory(SmallVectorImpl &result); +bool user_config_directories(std::vector &results); /// Get the directory where installed packages should put their /// machine-local cache, e.g. $XDG_CACHE_HOME. diff --git a/llvm/lib/Support/Unix/Path.inc b/llvm/lib/Support/Unix/Path.inc --- a/llvm/lib/Support/Unix/Path.inc +++ b/llvm/lib/Support/Unix/Path.inc @@ -1363,27 +1363,34 @@ return false; } -bool user_config_directory(SmallVectorImpl &result) { +bool user_config_directories(std::vector &results) { + bool found = false; + SmallString<128> result; #ifdef __APPLE__ // Mac: ~/Library/Preferences/ if (home_directory(result)) { append(result, "Library", "Preferences"); - return true; + results.push_back(result.c_str()); + found = true; } -#else +#endif + // XDG_CONFIG_HOME as defined in the XDG Base Directory Specification: // http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html if (const char *RequestedDir = getenv("XDG_CONFIG_HOME")) { result.clear(); result.append(RequestedDir, RequestedDir + strlen(RequestedDir)); - return true; + results.push_back(result.c_str()); + found = true; } -#endif + // Fallback: ~/.config + result.clear(); if (!home_directory(result)) { - return false; + return found; } append(result, ".config"); + results.push_back(result.c_str()); return true; } diff --git a/llvm/lib/Support/Windows/Path.inc b/llvm/lib/Support/Windows/Path.inc --- a/llvm/lib/Support/Windows/Path.inc +++ b/llvm/lib/Support/Windows/Path.inc @@ -1434,10 +1434,13 @@ return getKnownFolderPath(FOLDERID_Profile, result); } -bool user_config_directory(SmallVectorImpl &result) { +bool user_config_directories(std::vector &results) { // Either local or roaming appdata may be suitable in some cases, depending // on the data. Local is more conservative, Roaming may not always be correct. - return getKnownFolderPath(FOLDERID_LocalAppData, result); + SmallString result; + bool found = getKnownFolderPath(FOLDERID_LocalAppData, &result); + results.push_back(result.c_str()); + return found; } bool cache_directory(SmallVectorImpl &result) { diff --git a/llvm/unittests/Support/Path.cpp b/llvm/unittests/Support/Path.cpp --- a/llvm/unittests/Support/Path.cpp +++ b/llvm/unittests/Support/Path.cpp @@ -509,9 +509,10 @@ TEST(Support, ConfigDirectoryWithEnv) { WithEnv Env("XDG_CONFIG_HOME", "/xdg/config"); - SmallString<128> ConfigDir; - EXPECT_TRUE(path::user_config_directory(ConfigDir)); - EXPECT_EQ("/xdg/config", ConfigDir); + std::vector ConfigDirs; + EXPECT_TRUE(path::user_config_directories(ConfigDirs)); + std::vector Expected = {"/xdg/config"}; + EXPECT_EQ(Expected, ConfigDirs); } TEST(Support, ConfigDirectoryNoEnv) { @@ -521,9 +522,10 @@ ASSERT_TRUE(path::home_directory(Fallback)); path::append(Fallback, ".config"); - SmallString<128> CacheDir; - EXPECT_TRUE(path::user_config_directory(CacheDir)); - EXPECT_EQ(Fallback, CacheDir); + std::vector ConfigDirs; + EXPECT_TRUE(path::user_config_directories(ConfigDirs)); + std::vector Expected = {std::string(Fallback)}; + EXPECT_EQ(Expected, ConfigDirs); } TEST(Support, CacheDirectoryWithEnv) { @@ -549,13 +551,41 @@ #ifdef __APPLE__ TEST(Support, ConfigDirectory) { - SmallString<128> Fallback; - ASSERT_TRUE(path::home_directory(Fallback)); - path::append(Fallback, "Library/Preferences"); + WithEnv Env("XDG_CONFIG_HOME", nullptr); - SmallString<128> ConfigDir; - EXPECT_TRUE(path::user_config_directory(ConfigDir)); - EXPECT_EQ(Fallback, ConfigDir); + SmallString<128> HomerDir; + ASSERT_TRUE(path::home_directory(HomerDir)); + + SmallString<128> Preferences = HomerDir; + path::append(Preferences, "Library/Preferences"); + + SmallString<128> ConfigDir = HomerDir; + path::append(ConfigDir, ".config"); + + std::vector ConfigDirs; + EXPECT_TRUE(path::user_config_directories(ConfigDirs)); + std::vector Expected = {std::string(Preferences), + std::string(ConfigDir)}; + EXPECT_TRUE(Expected == ConfigDirs); +} + +TEST(Support, XDGConfigDirectory) { + WithEnv Env("XDG_CONFIG_HOME", "/xdg/config"); + + SmallString<128> HomerDir; + ASSERT_TRUE(path::home_directory(HomerDir)); + + SmallString<128> Preferences = HomerDir; + path::append(Preferences, "Library/Preferences"); + + SmallString<128> ConfigDir = HomerDir; + path::append(ConfigDir, ".config"); + + std::vector ConfigDirs; + EXPECT_TRUE(path::user_config_directories(ConfigDirs)); + std::vector Expected = {std::string(Preferences), "/xdg/config", + std::string(ConfigDir)}; + EXPECT_TRUE(Expected == ConfigDirs); } #endif