Index: include/lldb/Core/FileSpecList.h
===================================================================
--- include/lldb/Core/FileSpecList.h
+++ include/lldb/Core/FileSpecList.h
@@ -119,16 +119,11 @@
/// @param[in] full
/// Should FileSpec::Equal be called with "full" true or false.
///
- /// @param[in] remove_backup_dots
- /// Should FileSpec::Equal be called with "remove_backup_dots" true or
- /// false.
- ///
/// @return
/// The index of the file that matches \a file if it is found,
/// else UINT32_MAX is returned.
//------------------------------------------------------------------
- size_t FindFileIndex(size_t idx, const FileSpec &file, bool full,
- bool remove_backup_dots = false) const;
+ size_t FindFileIndex(size_t idx, const FileSpec &file, bool full) const;
//------------------------------------------------------------------
/// Get file at index.
Index: include/lldb/Utility/FileSpec.h
===================================================================
--- include/lldb/Utility/FileSpec.h
+++ include/lldb/Utility/FileSpec.h
@@ -256,8 +256,7 @@
//------------------------------------------------------------------
static int Compare(const FileSpec &lhs, const FileSpec &rhs, bool full);
- static bool Equal(const FileSpec &a, const FileSpec &b, bool full,
- bool remove_backups = false);
+ static bool Equal(const FileSpec &a, const FileSpec &b, bool full);
//------------------------------------------------------------------
/// Case sensitivity of path.
@@ -488,12 +487,6 @@
size_t MemorySize() const;
//------------------------------------------------------------------
- /// Normalize a pathname by collapsing redundant separators and
- /// up-level references.
- //------------------------------------------------------------------
- FileSpec GetNormalizedPath() const;
-
- //------------------------------------------------------------------
/// Change the file specified with a new path.
///
/// Update the contents of this object with a new path. The path will
Index: lldb.xcodeproj/xcshareddata/xcschemes/darwin-debug.xcscheme
===================================================================
--- lldb.xcodeproj/xcshareddata/xcschemes/darwin-debug.xcscheme
+++ lldb.xcodeproj/xcshareddata/xcschemes/darwin-debug.xcscheme
@@ -26,6 +26,7 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.GDB"
+ language = ""
shouldUseLaunchSchemeArgsEnv = "YES">
@@ -46,6 +47,7 @@
displayScaleIsEnabled = "NO"
displayScale = "1.00"
enableThreadSanitizer = "YES"
+ language = ""
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
Index: lldb.xcodeproj/xcshareddata/xcschemes/desktop.xcscheme
===================================================================
--- lldb.xcodeproj/xcshareddata/xcschemes/desktop.xcscheme
+++ lldb.xcodeproj/xcshareddata/xcschemes/desktop.xcscheme
@@ -30,11 +30,20 @@
shouldUseLaunchSchemeArgsEnv = "YES">
+
+
+
+
-
+
-
+
+
+
+
+
Index: lldb.xcodeproj/xcshareddata/xcschemes/lldb-gtest.xcscheme
===================================================================
--- lldb.xcodeproj/xcshareddata/xcschemes/lldb-gtest.xcscheme
+++ lldb.xcodeproj/xcshareddata/xcschemes/lldb-gtest.xcscheme
@@ -26,6 +26,7 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ language = ""
shouldUseLaunchSchemeArgsEnv = "YES">
@@ -45,6 +46,7 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ language = ""
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
Index: source/Breakpoint/BreakpointResolverFileLine.cpp
===================================================================
--- source/Breakpoint/BreakpointResolverFileLine.cpp
+++ source/Breakpoint/BreakpointResolverFileLine.cpp
@@ -121,8 +121,15 @@
return; // Nothing to do. Contexts are precise.
llvm::StringRef relative_path;
- if (is_relative)
- relative_path = m_file_spec.GetNormalizedPath().GetDirectory().GetStringRef();
+ if (is_relative) {
+ relative_path = m_file_spec.GetDirectory().GetStringRef();
+ // Don't let any path start with "./" or "../". Since all paths are
+ // normalized now, paths can only start with "./" or "../" if they are
+ // relative. This means we can safely skip any leading "./" or "../" but
+ // we must leave the slash character though.
+ while (relative_path.consume_front("."))
+ /* Do nothing. */;
+ }
Log * log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS);
for(uint32_t i = 0; i < sc_list.GetSize(); ++i) {
Index: source/Core/FileSpecList.cpp
===================================================================
--- source/Core/FileSpecList.cpp
+++ source/Core/FileSpecList.cpp
@@ -82,7 +82,7 @@
// it is found, else std::numeric_limits::max() is returned.
//------------------------------------------------------------------
size_t FileSpecList::FindFileIndex(size_t start_idx, const FileSpec &file_spec,
- bool full, bool remove_dots) const {
+ bool full) const {
const size_t num_files = m_files.size();
// When looking for files, we will compare only the filename if the
@@ -96,7 +96,7 @@
file_spec.IsCaseSensitive() || m_files[idx].IsCaseSensitive()))
return idx;
} else {
- if (FileSpec::Equal(m_files[idx], file_spec, full, remove_dots))
+ if (FileSpec::Equal(m_files[idx], file_spec, full))
return idx;
}
}
Index: source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
===================================================================
--- source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
+++ source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
@@ -5098,9 +5098,6 @@
// It is OK to resolve this path because we must find a file on
// disk for us to accept it anyway if it is rpath relative.
FileSpec file_spec(path, true);
- // Remove any redundant parts of the path (like "../foo") since
- // LC_RPATH values often contain "..".
- file_spec = file_spec.GetNormalizedPath();
if (file_spec.Exists() && files.AppendIfUnique(file_spec)) {
count++;
break;
@@ -5118,7 +5115,6 @@
for (const auto &at_exec_relative_path : at_exec_relative_paths) {
FileSpec file_spec =
exec_dir.CopyByAppendingPathComponent(at_exec_relative_path);
- file_spec = file_spec.GetNormalizedPath();
if (file_spec.Exists() && files.AppendIfUnique(file_spec))
count++;
}
Index: source/Plugins/SymbolFile/DWARF/DWARFDebugLine.h
===================================================================
--- source/Plugins/SymbolFile/DWARF/DWARFDebugLine.h
+++ source/Plugins/SymbolFile/DWARF/DWARFDebugLine.h
@@ -90,7 +90,7 @@
include_directories.clear();
file_names.clear();
}
- bool GetFile(uint32_t file_idx, const char *comp_dir,
+ bool GetFile(uint32_t file_idx, const lldb_private::FileSpec &cu_comp_dir,
lldb_private::FileSpec &file) const;
};
@@ -199,7 +199,8 @@
static bool
ParseSupportFiles(const lldb::ModuleSP &module_sp,
const lldb_private::DWARFDataExtractor &debug_line_data,
- const char *cu_comp_dir, dw_offset_t stmt_list,
+ const lldb_private::FileSpec &cu_comp_dir,
+ dw_offset_t stmt_list,
lldb_private::FileSpecList &support_files);
static bool
ParsePrologue(const lldb_private::DWARFDataExtractor &debug_line_data,
Index: source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp
===================================================================
--- source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp
+++ source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp
@@ -444,7 +444,7 @@
bool DWARFDebugLine::ParseSupportFiles(
const lldb::ModuleSP &module_sp, const DWARFDataExtractor &debug_line_data,
- const char *cu_comp_dir, dw_offset_t stmt_list,
+ const lldb_private::FileSpec &cu_comp_dir, dw_offset_t stmt_list,
FileSpecList &support_files) {
lldb::offset_t offset = stmt_list;
@@ -861,8 +861,8 @@
// buff.Append8(0); // Terminate the file names section with empty string
//}
-bool DWARFDebugLine::Prologue::GetFile(uint32_t file_idx, const char *comp_dir,
- FileSpec &file) const {
+bool DWARFDebugLine::Prologue::GetFile(uint32_t file_idx,
+ const lldb_private::FileSpec &comp_dir, FileSpec &file) const {
uint32_t idx = file_idx - 1; // File indexes are 1 based...
if (idx < file_names.size()) {
file.SetFile(file_names[idx].name, false);
@@ -876,7 +876,7 @@
}
}
- if (comp_dir && comp_dir[0])
+ if (comp_dir)
file.PrependPathComponent(comp_dir);
}
return true;
Index: source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
===================================================================
--- source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -174,38 +174,39 @@
return colon_pos + 1;
}
-static const char *resolveCompDir(const char *path_from_dwarf) {
+static FileSpec resolveCompDir(const char *path_from_dwarf) {
if (!path_from_dwarf)
- return nullptr;
+ return FileSpec();
// DWARF2/3 suggests the form hostname:pathname for compilation directory.
// Remove the host part if present.
const char *local_path = removeHostnameFromPathname(path_from_dwarf);
if (!local_path)
- return nullptr;
+ return FileSpec();
bool is_symlink = false;
- FileSpec local_path_spec(local_path, false);
+ // Always normalize our compile unit directory to get rid of redundant
+ // slashes and other path anonalies before we use it for path prepending
+ FileSpec local_spec(local_path, false);
const auto &file_specs = GetGlobalPluginProperties()->GetSymLinkPaths();
for (size_t i = 0; i < file_specs.GetSize() && !is_symlink; ++i)
is_symlink = FileSpec::Equal(file_specs.GetFileSpecAtIndex(i),
- local_path_spec, true);
+ local_spec, true);
if (!is_symlink)
- return local_path;
+ return local_spec;
namespace fs = llvm::sys::fs;
- if (fs::get_file_type(local_path_spec.GetPath(), false) !=
+ if (fs::get_file_type(local_spec.GetPath(), false) !=
fs::file_type::symlink_file)
- return local_path;
+ return local_spec;
- FileSpec resolved_local_path_spec;
- const auto error =
- FileSystem::Readlink(local_path_spec, resolved_local_path_spec);
+ FileSpec resolved_symlink;
+ const auto error = FileSystem::Readlink(local_spec, resolved_symlink);
if (error.Success())
- return resolved_local_path_spec.GetCString();
+ return resolved_symlink;
- return nullptr;
+ return local_spec;
}
DWARFUnit *SymbolFileDWARF::GetBaseCompileUnit() {
@@ -912,7 +913,7 @@
const DWARFDIE cu_die = dwarf_cu->GetUnitDIEOnly();
if (cu_die) {
- const char *cu_comp_dir = resolveCompDir(
+ FileSpec cu_comp_dir = resolveCompDir(
cu_die.GetAttributeValueAsString(DW_AT_comp_dir, nullptr));
const dw_offset_t stmt_list = cu_die.GetAttributeValueAsUnsigned(
DW_AT_stmt_list, DW_INVALID_OFFSET);
Index: source/Symbol/CompileUnit.cpp
===================================================================
--- source/Symbol/CompileUnit.cpp
+++ source/Symbol/CompileUnit.cpp
@@ -287,9 +287,8 @@
// when finding file indexes
std::vector file_indexes;
const bool full_match = (bool)file_spec.GetDirectory();
- const bool remove_backup_dots = true;
bool file_spec_matches_cu_file_spec =
- FileSpec::Equal(file_spec, *this, full_match, remove_backup_dots);
+ FileSpec::Equal(file_spec, *this, full_match);
// If we are not looking for inlined functions and our file spec doesn't
// match then we are done...
@@ -297,11 +296,10 @@
return 0;
uint32_t file_idx =
- GetSupportFiles().FindFileIndex(1, file_spec, true, remove_backup_dots);
+ GetSupportFiles().FindFileIndex(1, file_spec, true);
while (file_idx != UINT32_MAX) {
file_indexes.push_back(file_idx);
- file_idx = GetSupportFiles().FindFileIndex(file_idx + 1, file_spec, true,
- remove_backup_dots);
+ file_idx = GetSupportFiles().FindFileIndex(file_idx + 1, file_spec, true);
}
const size_t num_file_indexes = file_indexes.size();
Index: source/Symbol/Declaration.cpp
===================================================================
--- source/Symbol/Declaration.cpp
+++ source/Symbol/Declaration.cpp
@@ -91,7 +91,7 @@
return lhs.GetFile() == rhs.GetFile();
#else
if (lhs.GetLine() == rhs.GetLine())
- return FileSpec::Equal(lhs.GetFile(), rhs.GetFile(), true, true);
+ return FileSpec::Equal(lhs.GetFile(), rhs.GetFile(), true);
#endif
return false;
}
Index: source/Utility/FileSpec.cpp
===================================================================
--- source/Utility/FileSpec.cpp
+++ source/Utility/FileSpec.cpp
@@ -62,17 +62,172 @@
return value == '/' || (!PathSyntaxIsPosix(syntax) && value == '\\');
}
-void Normalize(llvm::SmallVectorImpl &path, FileSpec::PathSyntax syntax) {
- if (PathSyntaxIsPosix(syntax))
+size_t RootDirStart(llvm::StringRef str, FileSpec::PathSyntax syntax);
+
+//------------------------------------------------------------------
+/// Safely get a character at the specified index.
+///
+/// @param[in] path
+/// A full, partial, or relative path to a file.
+///
+/// @param[in] i
+/// An index into path which may or may not be valid.
+///
+/// @return
+/// The character at index \a i if the index is valid, or 0 if
+/// the index is not valid.
+//------------------------------------------------------------------
+inline char safeCharAtIndex(const llvm::StringRef &path, size_t i) {
+ if (i < path.size())
+ return path[i];
+ return 0;
+}
+
+//------------------------------------------------------------------
+/// Check if a path needs to be normalized.
+///
+/// Check if a path needs to be normalized. We currently consider a
+/// path to need normalization if any of the following are true
+/// - path contains "/./"
+/// - path contains "/../"
+/// - path contains "//"
+/// - path ends with "/"
+/// Paths that start with "./" or with "../" are not considered to
+/// need normalization since we aren't trying to resolve the path,
+/// we are just trying to remove redundant things from the path.
+///
+/// @param[in] path
+/// A full, partial, or relative path to a file.
+///
+/// @return
+/// Returns \b true if the path needs to be normalized.
+//------------------------------------------------------------------
+bool needsNormalization(const llvm::StringRef &path) {
+ for (auto i = path.find('/'); i != llvm::StringRef::npos;
+ i = path.find('/', i + 1)) {
+ const auto nextChar = safeCharAtIndex(path, i+1);
+ switch (nextChar) {
+ case 0:
+ // '/'' at the end of the string which should be stripped unless
+ // it is the one and only character
+ return i > 0;
+ case '/':
+ // "//" in the middle of a path needs to be normalized
+ if (i > 0)
+ return true;
+ ++i;
+ break;
+
+ case '.': {
+ const auto nextNextChar = safeCharAtIndex(path, i+2);
+ switch (nextNextChar) {
+ default: break;
+ case 0: return true; // ends with "/."
+ case '/': return true; // contains "/./"
+ case '.':
+ switch (safeCharAtIndex(path, i+3)) {
+ default: break;
+ case 0: return true; // ends with "/.."
+ case '/': return true; // contains "/../"
+ }
+ break;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ return false;
+}
+
+void Normalize(llvm::SmallVectorImpl &path,
+ FileSpec::PathSyntax syntax) {
+
+ if (syntax == FileSpec::ePathSyntaxWindows) {
+ std::replace(path.begin(), path.end(), '\\', '/');
+ // Windows path can have \\ slashes which can be changed by replace
+ // call above to //. Here we remove the duplicate. Also remove duplicate
+ // '/' chara
+ auto iter = std::unique(path.begin(), path.end(), [](char &c1, char &c2) {
+ return (c1 == '/' && c2 == '/');
+ });
+ path.erase(iter, path.end());
+ }
+ llvm::StringRef path_ref(path.data(), path.size());
+
+// assert(needsNormalization("/") == false);
+// assert(needsNormalization("//") == false);
+// assert(needsNormalization("./"));
+// assert(needsNormalization("../"));
+// assert(needsNormalization("//a") == false);
+// assert(needsNormalization("/a//b"));
+// assert(needsNormalization("/a/."));
+// assert(needsNormalization("/a/.."));
+// assert(needsNormalization("/a/../"));
+// assert(needsNormalization("/a/../."));
+// assert(needsNormalization("/a/b/c.txt") == false);
+// assert(needsNormalization("/a/b/c..txt") == false);
+// assert(needsNormalization("/a/b/c.") == false);
+// assert(needsNormalization("/a/b/c") == false);
+ // Check if there is anything to normalize and bail if we don't find anything
+ //printf ("path = \"%s\"\n", path_ref.str().c_str()); // REMOVE THIS PRIOR TO CHECKING
+ if (!needsNormalization(path_ref))
return;
- std::replace(path.begin(), path.end(), '\\', '/');
- // Windows path can have \\ slashes which can be changed by replace
- // call above to //. Here we remove the duplicate.
- auto iter = std::unique(path.begin(), path.end(), [](char &c1, char &c2) {
- return (c1 == '/' && c2 == '/');
- });
- path.erase(iter, path.end());
+ llvm::SmallString<64> normalized;
+
+ // We will not go below root dir.
+ size_t root_dir_start = RootDirStart(path_ref, syntax);
+ const bool absolute = root_dir_start != llvm::StringRef::npos;
+ if (absolute) {
+ normalized += path_ref.take_front(root_dir_start + 1);
+ path_ref = path_ref.drop_front(root_dir_start + 1);
+ } else {
+ if (syntax == FileSpec::ePathSyntaxWindows && path.size() > 2 &&
+ path[1] == ':') {
+ normalized += path_ref.take_front(2);
+ path_ref = path_ref.drop_front(2);
+ }
+ }
+
+ bool anything_added = false;
+ llvm::SmallVector components, processed;
+ path_ref.split(components, '/', -1, false);
+ processed.reserve(components.size());
+ for (auto component : components) {
+ if (component == ".") {
+ if (!normalized.empty())
+ continue; // Skip '.' unless it is the first thing
+ }
+ else if (component != "..") {
+ processed.push_back(component);
+ continue; // Regular file name.
+ }
+ if (!processed.empty()) {
+ processed.pop_back();
+ continue; // Dots. Go one level up if we can.
+ }
+ if (absolute)
+ continue; // We're at the top level. Cannot go higher than that. Skip.
+
+ normalized += component; // We're a relative path. We need to keep these.
+ normalized += '/';
+ anything_added = true;
+ }
+ for (auto component : processed) {
+ normalized += component;
+ normalized += '/';
+ anything_added = true;
+ }
+
+ if (anything_added)
+ normalized.pop_back(); // Pop last '/'.
+ else if (normalized.empty())
+ normalized = ".";
+
+ path.swap(normalized);
}
void Denormalize(llvm::SmallVectorImpl &path,
@@ -256,10 +411,15 @@
filename_begin != root_dir_start &&
IsPathSeparator(resolve_path_ref[filename_begin], m_syntax))
++filename_begin;
- m_filename.SetString((filename_begin == llvm::StringRef::npos ||
- filename_begin >= resolve_path_ref.size())
- ? "."
- : resolve_path_ref.substr(filename_begin));
+ if (filename_begin < resolve_path_ref.size())
+ m_filename.SetString(resolve_path_ref.substr(filename_begin));
+ else {
+ // Make sure we don't end up with "." in both the directory and filename.
+ // If we do, clear the directory.
+ m_filename.SetString(".");
+ if (m_filename == m_directory)
+ m_directory.Clear();
+ }
}
void FileSpec::SetFile(llvm::StringRef path, bool resolve,
@@ -408,108 +568,24 @@
return ConstString::Compare(a.m_filename, b.m_filename, case_sensitive);
}
-bool FileSpec::Equal(const FileSpec &a, const FileSpec &b, bool full,
- bool remove_backups) {
- static ConstString g_dot_string(".");
- static ConstString g_dot_dot_string("..");
+bool FileSpec::Equal(const FileSpec &a, const FileSpec &b, bool full) {
// case sensitivity of equality test
const bool case_sensitive = a.IsCaseSensitive() || b.IsCaseSensitive();
- bool filenames_equal = ConstString::Equals(a.m_filename,
- b.m_filename,
- case_sensitive);
+ const bool filenames_equal = ConstString::Equals(a.m_filename,
+ b.m_filename,
+ case_sensitive);
- // The only way two FileSpecs can be equal if their filenames are
- // unequal is if we are removing backups and one or the other filename
- // is a backup string:
-
- if (!filenames_equal && !remove_backups)
+ if (!filenames_equal)
return false;
- bool last_component_is_dot = ConstString::Equals(a.m_filename, g_dot_string)
- || ConstString::Equals(a.m_filename,
- g_dot_dot_string)
- || ConstString::Equals(b.m_filename,
- g_dot_string)
- || ConstString::Equals(b.m_filename,
- g_dot_dot_string);
-
- if (!filenames_equal && !last_component_is_dot)
- return false;
-
if (!full && (a.GetDirectory().IsEmpty() || b.GetDirectory().IsEmpty()))
return filenames_equal;
- if (remove_backups == false)
- return a == b;
-
- if (a == b)
- return true;
-
- return Equal(a.GetNormalizedPath(), b.GetNormalizedPath(), full, false);
+ return a == b;
}
-FileSpec FileSpec::GetNormalizedPath() const {
- // Fast path. Do nothing if the path is not interesting.
- if (!m_directory.GetStringRef().contains(".") &&
- !m_directory.GetStringRef().contains("//") &&
- m_filename.GetStringRef() != ".." && m_filename.GetStringRef() != ".")
- return *this;
-
- llvm::SmallString<64> path, result;
- const bool normalize = false;
- GetPath(path, normalize);
- llvm::StringRef rest(path);
-
- // We will not go below root dir.
- size_t root_dir_start = RootDirStart(path, m_syntax);
- const bool absolute = root_dir_start != llvm::StringRef::npos;
- if (absolute) {
- result += rest.take_front(root_dir_start + 1);
- rest = rest.drop_front(root_dir_start + 1);
- } else {
- if (m_syntax == ePathSyntaxWindows && path.size() > 2 && path[1] == ':') {
- result += rest.take_front(2);
- rest = rest.drop_front(2);
- }
- }
-
- bool anything_added = false;
- llvm::SmallVector components, processed;
- rest.split(components, '/', -1, false);
- processed.reserve(components.size());
- for (auto component : components) {
- if (component == ".")
- continue; // Skip these.
- if (component != "..") {
- processed.push_back(component);
- continue; // Regular file name.
- }
- if (!processed.empty()) {
- processed.pop_back();
- continue; // Dots. Go one level up if we can.
- }
- if (absolute)
- continue; // We're at the top level. Cannot go higher than that. Skip.
-
- result += component; // We're a relative path. We need to keep these.
- result += '/';
- anything_added = true;
- }
- for (auto component : processed) {
- result += component;
- result += '/';
- anything_added = true;
- }
- if (anything_added)
- result.pop_back(); // Pop last '/'.
- else if (result.empty())
- result = ".";
-
- return FileSpec(result, false, m_syntax);
-}
-
//------------------------------------------------------------------
// Dump the object to the supplied stream. If the object contains
// a valid directory name, it will be displayed followed by a
@@ -793,7 +869,8 @@
continue;
result += components[i];
if (i != components.size() - 1 &&
- !IsPathSeparator(components[i].back(), syntax))
+ !IsPathSeparator(components[i].back(), syntax) &&
+ (result.empty() || !IsPathSeparator(result.back(), syntax)))
result += GetPreferredPathSeparator(syntax);
}
Index: unittests/Utility/FileSpecTest.cpp
===================================================================
--- unittests/Utility/FileSpecTest.cpp
+++ unittests/Utility/FileSpecTest.cpp
@@ -54,17 +54,14 @@
FileSpec fs_posix_trailing_slash("/foo/bar/", false,
FileSpec::ePathSyntaxPosix);
- EXPECT_STREQ("/foo/bar/.", fs_posix_trailing_slash.GetCString());
- EXPECT_STREQ("/foo/bar", fs_posix_trailing_slash.GetDirectory().GetCString());
- EXPECT_STREQ(".", fs_posix_trailing_slash.GetFilename().GetCString());
+ EXPECT_STREQ("/foo/bar", fs_posix_trailing_slash.GetCString());
+ EXPECT_STREQ("/foo", fs_posix_trailing_slash.GetDirectory().GetCString());
+ EXPECT_STREQ("bar", fs_posix_trailing_slash.GetFilename().GetCString());
FileSpec fs_windows_trailing_slash("F:\\bar\\", false,
FileSpec::ePathSyntaxWindows);
- EXPECT_STREQ("F:\\bar\\.", fs_windows_trailing_slash.GetCString());
- // EXPECT_STREQ("F:\\bar",
- // fs_windows_trailing_slash.GetDirectory().GetCString()); // It returns
- // "F:/bar"
- EXPECT_STREQ(".", fs_windows_trailing_slash.GetFilename().GetCString());
+ EXPECT_STREQ("F:\\bar", fs_windows_trailing_slash.GetCString());
+ EXPECT_STREQ("bar", fs_windows_trailing_slash.GetFilename().GetCString());
}
TEST(FileSpecTest, AppendPathComponent) {
@@ -131,32 +128,13 @@
EXPECT_STREQ("F:\\bar", fs_windows_root.GetCString());
}
-static void Compare(const FileSpec &one, const FileSpec &two, bool full_match,
- bool remove_backup_dots, bool result) {
- EXPECT_EQ(result, FileSpec::Equal(one, two, full_match, remove_backup_dots))
- << "File one: " << one.GetCString() << "\nFile two: " << two.GetCString()
- << "\nFull match: " << full_match
- << "\nRemove backup dots: " << remove_backup_dots;
-}
-
TEST(FileSpecTest, EqualSeparator) {
FileSpec backward("C:\\foo\\bar", false, FileSpec::ePathSyntaxWindows);
FileSpec forward("C:/foo/bar", false, FileSpec::ePathSyntaxWindows);
EXPECT_EQ(forward, backward);
-
- const bool full_match = true;
- const bool remove_backup_dots = true;
- const bool match = true;
- Compare(forward, backward, full_match, remove_backup_dots, match);
- Compare(forward, backward, full_match, !remove_backup_dots, match);
- Compare(forward, backward, !full_match, remove_backup_dots, match);
- Compare(forward, backward, !full_match, !remove_backup_dots, match);
}
TEST(FileSpecTest, EqualDotsWindows) {
- const bool full_match = true;
- const bool remove_backup_dots = true;
- const bool match = true;
std::pair tests[] = {
{R"(C:\foo\bar\baz)", R"(C:\foo\foo\..\bar\baz)"},
{R"(C:\bar\baz)", R"(C:\foo\..\bar\baz)"},
@@ -170,18 +148,11 @@
for (const auto &test : tests) {
FileSpec one(test.first, false, FileSpec::ePathSyntaxWindows);
FileSpec two(test.second, false, FileSpec::ePathSyntaxWindows);
- EXPECT_NE(one, two);
- Compare(one, two, full_match, remove_backup_dots, match);
- Compare(one, two, full_match, !remove_backup_dots, !match);
- Compare(one, two, !full_match, remove_backup_dots, match);
- Compare(one, two, !full_match, !remove_backup_dots, !match);
+ EXPECT_EQ(one, two);
}
}
TEST(FileSpecTest, EqualDotsPosix) {
- const bool full_match = true;
- const bool remove_backup_dots = true;
- const bool match = true;
std::pair tests[] = {
{R"(/foo/bar/baz)", R"(/foo/foo/../bar/baz)"},
{R"(/bar/baz)", R"(/foo/../bar/baz)"},
@@ -193,18 +164,11 @@
for (const auto &test : tests) {
FileSpec one(test.first, false, FileSpec::ePathSyntaxPosix);
FileSpec two(test.second, false, FileSpec::ePathSyntaxPosix);
- EXPECT_NE(one, two);
- Compare(one, two, full_match, remove_backup_dots, match);
- Compare(one, two, full_match, !remove_backup_dots, !match);
- Compare(one, two, !full_match, remove_backup_dots, match);
- Compare(one, two, !full_match, !remove_backup_dots, !match);
+ EXPECT_EQ(one, two);
}
}
TEST(FileSpecTest, EqualDotsPosixRoot) {
- const bool full_match = true;
- const bool remove_backup_dots = true;
- const bool match = true;
std::pair tests[] = {
{R"(/)", R"(/..)"},
{R"(/)", R"(/.)"},
@@ -214,11 +178,7 @@
for (const auto &test : tests) {
FileSpec one(test.first, false, FileSpec::ePathSyntaxPosix);
FileSpec two(test.second, false, FileSpec::ePathSyntaxPosix);
- EXPECT_NE(one, two);
- Compare(one, two, full_match, remove_backup_dots, match);
- Compare(one, two, full_match, !remove_backup_dots, !match);
- Compare(one, two, !full_match, remove_backup_dots, !match);
- Compare(one, two, !full_match, !remove_backup_dots, !match);
+ EXPECT_EQ(one, two);
}
}
@@ -245,12 +205,14 @@
{"foo/..", "."},
{"foo/../bar", "bar"},
{"../foo/..", ".."},
- {"./foo", "foo"},
+ {"./foo", "./foo"},
+ {"././foo", "./foo"},
+ {"../foo", "../foo"},
+ {"../../foo", "../../foo"},
};
for (auto test : posix_tests) {
EXPECT_EQ(test.second,
FileSpec(test.first, false, FileSpec::ePathSyntaxPosix)
- .GetNormalizedPath()
.GetPath());
}
@@ -274,12 +236,14 @@
{R"(foo\..)", R"(.)"},
{R"(foo\..\bar)", R"(bar)"},
{R"(..\foo\..)", R"(..)"},
- {R"(.\foo)", R"(foo)"},
+ {R"(.\foo)", R"(.\foo)"},
+ {R"(.\.\foo)", R"(.\foo)"},
+ {R"(..\foo)", R"(..\foo)"},
+ {R"(..\..\foo)", R"(..\..\foo)"},
};
for (auto test : windows_tests) {
EXPECT_EQ(test.second,
FileSpec(test.first, false, FileSpec::ePathSyntaxWindows)
- .GetNormalizedPath()
.GetPath())
<< "Original path: " << test.first;
}