Index: clang-tools-extra/clangd/index/BackgroundIndexStorage.cpp =================================================================== --- clang-tools-extra/clangd/index/BackgroundIndexStorage.cpp +++ clang-tools-extra/clangd/index/BackgroundIndexStorage.cpp @@ -106,15 +106,15 @@ std::function(PathRef)> GetProjectInfo) : IndexStorageMapMu(std::make_unique()), GetProjectInfo(std::move(GetProjectInfo)) { - llvm::SmallString<128> HomeDir; - llvm::sys::path::home_directory(HomeDir); - this->HomeDir = HomeDir.str().str(); + llvm::SmallString<128> CacheDir; + llvm::sys::path::cache_directory(CacheDir); + this->CacheDir = CacheDir.str().str(); } // Creates or fetches to storage from cache for the specified project. BackgroundIndexStorage *operator()(PathRef File) { std::lock_guard Lock(*IndexStorageMapMu); - Path CDBDirectory = HomeDir; + Path CDBDirectory = CacheDir; if (auto PI = GetProjectInfo(File)) CDBDirectory = PI->SourceRoot; auto &IndexStorage = IndexStorageMap[CDBDirectory]; @@ -132,7 +132,7 @@ return std::make_unique(CDBDirectory); } - Path HomeDir; + Path CacheDir; llvm::StringMap> IndexStorageMap; std::unique_ptr IndexStorageMapMu; Index: llvm/include/llvm/Support/Path.h =================================================================== --- llvm/include/llvm/Support/Path.h +++ llvm/include/llvm/Support/Path.h @@ -368,6 +368,13 @@ /// @result True if a home directory is set, false otherwise. bool home_directory(SmallVectorImpl &result); +/// Get the directory where installed packages should put their +/// machine-local cache. +/// +/// @param result Holds the resulting path name. +/// @result True if the appropriate directory was found. +bool cache_directory(SmallVectorImpl &result); + /// Has root name? /// /// root_name != "" Index: llvm/lib/Support/Unix/Path.inc =================================================================== --- llvm/lib/Support/Unix/Path.inc +++ llvm/lib/Support/Unix/Path.inc @@ -1138,6 +1138,20 @@ return true; } +bool cache_directory(SmallVectorImpl &result) { + char *RequestedDir = getenv("XDG_CACHE_HOME"); + if (RequestedDir) { + result.clear(); + result.append(RequestedDir, RequestedDir + strlen(RequestedDir)); + return true; + } + if (!home_directory(result)) { + return false; + } + append(result, ".cache"); + return true; +} + static bool getDarwinConfDir(bool TempDir, SmallVectorImpl &Result) { #if defined(_CS_DARWIN_USER_TEMP_DIR) && defined(_CS_DARWIN_USER_CACHE_DIR) // On Darwin, use DARWIN_USER_TEMP_DIR or DARWIN_USER_CACHE_DIR. Index: llvm/lib/Support/Windows/Path.inc =================================================================== --- llvm/lib/Support/Windows/Path.inc +++ llvm/lib/Support/Windows/Path.inc @@ -1372,6 +1372,10 @@ return getKnownFolderPath(FOLDERID_Profile, result); } +bool cache_directory(SmallVectorImpl &result) { + return getKnownFolderPath(FOLDERID_LocalAppData, result); +} + static bool getTempDirEnvVar(const wchar_t *Var, SmallVectorImpl &Res) { SmallVector Buf; size_t Size = 1024; Index: llvm/unittests/Support/Path.cpp =================================================================== --- llvm/unittests/Support/Path.cpp +++ llvm/unittests/Support/Path.cpp @@ -358,6 +358,136 @@ } #endif +TEST(Support, CacheDirectoryWithEnv) { + + std::string expected; + + // The value of the environment variable is set to a non-standard + // location for the test, so we have to store the original value + // even if it's not set. + // Use an std::string to copy the data + +#ifdef _WIN32 + std::wstring OriginalStorage; + if (wchar_t const *path = ::_wgetenv(L"XDG_CACHE_HOME")) { + OriginalStorage = path; + } + + ::_wputenv("XDG_CACHE_HOME", L"C:\\xdg\\cache"); + + if (wchar_t const *localAppData = ::_wgetenv(L"LOCALAPPDATA")) { + auto pathLen = ::wcslen(path); + ArrayRef ref{reinterpret_cast(path), + pathLen * sizeof(wchar_t)}; + convertUTF16ToUTF8String(ref, expected); + } + + // LocalAppData should always be set, but better safe than sorry + if (!expected.empty()) { + SmallString<128> CacheDir; + auto status = path::cache_directory(CacheDir); + EXPECT_TRUE(status); + EXPECT_EQ(expected, CacheDir); + } + + if (!OriginalStorage.empty()) { + ::_wputenv("XDG_CACHE_HOME", OriginalStorage.c_str()); + } else { + ::_wputenv("XDG_CACHE_HOME", nullptr); + } +#else + std::string OriginalStorage; + if (char const *path = ::getenv("XDG_CACHE_HOME")) { + OriginalStorage = path; + } + + expected = "/xdg/cache"; + ::setenv("XDG_CACHE_HOME", expected.c_str(), 1); + EXPECT_EQ(expected, std::string(::getenv("XDG_CACHE_HOME"))); + + { + SmallString<128> CacheDir; + auto status = path::cache_directory(CacheDir); + EXPECT_TRUE(status); + EXPECT_EQ(expected, CacheDir); + } + + if (!OriginalStorage.empty()) { + ::setenv("XDG_CACHE_HOME", OriginalStorage.c_str(), 1); + } else { + ::unsetenv("XDG_CACHE_HOME"); + } +#endif +} + +TEST(Support, CacheDirectoryNoEnv) { + std::string expected; +#ifdef _WIN32 + std::wstring OriginalStorage; + if (wchar_t const *path = ::_wgetenv(L"XDG_CACHE_HOME")) { + OriginalStorage = path; + } + + ::_wputenv("XDG_CACHE_HOME", nullptr); + EXPECT_EQ(nullptr, ::_wgetenv("XDG_CACHE_HOME")); + + if (wchar_t const *localAppData = ::_wgetenv(L"LOCALAPPDATA")) { + auto pathLen = ::wcslen(path); + ArrayRef ref{reinterpret_cast(path), + pathLen * sizeof(wchar_t)}; + convertUTF16ToUTF8String(ref, expected); + } + + // LocalAppData should always be set, but better safe than sorry + if (!expected.empty()) { + SmallString<128> CacheDir; + auto status = path::cache_directory(CacheDir); + EXPECT_TRUE(status); + EXPECT_EQ(expected, CacheDir); + } + + if (!OriginalStorage.empty()) { + ::_wputenv("XDG_CACHE_HOME", OriginalStorage.c_str()); + } else { + ::_wputenv("XDG_CACHE_HOME", nullptr); + } +#else + std::string OriginalStorage; + if (char const *path = ::getenv("XDG_CACHE_HOME")) { + OriginalStorage = path; + } + + ::unsetenv("XDG_CACHE_HOME"); + EXPECT_EQ(nullptr, ::getenv("XDG_CACHE_HOME")); + + SmallString<128> HomeDir; + if (path::home_directory(HomeDir)) { + path::append(HomeDir, ".cache"); + expected = std::string(HomeDir.str()); + } + + if (!expected.empty()) { + SmallString<128> CacheDir; + auto status = path::cache_directory(CacheDir); + EXPECT_TRUE(status); + EXPECT_EQ(expected, CacheDir); + } + + { + SmallString<128> CacheDir; + auto status = path::cache_directory(CacheDir); + EXPECT_TRUE(status); + EXPECT_EQ(expected, CacheDir); + } + + if (!OriginalStorage.empty()) { + ::setenv("XDG_CACHE_HOME", OriginalStorage.c_str(), 1); + } else { + ::unsetenv("XDG_CACHE_HOME"); + } +#endif +} + TEST(Support, TempDirectory) { SmallString<32> TempDir; path::system_temp_directory(false, TempDir);