diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Basic/VirtualFileSystem.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/Basic/VirtualFileSystem.cpp | 134 |
1 files changed, 108 insertions, 26 deletions
diff --git a/contrib/llvm/tools/clang/lib/Basic/VirtualFileSystem.cpp b/contrib/llvm/tools/clang/lib/Basic/VirtualFileSystem.cpp index 8ace2b3..50fcb22 100644 --- a/contrib/llvm/tools/clang/lib/Basic/VirtualFileSystem.cpp +++ b/contrib/llvm/tools/clang/lib/Basic/VirtualFileSystem.cpp @@ -47,7 +47,7 @@ Status::Status(const file_status &Status) User(Status.getUser()), Group(Status.getGroup()), Size(Status.getSize()), Type(Status.type()), Perms(Status.permissions()), IsVFSMapped(false) {} -Status::Status(StringRef Name, UniqueID UID, sys::TimeValue MTime, +Status::Status(StringRef Name, UniqueID UID, sys::TimePoint<> MTime, uint32_t User, uint32_t Group, uint64_t Size, file_type Type, perms Perms) : Name(Name), UID(UID), MTime(MTime), User(User), Group(Group), Size(Size), @@ -494,8 +494,8 @@ public: InMemoryFileSystem::InMemoryFileSystem(bool UseNormalizedPaths) : Root(new detail::InMemoryDirectory( - Status("", getNextVirtualUniqueID(), llvm::sys::TimeValue::MinTime(), - 0, 0, 0, llvm::sys::fs::file_type::directory_file, + Status("", getNextVirtualUniqueID(), llvm::sys::TimePoint<>(), 0, 0, + 0, llvm::sys::fs::file_type::directory_file, llvm::sys::fs::perms::all_all))), UseNormalizedPaths(UseNormalizedPaths) {} @@ -532,7 +532,7 @@ bool InMemoryFileSystem::addFile(const Twine &P, time_t ModificationTime, // End of the path, create a new file. // FIXME: expose the status details in the interface. Status Stat(P.str(), getNextVirtualUniqueID(), - llvm::sys::TimeValue(ModificationTime, 0), 0, 0, + llvm::sys::toTimePoint(ModificationTime), 0, 0, Buffer->getBufferSize(), llvm::sys::fs::file_type::regular_file, llvm::sys::fs::all_all); @@ -545,9 +545,9 @@ bool InMemoryFileSystem::addFile(const Twine &P, time_t ModificationTime, // FIXME: expose the status details in the interface. Status Stat( StringRef(Path.str().begin(), Name.end() - Path.str().begin()), - getNextVirtualUniqueID(), llvm::sys::TimeValue(ModificationTime, 0), - 0, 0, Buffer->getBufferSize(), - llvm::sys::fs::file_type::directory_file, llvm::sys::fs::all_all); + getNextVirtualUniqueID(), llvm::sys::toTimePoint(ModificationTime), 0, + 0, Buffer->getBufferSize(), llvm::sys::fs::file_type::directory_file, + llvm::sys::fs::all_all); Dir = cast<detail::InMemoryDirectory>(Dir->addChild( Name, llvm::make_unique<detail::InMemoryDirectory>(std::move(Stat)))); continue; @@ -801,6 +801,7 @@ public: /// 'case-sensitive': <boolean, default=true> /// 'use-external-names': <boolean, default=true> /// 'overlay-relative': <boolean, default=false> +/// 'ignore-non-existent-contents': <boolean, default=true> /// /// Virtual directories are represented as /// \verbatim @@ -860,6 +861,14 @@ class RedirectingFileSystem : public vfs::FileSystem { /// \brief Whether to use to use the value of 'external-contents' for the /// names of files. This global value is overridable on a per-file basis. bool UseExternalNames = true; + + /// \brief Whether an invalid path obtained via 'external-contents' should + /// cause iteration on the VFS to stop. If 'true', the VFS should ignore + /// the entry and continue with the next. Allows YAML files to be shared + /// across multiple compiler invocations regardless of prior existent + /// paths in 'external-contents'. This global value is overridable on a + /// per-file basis. + bool IgnoreNonExistentContents = true; /// @} /// Virtual file paths and external files could be canonicalized without "..", @@ -878,9 +887,6 @@ private: RedirectingFileSystem(IntrusiveRefCntPtr<FileSystem> ExternalFS) : ExternalFS(std::move(ExternalFS)) {} - /// \brief Looks up \p Path in \c Roots. - ErrorOr<Entry *> lookupPath(const Twine &Path); - /// \brief Looks up the path <tt>[Start, End)</tt> in \p From, possibly /// recursing into the contents of \p From if it is a directory. ErrorOr<Entry *> lookupPath(sys::path::const_iterator Start, @@ -890,6 +896,9 @@ private: ErrorOr<Status> status(const Twine &Path, Entry *E); public: + /// \brief Looks up \p Path in \c Roots. + ErrorOr<Entry *> lookupPath(const Twine &Path); + /// \brief Parses \p Buffer, which is expected to be in YAML format and /// returns a virtual file system representing its contents. static RedirectingFileSystem * @@ -937,6 +946,10 @@ public: return ExternalContentsPrefixDir; } + bool ignoreNonExistentContents() const { + return IgnoreNonExistentContents; + } + #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) LLVM_DUMP_METHOD void dump() const { for (const std::unique_ptr<Entry> &Root : Roots) @@ -1060,8 +1073,9 @@ class RedirectingFileSystemParser { // ... or create a new one std::unique_ptr<Entry> E = llvm::make_unique<RedirectingDirectoryEntry>( - Name, Status("", getNextVirtualUniqueID(), sys::TimeValue::now(), 0, 0, - 0, file_type::directory_file, sys::fs::all_all)); + Name, + Status("", getNextVirtualUniqueID(), std::chrono::system_clock::now(), + 0, 0, 0, file_type::directory_file, sys::fs::all_all)); if (!ParentEntry) { // Add a new root to the overlay FS->Roots.push_back(std::move(E)); @@ -1262,8 +1276,8 @@ class RedirectingFileSystemParser { case EK_Directory: Result = llvm::make_unique<RedirectingDirectoryEntry>( LastComponent, std::move(EntryArrayContents), - Status("", getNextVirtualUniqueID(), sys::TimeValue::now(), 0, 0, 0, - file_type::directory_file, sys::fs::all_all)); + Status("", getNextVirtualUniqueID(), std::chrono::system_clock::now(), + 0, 0, 0, file_type::directory_file, sys::fs::all_all)); break; } @@ -1279,8 +1293,8 @@ class RedirectingFileSystemParser { Entries.push_back(std::move(Result)); Result = llvm::make_unique<RedirectingDirectoryEntry>( *I, std::move(Entries), - Status("", getNextVirtualUniqueID(), sys::TimeValue::now(), 0, 0, 0, - file_type::directory_file, sys::fs::all_all)); + Status("", getNextVirtualUniqueID(), std::chrono::system_clock::now(), + 0, 0, 0, file_type::directory_file, sys::fs::all_all)); } return Result; } @@ -1301,6 +1315,7 @@ public: KeyStatusPair("case-sensitive", false), KeyStatusPair("use-external-names", false), KeyStatusPair("overlay-relative", false), + KeyStatusPair("ignore-non-existent-contents", false), KeyStatusPair("roots", true), }; @@ -1359,6 +1374,9 @@ public: } else if (Key == "use-external-names") { if (!parseScalarBool(I->getValue(), FS->UseExternalNames)) return false; + } else if (Key == "ignore-non-existent-contents") { + if (!parseScalarBool(I->getValue(), FS->IgnoreNonExistentContents)) + return false; } else { llvm_unreachable("key missing from Keys"); } @@ -1588,6 +1606,47 @@ vfs::getVFSFromYAML(std::unique_ptr<MemoryBuffer> Buffer, std::move(ExternalFS)); } +static void getVFSEntries(Entry *SrcE, SmallVectorImpl<StringRef> &Path, + SmallVectorImpl<YAMLVFSEntry> &Entries) { + auto Kind = SrcE->getKind(); + if (Kind == EK_Directory) { + auto *DE = dyn_cast<RedirectingDirectoryEntry>(SrcE); + assert(DE && "Must be a directory"); + for (std::unique_ptr<Entry> &SubEntry : + llvm::make_range(DE->contents_begin(), DE->contents_end())) { + Path.push_back(SubEntry->getName()); + getVFSEntries(SubEntry.get(), Path, Entries); + Path.pop_back(); + } + return; + } + + assert(Kind == EK_File && "Must be a EK_File"); + auto *FE = dyn_cast<RedirectingFileEntry>(SrcE); + assert(FE && "Must be a file"); + SmallString<128> VPath; + for (auto &Comp : Path) + llvm::sys::path::append(VPath, Comp); + Entries.push_back(YAMLVFSEntry(VPath.c_str(), FE->getExternalContentsPath())); +} + +void vfs::collectVFSFromYAML(std::unique_ptr<MemoryBuffer> Buffer, + SourceMgr::DiagHandlerTy DiagHandler, + StringRef YAMLFilePath, + SmallVectorImpl<YAMLVFSEntry> &CollectedEntries, + void *DiagContext, + IntrusiveRefCntPtr<FileSystem> ExternalFS) { + RedirectingFileSystem *VFS = RedirectingFileSystem::create( + std::move(Buffer), DiagHandler, YAMLFilePath, DiagContext, + std::move(ExternalFS)); + ErrorOr<Entry *> RootE = VFS->lookupPath("/"); + if (!RootE) + return; + SmallVector<StringRef, 8> Components; + Components.push_back("/"); + getVFSEntries(*RootE, Components, CollectedEntries); +} + UniqueID vfs::getNextVirtualUniqueID() { static std::atomic<unsigned> UID; unsigned ID = ++UID; @@ -1619,7 +1678,7 @@ public: JSONWriter(llvm::raw_ostream &OS) : OS(OS) {} void write(ArrayRef<YAMLVFSEntry> Entries, Optional<bool> UseExternalNames, Optional<bool> IsCaseSensitive, Optional<bool> IsOverlayRelative, - StringRef OverlayDir); + Optional<bool> IgnoreNonExistentContents, StringRef OverlayDir); }; } @@ -1675,6 +1734,7 @@ void JSONWriter::write(ArrayRef<YAMLVFSEntry> Entries, Optional<bool> UseExternalNames, Optional<bool> IsCaseSensitive, Optional<bool> IsOverlayRelative, + Optional<bool> IgnoreNonExistentContents, StringRef OverlayDir) { using namespace llvm::sys; @@ -1692,6 +1752,9 @@ void JSONWriter::write(ArrayRef<YAMLVFSEntry> Entries, OS << " 'overlay-relative': '" << (UseOverlayRelative ? "true" : "false") << "',\n"; } + if (IgnoreNonExistentContents.hasValue()) + OS << " 'ignore-non-existent-contents': '" + << (IgnoreNonExistentContents.getValue() ? "true" : "false") << "',\n"; OS << " 'roots': [\n"; if (!Entries.empty()) { @@ -1748,7 +1811,8 @@ void YAMLVFSWriter::write(llvm::raw_ostream &OS) { }); JSONWriter(OS).write(Mappings, UseExternalNames, IsCaseSensitive, - IsOverlayRelative, OverlayDir); + IsOverlayRelative, IgnoreNonExistentContents, + OverlayDir); } VFSFromYamlDirIterImpl::VFSFromYamlDirIterImpl( @@ -1756,29 +1820,47 @@ VFSFromYamlDirIterImpl::VFSFromYamlDirIterImpl( RedirectingDirectoryEntry::iterator Begin, RedirectingDirectoryEntry::iterator End, std::error_code &EC) : Dir(_Path.str()), FS(FS), Current(Begin), End(End) { - if (Current != End) { + while (Current != End) { SmallString<128> PathStr(Dir); llvm::sys::path::append(PathStr, (*Current)->getName()); llvm::ErrorOr<vfs::Status> S = FS.status(PathStr); - if (S) + if (S) { CurrentEntry = *S; - else + return; + } + // Skip entries which do not map to a reliable external content. + if (FS.ignoreNonExistentContents() && + S.getError() == llvm::errc::no_such_file_or_directory) { + ++Current; + continue; + } else { EC = S.getError(); + break; + } } } std::error_code VFSFromYamlDirIterImpl::increment() { assert(Current != End && "cannot iterate past end"); - if (++Current != End) { + while (++Current != End) { SmallString<128> PathStr(Dir); llvm::sys::path::append(PathStr, (*Current)->getName()); llvm::ErrorOr<vfs::Status> S = FS.status(PathStr); - if (!S) - return S.getError(); + if (!S) { + // Skip entries which do not map to a reliable external content. + if (FS.ignoreNonExistentContents() && + S.getError() == llvm::errc::no_such_file_or_directory) { + continue; + } else { + return S.getError(); + } + } CurrentEntry = *S; - } else { - CurrentEntry = Status(); + break; } + + if (Current == End) + CurrentEntry = Status(); return std::error_code(); } |