Index: include/clang/Basic/VirtualFileSystem.h =================================================================== --- include/clang/Basic/VirtualFileSystem.h +++ include/clang/Basic/VirtualFileSystem.h @@ -126,6 +126,21 @@ virtual std::error_code close() = 0; }; +/// A member of a directory, yielded by a directory_iterator. +/// Only information available on most platforms is included. +class directory_entry { + std::string Path; + llvm::sys::fs::file_type Type; + +public: + directory_entry() = default; + directory_entry(std::string Path, llvm::sys::fs::file_type Type) + : Path(std::move(Path)), Type(Type) {} + + llvm::StringRef path() const { return Path; } + llvm::sys::fs::file_type type() const { return Type; } +}; + namespace detail { /// An interface for virtual file systems to provide an iterator over the @@ -134,10 +149,10 @@ virtual ~DirIterImpl(); /// Sets \c CurrentEntry to the next entry in the directory on success, - /// or returns a system-defined \c error_code. + /// to directory_entry() at end, or returns a system-defined \c error_code. virtual std::error_code increment() = 0; - Status CurrentEntry; + directory_entry CurrentEntry; }; } // namespace detail @@ -151,7 +166,7 @@ directory_iterator(std::shared_ptr I) : Impl(std::move(I)) { assert(Impl.get() != nullptr && "requires non-null implementation"); - if (!Impl->CurrentEntry.isStatusKnown()) + if (Impl->CurrentEntry.path().empty()) Impl.reset(); // Normalize the end iterator to Impl == nullptr. } @@ -162,17 +177,17 @@ directory_iterator &increment(std::error_code &EC) { assert(Impl && "attempting to increment past end"); EC = Impl->increment(); - if (!Impl->CurrentEntry.isStatusKnown()) + if (Impl->CurrentEntry.path().empty()) Impl.reset(); // Normalize the end iterator to Impl == nullptr. return *this; } - const Status &operator*() const { return Impl->CurrentEntry; } - const Status *operator->() const { return &Impl->CurrentEntry; } + const directory_entry &operator*() const { return Impl->CurrentEntry; } + const directory_entry *operator->() const { return &Impl->CurrentEntry; } bool operator==(const directory_iterator &RHS) const { if (Impl && RHS.Impl) - return Impl->CurrentEntry.equivalent(RHS.Impl->CurrentEntry); + return Impl->CurrentEntry.path() == RHS.Impl->CurrentEntry.path(); return !Impl && !RHS.Impl; } bool operator!=(const directory_iterator &RHS) const { @@ -201,8 +216,8 @@ /// Equivalent to operator++, with an error code. recursive_directory_iterator &increment(std::error_code &EC); - const Status &operator*() const { return *State->top(); } - const Status *operator->() const { return &*State->top(); } + const directory_entry &operator*() const { return *State->top(); } + const directory_entry *operator->() const { return &*State->top(); } bool operator==(const recursive_directory_iterator &Other) const { return State == Other.State; // identity Index: lib/Basic/VirtualFileSystem.cpp =================================================================== --- lib/Basic/VirtualFileSystem.cpp +++ lib/Basic/VirtualFileSystem.cpp @@ -315,27 +315,16 @@ public: RealFSDirIter(const Twine &Path, std::error_code &EC) : Iter(Path, EC) { - if (Iter != llvm::sys::fs::directory_iterator()) { - llvm::sys::fs::file_status S; - std::error_code ErrorCode = llvm::sys::fs::status(Iter->path(), S, true); - CurrentEntry = Status::copyWithNewName(S, Iter->path()); - if (!EC) - EC = ErrorCode; - } + if (Iter != llvm::sys::fs::directory_iterator()) + CurrentEntry = directory_entry(Iter->path(), Iter->type()); } std::error_code increment() override { std::error_code EC; Iter.increment(EC); - if (Iter == llvm::sys::fs::directory_iterator()) { - CurrentEntry = Status(); - } else { - llvm::sys::fs::file_status S; - std::error_code ErrorCode = llvm::sys::fs::status(Iter->path(), S, true); - CurrentEntry = Status::copyWithNewName(S, Iter->path()); - if (!EC) - EC = ErrorCode; - } + CurrentEntry = (Iter == llvm::sys::fs::directory_iterator()) + ? directory_entry() + : directory_entry(Iter->path(), Iter->type()); return EC; } }; @@ -446,11 +435,11 @@ while (true) { std::error_code EC = incrementDirIter(IsFirstTime); if (EC || CurrentDirIter == directory_iterator()) { - CurrentEntry = Status(); + CurrentEntry = directory_entry(); return EC; } CurrentEntry = *CurrentDirIter; - StringRef Name = llvm::sys::path::filename(CurrentEntry.getName()); + StringRef Name = llvm::sys::path::filename(CurrentEntry.path()); if (SeenNames.insert(Name).second) return EC; // name not seen before } @@ -850,11 +839,21 @@ if (I != E) { SmallString<256> Path(RequestedDirName); llvm::sys::path::append(Path, I->second->getFileName()); - CurrentEntry = detail::getNodeStatus(I->second.get(), Path); + sys::fs::file_type Type; + switch (I->second->getKind()) { + case detail::IME_File: + case detail::IME_HardLink: + Type = sys::fs::file_type::regular_file; + break; + case detail::IME_Directory: + Type = sys::fs::file_type::directory_file; + break; + } + CurrentEntry = directory_entry(Path.str(), Type); } else { // When we're at the end, make CurrentEntry invalid and DirIterImpl will // do the rest. - CurrentEntry = Status(); + CurrentEntry = directory_entry(); } } @@ -1010,17 +1009,14 @@ static bool classof(const Entry *E) { return E->getKind() == EK_File; } }; -class RedirectingFileSystem; - class VFSFromYamlDirIterImpl : public clang::vfs::detail::DirIterImpl { std::string Dir; - RedirectingFileSystem &FS; RedirectingDirectoryEntry::iterator Current, End; std::error_code incrementImpl(); public: - VFSFromYamlDirIterImpl(const Twine &Path, RedirectingFileSystem &FS, + VFSFromYamlDirIterImpl(const Twine &Path, RedirectingDirectoryEntry::iterator Begin, RedirectingDirectoryEntry::iterator End, std::error_code &EC); @@ -1184,8 +1180,8 @@ } auto *D = cast(*E); - return directory_iterator(std::make_shared(Dir, - *this, D->contents_begin(), D->contents_end(), EC)); + return directory_iterator(std::make_shared( + Dir, D->contents_begin(), D->contents_end(), EC)); } void setExternalContentsPrefixDir(StringRef PrefixDir) { @@ -2079,10 +2075,9 @@ } VFSFromYamlDirIterImpl::VFSFromYamlDirIterImpl( - const Twine &_Path, RedirectingFileSystem &FS, - RedirectingDirectoryEntry::iterator Begin, + const Twine &_Path, RedirectingDirectoryEntry::iterator Begin, RedirectingDirectoryEntry::iterator End, std::error_code &EC) - : Dir(_Path.str()), FS(FS), Current(Begin), End(End) { + : Dir(_Path.str()), Current(Begin), End(End) { EC = incrementImpl(); } @@ -2096,23 +2091,21 @@ while (Current != End) { SmallString<128> PathStr(Dir); llvm::sys::path::append(PathStr, (*Current)->getName()); - llvm::ErrorOr S = FS.status(PathStr); - 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) { - ++Current; - continue; - } else { - return S.getError(); - } + sys::fs::file_type Type; + switch ((*Current)->getKind()) { + case EK_Directory: + Type = sys::fs::file_type::directory_file; + break; + case EK_File: + Type = sys::fs::file_type::regular_file; + break; } - CurrentEntry = *S; + CurrentEntry = directory_entry(PathStr.str(), Type); break; } if (Current == End) - CurrentEntry = Status(); + CurrentEntry = directory_entry(); return {}; } @@ -2130,10 +2123,10 @@ vfs::recursive_directory_iterator & recursive_directory_iterator::increment(std::error_code &EC) { assert(FS && State && !State->empty() && "incrementing past end"); - assert(State->top()->isStatusKnown() && "non-canonical end iterator"); + assert(!State->top()->path().empty() && "non-canonical end iterator"); vfs::directory_iterator End; - if (State->top()->isDirectory()) { - vfs::directory_iterator I = FS->dir_begin(State->top()->getName(), EC); + if (State->top()->type() == sys::fs::file_type::directory_file) { + vfs::directory_iterator I = FS->dir_begin(State->top()->path(), EC); if (I != End) { State->push(I); return *this; Index: lib/Driver/ToolChains/BareMetal.cpp =================================================================== --- lib/Driver/ToolChains/BareMetal.cpp +++ lib/Driver/ToolChains/BareMetal.cpp @@ -122,7 +122,7 @@ for (vfs::directory_iterator LI = getDriver().getVFS().dir_begin(Dir.str(), EC), LE; !EC && LI != LE; LI = LI.increment(EC)) { - StringRef VersionText = llvm::sys::path::filename(LI->getName()); + StringRef VersionText = llvm::sys::path::filename(LI->path()); auto CandidateVersion = Generic_GCC::GCCVersion::Parse(VersionText); if (CandidateVersion.Major == -1) continue; Index: lib/Driver/ToolChains/Gnu.cpp =================================================================== --- lib/Driver/ToolChains/Gnu.cpp +++ lib/Driver/ToolChains/Gnu.cpp @@ -1764,7 +1764,7 @@ std::error_code EC; for (vfs::directory_iterator LI = D.getVFS().dir_begin(PrefixDir, EC), LE; !EC && LI != LE; LI = LI.increment(EC)) { - StringRef VersionText = llvm::sys::path::filename(LI->getName()); + StringRef VersionText = llvm::sys::path::filename(LI->path()); GCCVersion CandidateVersion = GCCVersion::Parse(VersionText); // Filter out obviously bad entries. @@ -2209,17 +2209,17 @@ LI = D.getVFS().dir_begin(LibDir + "/" + LibSuffix, EC), LE; !EC && LI != LE; LI = LI.increment(EC)) { - StringRef VersionText = llvm::sys::path::filename(LI->getName()); + StringRef VersionText = llvm::sys::path::filename(LI->path()); GCCVersion CandidateVersion = GCCVersion::Parse(VersionText); if (CandidateVersion.Major != -1) // Filter obviously bad entries. - if (!CandidateGCCInstallPaths.insert(LI->getName()).second) + if (!CandidateGCCInstallPaths.insert(LI->path()).second) continue; // Saw this path before; no need to look at it again. if (CandidateVersion.isOlderThan(4, 1, 1)) continue; if (CandidateVersion <= Version) continue; - if (!ScanGCCForMultilibs(TargetTriple, Args, LI->getName(), + if (!ScanGCCForMultilibs(TargetTriple, Args, LI->path(), NeedsBiarchSuffix)) continue; Index: lib/Frontend/CompilerInstance.cpp =================================================================== --- lib/Frontend/CompilerInstance.cpp +++ lib/Frontend/CompilerInstance.cpp @@ -185,10 +185,10 @@ // used here since we're not interested in validating the PCH at this time, // but only to check whether this is a file containing an AST. if (!ASTReader::readASTFileControlBlock( - Dir->getName(), FileMgr, CI.getPCHContainerReader(), + Dir->path(), FileMgr, CI.getPCHContainerReader(), /*FindModuleFileExtensions=*/false, Validator, /*ValidateDiagnosticOptions=*/false)) - MDC->addFile(Dir->getName()); + MDC->addFile(Dir->path()); } } Index: lib/Frontend/FrontendAction.cpp =================================================================== --- lib/Frontend/FrontendAction.cpp +++ lib/Frontend/FrontendAction.cpp @@ -347,12 +347,12 @@ Dir != End && !EC; Dir.increment(EC)) { // Check whether this entry has an extension typically associated with // headers. - if (!llvm::StringSwitch(llvm::sys::path::extension(Dir->getName())) - .Cases(".h", ".H", ".hh", ".hpp", true) - .Default(false)) + if (!llvm::StringSwitch(llvm::sys::path::extension(Dir->path())) + .Cases(".h", ".H", ".hh", ".hpp", true) + .Default(false)) continue; - const FileEntry *Header = FileMgr.getFile(Dir->getName()); + const FileEntry *Header = FileMgr.getFile(Dir->path()); // FIXME: This shouldn't happen unless there is a file system race. Is // that worth diagnosing? if (!Header) @@ -365,7 +365,7 @@ // Compute the relative path from the directory to this file. SmallVector Components; - auto PathIt = llvm::sys::path::rbegin(Dir->getName()); + auto PathIt = llvm::sys::path::rbegin(Dir->path()); for (int I = 0; I != Dir.level() + 1; ++I, ++PathIt) Components.push_back(*PathIt); SmallString<128> RelativeHeader(UmbrellaDir.NameAsWritten); @@ -696,10 +696,10 @@ Dir != DirEnd && !EC; Dir.increment(EC)) { // Check whether this is an acceptable AST file. if (ASTReader::isAcceptableASTFile( - Dir->getName(), FileMgr, CI.getPCHContainerReader(), + Dir->path(), FileMgr, CI.getPCHContainerReader(), CI.getLangOpts(), CI.getTargetOpts(), CI.getPreprocessorOpts(), SpecificModuleCachePath)) { - PPOpts.ImplicitPCHInclude = Dir->getName(); + PPOpts.ImplicitPCHInclude = Dir->path(); Found = true; break; } Index: lib/Lex/HeaderSearch.cpp =================================================================== --- lib/Lex/HeaderSearch.cpp +++ lib/Lex/HeaderSearch.cpp @@ -1574,17 +1574,17 @@ vfs::FileSystem &FS = *FileMgr.getVirtualFileSystem(); for (vfs::directory_iterator Dir = FS.dir_begin(DirNative, EC), DirEnd; Dir != DirEnd && !EC; Dir.increment(EC)) { - if (llvm::sys::path::extension(Dir->getName()) != ".framework") + if (llvm::sys::path::extension(Dir->path()) != ".framework") continue; const DirectoryEntry *FrameworkDir = - FileMgr.getDirectory(Dir->getName()); + FileMgr.getDirectory(Dir->path()); if (!FrameworkDir) continue; // Load this framework module. - loadFrameworkModule(llvm::sys::path::stem(Dir->getName()), - FrameworkDir, IsSystem); + loadFrameworkModule(llvm::sys::path::stem(Dir->path()), FrameworkDir, + IsSystem); } continue; } @@ -1642,10 +1642,9 @@ vfs::FileSystem &FS = *FileMgr.getVirtualFileSystem(); for (vfs::directory_iterator Dir = FS.dir_begin(DirNative, EC), DirEnd; Dir != DirEnd && !EC; Dir.increment(EC)) { - bool IsFramework = - llvm::sys::path::extension(Dir->getName()) == ".framework"; + bool IsFramework = llvm::sys::path::extension(Dir->path()) == ".framework"; if (IsFramework == SearchDir.isFramework()) - loadModuleMapFile(Dir->getName(), SearchDir.isSystemHeaderDirectory(), + loadModuleMapFile(Dir->path(), SearchDir.isSystemHeaderDirectory(), SearchDir.isFramework()); } Index: lib/Lex/ModuleMap.cpp =================================================================== --- lib/Lex/ModuleMap.cpp +++ lib/Lex/ModuleMap.cpp @@ -1001,11 +1001,11 @@ for (vfs::directory_iterator Dir = FS.dir_begin(SubframeworksDirName, EC), DirEnd; Dir != DirEnd && !EC; Dir.increment(EC)) { - if (!StringRef(Dir->getName()).endswith(".framework")) + if (!StringRef(Dir->path()).endswith(".framework")) continue; if (const DirectoryEntry *SubframeworkDir = - FileMgr.getDirectory(Dir->getName())) { + FileMgr.getDirectory(Dir->path())) { // Note: as an egregious but useful hack, we use the real path here and // check whether it is actually a subdirectory of the parent directory. // This will not be the case if the 'subframework' is actually a symlink @@ -2374,10 +2374,9 @@ vfs::FileSystem &FS = *SourceMgr.getFileManager().getVirtualFileSystem(); for (vfs::recursive_directory_iterator I(FS, Dir->getName(), EC), E; I != E && !EC; I.increment(EC)) { - if (const FileEntry *FE = - SourceMgr.getFileManager().getFile(I->getName())) { + if (const FileEntry *FE = SourceMgr.getFileManager().getFile(I->path())) { - Module::Header Header = {I->getName(), FE}; + Module::Header Header = {I->path(), FE}; Headers.push_back(std::move(Header)); } } Index: lib/Lex/PPLexerChange.cpp =================================================================== --- lib/Lex/PPLexerChange.cpp +++ lib/Lex/PPLexerChange.cpp @@ -312,12 +312,12 @@ // Check whether this entry has an extension typically associated with // headers. - if (!StringSwitch(llvm::sys::path::extension(Entry->getName())) + if (!StringSwitch(llvm::sys::path::extension(Entry->path())) .Cases(".h", ".H", ".hh", ".hpp", true) .Default(false)) continue; - if (const FileEntry *Header = getFileManager().getFile(Entry->getName())) + if (const FileEntry *Header = getFileManager().getFile(Entry->path())) if (!getSourceManager().hasFileInfo(Header)) { if (!ModMap.isHeaderInUnavailableModule(Header)) { // Find the relative path that would access this header. Index: unittests/Basic/VirtualFileSystemTest.cpp =================================================================== --- unittests/Basic/VirtualFileSystemTest.cpp +++ unittests/Basic/VirtualFileSystemTest.cpp @@ -104,7 +104,8 @@ Path(_Path.str()) { for ( ; I != FilesAndDirs.end(); ++I) { if (isInPath(I->first)) { - CurrentEntry = I->second; + CurrentEntry = + vfs::directory_entry(I->second.getName(), I->second.getType()); break; } } @@ -113,12 +114,13 @@ ++I; for ( ; I != FilesAndDirs.end(); ++I) { if (isInPath(I->first)) { - CurrentEntry = I->second; + CurrentEntry = + vfs::directory_entry(I->second.getName(), I->second.getType()); break; } } if (I == FilesAndDirs.end()) - CurrentEntry = vfs::Status(); + CurrentEntry = vfs::directory_entry(); return std::error_code(); } }; @@ -398,11 +400,11 @@ ASSERT_FALSE(EC); ASSERT_NE(vfs::directory_iterator(), I); // Check either a or c, since we can't rely on the iteration order. - EXPECT_TRUE(I->getName().endswith("a") || I->getName().endswith("c")); + EXPECT_TRUE(I->path().endswith("a") || I->path().endswith("c")); I.increment(EC); ASSERT_FALSE(EC); ASSERT_NE(vfs::directory_iterator(), I); - EXPECT_TRUE(I->getName().endswith("a") || I->getName().endswith("c")); + EXPECT_TRUE(I->path().endswith("a") || I->path().endswith("c")); I.increment(EC); EXPECT_EQ(vfs::directory_iterator(), I); } @@ -438,7 +440,7 @@ << "EC message: " << EC2.message() << "\n"; } ASSERT_FALSE(EC); - EXPECT_TRUE(I->getName() == _b); + EXPECT_TRUE(I->path() == _b); } } #endif @@ -464,7 +466,7 @@ std::vector Contents; for (auto E = vfs::recursive_directory_iterator(); !EC && I != E; I.increment(EC)) { - Contents.push_back(I->getName()); + Contents.push_back(I->path()); } // Check contents, which may be in any order @@ -507,7 +509,7 @@ I != E; I.increment(EC)) { auto EC2 = std::make_error_code(std::errc::no_such_file_or_directory); if (EC == EC2) { - VisitedBrokenSymlinks.push_back(I->getName()); + VisitedBrokenSymlinks.push_back(I->path()); continue; } // For bot debugging. @@ -523,7 +525,7 @@ << "EC message: " << EC2.message() << "\n"; } ASSERT_FALSE(EC); - VisitedNonBrokenSymlinks.push_back(I->getName()); + VisitedNonBrokenSymlinks.push_back(I->path()); } // Check visited file names. @@ -549,7 +551,7 @@ // Do not rely on iteration order to check for contents, sort both // content vectors before comparison. for (DirIter E; !EC && I != E; I.increment(EC)) - InputToCheck.push_back(I->getName()); + InputToCheck.push_back(I->path()); llvm::sort(InputToCheck.begin(), InputToCheck.end()); llvm::sort(Expected.begin(), Expected.end()); @@ -656,14 +658,14 @@ O->pushOverlay(Upper); std::error_code EC; - Lower->addRegularFile("/onlyInLow", sys::fs::owner_read); - Lower->addRegularFile("/hiddenByMid", sys::fs::owner_read); - Lower->addRegularFile("/hiddenByUp", sys::fs::owner_read); - Middle->addRegularFile("/onlyInMid", sys::fs::owner_write); - Middle->addRegularFile("/hiddenByMid", sys::fs::owner_write); - Middle->addRegularFile("/hiddenByUp", sys::fs::owner_write); - Upper->addRegularFile("/onlyInUp", sys::fs::owner_all); - Upper->addRegularFile("/hiddenByUp", sys::fs::owner_all); + Lower->addRegularFile("/onlyInLow"); + Lower->addDirectory("/hiddenByMid"); + Lower->addDirectory("/hiddenByUp"); + Middle->addRegularFile("/onlyInMid"); + Middle->addRegularFile("/hiddenByMid"); + Middle->addDirectory("/hiddenByUp"); + Upper->addRegularFile("/onlyInUp"); + Upper->addRegularFile("/hiddenByUp"); checkContents( O->dir_begin("/", EC), {"/hiddenByUp", "/onlyInUp", "/hiddenByMid", "/onlyInMid", "/onlyInLow"}); @@ -673,19 +675,19 @@ std::error_code EC; vfs::directory_iterator I = O->dir_begin("/", EC), E; for ( ; !EC && I != E; I.increment(EC)) - if (I->getName() == "/hiddenByUp") + if (I->path() == "/hiddenByUp") break; ASSERT_NE(E, I); - EXPECT_EQ(sys::fs::owner_all, I->getPermissions()); + EXPECT_EQ(sys::fs::file_type::regular_file, I->type()); } { std::error_code EC; vfs::directory_iterator I = O->dir_begin("/", EC), E; for ( ; !EC && I != E; I.increment(EC)) - if (I->getName() == "/hiddenByMid") + if (I->path() == "/hiddenByMid") break; ASSERT_NE(E, I); - EXPECT_EQ(sys::fs::owner_write, I->getPermissions()); + EXPECT_EQ(sys::fs::file_type::regular_file, I->type()); } } @@ -792,10 +794,10 @@ std::error_code EC; vfs::directory_iterator I = FS.dir_begin("/", EC); ASSERT_FALSE(EC); - ASSERT_EQ("/a", I->getName()); + ASSERT_EQ("/a", I->path()); I.increment(EC); ASSERT_FALSE(EC); - ASSERT_EQ("/b", I->getName()); + ASSERT_EQ("/b", I->path()); I.increment(EC); ASSERT_FALSE(EC); ASSERT_EQ(vfs::directory_iterator(), I); @@ -804,7 +806,7 @@ ASSERT_FALSE(EC); // When on Windows, we end up with "/b\\c" as the name. Convert to Posix // path for the sake of the comparison. - ASSERT_EQ("/b/c", getPosixPath(I->getName())); + ASSERT_EQ("/b/c", getPosixPath(I->path())); I.increment(EC); ASSERT_FALSE(EC); ASSERT_EQ(vfs::directory_iterator(), I); @@ -967,7 +969,7 @@ clang::vfs::directory_iterator It = NormalizedFS.dir_begin("../b", EC); // When on Windows, we end up with "../b\\c" as the name. Convert to Posix // path for the sake of the comparison. - ASSERT_EQ("../b/c", getPosixPath(It->getName())); + ASSERT_EQ("../b/c", getPosixPath(It->path())); } TEST_F(InMemoryFileSystemTest, AddHardLinkToFile) { @@ -1067,7 +1069,7 @@ std::vector Nodes; for (auto E = vfs::recursive_directory_iterator(); !EC && I != E; I.increment(EC)) { - Nodes.push_back(getPosixPath(I->getName())); + Nodes.push_back(getPosixPath(I->path())); } EXPECT_THAT(Nodes, testing::UnorderedElementsAre("/a", "/a/b", "/c", "/c/d")); }