[VFS] Fix status() of opened redirected file

Make RedirectedFileSystem::openFilForRead(path)->status() the same as
RedirectedFileSystem::status(path). Previously we would just get the
status of the underlying real file, which would not have the IsVFSMapped
bit set.

This fixes rebuilding a module that has an include that is relative to
the includer where we will lookup the real path of that file before we
lookup the VFS location.

rdar://problem/23640339

llvm-svn: 255312
This commit is contained in:
Ben Langmuir 2015-12-10 23:41:39 +00:00
parent 8376037861
commit f13302e63f
6 changed files with 59 additions and 23 deletions

View File

@ -1266,20 +1266,27 @@ RedirectingFileSystem::lookupPath(sys::path::const_iterator Start,
return make_error_code(llvm::errc::no_such_file_or_directory);
}
static Status getRedirectedFileStatus(const Twine &Path, bool UseExternalNames,
Status ExternalStatus) {
Status S = ExternalStatus;
if (!UseExternalNames)
S = Status::copyWithNewName(S, Path.str());
S.IsVFSMapped = true;
return S;
}
ErrorOr<Status> RedirectingFileSystem::status(const Twine &Path, Entry *E) {
assert(E != nullptr);
std::string PathStr(Path.str());
if (auto *F = dyn_cast<RedirectingFileEntry>(E)) {
ErrorOr<Status> S = ExternalFS->status(F->getExternalContentsPath());
assert(!S || S->getName() == F->getExternalContentsPath());
if (S && !F->useExternalName(UseExternalNames))
*S = Status::copyWithNewName(*S, PathStr);
if (S)
S->IsVFSMapped = true;
return getRedirectedFileStatus(Path, F->useExternalName(UseExternalNames),
*S);
return S;
} else { // directory
auto *DE = cast<RedirectingDirectoryEntry>(E);
return Status::copyWithNewName(DE->getStatus(), PathStr);
return Status::copyWithNewName(DE->getStatus(), Path.str());
}
}
@ -1291,22 +1298,17 @@ ErrorOr<Status> RedirectingFileSystem::status(const Twine &Path) {
}
namespace {
/// Provide a file wrapper that returns the external name when asked.
class NamedFileAdaptor : public File {
/// Provide a file wrapper with an overriden status.
class FileWithFixedStatus : public File {
std::unique_ptr<File> InnerFile;
std::string NewName;
Status S;
public:
NamedFileAdaptor(std::unique_ptr<File> InnerFile, std::string NewName)
: InnerFile(std::move(InnerFile)), NewName(std::move(NewName)) {}
FileWithFixedStatus(std::unique_ptr<File> InnerFile, Status S)
: InnerFile(std::move(InnerFile)), S(S) {}
llvm::ErrorOr<Status> status() override {
auto InnerStatus = InnerFile->status();
if (InnerStatus)
return Status::copyWithNewName(*InnerStatus, NewName);
return InnerStatus.getError();
}
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
ErrorOr<Status> status() override { return S; }
ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
getBuffer(const Twine &Name, int64_t FileSize, bool RequiresNullTerminator,
bool IsVolatile) override {
return InnerFile->getBuffer(Name, FileSize, RequiresNullTerminator,
@ -1330,11 +1332,15 @@ RedirectingFileSystem::openFileForRead(const Twine &Path) {
if (!Result)
return Result;
if (!F->useExternalName(UseExternalNames))
return std::unique_ptr<File>(
new NamedFileAdaptor(std::move(*Result), Path.str()));
auto ExternalStatus = (*Result)->status();
if (!ExternalStatus)
return ExternalStatus.getError();
return Result;
// FIXME: Update the status with the name and VFSMapped.
Status S = getRedirectedFileStatus(Path, F->useExternalName(UseExternalNames),
*ExternalStatus);
return std::unique_ptr<File>(
llvm::make_unique<FileWithFixedStatus>(std::move(*Result), S));
}
IntrusiveRefCntPtr<FileSystem>

View File

@ -1,2 +1,3 @@
#import <SomeFramework/public_header2.h>
#import "public_header3.h" // includer-relative
void from_framework(void);

View File

@ -0,0 +1 @@
// public_header3.h

View File

@ -22,7 +22,9 @@
{ 'name': 'public_header.h', 'type': 'file',
'external-contents': 'INPUT_DIR/public_header.h' },
{ 'name': 'public_header2.h', 'type': 'file',
'external-contents': 'INPUT_DIR/public_header2.h' }
'external-contents': 'INPUT_DIR/public_header2.h' },
{ 'name': 'public_header3.h', 'type': 'file',
'external-contents': 'INPUT_DIR/public_header3.h' }
]
}
]

View File

@ -70,5 +70,6 @@
#ifndef WITH_PREFIX
#import <SomeFramework/public_header.h> // expected-warning{{treating}}
#import <SomeFramework/public_header2.h> // expected-warning{{treating}}
#import <SomeFramework/public_header3.h> // expected-warning{{treating}}
@import SomeFramework.public_header2;
#endif

View File

@ -20,6 +20,18 @@ using namespace llvm;
using llvm::sys::fs::UniqueID;
namespace {
struct DummyFile : public vfs::File {
vfs::Status S;
explicit DummyFile(vfs::Status S) : S(S) {}
llvm::ErrorOr<vfs::Status> status() override { return S; }
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
getBuffer(const Twine &Name, int64_t FileSize, bool RequiresNullTerminator,
bool IsVolatile) override {
llvm_unreachable("unimplemented");
}
virtual std::error_code close() override { return std::error_code(); }
};
class DummyFileSystem : public vfs::FileSystem {
int FSID; // used to produce UniqueIDs
int FileID; // used to produce UniqueIDs
@ -42,7 +54,10 @@ public:
}
ErrorOr<std::unique_ptr<vfs::File>>
openFileForRead(const Twine &Path) override {
llvm_unreachable("unimplemented");
auto S = status(Path);
if (S)
return std::unique_ptr<vfs::File>(new DummyFile{*S});
return S.getError();
}
llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override {
return std::string();
@ -718,10 +733,20 @@ TEST_F(VFSFromYAMLTest, MappedFiles) {
ErrorOr<vfs::Status> S = O->status("//root/file1");
ASSERT_FALSE(S.getError());
EXPECT_EQ("//root/foo/bar/a", S->getName());
EXPECT_TRUE(S->IsVFSMapped);
ErrorOr<vfs::Status> SLower = O->status("//root/foo/bar/a");
EXPECT_EQ("//root/foo/bar/a", SLower->getName());
EXPECT_TRUE(S->equivalent(*SLower));
EXPECT_FALSE(SLower->IsVFSMapped);
// file after opening
auto OpenedF = O->openFileForRead("//root/file1");
ASSERT_FALSE(OpenedF.getError());
auto OpenedS = (*OpenedF)->status();
ASSERT_FALSE(OpenedS.getError());
EXPECT_EQ("//root/foo/bar/a", OpenedS->getName());
EXPECT_TRUE(OpenedS->IsVFSMapped);
// directory
S = O->status("//root/");