[Lldb-commits] [lldb] r261771 - Some fixes for case insensitive paths on Windows.
Zachary Turner via lldb-commits
lldb-commits at lists.llvm.org
Wed Feb 24 13:26:48 PST 2016
Author: zturner
Date: Wed Feb 24 15:26:47 2016
New Revision: 261771
URL: http://llvm.org/viewvc/llvm-project?rev=261771&view=rev
Log:
Some fixes for case insensitive paths on Windows.
Paths on Windows are not case-sensitive. Because of this, if a file
is called main.cpp, you should be able to set a breakpoint on it
by using the name Main.cpp. In an ideal world, you could just
tell people to match the case, but in practice this can be a real
problem as it requires you to know whether the person who compiled
the program ran "clang++ main.cpp" or "clang++ Main.cpp", both of
which would work, regardless of what the file was actually called.
This fixes http://llvm.org/pr22667
Patch by Petr Hons
Differential Revision: http://reviews.llvm.org/D17492
Reviewed by: zturner
Added:
lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_case_sensitivity/
lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_case_sensitivity/Makefile
lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_case_sensitivity/TestBreakpointCaseSensitivity.py
lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_case_sensitivity/main.c
Modified:
lldb/trunk/include/lldb/Core/ConstString.h
lldb/trunk/include/lldb/Host/FileSpec.h
lldb/trunk/source/Core/ConstString.cpp
lldb/trunk/source/Core/FileSpecList.cpp
lldb/trunk/source/Host/common/FileSpec.cpp
Modified: lldb/trunk/include/lldb/Core/ConstString.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Core/ConstString.h?rev=261771&r1=261770&r2=261771&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Core/ConstString.h (original)
+++ lldb/trunk/include/lldb/Core/ConstString.h Wed Feb 24 15:26:47 2016
@@ -291,12 +291,37 @@ public:
}
//------------------------------------------------------------------
+ /// Equal to operator
+ ///
+ /// Returns true if this string is equal to the string in \a rhs.
+ /// If case sensitive equality is tested, this operation is very
+ /// fast as it results in a pointer comparison since all strings
+ /// are in a uniqued in a global string pool.
+ ///
+ /// @param[in] rhs
+ /// The Left Hand Side const ConstString object reference.
+ ///
+ /// @param[in] rhs
+ /// The Right Hand Side const ConstString object reference.
+ ///
+ /// @param[in] case_sensitive
+ /// Case sensitivity. If true, case sensitive equality
+ /// will be tested, otherwise character case will be ignored
+ ///
+ /// @return
+ /// @li \b true if this object is equal to \a rhs.
+ /// @li \b false if this object is not equal to \a rhs.
+ //------------------------------------------------------------------
+ static bool
+ Equals(const ConstString &lhs, const ConstString &rhs, const bool case_sensitive = true);
+
+ //------------------------------------------------------------------
/// Compare two string objects.
///
/// Compares the C string values contained in \a lhs and \a rhs and
/// returns an integer result.
///
- /// NOTE: only call this function when you want a true string
+ /// NOTE: only call this function when you want a true string
/// comparison. If you want string equality use the, use the ==
/// operator as it is much more efficient. Also if you want string
/// inequality, use the != operator for the same reasons.
@@ -307,13 +332,17 @@ public:
/// @param[in] rhs
/// The Right Hand Side const ConstString object reference.
///
+ /// @param[in] case_sensitive
+ /// Case sensitivity of compare. If true, case sensitive compare
+ /// will be performed, otherwise character case will be ignored
+ ///
/// @return
/// @li -1 if lhs < rhs
/// @li 0 if lhs == rhs
/// @li 1 if lhs > rhs
//------------------------------------------------------------------
static int
- Compare (const ConstString& lhs, const ConstString& rhs);
+ Compare(const ConstString &lhs, const ConstString &rhs, const bool case_sensitive = true);
//------------------------------------------------------------------
/// Dump the object description to a stream.
Modified: lldb/trunk/include/lldb/Host/FileSpec.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Host/FileSpec.h?rev=261771&r1=261770&r2=261771&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Host/FileSpec.h (original)
+++ lldb/trunk/include/lldb/Host/FileSpec.h Wed Feb 24 15:26:47 2016
@@ -261,6 +261,19 @@ public:
Equal (const FileSpec& a, const FileSpec& b, bool full, bool remove_backups = false);
//------------------------------------------------------------------
+ /// Case sensitivity of path.
+ ///
+ /// @return
+ /// \b true if the file path is case sensitive (POSIX), false
+ /// if case insensitive (Windows).
+ //------------------------------------------------------------------
+ bool
+ IsCaseSensitive() const
+ {
+ return m_syntax != ePathSyntaxWindows;
+ }
+
+ //------------------------------------------------------------------
/// Dump this object to a Stream.
///
/// Dump the object to the supplied stream \a s. If the object
Added: lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_case_sensitivity/Makefile
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_case_sensitivity/Makefile?rev=261771&view=auto
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_case_sensitivity/Makefile (added)
+++ lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_case_sensitivity/Makefile Wed Feb 24 15:26:47 2016
@@ -0,0 +1,6 @@
+LEVEL = ../../../make
+
+C_SOURCES := main.c
+CFLAGS_EXTRAS += -std=c99
+
+include $(LEVEL)/Makefile.rules
Added: lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_case_sensitivity/TestBreakpointCaseSensitivity.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_case_sensitivity/TestBreakpointCaseSensitivity.py?rev=261771&view=auto
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_case_sensitivity/TestBreakpointCaseSensitivity.py (added)
+++ lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_case_sensitivity/TestBreakpointCaseSensitivity.py Wed Feb 24 15:26:47 2016
@@ -0,0 +1,120 @@
+"""
+Test case sensitivity of paths on Windows / POSIX
+llvm.org/pr22667
+"""
+
+import os
+import lldb
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test.decorators import *
+from lldbsuite.test import lldbplatform, lldbplatformutil
+
+class BreakpointCaseSensitivityTestCase(TestBase):
+ mydir = TestBase.compute_mydir(__file__)
+ BREAKPOINT_TEXT = 'Set a breakpoint here'
+
+ def setUp(self):
+ # Call super's setUp().
+ TestBase.setUp(self)
+ self.line = line_number('main.c', self.BREAKPOINT_TEXT)
+
+ @skipIf(oslist=no_match(['windows'])) # Skip for non-windows platforms
+ def test_breakpoint_matches_file_with_different_case(self):
+ """Set breakpoint on file, should match files with different case on Windows"""
+ self.build()
+ self.case_sensitivity_breakpoint(True)
+
+ @skipIf(oslist=['windows']) # Skip for windows platforms
+ def test_breakpoint_doesnt_match_file_with_different_case(self):
+ """Set breakpoint on file, shouldn't match files with different case on POSIX systems"""
+ self.build()
+ self.case_sensitivity_breakpoint(False)
+
+ def case_sensitivity_breakpoint(self, case_insensitive):
+ """Set breakpoint on file, should match files with different case if case_insensitive is True"""
+
+ # use different case to check CreateTarget
+ exe = 'a.out'
+ if case_insensitive:
+ exe = exe.upper()
+
+ exe = os.path.join(os.getcwd(), exe)
+
+ # Create a target by the debugger.
+ self.target = self.dbg.CreateTarget(exe)
+ self.assertTrue(self.target, VALID_TARGET)
+ cwd = self.get_process_working_directory();
+
+ # try both BreakpointCreateByLocation and BreakpointCreateBySourceRegex
+ for regex in [False, True]:
+ # should always hit
+ self.check_breakpoint('main.c', regex, True)
+ # should always hit
+ self.check_breakpoint(os.path.join(cwd, 'main.c'), regex, True)
+ # different case for directory
+ self.check_breakpoint(os.path.join(cwd.upper(), 'main.c'),
+ regex,
+ case_insensitive)
+ # different case for file
+ self.check_breakpoint('Main.c',
+ regex,
+ case_insensitive)
+ # different case for both
+ self.check_breakpoint(os.path.join(cwd.upper(), 'Main.c'),
+ regex,
+ case_insensitive)
+
+ def check_breakpoint(self, file, source_regex, should_hit):
+ """
+ Check breakpoint hit at given file set by given method
+
+ file:
+ File where insert the breakpoint
+
+ source_regex:
+ True for testing using BreakpointCreateBySourceRegex,
+ False for BreakpointCreateByLocation
+
+ should_hit:
+ True if the breakpoint should hit, False otherwise
+ """
+
+ desc = ' file %s set by %s' % (file, 'regex' if source_regex else 'location')
+ if source_regex:
+ breakpoint = self.target.BreakpointCreateBySourceRegex(self.BREAKPOINT_TEXT,
+ lldb.SBFileSpec(file))
+ else:
+ breakpoint = self.target.BreakpointCreateByLocation(file, self.line)
+
+ self.assertEqual(breakpoint and breakpoint.GetNumLocations() == 1,
+ should_hit,
+ VALID_BREAKPOINT + desc)
+
+ # Get the breakpoint location from breakpoint after we verified that,
+ # indeed, it has one location.
+ location = breakpoint.GetLocationAtIndex(0)
+ self.assertEqual(location and location.IsEnabled(),
+ should_hit,
+ VALID_BREAKPOINT_LOCATION + desc)
+
+ process = self.target.LaunchSimple(None, None, self.get_process_working_directory())
+ self.assertTrue(process, PROCESS_IS_VALID + desc)
+
+ if should_hit:
+ # Did we hit our breakpoint?
+ from lldbsuite.test.lldbutil import get_threads_stopped_at_breakpoint
+ threads = get_threads_stopped_at_breakpoint (process, breakpoint)
+ self.assertEqual(len(threads), 1, "There should be a thread stopped at breakpoint" + desc)
+ # The hit count for the breakpoint should be 1.
+ self.assertEqual(breakpoint.GetHitCount(), 1)
+
+ else:
+ # check the breakpoint was not hit
+ self.assertEqual(lldb.eStateExited, process.GetState())
+ self.assertEqual(breakpoint.GetHitCount(), 0)
+
+ # let process finish
+ process.Continue()
+
+ # cleanup
+ self.target.BreakpointDelete(breakpoint.GetID())
Added: lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_case_sensitivity/main.c
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_case_sensitivity/main.c?rev=261771&view=auto
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_case_sensitivity/main.c (added)
+++ lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_case_sensitivity/main.c Wed Feb 24 15:26:47 2016
@@ -0,0 +1,8 @@
+#include <stdio.h>
+
+int
+main()
+{
+ printf("Set a breakpoint here.\n");
+ return 0;
+}
Modified: lldb/trunk/source/Core/ConstString.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Core/ConstString.cpp?rev=261771&r1=261770&r2=261771&view=diff
==============================================================================
--- lldb/trunk/source/Core/ConstString.cpp (original)
+++ lldb/trunk/source/Core/ConstString.cpp Wed Feb 24 15:26:47 2016
@@ -265,8 +265,25 @@ ConstString::GetLength () const
return StringPool().GetConstCStringLength (m_string);
}
+bool
+ConstString::Equals(const ConstString &lhs, const ConstString &rhs, const bool case_sensitive)
+{
+ if (lhs.m_string == rhs.m_string)
+ return true;
+
+ // Since the pointers weren't equal, and identical ConstStrings always have identical pointers,
+ // the result must be false for case sensitive equality test.
+ if (case_sensitive)
+ return false;
+
+ // perform case insensitive equality test
+ llvm::StringRef lhs_string_ref(lhs.m_string, StringPool().GetConstCStringLength(lhs.m_string));
+ llvm::StringRef rhs_string_ref(rhs.m_string, StringPool().GetConstCStringLength(rhs.m_string));
+ return lhs_string_ref.equals_lower(rhs_string_ref);
+}
+
int
-ConstString::Compare (const ConstString& lhs, const ConstString& rhs)
+ConstString::Compare(const ConstString &lhs, const ConstString &rhs, const bool case_sensitive)
{
// If the iterators are the same, this is the same string
const char *lhs_cstr = lhs.m_string;
@@ -277,7 +294,15 @@ ConstString::Compare (const ConstString&
{
llvm::StringRef lhs_string_ref (lhs_cstr, StringPool().GetConstCStringLength (lhs_cstr));
llvm::StringRef rhs_string_ref (rhs_cstr, StringPool().GetConstCStringLength (rhs_cstr));
- return lhs_string_ref.compare(rhs_string_ref);
+
+ if (case_sensitive)
+ {
+ return lhs_string_ref.compare(rhs_string_ref);
+ }
+ else
+ {
+ return lhs_string_ref.compare_lower(rhs_string_ref);
+ }
}
if (lhs_cstr)
Modified: lldb/trunk/source/Core/FileSpecList.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Core/FileSpecList.cpp?rev=261771&r1=261770&r2=261771&view=diff
==============================================================================
--- lldb/trunk/source/Core/FileSpecList.cpp (original)
+++ lldb/trunk/source/Core/FileSpecList.cpp Wed Feb 24 15:26:47 2016
@@ -119,7 +119,8 @@ FileSpecList::FindFileIndex (size_t star
{
if (compare_filename_only)
{
- if (m_files[idx].GetFilename() == file_spec.GetFilename())
+ if (ConstString::Equals(m_files[idx].GetFilename(), file_spec.GetFilename(),
+ file_spec.IsCaseSensitive() || m_files[idx].IsCaseSensitive()))
return idx;
}
else
Modified: lldb/trunk/source/Host/common/FileSpec.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Host/common/FileSpec.cpp?rev=261771&r1=261770&r2=261771&view=diff
==============================================================================
--- lldb/trunk/source/Host/common/FileSpec.cpp (original)
+++ lldb/trunk/source/Host/common/FileSpec.cpp Wed Feb 24 15:26:47 2016
@@ -396,60 +396,62 @@ FileSpec::operator!() const
bool
FileSpec::operator== (const FileSpec& rhs) const
{
- if (m_filename == rhs.m_filename)
+ // case sensitivity of equality test
+ const bool case_sensitive = IsCaseSensitive() || rhs.IsCaseSensitive();
+
+ if (!ConstString::Equals(m_filename, rhs.m_filename, case_sensitive))
+ return false;
+
+ if (ConstString::Equals(m_directory, rhs.m_directory, case_sensitive))
+ return true;
+
+ // TODO: determine if we want to keep this code in here.
+ // The code below was added to handle a case where we were
+ // trying to set a file and line breakpoint and one path
+ // was resolved, and the other not and the directory was
+ // in a mount point that resolved to a more complete path:
+ // "/tmp/a.c" == "/private/tmp/a.c". I might end up pulling
+ // this out...
+ if (IsResolved() && rhs.IsResolved())
{
- if (m_directory == rhs.m_directory)
- return true;
-
- // TODO: determine if we want to keep this code in here.
- // The code below was added to handle a case where we were
- // trying to set a file and line breakpoint and one path
- // was resolved, and the other not and the directory was
- // in a mount point that resolved to a more complete path:
- // "/tmp/a.c" == "/private/tmp/a.c". I might end up pulling
- // this out...
- if (IsResolved() && rhs.IsResolved())
- {
- // Both paths are resolved, no need to look further...
- return false;
- }
-
- FileSpec resolved_lhs(*this);
+ // Both paths are resolved, no need to look further...
+ return false;
+ }
- // If "this" isn't resolved, resolve it
- if (!IsResolved())
+ FileSpec resolved_lhs(*this);
+
+ // If "this" isn't resolved, resolve it
+ if (!IsResolved())
+ {
+ if (resolved_lhs.ResolvePath())
{
- if (resolved_lhs.ResolvePath())
- {
- // This path wasn't resolved but now it is. Check if the resolved
- // directory is the same as our unresolved directory, and if so,
- // we can mark this object as resolved to avoid more future resolves
- m_is_resolved = (m_directory == resolved_lhs.m_directory);
- }
- else
- return false;
+ // This path wasn't resolved but now it is. Check if the resolved
+ // directory is the same as our unresolved directory, and if so,
+ // we can mark this object as resolved to avoid more future resolves
+ m_is_resolved = (m_directory == resolved_lhs.m_directory);
}
-
- FileSpec resolved_rhs(rhs);
- if (!rhs.IsResolved())
+ else
+ return false;
+ }
+
+ FileSpec resolved_rhs(rhs);
+ if (!rhs.IsResolved())
+ {
+ if (resolved_rhs.ResolvePath())
{
- if (resolved_rhs.ResolvePath())
- {
- // rhs's path wasn't resolved but now it is. Check if the resolved
- // directory is the same as rhs's unresolved directory, and if so,
- // we can mark this object as resolved to avoid more future resolves
- rhs.m_is_resolved = (rhs.m_directory == resolved_rhs.m_directory);
- }
- else
- return false;
+ // rhs's path wasn't resolved but now it is. Check if the resolved
+ // directory is the same as rhs's unresolved directory, and if so,
+ // we can mark this object as resolved to avoid more future resolves
+ rhs.m_is_resolved = (rhs.m_directory == resolved_rhs.m_directory);
}
-
- // If we reach this point in the code we were able to resolve both paths
- // and since we only resolve the paths if the basenames are equal, then
- // we can just check if both directories are equal...
- return resolved_lhs.GetDirectory() == resolved_rhs.GetDirectory();
+ else
+ return false;
}
- return false;
+
+ // If we reach this point in the code we were able to resolve both paths
+ // and since we only resolve the paths if the basenames are equal, then
+ // we can just check if both directories are equal...
+ return ConstString::Equals(m_directory, rhs.m_directory, case_sensitive);
}
//------------------------------------------------------------------
@@ -507,6 +509,9 @@ FileSpec::Compare(const FileSpec& a, con
{
int result = 0;
+ // case sensitivity of compare
+ const bool case_sensitive = a.IsCaseSensitive() || b.IsCaseSensitive();
+
// If full is true, then we must compare both the directory and filename.
// If full is false, then if either directory is empty, then we match on
@@ -516,32 +521,35 @@ FileSpec::Compare(const FileSpec& a, con
if (full || (a.m_directory && b.m_directory))
{
- result = ConstString::Compare(a.m_directory, b.m_directory);
+ result = ConstString::Compare(a.m_directory, b.m_directory, case_sensitive);
if (result)
return result;
}
- return ConstString::Compare (a.m_filename, b.m_filename);
+ 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)
{
+ // case sensitivity of equality test
+ const bool case_sensitive = a.IsCaseSensitive() || b.IsCaseSensitive();
+
if (!full && (a.GetDirectory().IsEmpty() || b.GetDirectory().IsEmpty()))
- return a.m_filename == b.m_filename;
+ return ConstString::Equals(a.m_filename, b.m_filename, case_sensitive);
else if (remove_backups == false)
return a == b;
else
{
- if (a.m_filename != b.m_filename)
+ if (!ConstString::Equals(a.m_filename, b.m_filename, case_sensitive))
return false;
- if (a.m_directory == b.m_directory)
+ if (ConstString::Equals(a.m_directory, b.m_directory, case_sensitive))
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;
+ return ConstString::Equals(a_without_dots, b_without_dots, case_sensitive);
}
}
More information about the lldb-commits
mailing list