[llvm-branch-commits] [lldb] 32eed90 - [lldb] Fix Unicode code point formatting to use proper notation (#211131)

Tobias Hieta via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Wed Jul 22 22:56:10 PDT 2026


Author: Adrian Prantl
Date: 2026-07-23T07:56:02+02:00
New Revision: 32eed90cb80eb7b88a3d3cf0fed7258d69a65075

URL: https://github.com/llvm/llvm-project/commit/32eed90cb80eb7b88a3d3cf0fed7258d69a65075
DIFF: https://github.com/llvm/llvm-project/commit/32eed90cb80eb7b88a3d3cf0fed7258d69a65075.diff

LOG: [lldb] Fix Unicode code point formatting to use proper notation  (#211131)

- use uppercase hex digits

- only emit "U+" notation for valid code points (<= U+10FFFF),
zero-padded to a minimum of four digits.

rdar://173817553

Assisted-by: claude
(cherry picked from commit 0cd942fa1b6de94fd6d7fa7ba73f0233293115f8)

Added: 
    

Modified: 
    lldb/source/Core/DumpDataExtractor.cpp
    lldb/test/API/functionalities/data-formatter/builtin-formats/TestBuiltinFormats.py
    lldb/test/API/lang/cpp/char1632_t/TestChar1632T.py
    lldb/test/Shell/SymbolFile/NativePDB/globals-fundamental.cpp
    lldb/unittests/Core/DumpDataExtractorTest.cpp

Removed: 
    


################################################################################
diff  --git a/lldb/source/Core/DumpDataExtractor.cpp b/lldb/source/Core/DumpDataExtractor.cpp
index 4e4e45b4f2f23..0ae6d26809e80 100644
--- a/lldb/source/Core/DumpDataExtractor.cpp
+++ b/lldb/source/Core/DumpDataExtractor.cpp
@@ -698,12 +698,19 @@ lldb::offset_t lldb_private::DumpDataExtractor(
     } break;
 
     case eFormatUnicode16:
-      s->Printf("U+%4.4x", DE.GetU16(&offset));
+      // The Unicode notation is "U+" followed by uppercase hexadecimal digits,
+      // zero-padded to a minimum of four.
+      s->Format("U+{0:X-4}", DE.GetU16(&offset));
       break;
 
-    case eFormatUnicode32:
-      s->Printf("U+0x%8.8x", DE.GetU32(&offset));
-      break;
+    case eFormatUnicode32: {
+      const uint32_t cp = DE.GetU32(&offset);
+      // Use Unicode notation for valid code points, i.e., <= U+10FFFF.
+      if (cp <= 0x10FFFF)
+        s->Format("U+{0:X-4}", cp);
+      else
+        s->Format("0x{0:x-8}", cp);
+    } break;
 
     case eFormatAddressInfo: {
       addr_t addr = DE.GetMaxU64Bitfield(&offset, item_byte_size, item_bit_size,

diff  --git a/lldb/test/API/functionalities/data-formatter/builtin-formats/TestBuiltinFormats.py b/lldb/test/API/functionalities/data-formatter/builtin-formats/TestBuiltinFormats.py
index 60698f95412e3..98dfb1de086b6 100644
--- a/lldb/test/API/functionalities/data-formatter/builtin-formats/TestBuiltinFormats.py
+++ b/lldb/test/API/functionalities/data-formatter/builtin-formats/TestBuiltinFormats.py
@@ -224,10 +224,19 @@ def test(self):
 
         # unicode16
         self.assertIn("= U+5678 U+1234\n", self.getFormatted("unicode16", "0x12345678"))
+        self.assertIn(
+            "= U+ABCD\n", self.getFormatted("unicode16", "(unsigned short)0xabcd")
+        )
 
         # unicode32
-        self.assertIn(
-            "= U+0x89abcdef U+0x01234567\n",
+        # Values in the valid code point range (up to U+10FFFF) use the "U+"
+        # notation with four to six uppercase hex digits; larger values are not
+        # code points and fall back to a plain hex display.
+        self.assertIn("= U+20E3\n", self.getFormatted("unicode32", "0x20e3"))
+        self.assertIn("= U+10FFFF\n", self.getFormatted("unicode32", "0x10FFFF"))
+        self.assertIn("= 0x00110000\n", self.getFormatted("unicode32", "0x110000"))
+        self.assertIn(
+            "= 0x89abcdef 0x01234567\n",
             self.getFormatted("unicode32", "(__UINT64_TYPE__)0x123456789ABCDEFll"),
         )
 

diff  --git a/lldb/test/API/lang/cpp/char1632_t/TestChar1632T.py b/lldb/test/API/lang/cpp/char1632_t/TestChar1632T.py
index cd4dc9a406f5c..6edac71e06f52 100644
--- a/lldb/test/API/lang/cpp/char1632_t/TestChar1632T.py
+++ b/lldb/test/API/lang/cpp/char1632_t/TestChar1632T.py
@@ -117,10 +117,8 @@ def test(self):
 
         # check that zero values are properly handles
         self.expect_expr("cs16_zero", result_summary="U+0000 u'\\0'")
-        self.expect_expr("cs32_zero", result_summary="U+0x00000000 U'\\0'")
+        self.expect_expr("cs32_zero", result_summary="U+0000 U'\\0'")
 
         # Check that we can run expressions that return charN_t
         self.expect_expr("u'a'", result_type="char16_t", result_summary="U+0061 u'a'")
-        self.expect_expr(
-            "U'a'", result_type="char32_t", result_summary="U+0x00000061 U'a'"
-        )
+        self.expect_expr("U'a'", result_type="char32_t", result_summary="U+0061 U'a'")

diff  --git a/lldb/test/Shell/SymbolFile/NativePDB/globals-fundamental.cpp b/lldb/test/Shell/SymbolFile/NativePDB/globals-fundamental.cpp
index 299dd0b02671d..d572340200a91 100644
--- a/lldb/test/Shell/SymbolFile/NativePDB/globals-fundamental.cpp
+++ b/lldb/test/Shell/SymbolFile/NativePDB/globals-fundamental.cpp
@@ -39,7 +39,7 @@ char16_t C16_24 = u'\24';
 // CHECK-NEXT: (char16_t) C16_24 = U+0014
 char32_t C32_42 = U'\42';
 // CHECK-NEXT: (lldb) target variable C32_42
-// CHECK-NEXT: (char32_t) C32_42 = U+0x00000022
+// CHECK-NEXT: (char32_t) C32_42 = U+0022
 wchar_t WC1 = L'1';
 // CHECK-NEXT: (lldb) target variable WC1
 // CHECK-NEXT: (wchar_t) WC1 = L'1'
@@ -130,7 +130,7 @@ const char16_t CC16_24 = u'\24';
 // CHECK-NEXT: (const char16_t) CC16_24 = U+0014
 const char32_t CC32_42 = U'\42';
 // CHECK-NEXT: (lldb) target variable CC32_42
-// CHECK-NEXT: (const char32_t) CC32_42 = U+0x00000022
+// CHECK-NEXT: (const char32_t) CC32_42 = U+0022
 const wchar_t CWC1 = L'1';
 // CHECK-NEXT: (lldb) target variable CWC1
 // CHECK-NEXT: (const wchar_t) CWC1 = L'1'
@@ -222,7 +222,7 @@ constexpr char16_t ConstexprC16_24 = u'\24';
 // CHECK-NEXT: (const char16_t) ConstexprC16_24 = U+0014
 constexpr char32_t ConstexprC32_42 = U'\42';
 // CHECK-NEXT: (lldb) target variable ConstexprC32_42
-// CHECK-NEXT: (const char32_t) ConstexprC32_42 = U+0x00000022
+// CHECK-NEXT: (const char32_t) ConstexprC32_42 = U+0022
 constexpr wchar_t ConstexprWC1 = L'1';
 // CHECK-NEXT: (lldb) target variable ConstexprWC1
 // CHECK-NEXT: (const wchar_t) ConstexprWC1 = L'1'
@@ -641,7 +641,7 @@ char16_t &RC16_24 = C16_24;
 // FIXME: (char16_t &) RC16_24 = {{.*}} (&::RC16_24 = U+0014)
 char32_t &RC32_42 = C32_42;
 // CHECK: (lldb) target variable RC32_42
-// FIXME: (char32_t &) RC32_42 = {{.*}} (&::RC32_42 = U+0x00000022)
+// FIXME: (char32_t &) RC32_42 = {{.*}} (&::RC32_42 = U+0022)
 wchar_t &RWC1 = WC1;
 // CHECK: (lldb) target variable RWC1
 // FIXME: (wchar_t &) RWC1 = {{.*}} (&::RWC1 = L'1')
@@ -653,7 +653,7 @@ const char16_t &CRC16_24 = C16_24;
 // FIXME: (const char16_t &) CRC16_24 = {{.*}} (&::CRC16_24 = U+0014)
 const char32_t &CRC32_42 = C32_42;
 // CHECK: (lldb) target variable CRC32_42
-// FIXME: (const char32_t &) CRC32_42 = {{.*}} (&::CRC32_42 = U+0x00000022)
+// FIXME: (const char32_t &) CRC32_42 = {{.*}} (&::CRC32_42 = U+0022)
 const wchar_t &CRWC1 = WC1;
 // CHECK: (lldb) target variable CRWC1
 // FIXME: (const wchar_t &) CRWC1 = {{.*}} (&::CRWC1 = L'1')

diff  --git a/lldb/unittests/Core/DumpDataExtractorTest.cpp b/lldb/unittests/Core/DumpDataExtractorTest.cpp
index 6302f1e1d31a6..e2b6f788c5c6a 100644
--- a/lldb/unittests/Core/DumpDataExtractorTest.cpp
+++ b/lldb/unittests/Core/DumpDataExtractorTest.cpp
@@ -172,8 +172,15 @@ TEST_F(DumpDataExtractorTest, Formats) {
   // Unicode8 doesn't have a specific formatter.
   TestDump<uint8_t>(0x34, lldb::Format::eFormatUnicode8, "0x34");
   TestDump<uint16_t>(0x1122, lldb::Format::eFormatUnicode16, "U+1122");
-  TestDump<uint32_t>(0x12345678, lldb::Format::eFormatUnicode32,
-                     "U+0x12345678");
+  TestDump<uint16_t>(0xabcd, lldb::Format::eFormatUnicode16, "U+ABCD");
+  // Code points up to and including U+10FFFF use the "U+" notation of the
+  // Unicode Standard: uppercase hex, four to six digits, zero-padded to four.
+  TestDump<uint32_t>(0x12, lldb::Format::eFormatUnicode32, "U+0012");
+  TestDump<uint32_t>(0x20e3, lldb::Format::eFormatUnicode32, "U+20E3");
+  TestDump<uint32_t>(0x10FFFF, lldb::Format::eFormatUnicode32, "U+10FFFF");
+  // Values that are not valid code points fall back to plain hex.
+  TestDump<uint32_t>(0x110000, lldb::Format::eFormatUnicode32, "0x00110000");
+  TestDump<uint32_t>(0x12345678, lldb::Format::eFormatUnicode32, "0x12345678");
   TestDump<unsigned int>(654321, lldb::Format::eFormatUnsigned, "654321");
   // This pointer is printed based on the size of uint64_t, so the test is the
   // same for 32/64 bit host.


        


More information about the llvm-branch-commits mailing list