forked from OSchip/llvm-project
Support: Add RedirectingFileSystem::create from simple list of redirections
Add an overload of `RedirectingFileSystem::create` that builds a redirecting filesystem off of a simple vector of string pairs. This is intended to be used to support `clang::arcmt::FileRemapper` and `clang::PreprocessorOptions::RemappedFiles`. Differential Revision: https://reviews.llvm.org/D91317
This commit is contained in:
parent
a22eda548b
commit
75cd8d756d
|
@ -731,6 +731,11 @@ public:
|
||||||
SourceMgr::DiagHandlerTy DiagHandler, StringRef YAMLFilePath,
|
SourceMgr::DiagHandlerTy DiagHandler, StringRef YAMLFilePath,
|
||||||
void *DiagContext, IntrusiveRefCntPtr<FileSystem> ExternalFS);
|
void *DiagContext, IntrusiveRefCntPtr<FileSystem> ExternalFS);
|
||||||
|
|
||||||
|
/// Redirect each of the remapped files from first to second.
|
||||||
|
static std::unique_ptr<RedirectingFileSystem>
|
||||||
|
create(ArrayRef<std::pair<std::string, std::string>> RemappedFiles,
|
||||||
|
bool UseExternalNames, FileSystem &ExternalFS);
|
||||||
|
|
||||||
ErrorOr<Status> status(const Twine &Path) override;
|
ErrorOr<Status> status(const Twine &Path) override;
|
||||||
ErrorOr<std::unique_ptr<File>> openFileForRead(const Twine &Path) override;
|
ErrorOr<std::unique_ptr<File>> openFileForRead(const Twine &Path) override;
|
||||||
|
|
||||||
|
|
|
@ -1272,7 +1272,8 @@ class llvm::vfs::RedirectingFileSystemParser {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
RedirectingFileSystem::Entry *
|
public:
|
||||||
|
static RedirectingFileSystem::Entry *
|
||||||
lookupOrCreateEntry(RedirectingFileSystem *FS, StringRef Name,
|
lookupOrCreateEntry(RedirectingFileSystem *FS, StringRef Name,
|
||||||
RedirectingFileSystem::Entry *ParentEntry = nullptr) {
|
RedirectingFileSystem::Entry *ParentEntry = nullptr) {
|
||||||
if (!ParentEntry) { // Look for a existent root
|
if (!ParentEntry) { // Look for a existent root
|
||||||
|
@ -1314,6 +1315,7 @@ class llvm::vfs::RedirectingFileSystemParser {
|
||||||
return DE->getLastContent();
|
return DE->getLastContent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
void uniqueOverlayTree(RedirectingFileSystem *FS,
|
void uniqueOverlayTree(RedirectingFileSystem *FS,
|
||||||
RedirectingFileSystem::Entry *SrcE,
|
RedirectingFileSystem::Entry *SrcE,
|
||||||
RedirectingFileSystem::Entry *NewParentE = nullptr) {
|
RedirectingFileSystem::Entry *NewParentE = nullptr) {
|
||||||
|
@ -1682,6 +1684,61 @@ RedirectingFileSystem::create(std::unique_ptr<MemoryBuffer> Buffer,
|
||||||
return FS;
|
return FS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<RedirectingFileSystem> RedirectingFileSystem::create(
|
||||||
|
ArrayRef<std::pair<std::string, std::string>> RemappedFiles,
|
||||||
|
bool UseExternalNames, FileSystem &ExternalFS) {
|
||||||
|
std::unique_ptr<RedirectingFileSystem> FS(
|
||||||
|
new RedirectingFileSystem(&ExternalFS));
|
||||||
|
FS->UseExternalNames = UseExternalNames;
|
||||||
|
|
||||||
|
StringMap<RedirectingFileSystem::Entry *> Entries;
|
||||||
|
|
||||||
|
for (auto &Mapping : llvm::reverse(RemappedFiles)) {
|
||||||
|
SmallString<128> From = StringRef(Mapping.first);
|
||||||
|
SmallString<128> To = StringRef(Mapping.second);
|
||||||
|
{
|
||||||
|
auto EC = ExternalFS.makeAbsolute(From);
|
||||||
|
(void)EC;
|
||||||
|
assert(!EC && "Could not make absolute path");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if we've already mapped this file. The first one we see (in the
|
||||||
|
// reverse iteration) wins.
|
||||||
|
RedirectingFileSystem::Entry *&ToEntry = Entries[From];
|
||||||
|
if (ToEntry)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Add parent directories.
|
||||||
|
RedirectingFileSystem::Entry *Parent = nullptr;
|
||||||
|
StringRef FromDirectory = llvm::sys::path::parent_path(From);
|
||||||
|
for (auto I = llvm::sys::path::begin(FromDirectory),
|
||||||
|
E = llvm::sys::path::end(FromDirectory);
|
||||||
|
I != E; ++I) {
|
||||||
|
Parent = RedirectingFileSystemParser::lookupOrCreateEntry(FS.get(), *I,
|
||||||
|
Parent);
|
||||||
|
}
|
||||||
|
assert(Parent && "File without a directory?");
|
||||||
|
{
|
||||||
|
auto EC = ExternalFS.makeAbsolute(To);
|
||||||
|
(void)EC;
|
||||||
|
assert(!EC && "Could not make absolute path");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the file.
|
||||||
|
auto NewFile =
|
||||||
|
std::make_unique<RedirectingFileSystem::RedirectingFileEntry>(
|
||||||
|
llvm::sys::path::filename(From), To,
|
||||||
|
UseExternalNames
|
||||||
|
? RedirectingFileSystem::RedirectingFileEntry::NK_External
|
||||||
|
: RedirectingFileSystem::RedirectingFileEntry::NK_Virtual);
|
||||||
|
ToEntry = NewFile.get();
|
||||||
|
cast<RedirectingFileSystem::RedirectingDirectoryEntry>(Parent)->addContent(
|
||||||
|
std::move(NewFile));
|
||||||
|
}
|
||||||
|
|
||||||
|
return FS;
|
||||||
|
}
|
||||||
|
|
||||||
ErrorOr<RedirectingFileSystem::Entry *>
|
ErrorOr<RedirectingFileSystem::Entry *>
|
||||||
RedirectingFileSystem::lookupPath(const Twine &Path_) const {
|
RedirectingFileSystem::lookupPath(const Twine &Path_) const {
|
||||||
SmallString<256> Path;
|
SmallString<256> Path;
|
||||||
|
|
|
@ -2287,3 +2287,89 @@ TEST_F(VFSFromYAMLTest, YAMLVFSWriterTestHandleDirs) {
|
||||||
EXPECT_FALSE(FS->exists(_b.path("b")));
|
EXPECT_FALSE(FS->exists(_b.path("b")));
|
||||||
EXPECT_FALSE(FS->exists(_c.path("c")));
|
EXPECT_FALSE(FS->exists(_c.path("c")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(VFSFromRemappedFilesTest, Basic) {
|
||||||
|
IntrusiveRefCntPtr<vfs::InMemoryFileSystem> BaseFS =
|
||||||
|
new vfs::InMemoryFileSystem;
|
||||||
|
BaseFS->addFile("//root/b", 0, MemoryBuffer::getMemBuffer("contents of b"));
|
||||||
|
BaseFS->addFile("//root/c", 0, MemoryBuffer::getMemBuffer("contents of c"));
|
||||||
|
|
||||||
|
std::vector<std::pair<std::string, std::string>> RemappedFiles = {
|
||||||
|
{"//root/a/a", "//root/b"},
|
||||||
|
{"//root/a/b/c", "//root/c"},
|
||||||
|
};
|
||||||
|
auto RemappedFS = vfs::RedirectingFileSystem::create(
|
||||||
|
RemappedFiles, /*UseExternalNames=*/false, *BaseFS);
|
||||||
|
|
||||||
|
auto StatA = RemappedFS->status("//root/a/a");
|
||||||
|
auto StatB = RemappedFS->status("//root/a/b/c");
|
||||||
|
ASSERT_TRUE(StatA);
|
||||||
|
ASSERT_TRUE(StatB);
|
||||||
|
EXPECT_EQ("//root/a/a", StatA->getName());
|
||||||
|
EXPECT_EQ("//root/a/b/c", StatB->getName());
|
||||||
|
|
||||||
|
auto BufferA = RemappedFS->getBufferForFile("//root/a/a");
|
||||||
|
auto BufferB = RemappedFS->getBufferForFile("//root/a/b/c");
|
||||||
|
ASSERT_TRUE(BufferA);
|
||||||
|
ASSERT_TRUE(BufferB);
|
||||||
|
EXPECT_EQ("contents of b", (*BufferA)->getBuffer());
|
||||||
|
EXPECT_EQ("contents of c", (*BufferB)->getBuffer());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(VFSFromRemappedFilesTest, UseExternalNames) {
|
||||||
|
IntrusiveRefCntPtr<vfs::InMemoryFileSystem> BaseFS =
|
||||||
|
new vfs::InMemoryFileSystem;
|
||||||
|
BaseFS->addFile("//root/b", 0, MemoryBuffer::getMemBuffer("contents of b"));
|
||||||
|
BaseFS->addFile("//root/c", 0, MemoryBuffer::getMemBuffer("contents of c"));
|
||||||
|
|
||||||
|
std::vector<std::pair<std::string, std::string>> RemappedFiles = {
|
||||||
|
{"//root/a/a", "//root/b"},
|
||||||
|
{"//root/a/b/c", "//root/c"},
|
||||||
|
};
|
||||||
|
auto RemappedFS = vfs::RedirectingFileSystem::create(
|
||||||
|
RemappedFiles, /*UseExternalNames=*/true, *BaseFS);
|
||||||
|
|
||||||
|
auto StatA = RemappedFS->status("//root/a/a");
|
||||||
|
auto StatB = RemappedFS->status("//root/a/b/c");
|
||||||
|
ASSERT_TRUE(StatA);
|
||||||
|
ASSERT_TRUE(StatB);
|
||||||
|
EXPECT_EQ("//root/b", StatA->getName());
|
||||||
|
EXPECT_EQ("//root/c", StatB->getName());
|
||||||
|
|
||||||
|
auto BufferA = RemappedFS->getBufferForFile("//root/a/a");
|
||||||
|
auto BufferB = RemappedFS->getBufferForFile("//root/a/b/c");
|
||||||
|
ASSERT_TRUE(BufferA);
|
||||||
|
ASSERT_TRUE(BufferB);
|
||||||
|
EXPECT_EQ("contents of b", (*BufferA)->getBuffer());
|
||||||
|
EXPECT_EQ("contents of c", (*BufferB)->getBuffer());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(VFSFromRemappedFilesTest, LastMappingWins) {
|
||||||
|
IntrusiveRefCntPtr<vfs::InMemoryFileSystem> BaseFS =
|
||||||
|
new vfs::InMemoryFileSystem;
|
||||||
|
BaseFS->addFile("//root/b", 0, MemoryBuffer::getMemBuffer("contents of b"));
|
||||||
|
BaseFS->addFile("//root/c", 0, MemoryBuffer::getMemBuffer("contents of c"));
|
||||||
|
|
||||||
|
std::vector<std::pair<std::string, std::string>> RemappedFiles = {
|
||||||
|
{"//root/a", "//root/b"},
|
||||||
|
{"//root/a", "//root/c"},
|
||||||
|
};
|
||||||
|
auto RemappedFSKeepName = vfs::RedirectingFileSystem::create(
|
||||||
|
RemappedFiles, /*UseExternalNames=*/false, *BaseFS);
|
||||||
|
auto RemappedFSExternalName = vfs::RedirectingFileSystem::create(
|
||||||
|
RemappedFiles, /*UseExternalNames=*/true, *BaseFS);
|
||||||
|
|
||||||
|
auto StatKeepA = RemappedFSKeepName->status("//root/a");
|
||||||
|
auto StatExternalA = RemappedFSExternalName->status("//root/a");
|
||||||
|
ASSERT_TRUE(StatKeepA);
|
||||||
|
ASSERT_TRUE(StatExternalA);
|
||||||
|
EXPECT_EQ("//root/a", StatKeepA->getName());
|
||||||
|
EXPECT_EQ("//root/c", StatExternalA->getName());
|
||||||
|
|
||||||
|
auto BufferKeepA = RemappedFSKeepName->getBufferForFile("//root/a");
|
||||||
|
auto BufferExternalA = RemappedFSExternalName->getBufferForFile("//root/a");
|
||||||
|
ASSERT_TRUE(BufferKeepA);
|
||||||
|
ASSERT_TRUE(BufferExternalA);
|
||||||
|
EXPECT_EQ("contents of c", (*BufferKeepA)->getBuffer());
|
||||||
|
EXPECT_EQ("contents of c", (*BufferExternalA)->getBuffer());
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue