diff --git a/include/clang/Basic/FileManager.h b/include/clang/Basic/FileManager.h --- a/include/clang/Basic/FileManager.h +++ b/include/clang/Basic/FileManager.h @@ -299,6 +299,9 @@ std::error_code getNoncachedStatValue(StringRef Path, llvm::vfs::Status &Result); + /// Remove the real file \p Entry from the cache. + void invalidateCache(FileEntry *Entry); + /// If path is not absolute and FileSystemOptions set the working /// directory, the path is modified to be relative to the given /// working directory. diff --git a/include/clang/Basic/SourceManager.h b/include/clang/Basic/SourceManager.h --- a/include/clang/Basic/SourceManager.h +++ b/include/clang/Basic/SourceManager.h @@ -797,7 +797,7 @@ void clearIDTables(); - void invalidateCache(const FileEntry* Entry); + void invalidateCache(FileID FID); /// Initialize this source manager suitably to replay the compilation /// described by \p Old. Requires that \p Old outlive \p *this. diff --git a/lib/Basic/FileManager.cpp b/lib/Basic/FileManager.cpp --- a/lib/Basic/FileManager.cpp +++ b/lib/Basic/FileManager.cpp @@ -604,7 +604,7 @@ return std::error_code(); } -void FileManager::invalidateCache(const FileEntry *Entry) { +void FileManager::invalidateCache(FileEntry *Entry) { assert(Entry && "Cannot invalidate a NULL FileEntry"); FileEntriesToReread.insert(Entry->getLastRef()); Entry->IsValid = false; diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp --- a/lib/Basic/SourceManager.cpp +++ b/lib/Basic/SourceManager.cpp @@ -358,12 +358,23 @@ return false; } -void SourceManager::invalidateCache(const FileEntry* Entry) { +void SourceManager::invalidateCache(FileID FID) { + const FileEntry *Entry = getFileEntryForID(FID); + if (!Entry) + return; if (ContentCache *&E = FileInfos[Entry]) { - E->replaceBuffer(0, /*free*/ true); + E->setBuffer(nullptr); E = 0; } - getFileManager().invalidateCache(Entry); + if (!FID.isInvalid()) { + const SrcMgr::SLocEntry &SLocE = getSLocEntry(FID); + if (SLocE.isFile()) { + SrcMgr::ContentCache &CC = + const_cast(SLocE.getFile().getContentCache()); + CC.setBuffer(nullptr); + } + } + getFileManager().invalidateCache(const_cast(Entry)); } void SourceManager::initializeForReplay(const SourceManager &Old) { diff --git a/unittests/Basic/FileManagerTest.cpp b/unittests/Basic/FileManagerTest.cpp --- a/unittests/Basic/FileManagerTest.cpp +++ b/unittests/Basic/FileManagerTest.cpp @@ -6,7 +6,9 @@ // //===----------------------------------------------------------------------===// +#define private public #include "clang/Basic/FileManager.h" +#undef private #include "clang/Basic/FileSystemOptions.h" #include "clang/Basic/FileSystemStatCache.h" #include "llvm/ADT/STLExtras.h" @@ -98,6 +100,22 @@ FileManager manager; }; +// If file entry valid, mark the file entry invalid, until reread. +TEST_F(FileManagerTest, invalidateCacheSuccess) { + manager.setStatCache(std::make_unique()); + + manager.getVirtualFile("file.cpp", 100, 0); + auto file = manager.getFile("file.cpp"); + + // Check for file null assertion success + manager.InvalidateCache(NULL); + + manager.InvalidateCache(*file); + ASSERT_TRUE(manager.FileEntriesToReread); + + ASSERT_FALSE((*file)->isValid()); +} + // When a virtual file is added, its getDir() field is set correctly // (not NULL, correct name). TEST_F(FileManagerTest, getVirtualFileSetsTheDirFieldCorrectly) { diff --git a/unittests/Basic/SourceManagerTest.cpp b/unittests/Basic/SourceManagerTest.cpp --- a/unittests/Basic/SourceManagerTest.cpp +++ b/unittests/Basic/SourceManagerTest.cpp @@ -9,7 +9,9 @@ #include "clang/Basic/SourceManager.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/DiagnosticOptions.h" +#define private public #include "clang/Basic/FileManager.h" +#undef private #include "clang/Basic/LangOptions.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/TargetOptions.h" @@ -51,6 +53,26 @@ IntrusiveRefCntPtr Target; }; +// Test for invalidate cache success, making the file entry invalid, until +// reread +TEST_F(SourceManagerTest, invalidateCacheSuccess) { + const char *Source = "int x;"; + + std::unique_ptr Buf = + llvm::MemoryBuffer::getMemBuffer(source); + const FileEntry *SourceFile = + FileMgr.getVirtualFile("mainFile.cpp", Buf->getBufferSize(), 0); + + FileID mainFileID = SourceMgr.createFileID(std::move(Buf)); + SourceMgr.overrideFileContents(SourceFile, std::move(Buf)); + SourceMgr.setMainFileID(mainFileID); + SourceMgr::invalidateCache(mainFileID); + + EXPECT_FALSE(SrcMgr::ContentCache); + EXPECT_TRUE(SourceFile->FileEntriesToReread); + EXPECT_FALSE(SourceFile->isValid()); +} + TEST_F(SourceManagerTest, isBeforeInTranslationUnit) { const char *source = "#define M(x) [x]\n"