Index: include/lldb/Utility/FileSpec.h =================================================================== --- include/lldb/Utility/FileSpec.h +++ include/lldb/Utility/FileSpec.h @@ -532,7 +532,14 @@ void AppendPathComponent(llvm::StringRef component); void AppendPathComponent(const FileSpec &new_path); - void RemoveLastPathComponent(); + //------------------------------------------------------------------ + /// Removes the last path component by replacing the current path with its + /// parent. When the current path has no parent, this is a no-op. + /// + /// @return + /// A boolean value indicating whether the path was updated. + //------------------------------------------------------------------ + bool RemoveLastPathComponent(); ConstString GetLastPathComponent() const; Index: source/Utility/FileSpec.cpp =================================================================== --- source/Utility/FileSpec.cpp +++ source/Utility/FileSpec.cpp @@ -785,36 +785,15 @@ return AppendPathComponent(new_path.GetPath(false)); } -void FileSpec::RemoveLastPathComponent() { - // CLEANUP: Use StringRef for string handling. - - const bool resolve = false; - if (m_filename.IsEmpty() && m_directory.IsEmpty()) { - SetFile("", resolve); - return; - } - if (m_directory.IsEmpty()) { - SetFile("", resolve); - return; +bool FileSpec::RemoveLastPathComponent() { + llvm::SmallString<64> current_path; + GetPath(current_path, false); + if (llvm::sys::path::has_parent_path(current_path, m_style)) { + SetFile(llvm::sys::path::parent_path(current_path, m_style), false, + m_style); + return true; } - if (m_filename.IsEmpty()) { - const char *dir_cstr = m_directory.GetCString(); - const char *last_slash_ptr = ::strrchr(dir_cstr, '/'); - - // check for obvious cases before doing the full thing - if (!last_slash_ptr) { - SetFile("", resolve); - return; - } - if (last_slash_ptr == dir_cstr) { - SetFile("/", resolve); - return; - } - size_t last_slash_pos = last_slash_ptr - dir_cstr + 1; - ConstString new_path(dir_cstr, last_slash_pos); - SetFile(new_path.GetCString(), resolve); - } else - SetFile(m_directory.GetCString(), resolve); + return false; } //------------------------------------------------------------------ /// Returns true if the filespec represents an implementation source Index: unittests/Utility/FileSpecTest.cpp =================================================================== --- unittests/Utility/FileSpecTest.cpp +++ unittests/Utility/FileSpecTest.cpp @@ -320,3 +320,44 @@ } } +TEST(FileSpecTest, RemoveLastPathComponent) { + FileSpec fs_posix("/foo/bar/baz", false, FileSpec::Style::posix); + EXPECT_STREQ("/foo/bar/baz", fs_posix.GetCString()); + EXPECT_TRUE(fs_posix.RemoveLastPathComponent()); + EXPECT_STREQ("/foo/bar", fs_posix.GetCString()); + EXPECT_TRUE(fs_posix.RemoveLastPathComponent()); + EXPECT_STREQ("/foo", fs_posix.GetCString()); + EXPECT_TRUE(fs_posix.RemoveLastPathComponent()); + EXPECT_STREQ("/", fs_posix.GetCString()); + EXPECT_FALSE(fs_posix.RemoveLastPathComponent()); + EXPECT_STREQ("/", fs_posix.GetCString()); + + FileSpec fs_posix_relative("./foo/bar/baz", false, FileSpec::Style::posix); + EXPECT_STREQ("foo/bar/baz", fs_posix_relative.GetCString()); + EXPECT_TRUE(fs_posix_relative.RemoveLastPathComponent()); + EXPECT_STREQ("foo/bar", fs_posix_relative.GetCString()); + EXPECT_TRUE(fs_posix_relative.RemoveLastPathComponent()); + EXPECT_STREQ("foo", fs_posix_relative.GetCString()); + EXPECT_FALSE(fs_posix_relative.RemoveLastPathComponent()); + EXPECT_STREQ("foo", fs_posix_relative.GetCString()); + + FileSpec fs_posix_relative2("./", false, FileSpec::Style::posix); + EXPECT_STREQ(".", fs_posix_relative2.GetCString()); + EXPECT_FALSE(fs_posix_relative2.RemoveLastPathComponent()); + EXPECT_STREQ(".", fs_posix_relative2.GetCString()); + EXPECT_FALSE(fs_posix_relative.RemoveLastPathComponent()); + EXPECT_STREQ(".", fs_posix_relative2.GetCString()); + + FileSpec fs_windows("C:\\foo\\bar\\baz", false, FileSpec::Style::windows); + EXPECT_STREQ("C:\\foo\\bar\\baz", fs_windows.GetCString()); + EXPECT_TRUE(fs_windows.RemoveLastPathComponent()); + EXPECT_STREQ("C:\\foo\\bar", fs_windows.GetCString()); + EXPECT_TRUE(fs_windows.RemoveLastPathComponent()); + EXPECT_STREQ("C:\\foo", fs_windows.GetCString()); + EXPECT_TRUE(fs_windows.RemoveLastPathComponent()); + EXPECT_STREQ("C:\\", fs_windows.GetCString()); + EXPECT_TRUE(fs_windows.RemoveLastPathComponent()); + EXPECT_STREQ("C:", fs_windows.GetCString()); + EXPECT_FALSE(fs_windows.RemoveLastPathComponent()); + EXPECT_STREQ("C:", fs_windows.GetCString()); +}