diff options
author | Jim Ingham <jingham@apple.com> | 2014-11-15 01:54:26 +0000 |
---|---|---|
committer | Jim Ingham <jingham@apple.com> | 2014-11-15 01:54:26 +0000 |
commit | 96a1596a7ada11147f984e78484ff75239b155a9 (patch) | |
tree | 24c0d7d8461258103880b681f344e4659bceb1dd /lldb/source/Host/common/FileSpec.cpp | |
parent | b1be683074685ea642efd932e006bc4427c2ed45 (diff) | |
download | bcm5719-llvm-96a1596a7ada11147f984e78484ff75239b155a9.tar.gz bcm5719-llvm-96a1596a7ada11147f984e78484ff75239b155a9.zip |
For some reason, sometimes the directory paths that clang emits have internal
relative paths, like:
/whatever/llvm/lib/Sema/../../include/llvm/Sema/
That causes problems with our type uniquing, since we use the declaration file
and line as one component of the uniquing, and different ways of getting to the
same file will have different directory spellings, though they are functionally
equivalent. We end up with two copies of the exact same type because of this,
and that makes the expression parser give "duplicate type" errors.
I added a method to resolve paths with ../ in them and used that in the FileSpec::Equals,
for comparing Declarations and for doing Breakpoint compares as well, since they also
suffer from this if you specify breakpoints by full path (since nobody knows what
../'s to insert...)
<rdar://problem/18765814>
llvm-svn: 222075
Diffstat (limited to 'lldb/source/Host/common/FileSpec.cpp')
-rw-r--r-- | lldb/source/Host/common/FileSpec.cpp | 118 |
1 files changed, 116 insertions, 2 deletions
diff --git a/lldb/source/Host/common/FileSpec.cpp b/lldb/source/Host/common/FileSpec.cpp index 0b21d19f8cf..1678e98aba7 100644 --- a/lldb/source/Host/common/FileSpec.cpp +++ b/lldb/source/Host/common/FileSpec.cpp @@ -448,15 +448,129 @@ FileSpec::Compare(const FileSpec& a, const FileSpec& b, bool full) } bool -FileSpec::Equal (const FileSpec& a, const FileSpec& b, bool full) +FileSpec::Equal (const FileSpec& a, const FileSpec& b, bool full, bool remove_backups) { if (!full && (a.GetDirectory().IsEmpty() || b.GetDirectory().IsEmpty())) return a.m_filename == b.m_filename; - else + else if (remove_backups == false) return a == b; + else + { + if (a.m_filename != b.m_filename) + return false; + if (a.m_directory == b.m_directory) + return true; + ConstString a_without_dots; + ConstString b_without_dots; + + RemoveBackupDots (a.m_directory, a_without_dots); + RemoveBackupDots (b.m_directory, b_without_dots); + return a_without_dots == b_without_dots; + } } +void +FileSpec::RemoveBackupDots (const ConstString &input_const_str, ConstString &result_const_str) +{ + const char *input = input_const_str.GetCString(); + result_const_str.Clear(); + if (!input || input[0] == '\0') + return; + + const char win_sep = '\\'; + const char unix_sep = '/'; + char found_sep; + const char *win_backup = "\\.."; + const char *unix_backup = "/.."; + + bool is_win = false; + + // Determine the platform for the path (win or unix): + + if (input[0] == win_sep) + is_win = true; + else if (input[0] == unix_sep) + is_win = false; + else if (input[1] == ':') + is_win = true; + else if (strchr(input, unix_sep) != nullptr) + is_win = false; + else if (strchr(input, win_sep) != nullptr) + is_win = true; + else + { + // No separators at all, no reason to do any work here. + result_const_str = input_const_str; + return; + } + + llvm::StringRef backup_sep; + if (is_win) + { + found_sep = win_sep; + backup_sep = win_backup; + } + else + { + found_sep = unix_sep; + backup_sep = unix_backup; + } + + llvm::StringRef input_ref(input); + llvm::StringRef curpos(input); + bool had_dots = false; + std::string result; + + while (1) + { + // Start of loop + llvm::StringRef before_sep; + std::pair<llvm::StringRef, llvm::StringRef> around_sep = curpos.split(backup_sep); + + before_sep = around_sep.first; + curpos = around_sep.second; + + if (curpos.empty()) + { + if (had_dots) + { + if (!before_sep.empty()) + { + result.append(before_sep.data(), before_sep.size()); + } + } + break; + } + had_dots = true; + + unsigned num_backups = 1; + while (curpos.startswith(backup_sep)) + { + num_backups++; + curpos = curpos.slice(backup_sep.size(), curpos.size()); + } + + size_t end_pos = before_sep.size(); + while (num_backups-- > 0) + { + end_pos = before_sep.rfind(found_sep, end_pos); + if (end_pos == llvm::StringRef::npos) + { + result_const_str = input_const_str; + return; + } + } + result.append(before_sep.data(), end_pos); + } + + if (had_dots) + result_const_str.SetCString(result.c_str()); + else + result_const_str = input_const_str; + + return; +} //------------------------------------------------------------------ // Dump the object to the supplied stream. If the object contains |