Index: lldb/trunk/include/lldb/Host/FileSystem.h =================================================================== --- lldb/trunk/include/lldb/Host/FileSystem.h +++ lldb/trunk/include/lldb/Host/FileSystem.h @@ -34,6 +34,9 @@ FileSystem() : m_fs(llvm::vfs::getRealFileSystem()) {} FileSystem(llvm::IntrusiveRefCntPtr fs) : m_fs(fs) {} + FileSystem(const FileSystem &fs) = delete; + FileSystem &operator=(const FileSystem &fs) = delete; + static FileSystem &Instance(); static void Initialize(); @@ -54,6 +57,20 @@ Status Open(File &File, const FileSpec &file_spec, uint32_t options, uint32_t permissions = lldb::eFilePermissionsFileDefault); + /// Get a directory iterator. + /// @{ + llvm::vfs::directory_iterator DirBegin(const FileSpec &file_spec, + std::error_code &ec); + llvm::vfs::directory_iterator DirBegin(const llvm::Twine &dir, + std::error_code &ec); + /// @} + + /// Returns the Status object for the given file. + /// @{ + llvm::ErrorOr GetStatus(const FileSpec &file_spec) const; + llvm::ErrorOr GetStatus(const llvm::Twine &path) const; + /// @} + /// Returns the modification time of the given file. /// @{ llvm::sys::TimePoint<> GetModificationTime(const FileSpec &file_spec) const; Index: lldb/trunk/source/Commands/CommandCompletions.cpp =================================================================== --- lldb/trunk/source/Commands/CommandCompletions.cpp +++ lldb/trunk/source/Commands/CommandCompletions.cpp @@ -101,7 +101,6 @@ if (CompletionBuffer.size() >= PATH_MAX) return matches.GetSize(); - namespace fs = llvm::sys::fs; namespace path = llvm::sys::path; llvm::StringRef SearchDir; @@ -178,11 +177,16 @@ // SearchDir now contains the directory to search in, and Prefix contains the // text we want to match against items in that directory. + FileSystem &fs = FileSystem::Instance(); std::error_code EC; - fs::directory_iterator Iter(SearchDir, EC, false); - fs::directory_iterator End; + llvm::vfs::directory_iterator Iter = fs.DirBegin(SearchDir, EC); + llvm::vfs::directory_iterator End; for (; Iter != End && !EC; Iter.increment(EC)) { auto &Entry = *Iter; + llvm::ErrorOr Status = fs.GetStatus(Entry.path()); + + if (!Status) + continue; auto Name = path::filename(Entry.path()); @@ -190,20 +194,18 @@ if (Name == "." || Name == ".." || !Name.startswith(PartialItem)) continue; - // We have a match. - - llvm::ErrorOr st = Entry.status(); - if (!st) - continue; + bool is_dir = Status->isDirectory(); // If it's a symlink, then we treat it as a directory as long as the target // is a directory. - bool is_dir = fs::is_directory(*st); - if (fs::is_symlink_file(*st)) { - fs::file_status target_st; - if (!fs::status(Entry.path(), target_st)) - is_dir = fs::is_directory(target_st); + if (Status->isSymlink()) { + FileSpec symlink_filespec(Entry.path()); + FileSpec resolved_filespec; + auto error = fs.ResolveSymbolicLink(symlink_filespec, resolved_filespec); + if (error.Success()) + is_dir = fs.IsDirectory(symlink_filespec); } + if (only_directories && !is_dir) continue; Index: lldb/trunk/source/Host/common/FileSystem.cpp =================================================================== --- lldb/trunk/source/Host/common/FileSystem.cpp +++ lldb/trunk/source/Host/common/FileSystem.cpp @@ -63,6 +63,25 @@ return g_fs; } +vfs::directory_iterator FileSystem::DirBegin(const FileSpec &file_spec, + std::error_code &ec) { + return DirBegin(file_spec.GetPath(), ec); +} + +vfs::directory_iterator FileSystem::DirBegin(const Twine &dir, + std::error_code &ec) { + return m_fs->dir_begin(dir, ec); +} + +llvm::ErrorOr +FileSystem::GetStatus(const FileSpec &file_spec) const { + return GetStatus(file_spec.GetPath()); +} + +llvm::ErrorOr FileSystem::GetStatus(const Twine &path) const { + return m_fs->status(path); +} + sys::TimePoint<> FileSystem::GetModificationTime(const FileSpec &file_spec) const { return GetModificationTime(file_spec.GetPath()); Index: lldb/trunk/unittests/Interpreter/TestCompletion.cpp =================================================================== --- lldb/trunk/unittests/Interpreter/TestCompletion.cpp +++ lldb/trunk/unittests/Interpreter/TestCompletion.cpp @@ -7,9 +7,11 @@ // //===----------------------------------------------------------------------===// +#include "lldb/Host/FileSystem.h" #include "lldb/Interpreter/CommandCompletions.h" #include "lldb/Utility/StringList.h" #include "lldb/Utility/TildeExpressionResolver.h" + #include "gmock/gmock.h" #include "gtest/gtest.h" @@ -65,6 +67,8 @@ SmallString<128> FileBaz; void SetUp() override { + FileSystem::Initialize(); + // chdir back into the original working dir this test binary started with. // A previous test may have have changed the working dir. ASSERT_NO_ERROR(fs::set_current_path(OriginalWorkingDir)); @@ -105,7 +109,10 @@ ASSERT_NO_ERROR(fs::current_path(OriginalWorkingDir)); } - void TearDown() override { ASSERT_NO_ERROR(fs::remove_directories(BaseDir)); } + void TearDown() override { + ASSERT_NO_ERROR(fs::remove_directories(BaseDir)); + FileSystem::Terminate(); + } static bool HasEquivalentFile(const Twine &Path, const StringList &Paths) { for (size_t I = 0; I < Paths.GetSize(); ++I) { @@ -140,7 +147,7 @@ }; SmallString<128> CompletionTest::OriginalWorkingDir; -} +} // namespace static std::vector toVector(const StringList &SL) { std::vector Result; @@ -170,8 +177,8 @@ ASSERT_EQ(Count, Results.GetSize()); EXPECT_TRUE(HasEquivalentFile(DirFooA, Results)); - Count = - CommandCompletions::DiskDirectories(Twine(BaseDir) + "/.", Results, Resolver); + Count = CommandCompletions::DiskDirectories(Twine(BaseDir) + "/.", Results, + Resolver); ASSERT_EQ(0u, Count); ASSERT_EQ(Count, Results.GetSize());