From f13302e63ff0c858ecac7cc30ea2201c523a43ba Mon Sep 17 00:00:00 2001 From: Ben Langmuir <blangmuir@apple.com> Date: Thu, 10 Dec 2015 23:41:39 +0000 Subject: [PATCH] [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 --- clang/lib/Basic/VirtualFileSystem.cpp | 48 +++++++++++-------- clang/test/VFS/Inputs/public_header.h | 1 + clang/test/VFS/Inputs/public_header3.h | 1 + clang/test/VFS/Inputs/vfsoverlay.yaml | 4 +- clang/test/VFS/real-path-found-first.m | 1 + .../unittests/Basic/VirtualFileSystemTest.cpp | 27 ++++++++++- 6 files changed, 59 insertions(+), 23 deletions(-) create mode 100644 clang/test/VFS/Inputs/public_header3.h diff --git a/clang/lib/Basic/VirtualFileSystem.cpp b/clang/lib/Basic/VirtualFileSystem.cpp index 501a5ddb8496..cf5a8d681eac 100644 --- a/clang/lib/Basic/VirtualFileSystem.cpp +++ b/clang/lib/Basic/VirtualFileSystem.cpp @@ -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> diff --git a/clang/test/VFS/Inputs/public_header.h b/clang/test/VFS/Inputs/public_header.h index 09d9969d319d..cc7bcb57eea1 100644 --- a/clang/test/VFS/Inputs/public_header.h +++ b/clang/test/VFS/Inputs/public_header.h @@ -1,2 +1,3 @@ #import <SomeFramework/public_header2.h> +#import "public_header3.h" // includer-relative void from_framework(void); diff --git a/clang/test/VFS/Inputs/public_header3.h b/clang/test/VFS/Inputs/public_header3.h new file mode 100644 index 000000000000..ac9deac6ab36 --- /dev/null +++ b/clang/test/VFS/Inputs/public_header3.h @@ -0,0 +1 @@ +// public_header3.h diff --git a/clang/test/VFS/Inputs/vfsoverlay.yaml b/clang/test/VFS/Inputs/vfsoverlay.yaml index f395d45ee3b7..504a1530d3c5 100644 --- a/clang/test/VFS/Inputs/vfsoverlay.yaml +++ b/clang/test/VFS/Inputs/vfsoverlay.yaml @@ -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' } ] } ] diff --git a/clang/test/VFS/real-path-found-first.m b/clang/test/VFS/real-path-found-first.m index 3b37a644bcbd..5838aa36c452 100644 --- a/clang/test/VFS/real-path-found-first.m +++ b/clang/test/VFS/real-path-found-first.m @@ -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 diff --git a/clang/unittests/Basic/VirtualFileSystemTest.cpp b/clang/unittests/Basic/VirtualFileSystemTest.cpp index 96b8295acdbb..ac07035d3e1f 100644 --- a/clang/unittests/Basic/VirtualFileSystemTest.cpp +++ b/clang/unittests/Basic/VirtualFileSystemTest.cpp @@ -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/");