https://github.com/30Wedge updated 
https://github.com/llvm/llvm-project/pull/151590

>From e816bb79765a31ecaf8d5c4236a485cb7303dc62 Mon Sep 17 00:00:00 2001
From: Andy MacGregor <amacgregor.2018.comcast....@gmail.com>
Date: Thu, 31 Jul 2025 16:24:06 -0400
Subject: [PATCH] [clang-format] Add an option to format integer literal case

---
 clang/docs/ClangFormatStyleOptions.rst        | 107 ++++++
 clang/docs/ReleaseNotes.rst                   |   2 +
 clang/include/clang/Format/Format.h           |  69 ++++
 clang/lib/Format/CMakeLists.txt               |   1 +
 clang/lib/Format/Format.cpp                   |  33 +-
 clang/lib/Format/NumericLiteralCaseFixer.cpp  | 174 +++++++++
 clang/lib/Format/NumericLiteralCaseFixer.h    |  32 ++
 clang/unittests/Format/CMakeLists.txt         |   1 +
 .../Format/NumericLiteralCaseTest.cpp         | 354 ++++++++++++++++++
 9 files changed, 771 insertions(+), 2 deletions(-)
 create mode 100644 clang/lib/Format/NumericLiteralCaseFixer.cpp
 create mode 100644 clang/lib/Format/NumericLiteralCaseFixer.h
 create mode 100644 clang/unittests/Format/NumericLiteralCaseTest.cpp

diff --git a/clang/docs/ClangFormatStyleOptions.rst 
b/clang/docs/ClangFormatStyleOptions.rst
index 3ac9e3795cae7..c23df84a756c4 100644
--- a/clang/docs/ClangFormatStyleOptions.rst
+++ b/clang/docs/ClangFormatStyleOptions.rst
@@ -5079,6 +5079,113 @@ the configuration (without a prefix: ``Auto``).
 
   For example: TESTSUITE
 
+.. _NumericLiteralCase:
+
+**NumericLiteralCase** (``NumericLiteralCaseStyle``) 
:versionbadge:`clang-format 22` :ref:`¶ <NumericLiteralCase>`
+  Capitalization style for numeric literal constants.
+
+  Nested configuration flags:
+
+  Separate control for each numeric literal component.
+
+  * ``NumericLiteralComponentStyle ExponentLetter``
+    Format floating point exponent separator letter case.
+
+    .. code-block:: c++
+
+      /* ExponentLetter = Leave */
+      float a = 6.02e23 + 1.0E10;
+      /* ExponentLetter = Upper */
+      float a = 6.02E23 + 1.0E10;
+      /* ExponentLetter = Lower */
+      float a = 6.02e23 + 1.0e10;
+
+    Possible values:
+
+    * ``NLCS_Leave`` (in configuration: ``Leave``)
+      Leave this component of the literal as is.
+
+    * ``NLCS_Upper`` (in configuration: ``Upper``)
+      Format this component with upper case characters.
+
+    * ``NLCS_Lower`` (in configuration: ``Lower``)
+      Format this component with lower case characters.
+
+
+  * ``NumericLiteralComponentStyle HexDigit``
+    Format hexadecimal digit case.
+
+    .. code-block:: c++
+
+      /* HexDigit = Leave */
+      a = 0xaBcDeF;
+      /* HexDigit = Upper */
+      a = 0xABCDEF;
+      /* HexDigit = Lower */
+      a = 0xabcdef;
+
+    Possible values:
+
+    * ``NLCS_Leave`` (in configuration: ``Leave``)
+      Leave this component of the literal as is.
+
+    * ``NLCS_Upper`` (in configuration: ``Upper``)
+      Format this component with upper case characters.
+
+    * ``NLCS_Lower`` (in configuration: ``Lower``)
+      Format this component with lower case characters.
+
+
+  * ``NumericLiteralComponentStyle Prefix``
+    Format integer prefix case.
+
+    .. code-block:: c++
+
+       /* Prefix = Leave */
+       a = 0XF0 | 0b1;
+       /* Prefix = Upper */
+       a = 0XF0 | 0B1;
+       /* Prefix = Lower */
+       a = 0xF0 | 0b1;
+
+    Possible values:
+
+    * ``NLCS_Leave`` (in configuration: ``Leave``)
+      Leave this component of the literal as is.
+
+    * ``NLCS_Upper`` (in configuration: ``Upper``)
+      Format this component with upper case characters.
+
+    * ``NLCS_Lower`` (in configuration: ``Lower``)
+      Format this component with lower case characters.
+
+
+  * ``NumericLiteralComponentStyle Suffix``
+    Format suffix case. This option excludes case-sensitive reserved
+    suffixes, such as ``min`` in C++.
+
+    .. code-block:: c++
+
+      /* Suffix = Leave */
+      a = 1uLL;
+      /* Suffix = Upper */
+      a = 1ULL;
+      /* Suffix = Lower */
+      a = 1ull;
+
+    Possible values:
+
+    * ``NLCS_Leave`` (in configuration: ``Leave``)
+      Leave this component of the literal as is.
+
+    * ``NLCS_Upper`` (in configuration: ``Upper``)
+      Format this component with upper case characters.
+
+    * ``NLCS_Lower`` (in configuration: ``Lower``)
+      Format this component with lower case characters.
+
+
+
 .. _ObjCBinPackProtocolList:
 
 **ObjCBinPackProtocolList** (``BinPackStyle``) :versionbadge:`clang-format 7` 
:ref:`¶ <ObjCBinPackProtocolList>`
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index fe1dd15c6f885..e15511db6940f 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -357,6 +357,8 @@ AST Matchers
 clang-format
 ------------
 - Add ``SpaceInEmptyBraces`` option and set it to ``Always`` for WebKit style.
+- Add ``NumericLiteralCase`` option for enforcing character case in numeric
+  literals.
 
 libclang
 --------
diff --git a/clang/include/clang/Format/Format.h 
b/clang/include/clang/Format/Format.h
index 5dfdb23594610..47fc513ab63b1 100644
--- a/clang/include/clang/Format/Format.h
+++ b/clang/include/clang/Format/Format.h
@@ -3558,6 +3558,74 @@ struct FormatStyle {
   /// \version 9
   std::vector<std::string> NamespaceMacros;
 
+  /// Control over each component in a numeric literal.
+  enum NumericLiteralComponentStyle : int8_t {
+    /// Leave this component of the literal as is.
+    NLCS_Leave,
+    /// Format this component with upper case characters.
+    NLCS_Upper,
+    /// Format this component with lower case characters.
+    NLCS_Lower,
+  };
+
+  /// Separate control for each numeric literal component.
+  struct NumericLiteralCaseStyle {
+    /// Format floating point exponent separator letter case.
+    /// \code
+    ///   /* ExponentLetter = Leave */
+    ///   float a = 6.02e23 + 1.0E10;
+    ///   /* ExponentLetter = Upper */
+    ///   float a = 6.02E23 + 1.0E10;
+    ///   /* ExponentLetter = Lower */
+    ///   float a = 6.02e23 + 1.0e10;
+    /// \endcode
+    NumericLiteralComponentStyle ExponentLetter;
+    /// Format hexadecimal digit case.
+    /// \code
+    ///   /* HexDigit = Leave */
+    ///   a = 0xaBcDeF;
+    ///   /* HexDigit = Upper */
+    ///   a = 0xABCDEF;
+    ///   /* HexDigit = Lower */
+    ///   a = 0xabcdef;
+    /// \endcode
+    NumericLiteralComponentStyle HexDigit;
+    /// Format integer prefix case.
+    /// \code
+    ///    /* Prefix = Leave */
+    ///    a = 0XF0 | 0b1;
+    ///    /* Prefix = Upper */
+    ///    a = 0XF0 | 0B1;
+    ///    /* Prefix = Lower */
+    ///    a = 0xF0 | 0b1;
+    /// \endcode
+    NumericLiteralComponentStyle Prefix;
+    /// Format suffix case. This option excludes case-sensitive reserved
+    /// suffixes, such as ``min`` in C++.
+    /// \code
+    ///   /* Suffix = Leave */
+    ///   a = 1uLL;
+    ///   /* Suffix = Upper */
+    ///   a = 1ULL;
+    ///   /* Suffix = Lower */
+    ///   a = 1ull;
+    /// \endcode
+    NumericLiteralComponentStyle Suffix;
+
+    bool operator==(const NumericLiteralCaseStyle &R) const {
+      return ExponentLetter == R.ExponentLetter && HexDigit == R.HexDigit &&
+             Prefix == R.Prefix && Suffix == R.Suffix;
+    }
+
+    bool operator!=(const NumericLiteralCaseStyle &R) const {
+      return !(*this == R);
+    }
+  };
+
+  /// Capitalization style for numeric literal constants.
+  /// \version 22
+  NumericLiteralCaseStyle NumericLiteralCase;
+
   /// Controls bin-packing Objective-C protocol conformance list
   /// items into as few lines as possible when they go over ``ColumnLimit``.
   ///
@@ -5469,6 +5537,7 @@ struct FormatStyle {
            MaxEmptyLinesToKeep == R.MaxEmptyLinesToKeep &&
            NamespaceIndentation == R.NamespaceIndentation &&
            NamespaceMacros == R.NamespaceMacros &&
+           NumericLiteralCase == R.NumericLiteralCase &&
            ObjCBinPackProtocolList == R.ObjCBinPackProtocolList &&
            ObjCBlockIndentWidth == R.ObjCBlockIndentWidth &&
            ObjCBreakBeforeNestedBlockParam ==
diff --git a/clang/lib/Format/CMakeLists.txt b/clang/lib/Format/CMakeLists.txt
index 24f435d2caee1..c4891ec3916ec 100644
--- a/clang/lib/Format/CMakeLists.txt
+++ b/clang/lib/Format/CMakeLists.txt
@@ -14,6 +14,7 @@ add_clang_library(clangFormat
   MatchFilePath.cpp
   NamespaceEndCommentsFixer.cpp
   NumericLiteralInfo.cpp
+  NumericLiteralCaseFixer.cpp
   ObjCPropertyAttributeOrderFixer.cpp
   QualifierAlignmentFixer.cpp
   SortJavaScriptImports.cpp
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index e3b22cdabaccd..a29309b8fa29f 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -16,6 +16,7 @@
 #include "DefinitionBlockSeparator.h"
 #include "IntegerLiteralSeparatorFixer.h"
 #include "NamespaceEndCommentsFixer.h"
+#include "NumericLiteralCaseFixer.h"
 #include "ObjCPropertyAttributeOrderFixer.h"
 #include "QualifierAlignmentFixer.h"
 #include "SortJavaScriptImports.h"
@@ -472,6 +473,25 @@ struct 
ScalarEnumerationTraits<FormatStyle::NamespaceIndentationKind> {
   }
 };
 
+template <>
+struct ScalarEnumerationTraits<FormatStyle::NumericLiteralComponentStyle> {
+  static void enumeration(IO &IO,
+                          FormatStyle::NumericLiteralComponentStyle &Value) {
+    IO.enumCase(Value, "Leave", FormatStyle::NLCS_Leave);
+    IO.enumCase(Value, "Upper", FormatStyle::NLCS_Upper);
+    IO.enumCase(Value, "Lower", FormatStyle::NLCS_Lower);
+  }
+};
+
+template <> struct MappingTraits<FormatStyle::NumericLiteralCaseStyle> {
+  static void mapping(IO &IO, FormatStyle::NumericLiteralCaseStyle &Base) {
+    IO.mapOptional("ExponentLetter", Base.ExponentLetter);
+    IO.mapOptional("HexDigit", Base.HexDigit);
+    IO.mapOptional("Prefix", Base.Prefix);
+    IO.mapOptional("Suffix", Base.Suffix);
+  }
+};
+
 template <> struct ScalarEnumerationTraits<FormatStyle::OperandAlignmentStyle> 
{
   static void enumeration(IO &IO, FormatStyle::OperandAlignmentStyle &Value) {
     IO.enumCase(Value, "DontAlign", FormatStyle::OAS_DontAlign);
@@ -1121,6 +1141,7 @@ template <> struct MappingTraits<FormatStyle> {
     IO.mapOptional("MaxEmptyLinesToKeep", Style.MaxEmptyLinesToKeep);
     IO.mapOptional("NamespaceIndentation", Style.NamespaceIndentation);
     IO.mapOptional("NamespaceMacros", Style.NamespaceMacros);
+    IO.mapOptional("NumericLiteralCase", Style.NumericLiteralCase);
     IO.mapOptional("ObjCBinPackProtocolList", Style.ObjCBinPackProtocolList);
     IO.mapOptional("ObjCBlockIndentWidth", Style.ObjCBlockIndentWidth);
     IO.mapOptional("ObjCBreakBeforeNestedBlockParam",
@@ -1653,6 +1674,10 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind 
Language) {
   LLVMStyle.LineEnding = FormatStyle::LE_DeriveLF;
   LLVMStyle.MaxEmptyLinesToKeep = 1;
   LLVMStyle.NamespaceIndentation = FormatStyle::NI_None;
+  LLVMStyle.NumericLiteralCase = {/*ExponentLetter=*/FormatStyle::NLCS_Leave,
+                                  /*HexDigit=*/FormatStyle::NLCS_Leave,
+                                  /*Prefix=*/FormatStyle::NLCS_Leave,
+                                  /*Suffix=*/FormatStyle::NLCS_Leave};
   LLVMStyle.ObjCBinPackProtocolList = FormatStyle::BPS_Auto;
   LLVMStyle.ObjCBlockIndentWidth = 2;
   LLVMStyle.ObjCBreakBeforeNestedBlockParam = true;
@@ -3890,6 +3915,10 @@ reformat(const FormatStyle &Style, StringRef Code,
     return IntegerLiteralSeparatorFixer().process(Env, Expanded);
   });
 
+  Passes.emplace_back([&](const Environment &Env) {
+    return NumericLiteralCaseFixer().process(Env, Expanded);
+  });
+
   if (Style.isCpp()) {
     if (Style.QualifierAlignment != FormatStyle::QAS_Leave)
       addQualifierAlignmentFixerPasses(Expanded, Passes);
@@ -4001,8 +4030,8 @@ reformat(const FormatStyle &Style, StringRef Code,
 
   if (Style.QualifierAlignment != FormatStyle::QAS_Leave) {
     // Don't make replacements that replace nothing. QualifierAlignment can
-    // produce them if one of its early passes changes e.g. `const volatile` to
-    // `volatile const` and then a later pass changes it back again.
+    // produce them if one of its early passes changes e.g. `const volatile`
+    // to `volatile const` and then a later pass changes it back again.
     tooling::Replacements NonNoOpFixes;
     for (const tooling::Replacement &Fix : Fixes) {
       StringRef OriginalCode = Code.substr(Fix.getOffset(), Fix.getLength());
diff --git a/clang/lib/Format/NumericLiteralCaseFixer.cpp 
b/clang/lib/Format/NumericLiteralCaseFixer.cpp
new file mode 100644
index 0000000000000..8d248eb332d62
--- /dev/null
+++ b/clang/lib/Format/NumericLiteralCaseFixer.cpp
@@ -0,0 +1,174 @@
+//===--- NumericLiteralCaseFixer.cpp -----------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file implements NumericLiteralCaseFixer that standardizes character
+/// case within numeric literal constants.
+///
+//===----------------------------------------------------------------------===//
+
+#include "NumericLiteralCaseFixer.h"
+#include "NumericLiteralInfo.h"
+
+#include "llvm/ADT/StringExtras.h"
+
+#include <algorithm>
+
+namespace clang {
+namespace format {
+
+static bool isNumericLiteralCaseFixerNeeded(const FormatStyle &Style) {
+  // Check if language is supported.
+  switch (Style.Language) {
+  case FormatStyle::LK_C:
+  case FormatStyle::LK_Cpp:
+  case FormatStyle::LK_ObjC:
+  case FormatStyle::LK_CSharp:
+  case FormatStyle::LK_Java:
+  case FormatStyle::LK_JavaScript:
+    break;
+  default:
+    return false;
+  }
+
+  // Check if style options are set.
+  const FormatStyle::NumericLiteralCaseStyle LeaveAllCasesUntouched{};
+  return Style.NumericLiteralCase != LeaveAllCasesUntouched;
+}
+
+static std::string
+transformComponent(StringRef Component,
+                   FormatStyle::NumericLiteralComponentStyle ConfigValue) {
+  switch (ConfigValue) {
+  case FormatStyle::NLCS_Upper:
+    return Component.upper();
+  case FormatStyle::NLCS_Lower:
+    return Component.lower();
+  case FormatStyle::NLCS_Leave:
+  default:
+    return Component.str();
+  }
+}
+
+/// @brief Test if Suffix matches a C++ literal reserved by the library.
+/// Matches against all suffixes reserved in the C++23 standard
+static bool matchesReservedSuffix(StringRef Suffix) {
+  static constexpr std::array<StringRef, 11> SortedReservedSuffixes = {
+      "d", "h", "i", "if", "il", "min", "ms", "ns", "s", "us", "y"};
+
+  // This can be static_assert when we have access to constexpr is_sorted in
+  // C++ 20.
+  assert(llvm::is_sorted(SortedReservedSuffixes) &&
+         "Must be sorted as precondition for lower_bound().");
+
+  auto entry = llvm::lower_bound(SortedReservedSuffixes, Suffix);
+  if (entry == SortedReservedSuffixes.cend())
+    return false;
+  return *entry == Suffix;
+}
+
+static std::string format(StringRef IntegerLiteral, const FormatStyle &Style) {
+  const char Separator = Style.isCpp() ? '\'' : '_';
+  const NumericLiteralInfo Info{IntegerLiteral, Separator};
+  const bool HasBaseLetter = Info.BaseLetterPos != llvm::StringRef::npos;
+  const bool HasExponent = Info.ExponentLetterPos != llvm::StringRef::npos;
+  const bool HasSuffix = Info.SuffixPos != llvm::StringRef::npos;
+
+  std::string Formatted;
+
+  if (HasBaseLetter) {
+    Formatted +=
+        transformComponent(IntegerLiteral.take_front(1 + Info.BaseLetterPos),
+                           Style.NumericLiteralCase.Prefix);
+  }
+  // Reformat this slice as HexDigit whether or not the digit has hexadecimal
+  // characters because binary/decimal/octal digits are unchanged.
+  Formatted += transformComponent(
+      IntegerLiteral.slice(HasBaseLetter ? 1 + Info.BaseLetterPos : 0,
+                           HasExponent ? Info.ExponentLetterPos
+                           : HasSuffix ? Info.SuffixPos
+                                       : IntegerLiteral.size()),
+      Style.NumericLiteralCase.HexDigit);
+
+  if (HasExponent) {
+    Formatted += transformComponent(
+        IntegerLiteral.slice(Info.ExponentLetterPos,
+                             HasSuffix ? Info.SuffixPos
+                                       : IntegerLiteral.size()),
+        Style.NumericLiteralCase.ExponentLetter);
+  }
+
+  if (HasSuffix) {
+    StringRef Suffix = IntegerLiteral.drop_front(Info.SuffixPos);
+    if (matchesReservedSuffix(Suffix) || Suffix.front() == '_') {
+      // In C++, it is idiomatic, but NOT standardized to define user-defined
+      // literals with a leading '_'. Omit user defined literals and standard
+      // reserved suffixes from transformation.
+      Formatted += Suffix.str();
+    } else {
+      Formatted += transformComponent(Suffix, Style.NumericLiteralCase.Suffix);
+    }
+  }
+
+  return Formatted;
+}
+
+std::pair<tooling::Replacements, unsigned>
+NumericLiteralCaseFixer::process(const Environment &Env,
+                                 const FormatStyle &Style) {
+  if (!isNumericLiteralCaseFixerNeeded(Style))
+    return {};
+
+  const auto &SourceMgr = Env.getSourceManager();
+  AffectedRangeManager AffectedRangeMgr(SourceMgr, Env.getCharRanges());
+
+  const auto ID = Env.getFileID();
+  const auto LangOpts = getFormattingLangOpts(Style);
+  Lexer Lex(ID, SourceMgr.getBufferOrFake(ID), SourceMgr, LangOpts);
+  Lex.SetCommentRetentionState(true);
+
+  Token Tok;
+  tooling::Replacements Result;
+
+  for (bool Skip = false; !Lex.LexFromRawLexer(Tok);) {
+    // Skip tokens that are too small to contain a formattable literal.
+    // Size=2 is the smallest possible literal that could contain formattable
+    // components, for example "1u".
+    auto Length = Tok.getLength();
+    if (Length < 2)
+      continue;
+
+    // Service clang-format off/on comments.
+    auto Location = Tok.getLocation();
+    auto Text = StringRef(SourceMgr.getCharacterData(Location), Length);
+    if (Tok.is(tok::comment)) {
+      if (isClangFormatOff(Text))
+        Skip = true;
+      else if (isClangFormatOn(Text))
+        Skip = false;
+      continue;
+    }
+
+    if (Skip || Tok.isNot(tok::numeric_constant) ||
+        !AffectedRangeMgr.affectsCharSourceRange(
+            CharSourceRange::getCharRange(Location, Tok.getEndLoc()))) {
+      continue;
+    }
+
+    const auto Formatted = format(Text, Style);
+    if (Formatted != Text) {
+      cantFail(Result.add(
+          tooling::Replacement(SourceMgr, Location, Length, Formatted)));
+    }
+  }
+
+  return {Result, 0};
+}
+
+} // namespace format
+} // namespace clang
diff --git a/clang/lib/Format/NumericLiteralCaseFixer.h 
b/clang/lib/Format/NumericLiteralCaseFixer.h
new file mode 100644
index 0000000000000..265d7343c468b
--- /dev/null
+++ b/clang/lib/Format/NumericLiteralCaseFixer.h
@@ -0,0 +1,32 @@
+//===--- NumericLiteralCaseFixer.h -------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file declares NumericLiteralCaseFixer that standardizes character case
+/// within numeric literal constants.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_FORMAT_NUMERICLITERALCASEFIXER_H
+#define LLVM_CLANG_LIB_FORMAT_NUMERICLITERALCASEFIXER_H
+
+#include "TokenAnalyzer.h"
+
+namespace clang {
+namespace format {
+
+class NumericLiteralCaseFixer {
+public:
+  std::pair<tooling::Replacements, unsigned> process(const Environment &Env,
+                                                     const FormatStyle &Style);
+};
+
+} // end namespace format
+} // end namespace clang
+
+#endif
diff --git a/clang/unittests/Format/CMakeLists.txt 
b/clang/unittests/Format/CMakeLists.txt
index c4c7b483ba68e..5ea7e965465d9 100644
--- a/clang/unittests/Format/CMakeLists.txt
+++ b/clang/unittests/Format/CMakeLists.txt
@@ -28,6 +28,7 @@ add_distinct_clang_unittest(FormatTests
   MatchFilePathTest.cpp
   NamespaceEndCommentsFixerTest.cpp
   NumericLiteralInfoTest.cpp
+  NumericLiteralCaseTest.cpp
   ObjCPropertyAttributeOrderFixerTest.cpp
   QualifierFixerTest.cpp
   SortImportsTestJS.cpp
diff --git a/clang/unittests/Format/NumericLiteralCaseTest.cpp 
b/clang/unittests/Format/NumericLiteralCaseTest.cpp
new file mode 100644
index 0000000000000..518b71333dd5d
--- /dev/null
+++ b/clang/unittests/Format/NumericLiteralCaseTest.cpp
@@ -0,0 +1,354 @@
+//===- unittest/Format/NumericLiteralCaseTest.cpp --------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "FormatTestBase.h"
+
+#define DEBUG_TYPE "numeric-literal-case-test"
+
+namespace clang {
+namespace format {
+namespace test {
+namespace {
+
+class NumericLiteralCaseTest : public FormatTestBase {};
+
+TEST_F(NumericLiteralCaseTest, Prefix) {
+  FormatStyle Style = getLLVMStyle();
+  EXPECT_EQ(Style.Language, FormatStyle::LK_Cpp);
+  EXPECT_EQ(Style.NumericLiteralCase.Prefix, FormatStyle::NLCS_Leave);
+  EXPECT_EQ(Style.NumericLiteralCase.HexDigit, FormatStyle::NLCS_Leave);
+  EXPECT_EQ(Style.NumericLiteralCase.ExponentLetter, FormatStyle::NLCS_Leave);
+  EXPECT_EQ(Style.NumericLiteralCase.Suffix, FormatStyle::NLCS_Leave);
+
+  constexpr StringRef Bin0{"b = 0b0'10'010uL;"};
+  constexpr StringRef Bin1{"b = 0B010'010Ul;"};
+  constexpr StringRef Hex0{"b = 0xdead'BEEFuL;"};
+  constexpr StringRef Hex1{"b = 0Xdead'BEEFUl;"};
+  verifyFormat(Bin0, Style);
+  verifyFormat(Bin1, Style);
+  verifyFormat(Hex0, Style);
+  verifyFormat(Hex1, Style);
+
+  Style.NumericLiteralCase.Prefix = FormatStyle::NLCS_Upper;
+  verifyFormat("b = 0B0'10'010uL;", Bin0, Style);
+  verifyFormat(Bin1, Style);
+  verifyFormat("b = 0Xdead'BEEFuL;", Hex0, Style);
+  verifyFormat(Hex1, Style);
+  verifyFormat("i = 0XaBcD.a0Ebp123F;", Style);
+  verifyFormat("j = 0XaBcD.a0EbP123f;", Style);
+
+  Style.NumericLiteralCase.Prefix = FormatStyle::NLCS_Lower;
+  verifyFormat(Bin0, Style);
+  verifyFormat("b = 0b010'010Ul;", Bin1, Style);
+  verifyFormat(Hex0, Style);
+  verifyFormat("b = 0xdead'BEEFUl;", Hex1, Style);
+}
+
+TEST_F(NumericLiteralCaseTest, HexDigit) {
+  FormatStyle Style = getLLVMStyle();
+
+  constexpr StringRef A{"a = 0xaBc0'123fuL;"};
+  constexpr StringRef B{"b = 0XaBc0'123FUl;"};
+  constexpr StringRef C{"c = 0xa'Bc.0p12'3f32;"};
+  constexpr StringRef D{"d = 0xa'Bc.0P12'3F128;"};
+  constexpr StringRef E{"e = 0b0011'00Ull;"};
+  constexpr StringRef F{"f = 0B0100'000zu;"};
+  constexpr StringRef G{"g = 0.123e-19f;"};
+  constexpr StringRef H{"h = 0.12'3E-19F16;"};
+  constexpr StringRef I{"i = 0x.0000aBcp12'3F128;"};
+  constexpr StringRef J{"j = 0xaa1'fP12'3F128;"};
+  constexpr StringRef K{"k = 0x0;"};
+  constexpr StringRef L{"l = 0xA;"};
+
+  verifyFormat(A, Style);
+  verifyFormat(B, Style);
+  verifyFormat(C, Style);
+  verifyFormat(D, Style);
+  verifyFormat(E, Style);
+  verifyFormat(F, Style);
+  verifyFormat(G, Style);
+  verifyFormat(H, Style);
+  verifyFormat(I, Style);
+  verifyFormat(J, Style);
+
+  Style.NumericLiteralCase.HexDigit = FormatStyle::NLCS_Upper;
+  verifyFormat("a = 0xABC0'123FuL;", A, Style);
+  verifyFormat("b = 0XABC0'123FUl;", B, Style);
+  verifyFormat("c = 0xA'BC.0p12'3f32;", C, Style);
+  verifyFormat("d = 0xA'BC.0P12'3F128;", D, Style);
+  verifyFormat("e = 0b0011'00Ull;", E, Style);
+  verifyFormat("f = 0B0100'000zu;", F, Style);
+  verifyFormat("g = 0.123e-19f;", G, Style);
+  verifyFormat("h = 0.12'3E-19F16;", H, Style);
+  verifyFormat("i = 0x.0000ABCp12'3F128;", I, Style);
+  verifyFormat("j = 0xAA1'FP12'3F128;", J, Style);
+
+  Style.NumericLiteralCase.HexDigit = FormatStyle::NLCS_Lower;
+  verifyFormat("a = 0xabc0'123fuL;", A, Style);
+  verifyFormat("b = 0Xabc0'123fUl;", B, Style);
+  verifyFormat("c = 0xa'bc.0p12'3f32;", C, Style);
+  verifyFormat("d = 0xa'bc.0P12'3F128;", D, Style);
+  verifyFormat("e = 0b0011'00Ull;", E, Style);
+  verifyFormat("f = 0B0100'000zu;", F, Style);
+  verifyFormat("g = 0.123e-19f;", G, Style);
+  verifyFormat("h = 0.12'3E-19F16;", H, Style);
+  verifyFormat("i = 0x.0000abcp12'3F128;", I, Style);
+  verifyFormat("j = 0xaa1'fP12'3F128;", J, Style);
+}
+
+TEST_F(NumericLiteralCaseTest, ExponentLetter) {
+  FormatStyle Style = getLLVMStyle();
+
+  constexpr StringRef A{"a = .0'01e-19f;"};
+  constexpr StringRef B{"b = .00'1E2F;"};
+  constexpr StringRef C{"c = 10'2.e99;"};
+  constexpr StringRef D{"d = 123.456E-1;"};
+  constexpr StringRef E{"e = 0x12abEe3.456p-10'0;"};
+  constexpr StringRef F{"f = 0x.deEfP23;"};
+  constexpr StringRef G{"g = 0xe0E1.p-1;"};
+
+  verifyFormat(A, Style);
+  verifyFormat(B, Style);
+  verifyFormat(C, Style);
+  verifyFormat(D, Style);
+  verifyFormat(E, Style);
+  verifyFormat(F, Style);
+  verifyFormat(G, Style);
+
+  Style.NumericLiteralCase.ExponentLetter = FormatStyle::NLCS_Lower;
+  verifyFormat(A, Style);
+  verifyFormat("b = .00'1e2F;", B, Style);
+  verifyFormat(C, Style);
+  verifyFormat("d = 123.456e-1;", D, Style);
+  verifyFormat(E, Style);
+  verifyFormat("f = 0x.deEfp23;", F, Style);
+  verifyFormat(G, Style);
+
+  Style.NumericLiteralCase.ExponentLetter = FormatStyle::NLCS_Upper;
+  verifyFormat("a = .0'01E-19f;", A, Style);
+  verifyFormat(B, Style);
+  verifyFormat("c = 10'2.E99;", C, Style);
+  verifyFormat(D, Style);
+  verifyFormat("e = 0x12abEe3.456P-10'0;", E, Style);
+  verifyFormat(F, Style);
+  verifyFormat("g = 0xe0E1.P-1;", G, Style);
+}
+
+TEST_F(NumericLiteralCaseTest, IntegerSuffix) {
+  FormatStyle Style = getLLVMStyle();
+
+  constexpr StringRef A{"a = 102u;"};
+  constexpr StringRef B{"b = 0177U;"};
+  constexpr StringRef C{"c = 0b101'111llU;"};
+  constexpr StringRef D{"d = 0xdead'BeefuZ;"};
+  constexpr StringRef E{"e = 3lU;"};
+  constexpr StringRef F{"f = 1zu;"};
+  constexpr StringRef G{"g = 0uLL;"};
+  constexpr StringRef H{"h = 10'233'213'0101uLL;"};
+
+  verifyFormat(A, Style);
+  verifyFormat(B, Style);
+  verifyFormat(C, Style);
+  verifyFormat(D, Style);
+  verifyFormat(E, Style);
+  verifyFormat(F, Style);
+  verifyFormat(G, Style);
+  verifyFormat(H, Style);
+
+  Style.NumericLiteralCase.Suffix = FormatStyle::NLCS_Lower;
+  verifyFormat(A, Style);
+  verifyFormat("b = 0177u;", B, Style);
+  verifyFormat("c = 0b101'111llu;", C, Style);
+  verifyFormat("d = 0xdead'Beefuz;", D, Style);
+  verifyFormat("e = 3lu;", E, Style);
+  verifyFormat(F, Style);
+  verifyFormat("g = 0ull;", G, Style);
+  verifyFormat("h = 10'233'213'0101ull;", H, Style);
+
+  Style.NumericLiteralCase.Suffix = FormatStyle::NLCS_Upper;
+  verifyFormat("a = 102U;", A, Style);
+  verifyFormat(B, Style);
+  verifyFormat("c = 0b101'111LLU;", C, Style);
+  verifyFormat("d = 0xdead'BeefUZ;", D, Style);
+  verifyFormat("e = 3LU;", E, Style);
+  verifyFormat("f = 1ZU;", F, Style);
+  verifyFormat("g = 0ULL;", G, Style);
+  verifyFormat("h = 10'233'213'0101ULL;", H, Style);
+}
+
+TEST_F(NumericLiteralCaseTest, FloatingPointSuffix) {
+  FormatStyle Style = getLLVMStyle();
+  // Floating point literals without suffixes.
+  std::vector<StringRef> FloatingPointStatements = {
+      StringRef("a = 0."),          StringRef("b = 1.0"),
+      StringRef("c = .123'45E-10"), StringRef("d = 12'3.0e1"),
+      StringRef("e = 0Xa0eE.P10"),  StringRef("f = 0xeE01.aFf3p6"),
+  };
+
+  struct FloatSuffix {
+    StringRef Lower;
+    StringRef Upper;
+  };
+  // All legal floating point literals defined in the C++23 standard.
+  std::vector<FloatSuffix> FloatingPointSuffixes = {
+      {"f", "F"},     {"l", "L"},       {"f16", "F16"},   {"f32", "F32"},
+      {"f64", "F64"}, {"f128", "F128"}, {"bf16", "BF16"},
+  };
+
+  // Test all combinations of literals with suffixes.
+  for (auto &Statement : FloatingPointStatements) {
+    for (auto &Suffix : FloatingPointSuffixes) {
+      std::string LowerLine =
+          std::string{Statement} + std::string{Suffix.Lower} + ";";
+      std::string UpperLine =
+          std::string{Statement} + std::string{Suffix.Upper} + ";";
+
+      Style.NumericLiteralCase.Suffix = FormatStyle::NLCS_Leave;
+      verifyFormat(LowerLine, Style);
+      verifyFormat(UpperLine, Style);
+
+      Style.NumericLiteralCase.Suffix = FormatStyle::NLCS_Lower;
+      verifyFormat(LowerLine, Style);
+      verifyFormat(LowerLine, UpperLine, Style);
+
+      Style.NumericLiteralCase.Suffix = FormatStyle::NLCS_Upper;
+      verifyFormat(UpperLine, LowerLine, Style);
+      verifyFormat(UpperLine, Style);
+    }
+  }
+}
+
+TEST_F(NumericLiteralCaseTest, CppStandardAndUserDefinedLiteralsAreUntouched) {
+  FormatStyle Style = getLLVMStyle();
+  Style.NumericLiteralCase.Prefix = FormatStyle::NLCS_Upper;
+  Style.NumericLiteralCase.HexDigit = FormatStyle::NLCS_Upper;
+  Style.NumericLiteralCase.ExponentLetter = FormatStyle::NLCS_Upper;
+  Style.NumericLiteralCase.Suffix = FormatStyle::NLCS_Upper;
+
+  // C++ user-defined suffixes begin with '_' or are reserved for the standard
+  // library.
+  constexpr StringRef UDLiterals{"a = 12.if;\n"
+                                 "b = -3i;\n"
+                                 "c = 100'01il;\n"
+                                 "d = 100'0.12il;\n"
+                                 "e = 12h;\n"
+                                 "f = 0XABE12h;\n"
+                                 "g = 0XFA03min;\n"
+                                 "h = 0X12B4Ds;\n"
+                                 "i = 20.13E-1ms;\n"
+                                 "j = 20.13E-1us;\n"
+                                 "k = 20.13E-1ns;\n"
+                                 "l = 20.13E-1y;\n"
+                                 "m = 20.13E-1d;\n"
+                                 "n = 20.13E-1d;\n"
+                                 "o = 1d;\n"
+                                 "p = 102_ffl_lzlz;\n"
+                                 "q = 10.2_l;\n"
+                                 "r = 0XABDE.0'1P-23_f;\n"
+                                 "s = 102_foo_bar;\n"
+                                 "t = 123.456_felfz_ballpen;\n"
+                                 "u = 0XBEAD1_spacebar;"};
+
+  verifyFormat(UDLiterals, Style);
+  Style.NumericLiteralCase.Suffix = FormatStyle::NLCS_Lower;
+  verifyFormat(UDLiterals, Style);
+}
+
+TEST_F(NumericLiteralCaseTest, FixRanges) {
+  FormatStyle Style = getLLVMStyle();
+  Style.NumericLiteralCase.Prefix = FormatStyle::NLCS_Lower;
+  Style.NumericLiteralCase.HexDigit = FormatStyle::NLCS_Lower;
+  Style.NumericLiteralCase.ExponentLetter = FormatStyle::NLCS_Lower;
+  Style.NumericLiteralCase.Suffix = FormatStyle::NLCS_Lower;
+
+  constexpr StringRef CodeBlock{"a = 0xFea3duLL;\n"
+                                "b = 0X.aEbp-12f;\n"
+                                "c = 0uLL;\n"
+                                "// clang-format off\n"
+                                "e = 0xBeAdu;\n"
+                                "// clang-format on\n"
+                                "g = 0xabCDu;\n"
+                                "h = 0b010uL;\n"
+                                "// clang-format off\n"
+                                "i = 0B1010'000Zu;\n"
+                                "// clang-format on\n"
+                                "k = 0XaBuL;"};
+
+  verifyFormat("a = 0xfea3dull;\n"
+               "b = 0x.aebp-12f;\n"
+               "c = 0ull;\n"
+               "// clang-format off\n"
+               "e = 0xBeAdu;\n"
+               "// clang-format on\n"
+               "g = 0xabcdu;\n"
+               "h = 0b010ul;\n"
+               "// clang-format off\n"
+               "i = 0B1010'000Zu;\n"
+               "// clang-format on\n"
+               "k = 0xabul;",
+               CodeBlock, Style);
+}
+
+TEST_F(NumericLiteralCaseTest, UnderScoreSeparatorLanguages) {
+  FormatStyle Style = getLLVMStyle();
+
+  constexpr StringRef CodeBlock{"a = 0xFea_3dl;\n"
+                                "b = 0123_345;\n"
+                                "c = 0b11____00lU;\n"
+                                "d = 0XB_e_A_du;\n"
+                                "e = 123_456.333__456e-10f;\n"
+                                "f = .1_0E-10D;\n"
+                                "g = 1_0.F;\n"
+                                "h = 0B1_0;"};
+  auto TestUnderscore = [&](auto Language) {
+    Style.Language = Language;
+    Style.NumericLiteralCase.Prefix = FormatStyle::NLCS_Lower;
+    Style.NumericLiteralCase.HexDigit = FormatStyle::NLCS_Upper;
+    Style.NumericLiteralCase.ExponentLetter = FormatStyle::NLCS_Lower;
+    Style.NumericLiteralCase.Suffix = FormatStyle::NLCS_Upper;
+    verifyFormat("a = 0xFEA_3DL;\n"
+                 "b = 0123_345;\n"
+                 "c = 0b11____00LU;\n"
+                 "d = 0xB_E_A_DU;\n"
+                 "e = 123_456.333__456e-10F;\n"
+                 "f = .1_0e-10D;\n"
+                 "g = 1_0.F;\n"
+                 "h = 0b1_0;",
+                 CodeBlock, Style);
+
+    Style.NumericLiteralCase.Prefix = FormatStyle::NLCS_Upper;
+    Style.NumericLiteralCase.HexDigit = FormatStyle::NLCS_Lower;
+    Style.NumericLiteralCase.ExponentLetter = FormatStyle::NLCS_Upper;
+    Style.NumericLiteralCase.Suffix = FormatStyle::NLCS_Lower;
+
+    verifyFormat("a = 0Xfea_3dl;\n"
+                 "b = 0123_345;\n"
+                 "c = 0B11____00lu;\n"
+                 "d = 0Xb_e_a_du;\n"
+                 "e = 123_456.333__456E-10f;\n"
+                 "f = .1_0E-10d;\n"
+                 "g = 1_0.f;\n"
+                 "h = 0B1_0;",
+                 CodeBlock, Style);
+  };
+
+  TestUnderscore(FormatStyle::LK_CSharp);
+  TestUnderscore(FormatStyle::LK_Java);
+  TestUnderscore(FormatStyle::LK_JavaScript);
+
+  Style.Language = FormatStyle::LK_JavaScript;
+  Style.NumericLiteralCase.Prefix = FormatStyle::NLCS_Upper;
+  verifyFormat("o = 0O0_10_010;", "o = 0o0_10_010;", Style);
+  Style.NumericLiteralCase.Prefix = FormatStyle::NLCS_Lower;
+  verifyFormat("o = 0o0_10_010;", "o = 0O0_10_010;", Style);
+}
+
+} // namespace
+} // namespace test
+} // namespace format
+} // namespace clang

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to