diff --git a/lldb/include/lldb/Utility/FileSpec.h b/lldb/include/lldb/Utility/FileSpec.h --- a/lldb/include/lldb/Utility/FileSpec.h +++ b/lldb/include/lldb/Utility/FileSpec.h @@ -408,6 +408,18 @@ /// A boolean value indicating whether the path was updated. bool RemoveLastPathComponent(); + /// Gets the components of the FileSpec's path. + /// For example, given the path: + /// /System/Library/PrivateFrameworks/UIFoundation.framework/UIFoundation + /// + /// This function returns: + /// {"System", "Library", "PrivateFrameworks", "UIFoundation.framework", + /// "UIFoundation"} + /// \return + /// A std::vector of llvm::StringRefs for each path component. + /// The lifetime of the StringRefs is tied to the lifetime of the FileSpec. + std::vector GetComponents() const; + protected: // Convenience method for setting the file without changing the style. void SetFile(llvm::StringRef path); diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp --- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp @@ -1236,13 +1236,9 @@ // "UIFoundation" and "UIFoundation.framework" -- most likely the latter // will be the one we find there. - FileSpec platform_pull_upart(platform_file); - std::vector path_parts; - path_parts.push_back(platform_pull_upart.GetFilename().AsCString()); - while (platform_pull_upart.RemoveLastPathComponent()) { - ConstString part = platform_pull_upart.GetFilename(); - path_parts.push_back(part.AsCString()); - } + std::vector path_parts = platform_file.GetComponents(); + // We want the components in reverse order. + std::reverse(path_parts.begin(), path_parts.end()); const size_t path_parts_size = path_parts.size(); size_t num_module_search_paths = module_search_paths_ptr->GetSize(); diff --git a/lldb/source/Utility/FileSpec.cpp b/lldb/source/Utility/FileSpec.cpp --- a/lldb/source/Utility/FileSpec.cpp +++ b/lldb/source/Utility/FileSpec.cpp @@ -463,6 +463,26 @@ } return false; } + +std::vector FileSpec::GetComponents() const { + std::vector components; + + auto dir_begin = llvm::sys::path::begin(m_directory.GetStringRef(), m_style); + auto dir_end = llvm::sys::path::end(m_directory.GetStringRef()); + + for (auto iter = dir_begin; iter != dir_end; ++iter) { + if (*iter == "/" || *iter == ".") + continue; + + components.push_back(*iter); + } + + if (!m_filename.IsEmpty() && m_filename != "/" && m_filename != ".") + components.push_back(m_filename.GetStringRef()); + + return components; +} + /// Returns true if the filespec represents an implementation source /// file (files with a ".c", ".cpp", ".m", ".mm" (many more) /// extension). diff --git a/lldb/unittests/Utility/FileSpecTest.cpp b/lldb/unittests/Utility/FileSpecTest.cpp --- a/lldb/unittests/Utility/FileSpecTest.cpp +++ b/lldb/unittests/Utility/FileSpecTest.cpp @@ -504,3 +504,33 @@ EXPECT_FALSE(win_noext.IsSourceImplementationFile()); EXPECT_FALSE(exe.IsSourceImplementationFile()); } + +TEST(FileSpecTest, TestGetComponents) { + std::pair> PosixTests[] = { + {"/", {}}, + {"/foo", {"foo"}}, + {"/foo/", {"foo"}}, + {"/foo/bar", {"foo", "bar"}}, + {"/llvm-project/lldb/unittests/Utility/FileSpecTest.cpp", + {"llvm-project", "lldb", "unittests", "Utility", "FileSpecTest.cpp"}}, + }; + + for (const auto &pair : PosixTests) { + FileSpec file_spec = PosixSpec(pair.first); + EXPECT_EQ(file_spec.GetComponents(), pair.second); + } + + std::pair> WindowsTests[] = { + {"C:\\", {"C:"}}, + {"C:\\Windows\\", {"C:", "Windows"}}, + {"C:\\Windows\\System32", {"C:", "Windows", "System32"}}, + {"C:\\llvm-project\\lldb\\unittests\\Utility\\FileSpecTest.cpp", + {"C:", "llvm-project", "lldb", "unittests", "Utility", + "FileSpecTest.cpp"}}, + }; + + for (const auto &pair : WindowsTests) { + FileSpec file_spec = WindowsSpec(pair.first); + EXPECT_EQ(file_spec.GetComponents(), pair.second); + } +}