Index: clangd/ClangdUnit.cpp =================================================================== --- clangd/ClangdUnit.cpp +++ clangd/ClangdUnit.cpp @@ -29,6 +29,7 @@ #include "clang/Serialization/ASTWriter.h" #include "clang/Tooling/CompilationDatabase.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Support/CrashRecoveryContext.h" #include "llvm/Support/raw_ostream.h" @@ -336,7 +337,9 @@ // dirs. } - auto StatCache = llvm::make_unique(); + llvm::SmallString<32> AbsFileName(FileName); + Inputs.FS->makeAbsolute(AbsFileName); + auto StatCache = llvm::make_unique(AbsFileName); auto BuiltPreamble = PrecompiledPreamble::Build( CI, ContentsBuffer.get(), Bounds, *PreambleDiagsEngine, StatCache->getProducingFS(Inputs.FS), PCHs, StoreInMemory, Index: clangd/FS.h =================================================================== --- clangd/FS.h +++ clangd/FS.h @@ -17,10 +17,10 @@ namespace clangd { /// Records status information for files open()ed or stat()ed during preamble -/// build, so we can avoid stat()s on the underlying FS when reusing the -/// preamble. For example, code completion can re-stat files when getting FileID -/// for source locations stored in preamble (e.g. checking whether a location is -/// in the main file). +/// build (except for the main file), so we can avoid stat()s on the underlying +/// FS when reusing the preamble. For example, code completion can re-stat files +/// when getting FileID for source locations stored in preamble (e.g. checking +/// whether a location is in the main file). /// /// The cache is keyed by absolute path of file name in cached status, as this /// is what preamble stores. @@ -35,7 +35,12 @@ /// Note that the cache is only valid when reusing preamble. class PreambleFileStatusCache { public: + /// \p MainFilePath is the absolute path of the main source file this preamble + /// corresponds to. The stat for the main file will not be cached. + PreambleFileStatusCache(llvm::StringRef MainFilePath); + void update(const vfs::FileSystem &FS, vfs::Status S); + /// \p Path is a path stored in preamble. llvm::Optional lookup(llvm::StringRef Path) const; @@ -56,6 +61,7 @@ getConsumingFS(IntrusiveRefCntPtr FS) const; private: + std::string MainFilePath; llvm::StringMap StatCache; }; Index: clangd/FS.cpp =================================================================== --- clangd/FS.cpp +++ clangd/FS.cpp @@ -10,14 +10,23 @@ #include "FS.h" #include "clang/Basic/VirtualFileSystem.h" #include "llvm/ADT/None.h" +#include "llvm/Support/Path.h" namespace clang { namespace clangd { +PreambleFileStatusCache::PreambleFileStatusCache(llvm::StringRef MainFilePath) + : MainFilePath(MainFilePath) { + assert(llvm::sys::path::is_absolute(MainFilePath)); +} + void PreambleFileStatusCache::update(const vfs::FileSystem &FS, vfs::Status S) { SmallString<32> PathStore(S.getName()); if (FS.makeAbsolute(PathStore)) return; + // Do not cache status for the main file. + if (PathStore == MainFilePath) + return; // Stores the latest status in cache as it can change in a preamble build. StatCache.insert({PathStore, std::move(S)}); } Index: unittests/clangd/FSTests.cpp =================================================================== --- unittests/clangd/FSTests.cpp +++ unittests/clangd/FSTests.cpp @@ -20,16 +20,20 @@ llvm::StringMap Files; Files["x"] = ""; Files["y"] = ""; + Files["main"] = ""; auto FS = buildTestFS(Files); FS->setCurrentWorkingDirectory(testRoot()); - PreambleFileStatusCache StatCache; + PreambleFileStatusCache StatCache(testPath("main")); auto ProduceFS = StatCache.getProducingFS(FS); EXPECT_TRUE(ProduceFS->openFileForRead("x")); EXPECT_TRUE(ProduceFS->status("y")); + EXPECT_TRUE(ProduceFS->status("main")); EXPECT_TRUE(StatCache.lookup(testPath("x")).hasValue()); EXPECT_TRUE(StatCache.lookup(testPath("y")).hasValue()); + // Main file is not cached. + EXPECT_FALSE(StatCache.lookup(testPath("main")).hasValue()); vfs::Status S("fake", llvm::sys::fs::UniqueID(0, 0), std::chrono::system_clock::now(), 0, 0, 1024,