[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