[clang] [clang-format] Add an option to format integer and float literal case (PR #151590)
Andy MacGregor via cfe-commits
cfe-commits at lists.llvm.org
Mon Aug 4 13:15:01 PDT 2025
https://github.com/30Wedge updated https://github.com/llvm/llvm-project/pull/151590
>From 2934f3ade1f585ba527507986d46577254e95e40 Mon Sep 17 00:00:00 2001
From: Andy MacGregor <amacgregor.2018.comcast.net at gmail.com>
Date: Thu, 31 Jul 2025 16:24:06 -0400
Subject: [PATCH 1/3] [clang-format] Add an option to format integer literal
case
---
clang/docs/ClangFormatStyleOptions.rst | 73 +++-
clang/docs/ReleaseNotes.rst | 2 +
clang/include/clang/Format/Format.h | 49 +++
clang/lib/Format/CMakeLists.txt | 1 +
clang/lib/Format/Format.cpp | 19 +
clang/lib/Format/NumericLiteralCaseFixer.cpp | 368 ++++++++++++++++++
clang/lib/Format/NumericLiteralCaseFixer.h | 32 ++
clang/unittests/Format/CMakeLists.txt | 1 +
.../Format/NumericLiteralCaseTest.cpp | 354 +++++++++++++++++
9 files changed, 898 insertions(+), 1 deletion(-)
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 02986a94a656c..abc73b0ae183c 100644
--- a/clang/docs/ClangFormatStyleOptions.rst
+++ b/clang/docs/ClangFormatStyleOptions.rst
@@ -4555,7 +4555,6 @@ the configuration (without a prefix: ``Auto``).
So inserting a trailing comma counteracts bin-packing.
-
.. _IntegerLiteralSeparator:
**IntegerLiteralSeparator** (``IntegerLiteralSeparatorStyle``) :versionbadge:`clang-format 16` :ref:`¶ <IntegerLiteralSeparator>`
@@ -5076,6 +5075,78 @@ the configuration (without a prefix: ``Auto``).
For example: TESTSUITE
+.. _NumericLiteralCase:
+
+**NumericLiteralCase** (``NumericLiteralCaseStyle``) :versionbadge:`clang-format 21` :ref:`¶ <NumericLiteralCase>`
+ Controls character case in numeric literals.
+
+ Possible values for each nexted configuration flag:
+
+ * ``0`` (Default) Do not modify characters.
+
+ * ``-1`` Convert characters to lower case.
+
+ * ``1`` Convert characters to upper case.
+
+ .. code-block:: yaml
+
+ # Example of usage:
+ NumericLiteralCaseStyle:
+ PrefixCase: -1
+ HexDigitCase: 1
+ FloatExponentSeparatorCase: 0
+ SuffixCase: -1
+
+ .. code-block:: c++
+
+ // Lower case prefix, upper case hexadecimal digits, lower case suffix
+ unsigned int 0xDEAFBEEFull;
+
+ Nested configuration flags:
+
+ * ``int PrefixCase`` Control numeric constant prefix case.
+
+ .. code-block:: c++
+
+ // PrefixCase: 1
+ int a = 0B101 | 0XF0;
+ // PrefixCase: -1
+ int a = 0b101 | 0xF0;
+ // PrefixCase: 0
+ int c = 0b101 | 0XF0;
+
+ * ``int HexDigitCase`` Control hexadecimal digit case.
+
+ .. code-block:: c++
+
+ // HexDigitCase: 1
+ int a = 0xBEAD;
+ // PrefixCase: -1
+ int b = 0xbead;
+ // PrefixCase: 0
+ int c = 0xBeAd;
+
+ * ``int FloatExponentSeparatorCase`` Control exponent separator case.
+
+ .. code-block:: c++
+
+ // FloatExponentSeparatorCase: 1
+ float a = 6.02E+23;
+ // FloatExponentSeparatorCase: -1
+ float b = 6.02e+23;
+
+ * ``int SuffixCase`` Control suffix case.
+
+ .. code-block:: c++
+
+ // SuffixCase: 1
+ unsigned long long a = 1ULL;
+ // SuffixCase: -1
+ unsigned long long a = 1ull;
+ // SuffixCase: 0
+ unsigned long long c = 1uLL;
+
+
.. _ObjCBinPackProtocolList:
**ObjCBinPackProtocolList** (``BinPackStyle``) :versionbadge:`clang-format 7` :ref:`¶ <ObjCBinPackProtocolList>`
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 4a2edae7509de..f45363f86c135 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -230,6 +230,8 @@ AST Matchers
clang-format
------------
+- Add ``NumericLiteralCase`` option for 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 31582a40de866..301db5012b980 100644
--- a/clang/include/clang/Format/Format.h
+++ b/clang/include/clang/Format/Format.h
@@ -3100,6 +3100,54 @@ struct FormatStyle {
/// \version 11
TrailingCommaStyle InsertTrailingCommas;
+ /// Character case format for different components of a numeric literal.
+ ///
+ /// For all options, ``0`` leave the case unchanged, ``-1``
+ /// uses lower case and, ``1`` uses upper case.
+ ///
+ struct NumericLiteralCaseStyle {
+ /// Format numeric constant prefixes.
+ /// \code{.text}
+ /// /* -1: lower case */ b = 0x01;
+ /// /* 0: don't care */
+ /// /* 1: upper case */ b = 0X01;
+ /// \endcode
+ int8_t PrefixCase;
+ /// Format hexadecimal digit case.
+ /// \code{.text}
+ /// /* -1: lower case */ b = 0xabcdef;
+ /// /* 0: don't care */
+ /// /* 1: upper case */ b = 0xABCDEF;
+ /// \endcode
+ int8_t HexDigitCase;
+ /// Format exponent separator character case in floating point literals.
+ /// \code{.text}
+ /// /* -1: lower case */ b = 6.02e23;
+ /// /* 0: don't care */
+ /// /* 1: upper case */ b = 6.02E23;
+ /// \endcode
+ int8_t FloatExponentSeparatorCase;
+ /// Format suffix case. This option excludes case-specific reserved
+ /// suffixes, such as ``min`` in C++.
+ /// \code{.text}
+ /// /* -1: lower case */ b = 10u;
+ /// /* 0: don't care */
+ /// /* 1: upper case */ b = 10U;
+ /// \endcode
+ int8_t SuffixCase;
+
+ bool operator==(const NumericLiteralCaseStyle &R) const {
+ return PrefixCase == R.PrefixCase && HexDigitCase == R.HexDigitCase &&
+ FloatExponentSeparatorCase == R.FloatExponentSeparatorCase &&
+ SuffixCase == R.SuffixCase;
+ }
+ };
+
+ /// Format numeric literals for languages that support flexible character case
+ /// in numeric literal constants.
+ /// \version 22
+ NumericLiteralCaseStyle NumericLiteralCase;
+
/// Separator format of integer literals of different bases.
///
/// If negative, remove separators. If ``0``, leave the literal as is. If
@@ -5424,6 +5472,7 @@ struct FormatStyle {
IndentWrappedFunctionNames == R.IndentWrappedFunctionNames &&
InsertBraces == R.InsertBraces &&
InsertNewlineAtEOF == R.InsertNewlineAtEOF &&
+ NumericLiteralCase == R.NumericLiteralCase &&
IntegerLiteralSeparator == R.IntegerLiteralSeparator &&
JavaImportGroups == R.JavaImportGroups &&
JavaScriptQuotes == R.JavaScriptQuotes &&
diff --git a/clang/lib/Format/CMakeLists.txt b/clang/lib/Format/CMakeLists.txt
index 9f4939824fdb8..a003f1a951af6 100644
--- a/clang/lib/Format/CMakeLists.txt
+++ b/clang/lib/Format/CMakeLists.txt
@@ -13,6 +13,7 @@ add_clang_library(clangFormat
MacroExpander.cpp
MatchFilePath.cpp
NamespaceEndCommentsFixer.cpp
+ NumericLiteralCaseFixer.cpp
ObjCPropertyAttributeOrderFixer.cpp
QualifierAlignmentFixer.cpp
SortJavaScriptImports.cpp
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index 063780721423f..711a3e7501328 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"
@@ -382,6 +383,16 @@ struct ScalarEnumerationTraits<FormatStyle::IndentExternBlockStyle> {
}
};
+template <> struct MappingTraits<FormatStyle::NumericLiteralCaseStyle> {
+ static void mapping(IO &IO, FormatStyle::NumericLiteralCaseStyle &Base) {
+ IO.mapOptional("PrefixCase", Base.PrefixCase);
+ IO.mapOptional("HexDigitCase", Base.HexDigitCase);
+ IO.mapOptional("FloatExponentSeparatorCase",
+ Base.FloatExponentSeparatorCase);
+ IO.mapOptional("SuffixCase", Base.SuffixCase);
+ }
+};
+
template <> struct MappingTraits<FormatStyle::IntegerLiteralSeparatorStyle> {
static void mapping(IO &IO, FormatStyle::IntegerLiteralSeparatorStyle &Base) {
IO.mapOptional("Binary", Base.Binary);
@@ -1093,6 +1104,7 @@ template <> struct MappingTraits<FormatStyle> {
IO.mapOptional("InsertBraces", Style.InsertBraces);
IO.mapOptional("InsertNewlineAtEOF", Style.InsertNewlineAtEOF);
IO.mapOptional("InsertTrailingCommas", Style.InsertTrailingCommas);
+ IO.mapOptional("NumericLiteralCase", Style.NumericLiteralCase);
IO.mapOptional("IntegerLiteralSeparator", Style.IntegerLiteralSeparator);
IO.mapOptional("JavaImportGroups", Style.JavaImportGroups);
IO.mapOptional("JavaScriptQuotes", Style.JavaScriptQuotes);
@@ -1618,6 +1630,9 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
LLVMStyle.InsertBraces = false;
LLVMStyle.InsertNewlineAtEOF = false;
LLVMStyle.InsertTrailingCommas = FormatStyle::TCS_None;
+ LLVMStyle.NumericLiteralCase = {/*PrefixCase=*/0, /*HexDigitCase=*/0,
+ /*FloatExponentSeparatorCase=*/0,
+ /*SuffixCase=*/0};
LLVMStyle.IntegerLiteralSeparator = {
/*Binary=*/0, /*BinaryMinDigits=*/0,
/*Decimal=*/0, /*DecimalMinDigits=*/0,
@@ -3872,6 +3887,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);
diff --git a/clang/lib/Format/NumericLiteralCaseFixer.cpp b/clang/lib/Format/NumericLiteralCaseFixer.cpp
new file mode 100644
index 0000000000000..88adaf83fe381
--- /dev/null
+++ b/clang/lib/Format/NumericLiteralCaseFixer.cpp
@@ -0,0 +1,368 @@
+//===--- 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 "llvm/ADT/StringExtras.h"
+
+#include <algorithm>
+
+namespace clang {
+namespace format {
+
+using CharTransformFn = char (*)(char C);
+namespace {
+
+/// @brief Collection of std::transform predicates for each part of a numeric
+/// literal
+struct FormatParameters {
+ FormatParameters(FormatStyle::LanguageKind Language,
+ const FormatStyle::NumericLiteralCaseStyle &CaseStyle);
+
+ CharTransformFn Prefix;
+ CharTransformFn HexDigit;
+ CharTransformFn FloatExponentSeparator;
+ CharTransformFn Suffix;
+
+ char Separator;
+};
+
+/// @brief Parse a single numeric constant from text into ranges that are
+/// appropriate for applying NumericLiteralCaseStyle rules.
+class QuickNumericalConstantParser {
+public:
+ QuickNumericalConstantParser(const StringRef &IntegerLiteral,
+ const FormatParameters &Transforms);
+
+ /// @brief Reformats the numeric constant if needed.
+ /// Calling this method invalidates the object's state.
+ /// @return std::nullopt if no reformatting is required. std::option<>
+ /// containing the reformatted string otherwise.
+ std::optional<std::string> formatIfNeeded() &&;
+
+private:
+ const StringRef &IntegerLiteral;
+ const FormatParameters &Transforms;
+
+ std::string Formatted;
+
+ std::string::iterator PrefixBegin;
+ std::string::iterator PrefixEnd;
+ std::string::iterator HexDigitBegin;
+ std::string::iterator HexDigitEnd;
+ std::string::iterator FloatExponentSeparatorBegin;
+ std::string::iterator FloatExponentSeparatorEnd;
+ std::string::iterator SuffixBegin;
+ std::string::iterator SuffixEnd;
+
+ void parse();
+ void applyFormatting();
+};
+
+} // namespace
+
+static char noOpTransform(char C) { return C; }
+
+static CharTransformFn getTransform(int8_t config_value) {
+ switch (config_value) {
+ case -1:
+ return llvm::toLower;
+ case 1:
+ return llvm::toUpper;
+ default:
+ return noOpTransform;
+ }
+}
+
+/// @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 const std::set<StringRef> ReservedSuffixes = {
+ "h", "min", "s", "ms", "us", "ns", "il", "i", "if", "d", "y",
+ };
+
+ return ReservedSuffixes.find(Suffix) != ReservedSuffixes.end();
+}
+
+FormatParameters::FormatParameters(
+ FormatStyle::LanguageKind Language,
+ const FormatStyle::NumericLiteralCaseStyle &CaseStyle)
+ : Prefix(getTransform(CaseStyle.PrefixCase)),
+ HexDigit(getTransform(CaseStyle.HexDigitCase)),
+ FloatExponentSeparator(
+ getTransform(CaseStyle.FloatExponentSeparatorCase)),
+ Suffix(getTransform(CaseStyle.SuffixCase)) {
+ switch (Language) {
+ case FormatStyle::LK_CSharp:
+ case FormatStyle::LK_Java:
+ case FormatStyle::LK_JavaScript:
+ Separator = '_';
+ break;
+ case FormatStyle::LK_C:
+ case FormatStyle::LK_Cpp:
+ case FormatStyle::LK_ObjC:
+ default:
+ Separator = '\'';
+ }
+}
+
+QuickNumericalConstantParser::QuickNumericalConstantParser(
+ const StringRef &IntegerLiteral, const FormatParameters &Transforms)
+ : IntegerLiteral(IntegerLiteral), Transforms(Transforms),
+ Formatted(IntegerLiteral), PrefixBegin(Formatted.begin()),
+ PrefixEnd(Formatted.begin()), HexDigitBegin(Formatted.begin()),
+ HexDigitEnd(Formatted.begin()),
+ FloatExponentSeparatorBegin(Formatted.begin()),
+ FloatExponentSeparatorEnd(Formatted.begin()),
+ SuffixBegin(Formatted.begin()), SuffixEnd(Formatted.begin()) {}
+
+void QuickNumericalConstantParser::parse() {
+ auto Cur = Formatted.begin();
+ auto End = Formatted.cend();
+
+ bool IsHex = false;
+ bool IsFloat = false;
+
+ // Find the range that contains the prefix.
+ PrefixBegin = Cur;
+ if (*Cur != '0') {
+ } else {
+ ++Cur;
+ const char C = *Cur;
+ switch (C) {
+ case 'x':
+ case 'X':
+ IsHex = true;
+ ++Cur;
+ break;
+ case 'b':
+ case 'B':
+ ++Cur;
+ break;
+ case 'o':
+ case 'O':
+ // Javascript uses 0o as octal prefix.
+ ++Cur;
+ break;
+ default:
+ break;
+ }
+ }
+ PrefixEnd = Cur;
+
+ // Find the range that contains hex digits.
+ HexDigitBegin = Cur;
+ if (IsHex) {
+ while (Cur != End) {
+ const char C = *Cur;
+ if (llvm::isHexDigit(C)) {
+ } else if (C == Transforms.Separator) {
+ } else if (C == '.') {
+ IsFloat = true;
+ } else {
+ break;
+ }
+ ++Cur;
+ }
+ }
+ HexDigitEnd = Cur;
+ if (Cur == End)
+ return;
+
+ // Find the range that contains a floating point exponent separator.
+ // Hex digits have already been scanned through the decimal point.
+ // Decimal/octal/binary literals must fast forward through the decimal first.
+ if (!IsHex) {
+ while (Cur != End) {
+ const char C = *Cur;
+ if (llvm::isDigit(C)) {
+ } else if (C == Transforms.Separator) {
+ } else if (C == '.') {
+ IsFloat = true;
+ } else {
+ break;
+ }
+ ++Cur;
+ }
+ }
+
+ const char LSep = IsHex ? 'p' : 'e';
+ const char USep = IsHex ? 'P' : 'E';
+ // The next character of a floating point literal will either be the
+ // separator, or the start of a suffix.
+ FloatExponentSeparatorBegin = Cur;
+ if (IsFloat) {
+ const char C = *Cur;
+ if ((C == LSep) || (C == USep))
+ ++Cur;
+ }
+ FloatExponentSeparatorEnd = Cur;
+ if (Cur == End)
+ return;
+
+ // Fast forward through the exponent part of a floating point literal.
+ if (!IsFloat) {
+ } else if (FloatExponentSeparatorBegin == FloatExponentSeparatorEnd) {
+ } else {
+ while (Cur != End) {
+ const char C = *Cur;
+ if (llvm::isDigit(C)) {
+ } else if (C == '+') {
+ } else if (C == '-') {
+ } else {
+ break;
+ }
+ ++Cur;
+ }
+ }
+ if (Cur == End)
+ return;
+
+ // Find the range containing a suffix if any.
+ SuffixBegin = Cur;
+ size_t const SuffixLen = End - Cur;
+ StringRef suffix(&(*SuffixBegin), SuffixLen);
+ if (!matchesReservedSuffix(suffix)) {
+ while (Cur != End) {
+ const char C = *Cur;
+ if (C == '_') {
+ // In C++, it is idiomatic, but NOT standard to define user-defined
+ // literals with a leading '_'. Omit user defined literals from
+ // transformation.
+ break;
+ } else {
+ }
+ ++Cur;
+ }
+ }
+ SuffixEnd = Cur;
+}
+
+void QuickNumericalConstantParser::applyFormatting() {
+
+ auto Start = Formatted.cbegin();
+ auto End = Formatted.cend();
+
+ assert((Start <= PrefixBegin) && (End >= PrefixBegin) &&
+ "PrefixBegin is out of bounds");
+ assert((Start <= PrefixEnd) && (End >= PrefixEnd) &&
+ "PrefixEnd is out of bounds");
+ assert((Start <= HexDigitBegin) && (End >= HexDigitBegin) &&
+ "HexDigitBegin is out of bounds");
+ assert((Start <= HexDigitEnd) && (End >= HexDigitEnd) &&
+ "HexDigitEnd is out of bounds");
+ assert((Start <= FloatExponentSeparatorBegin) &&
+ (End >= FloatExponentSeparatorBegin) &&
+ "FloatExponentSeparatorBegin is out of bounds");
+ assert((Start <= FloatExponentSeparatorEnd) &&
+ (End >= FloatExponentSeparatorEnd) &&
+ "FloatExponentSeparatorEnd is out of bounds");
+ assert((Start <= SuffixBegin) && (End >= SuffixBegin) &&
+ "SuffixBegin is out of bounds");
+ assert((Start <= SuffixEnd) && (End >= SuffixEnd) &&
+ "SuffixEnd is out of bounds");
+
+ std::transform(PrefixBegin, PrefixEnd, PrefixBegin, Transforms.Prefix);
+ std::transform(HexDigitBegin, HexDigitEnd, HexDigitBegin,
+ Transforms.HexDigit);
+ std::transform(FloatExponentSeparatorBegin, FloatExponentSeparatorEnd,
+ FloatExponentSeparatorBegin,
+ Transforms.FloatExponentSeparator);
+ std::transform(SuffixBegin, SuffixEnd, SuffixBegin, Transforms.Suffix);
+}
+
+std::optional<std::string> QuickNumericalConstantParser::formatIfNeeded() && {
+ parse();
+ applyFormatting();
+
+ return (Formatted == IntegerLiteral)
+ ? std::nullopt
+ : std::make_optional<std::string>(std::move(Formatted));
+}
+
+std::pair<tooling::Replacements, unsigned>
+NumericLiteralCaseFixer::process(const Environment &Env,
+ const FormatStyle &Style) {
+ 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 {};
+ }
+
+ const auto &CaseStyle = Style.NumericLiteralCase;
+
+ const FormatStyle::NumericLiteralCaseStyle no_case_style{};
+ const bool SkipCaseFormatting = CaseStyle == no_case_style;
+
+ if (SkipCaseFormatting)
+ return {};
+
+ const FormatParameters Transforms{Style.Language, CaseStyle};
+
+ 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;
+ bool Skip = false;
+
+ while (!Lex.LexFromRawLexer(Tok)) {
+ // Skip tokens that are too small to contain a formattable literal.
+ 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 =
+ QuickNumericalConstantParser(Text, Transforms).formatIfNeeded();
+ if (Formatted) {
+ assert(*Formatted != Text && "QuickNumericalConstantParser returned an "
+ "unchanged value instead of nullopt");
+ 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 edfc8d7a5beaa..cdb9d0740835a 100644
--- a/clang/unittests/Format/CMakeLists.txt
+++ b/clang/unittests/Format/CMakeLists.txt
@@ -27,6 +27,7 @@ add_distinct_clang_unittest(FormatTests
MacroExpanderTest.cpp
MatchFilePathTest.cpp
NamespaceEndCommentsFixerTest.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..3a86485191292
--- /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.PrefixCase, 0);
+ EXPECT_EQ(Style.NumericLiteralCase.HexDigitCase, 0);
+ EXPECT_EQ(Style.NumericLiteralCase.FloatExponentSeparatorCase, 0);
+ EXPECT_EQ(Style.NumericLiteralCase.SuffixCase, 0);
+
+ const StringRef Bin0{"b = 0b0'10'010uL;"};
+ const StringRef Bin1{"b = 0B010'010Ul;"};
+ const StringRef Hex0{"b = 0xdead'BEEFuL;"};
+ const StringRef Hex1{"b = 0Xdead'BEEFUl;"};
+ verifyFormat(Bin0, Style);
+ verifyFormat(Bin1, Style);
+ verifyFormat(Hex0, Style);
+ verifyFormat(Hex1, Style);
+
+ Style.NumericLiteralCase.PrefixCase = 1;
+ 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.PrefixCase = -1;
+ 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();
+
+ const StringRef A{"a = 0xaBc0'123fuL;"};
+ const StringRef B{"b = 0XaBc0'123FUl;"};
+ const StringRef C{"c = 0xa'Bc.0p12'3f32;"};
+ const StringRef D{"d = 0xa'Bc.0P12'3F128;"};
+ const StringRef E{"e = 0b0011'00Ull;"};
+ const StringRef F{"f = 0B0100'000zu;"};
+ const StringRef G{"g = 0.123e-19f;"};
+ const StringRef H{"h = 0.12'3E-19F16;"};
+ const StringRef I{"i = 0x.0000aBcp12'3F128;"};
+ const StringRef J{"j = 0xaa1'fP12'3F128;"};
+ const StringRef K{"k = 0x0;"};
+ const 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.HexDigitCase = 1;
+ 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.HexDigitCase = -1;
+ 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, FloatExponentSeparator) {
+ FormatStyle Style = getLLVMStyle();
+
+ const StringRef A{"a = .0'01e-19f;"};
+ const StringRef B{"b = .00'1E2F;"};
+ const StringRef C{"c = 10'2.e99;"};
+ const StringRef D{"d = 123.456E-1;"};
+ const StringRef E{"e = 0x12abEe3.456p-10'0;"};
+ const StringRef F{"f = 0x.deEfP23;"};
+ const 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.FloatExponentSeparatorCase = -1;
+ 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.FloatExponentSeparatorCase = 1;
+ 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, IntegerLiteralSuffix) {
+ FormatStyle Style = getLLVMStyle();
+
+ const StringRef A{"a = 102u;"};
+ const StringRef B{"b = 0177U;"};
+ const StringRef C{"c = 0b101'111llU;"};
+ const StringRef D{"d = 0xdead'BeefuZ;"};
+ const StringRef E{"e = 3lU;"};
+ const StringRef F{"f = 1zu;"};
+ const StringRef G{"g = 0uLL;"};
+ const 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.SuffixCase = -1;
+ 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.SuffixCase = 1;
+ 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, FloatingPointLiteralSuffix) {
+ 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.SuffixCase = 0;
+ verifyFormat(LowerLine, Style);
+ verifyFormat(UpperLine, Style);
+
+ Style.NumericLiteralCase.SuffixCase = -1;
+ verifyFormat(LowerLine, Style);
+ verifyFormat(LowerLine, UpperLine, Style);
+
+ Style.NumericLiteralCase.SuffixCase = 1;
+ verifyFormat(UpperLine, LowerLine, Style);
+ verifyFormat(UpperLine, Style);
+ }
+ }
+}
+
+TEST_F(NumericLiteralCaseTest, CppStandardAndUserDefinedLiteralsAreUntouched) {
+ FormatStyle Style = getLLVMStyle();
+ Style.NumericLiteralCase.PrefixCase = 1;
+ Style.NumericLiteralCase.HexDigitCase = 1;
+ Style.NumericLiteralCase.FloatExponentSeparatorCase = 1;
+ Style.NumericLiteralCase.SuffixCase = 1;
+
+ // C++ user-defined suffixes begin with '_' or are reserved for the standard
+ // library.
+ const 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;\n"};
+
+ verifyFormat(UDLiterals, Style);
+ Style.NumericLiteralCase.SuffixCase = -1;
+ verifyFormat(UDLiterals, Style);
+}
+
+TEST_F(NumericLiteralCaseTest, FixRanges) {
+ FormatStyle Style = getLLVMStyle();
+ Style.NumericLiteralCase.PrefixCase = -1;
+ Style.NumericLiteralCase.HexDigitCase = -1;
+ Style.NumericLiteralCase.FloatExponentSeparatorCase = -1;
+ Style.NumericLiteralCase.SuffixCase = -1;
+
+ const 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;\n"};
+
+ 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;\n",
+ CodeBlock, Style);
+}
+
+TEST_F(NumericLiteralCaseTest, UnderScoreSeparatorLanguages) {
+ FormatStyle Style = getLLVMStyle();
+
+ const 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;\n"};
+ auto TestUnderscore = [&](auto Language) {
+ Style.Language = Language;
+ Style.NumericLiteralCase.PrefixCase = -1;
+ Style.NumericLiteralCase.HexDigitCase = 1;
+ Style.NumericLiteralCase.FloatExponentSeparatorCase = -1;
+ Style.NumericLiteralCase.SuffixCase = 1;
+ 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;\n",
+ CodeBlock, Style);
+
+ Style.NumericLiteralCase.PrefixCase = 1;
+ Style.NumericLiteralCase.HexDigitCase = -1;
+ Style.NumericLiteralCase.FloatExponentSeparatorCase = 1;
+ Style.NumericLiteralCase.SuffixCase = -1;
+
+ 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;\n",
+ CodeBlock, Style);
+ };
+
+ TestUnderscore(FormatStyle::LK_CSharp);
+ TestUnderscore(FormatStyle::LK_Java);
+ TestUnderscore(FormatStyle::LK_JavaScript);
+
+ Style.Language = FormatStyle::LK_JavaScript;
+ Style.NumericLiteralCase.PrefixCase = 1;
+ verifyFormat("o = 0O0_10_010;", "o = 0o0_10_010;", Style);
+ Style.NumericLiteralCase.PrefixCase = -1;
+ verifyFormat("o = 0o0_10_010;", "o = 0O0_10_010;", Style);
+}
+
+} // namespace
+} // namespace test
+} // namespace format
+} // namespace clang
>From 7a0eacb2b85abe324724c82ce296afd5b99876fa Mon Sep 17 00:00:00 2001
From: Andy MacGregor <amacgregor.2018.comcast.net at gmail.com>
Date: Sat, 2 Aug 2025 14:55:04 -0400
Subject: [PATCH 2/3] fixup! [clang-format] Add an option to format integer
literal case
---
clang/docs/ClangFormatStyleOptions.rst | 130 +++++++----
clang/docs/ReleaseNotes.rst | 4 +-
clang/include/clang/Format/Format.h | 120 +++++-----
clang/lib/Format/Format.cpp | 52 +++--
clang/lib/Format/NumericLiteralCaseFixer.cpp | 205 ++++++++----------
clang/lib/Format/NumericLiteralCaseFixer.h | 3 +
.../Format/NumericLiteralCaseTest.cpp | 76 ++++---
7 files changed, 326 insertions(+), 264 deletions(-)
diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst
index abc73b0ae183c..ffe3ebbe6a711 100644
--- a/clang/docs/ClangFormatStyleOptions.rst
+++ b/clang/docs/ClangFormatStyleOptions.rst
@@ -4555,6 +4555,7 @@ the configuration (without a prefix: ``Auto``).
So inserting a trailing comma counteracts bin-packing.
+
.. _IntegerLiteralSeparator:
**IntegerLiteralSeparator** (``IntegerLiteralSeparatorStyle``) :versionbadge:`clang-format 16` :ref:`¶ <IntegerLiteralSeparator>`
@@ -5077,74 +5078,109 @@ the configuration (without a prefix: ``Auto``).
.. _NumericLiteralCase:
-**NumericLiteralCase** (``NumericLiteralCaseStyle``) :versionbadge:`clang-format 21` :ref:`¶ <NumericLiteralCase>`
- Controls character case in numeric literals.
+**NumericLiteralCase** (``NumericLiteralCaseStyle``) :versionbadge:`clang-format 22` :ref:`¶ <NumericLiteralCase>`
+ Capitalization style for numeric literal constants.
- Possible values for each nexted configuration flag:
+ Nested configuration flags:
- * ``0`` (Default) Do not modify characters.
+ Character case format for different components of a numeric literal.
- * ``-1`` Convert characters to lower case.
+ * ``NumericLiteralComponentStyle UpperCaseFloatExponentSeparator``
+ Format floating point exponent separator character case.
- * ``1`` Convert characters to upper case.
+ .. code-block:: text
- .. code-block:: yaml
+ /* UpperCaseFloatExponentSeparator = Leave */
+ float a = 6.02e23 + 1.0E10;
+ /* UpperCaseFloatExponentSeparator = Always */
+ float a = 6.02E23 + 1.0E10;
+ /* UpperCaseFloatExponentSeparator = Never */
+ float a = 6.02e23 + 1.0e10;
- # Example of usage:
- NumericLiteralCaseStyle:
- PrefixCase: -1
- HexDigitCase: 1
- FloatExponentSeparatorCase: 0
- SuffixCase: -1
+ Possible values:
- .. code-block:: c++
+ * ``NLCS_Leave`` (in configuration: ``Leave``)
+ Leave this component of the literal as is.
- // Lower case prefix, upper case hexadecimal digits, lower case suffix
- unsigned int 0xDEAFBEEFull;
+ * ``NLCS_Always`` (in configuration: ``Always``)
+ Always format this component with upper case characters.
- Nested configuration flags:
+ * ``NLCS_Never`` (in configuration: ``Never``)
+ Never format this component with upper case characters.
- * ``int PrefixCase`` Control numeric constant prefix case.
- .. code-block:: c++
+ * ``NumericLiteralComponentStyle UpperCaseHexDigit``
+ Format hexadecimal digit case.
- // PrefixCase: 1
- int a = 0B101 | 0XF0;
- // PrefixCase: -1
- int a = 0b101 | 0xF0;
- // PrefixCase: 0
- int c = 0b101 | 0XF0;
+ .. code-block:: text
- * ``int HexDigitCase`` Control hexadecimal digit case.
+ /* UpperCaseHexDigit = Leave */
+ a = 0xaBcDeF;
+ /* UpperCaseHexDigit = Always */
+ a = 0xABCDEF;
+ /* UpperCaseHexDigit = Never */
+ a = 0xabcdef;
- .. code-block:: c++
+ Possible values:
- // HexDigitCase: 1
- int a = 0xBEAD;
- // PrefixCase: -1
- int b = 0xbead;
- // PrefixCase: 0
- int c = 0xBeAd;
+ * ``NLCS_Leave`` (in configuration: ``Leave``)
+ Leave this component of the literal as is.
- * ``int FloatExponentSeparatorCase`` Control exponent separator case.
+ * ``NLCS_Always`` (in configuration: ``Always``)
+ Always format this component with upper case characters.
- .. code-block:: c++
+ * ``NLCS_Never`` (in configuration: ``Never``)
+ Never format this component with upper case characters.
- // FloatExponentSeparatorCase: 1
- float a = 6.02E+23;
- // FloatExponentSeparatorCase: -1
- float b = 6.02e+23;
- * ``int SuffixCase`` Control suffix case.
+ * ``NumericLiteralComponentStyle UpperCasePrefix``
+ Format integer prefix case.
- .. code-block:: c++
+ .. code-block:: text
+
+ /* UpperCasePrefix = Leave */
+ a = 0XF0 | 0b1;
+ /* UpperCasePrefix = Always */
+ a = 0XF0 | 0B1;
+ /* UpperCasePrefix = Never */
+ a = 0xF0 | 0b1;
+
+ Possible values:
+
+ * ``NLCS_Leave`` (in configuration: ``Leave``)
+ Leave this component of the literal as is.
+
+ * ``NLCS_Always`` (in configuration: ``Always``)
+ Always format this component with upper case characters.
+
+ * ``NLCS_Never`` (in configuration: ``Never``)
+ Never format this component with upper case characters.
+
+
+ * ``NumericLiteralComponentStyle UpperCaseSuffix``
+ Format suffix case. This option excludes case-specific reserved
+ suffixes, such as ``min`` in C++.
+
+ .. code-block:: text
+
+ /* UpperCaseSuffix = Leave */
+ a = 1uLL;
+ /* UpperCaseSuffix = Always */
+ a = 1ULL;
+ /* UpperCaseSuffix = Never */
+ a = 1ull;
+
+ Possible values:
+
+ * ``NLCS_Leave`` (in configuration: ``Leave``)
+ Leave this component of the literal as is.
+
+ * ``NLCS_Always`` (in configuration: ``Always``)
+ Always format this component with upper case characters.
+
+ * ``NLCS_Never`` (in configuration: ``Never``)
+ Never format this component with upper case characters.
- // SuffixCase: 1
- unsigned long long a = 1ULL;
- // SuffixCase: -1
- unsigned long long a = 1ull;
- // SuffixCase: 0
- unsigned long long c = 1uLL;
.. _ObjCBinPackProtocolList:
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index f45363f86c135..73427862a2f5c 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -230,8 +230,8 @@ AST Matchers
clang-format
------------
-- Add ``NumericLiteralCase`` option for for enforcing character case in
- numeric literals.
+- 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 301db5012b980..bb6ba01fbf8fd 100644
--- a/clang/include/clang/Format/Format.h
+++ b/clang/include/clang/Format/Format.h
@@ -3100,54 +3100,6 @@ struct FormatStyle {
/// \version 11
TrailingCommaStyle InsertTrailingCommas;
- /// Character case format for different components of a numeric literal.
- ///
- /// For all options, ``0`` leave the case unchanged, ``-1``
- /// uses lower case and, ``1`` uses upper case.
- ///
- struct NumericLiteralCaseStyle {
- /// Format numeric constant prefixes.
- /// \code{.text}
- /// /* -1: lower case */ b = 0x01;
- /// /* 0: don't care */
- /// /* 1: upper case */ b = 0X01;
- /// \endcode
- int8_t PrefixCase;
- /// Format hexadecimal digit case.
- /// \code{.text}
- /// /* -1: lower case */ b = 0xabcdef;
- /// /* 0: don't care */
- /// /* 1: upper case */ b = 0xABCDEF;
- /// \endcode
- int8_t HexDigitCase;
- /// Format exponent separator character case in floating point literals.
- /// \code{.text}
- /// /* -1: lower case */ b = 6.02e23;
- /// /* 0: don't care */
- /// /* 1: upper case */ b = 6.02E23;
- /// \endcode
- int8_t FloatExponentSeparatorCase;
- /// Format suffix case. This option excludes case-specific reserved
- /// suffixes, such as ``min`` in C++.
- /// \code{.text}
- /// /* -1: lower case */ b = 10u;
- /// /* 0: don't care */
- /// /* 1: upper case */ b = 10U;
- /// \endcode
- int8_t SuffixCase;
-
- bool operator==(const NumericLiteralCaseStyle &R) const {
- return PrefixCase == R.PrefixCase && HexDigitCase == R.HexDigitCase &&
- FloatExponentSeparatorCase == R.FloatExponentSeparatorCase &&
- SuffixCase == R.SuffixCase;
- }
- };
-
- /// Format numeric literals for languages that support flexible character case
- /// in numeric literal constants.
- /// \version 22
- NumericLiteralCaseStyle NumericLiteralCase;
-
/// Separator format of integer literals of different bases.
///
/// If negative, remove separators. If ``0``, leave the literal as is. If
@@ -3606,6 +3558,76 @@ 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,
+ /// Always format this component with upper case characters.
+ NLCS_Always,
+ /// Never format this component with upper case characters.
+ NLCS_Never,
+ };
+
+ /// Character case format for different components of a numeric literal.
+ struct NumericLiteralCaseStyle {
+ /// Format floating point exponent separator character case.
+ /// \code{.text}
+ /// /* UpperCaseFloatExponentSeparator = Leave */
+ /// float a = 6.02e23 + 1.0E10;
+ /// /* UpperCaseFloatExponentSeparator = Always */
+ /// float a = 6.02E23 + 1.0E10;
+ /// /* UpperCaseFloatExponentSeparator = Never */
+ /// float a = 6.02e23 + 1.0e10;
+ /// \endcode
+ NumericLiteralComponentStyle UpperCaseFloatExponentSeparator;
+ /// Format hexadecimal digit case.
+ /// \code{.text}
+ /// /* UpperCaseHexDigit = Leave */
+ /// a = 0xaBcDeF;
+ /// /* UpperCaseHexDigit = Always */
+ /// a = 0xABCDEF;
+ /// /* UpperCaseHexDigit = Never */
+ /// a = 0xabcdef;
+ /// \endcode
+ NumericLiteralComponentStyle UpperCaseHexDigit;
+ /// Format integer prefix case.
+ /// \code{.text}
+ /// /* UpperCasePrefix = Leave */
+ /// a = 0XF0 | 0b1;
+ /// /* UpperCasePrefix = Always */
+ /// a = 0XF0 | 0B1;
+ /// /* UpperCasePrefix = Never */
+ /// a = 0xF0 | 0b1;
+ /// \endcode
+ NumericLiteralComponentStyle UpperCasePrefix;
+ /// Format suffix case. This option excludes case-specific reserved
+ /// suffixes, such as ``min`` in C++.
+ /// \code{.text}
+ /// /* UpperCaseSuffix = Leave */
+ /// a = 1uLL;
+ /// /* UpperCaseSuffix = Always */
+ /// a = 1ULL;
+ /// /* UpperCaseSuffix = Never */
+ /// a = 1ull;
+ /// \endcode
+ NumericLiteralComponentStyle UpperCaseSuffix;
+
+ bool operator==(const NumericLiteralCaseStyle &R) const {
+ return UpperCaseFloatExponentSeparator ==
+ R.UpperCaseFloatExponentSeparator &&
+ UpperCaseHexDigit == R.UpperCaseHexDigit &&
+ UpperCasePrefix == R.UpperCasePrefix &&
+ UpperCaseSuffix == R.UpperCaseSuffix;
+ }
+ 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``.
///
@@ -5472,7 +5494,6 @@ struct FormatStyle {
IndentWrappedFunctionNames == R.IndentWrappedFunctionNames &&
InsertBraces == R.InsertBraces &&
InsertNewlineAtEOF == R.InsertNewlineAtEOF &&
- NumericLiteralCase == R.NumericLiteralCase &&
IntegerLiteralSeparator == R.IntegerLiteralSeparator &&
JavaImportGroups == R.JavaImportGroups &&
JavaScriptQuotes == R.JavaScriptQuotes &&
@@ -5487,6 +5508,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/Format.cpp b/clang/lib/Format/Format.cpp
index 711a3e7501328..c07f5bc33b859 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -383,16 +383,6 @@ struct ScalarEnumerationTraits<FormatStyle::IndentExternBlockStyle> {
}
};
-template <> struct MappingTraits<FormatStyle::NumericLiteralCaseStyle> {
- static void mapping(IO &IO, FormatStyle::NumericLiteralCaseStyle &Base) {
- IO.mapOptional("PrefixCase", Base.PrefixCase);
- IO.mapOptional("HexDigitCase", Base.HexDigitCase);
- IO.mapOptional("FloatExponentSeparatorCase",
- Base.FloatExponentSeparatorCase);
- IO.mapOptional("SuffixCase", Base.SuffixCase);
- }
-};
-
template <> struct MappingTraits<FormatStyle::IntegerLiteralSeparatorStyle> {
static void mapping(IO &IO, FormatStyle::IntegerLiteralSeparatorStyle &Base) {
IO.mapOptional("Binary", Base.Binary);
@@ -483,6 +473,26 @@ 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, "Always", FormatStyle::NLCS_Always);
+ IO.enumCase(Value, "Never", FormatStyle::NLCS_Never);
+ }
+};
+
+template <> struct MappingTraits<FormatStyle::NumericLiteralCaseStyle> {
+ static void mapping(IO &IO, FormatStyle::NumericLiteralCaseStyle &Base) {
+ IO.mapOptional("UpperCaseFloatExponentSeparatorCase",
+ Base.UpperCaseFloatExponentSeparator);
+ IO.mapOptional("UpperCaseHexDigit", Base.UpperCaseHexDigit);
+ IO.mapOptional("UpperCasePrefix", Base.UpperCasePrefix);
+ IO.mapOptional("UpperCaseSuffix", Base.UpperCaseSuffix);
+ }
+};
+
template <> struct ScalarEnumerationTraits<FormatStyle::OperandAlignmentStyle> {
static void enumeration(IO &IO, FormatStyle::OperandAlignmentStyle &Value) {
IO.enumCase(Value, "DontAlign", FormatStyle::OAS_DontAlign);
@@ -1104,7 +1114,6 @@ template <> struct MappingTraits<FormatStyle> {
IO.mapOptional("InsertBraces", Style.InsertBraces);
IO.mapOptional("InsertNewlineAtEOF", Style.InsertNewlineAtEOF);
IO.mapOptional("InsertTrailingCommas", Style.InsertTrailingCommas);
- IO.mapOptional("NumericLiteralCase", Style.NumericLiteralCase);
IO.mapOptional("IntegerLiteralSeparator", Style.IntegerLiteralSeparator);
IO.mapOptional("JavaImportGroups", Style.JavaImportGroups);
IO.mapOptional("JavaScriptQuotes", Style.JavaScriptQuotes);
@@ -1122,6 +1131,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",
@@ -1630,9 +1640,6 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
LLVMStyle.InsertBraces = false;
LLVMStyle.InsertNewlineAtEOF = false;
LLVMStyle.InsertTrailingCommas = FormatStyle::TCS_None;
- LLVMStyle.NumericLiteralCase = {/*PrefixCase=*/0, /*HexDigitCase=*/0,
- /*FloatExponentSeparatorCase=*/0,
- /*SuffixCase=*/0};
LLVMStyle.IntegerLiteralSeparator = {
/*Binary=*/0, /*BinaryMinDigits=*/0,
/*Decimal=*/0, /*DecimalMinDigits=*/0,
@@ -1650,6 +1657,11 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
LLVMStyle.LineEnding = FormatStyle::LE_DeriveLF;
LLVMStyle.MaxEmptyLinesToKeep = 1;
LLVMStyle.NamespaceIndentation = FormatStyle::NI_None;
+ LLVMStyle.NumericLiteralCase = {
+ /*UpperCaseFloatExponentSeparator=*/FormatStyle::NLCS_Leave,
+ /*UpperCaseHexDigit=*/FormatStyle::NLCS_Leave,
+ /*UpperCasePrefix=*/FormatStyle::NLCS_Leave,
+ /*UpperCaseSuffix=*/FormatStyle::NLCS_Leave};
LLVMStyle.ObjCBinPackProtocolList = FormatStyle::BPS_Auto;
LLVMStyle.ObjCBlockIndentWidth = 2;
LLVMStyle.ObjCBreakBeforeNestedBlockParam = true;
@@ -3887,9 +3899,11 @@ reformat(const FormatStyle &Style, StringRef Code,
return IntegerLiteralSeparatorFixer().process(Env, Expanded);
});
- Passes.emplace_back([&](const Environment &Env) {
- return NumericLiteralCaseFixer().process(Env, Expanded);
- });
+ if (NumericLiteralCaseFixer::isActive(Style)) {
+ Passes.emplace_back([&](const Environment &Env) {
+ return NumericLiteralCaseFixer().process(Env, Expanded);
+ });
+ }
if (Style.isCpp()) {
if (Style.QualifierAlignment != FormatStyle::QAS_Leave)
@@ -4002,8 +4016,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
index 88adaf83fe381..8a05a73ff5c65 100644
--- a/clang/lib/Format/NumericLiteralCaseFixer.cpp
+++ b/clang/lib/Format/NumericLiteralCaseFixer.cpp
@@ -47,7 +47,7 @@ class QuickNumericalConstantParser {
/// @brief Reformats the numeric constant if needed.
/// Calling this method invalidates the object's state.
- /// @return std::nullopt if no reformatting is required. std::option<>
+ /// @return std::nullopt if no reformatting is required. std::optional<>
/// containing the reformatted string otherwise.
std::optional<std::string> formatIfNeeded() &&;
@@ -76,10 +76,11 @@ static char noOpTransform(char C) { return C; }
static CharTransformFn getTransform(int8_t config_value) {
switch (config_value) {
- case -1:
- return llvm::toLower;
- case 1:
+ case FormatStyle::NLCS_Always:
return llvm::toUpper;
+ case FormatStyle::NLCS_Never:
+ return llvm::toLower;
+ case FormatStyle::NLCS_Leave:
default:
return noOpTransform;
}
@@ -88,21 +89,24 @@ static CharTransformFn getTransform(int8_t config_value) {
/// @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 const std::set<StringRef> ReservedSuffixes = {
- "h", "min", "s", "ms", "us", "ns", "il", "i", "if", "d", "y",
- };
-
- return ReservedSuffixes.find(Suffix) != ReservedSuffixes.end();
+ static const std::array<StringRef, 11> SortedReservedSuffixes = {
+ "d", "h", "i", "if", "il", "min", "ms", "ns", "s", "us", "y"};
+
+ auto entry = std::lower_bound(SortedReservedSuffixes.cbegin(),
+ SortedReservedSuffixes.cend(), Suffix);
+ if (entry == SortedReservedSuffixes.cend())
+ return false;
+ return *entry == Suffix;
}
FormatParameters::FormatParameters(
FormatStyle::LanguageKind Language,
const FormatStyle::NumericLiteralCaseStyle &CaseStyle)
- : Prefix(getTransform(CaseStyle.PrefixCase)),
- HexDigit(getTransform(CaseStyle.HexDigitCase)),
+ : Prefix(getTransform(CaseStyle.UpperCasePrefix)),
+ HexDigit(getTransform(CaseStyle.UpperCaseHexDigit)),
FloatExponentSeparator(
- getTransform(CaseStyle.FloatExponentSeparatorCase)),
- Suffix(getTransform(CaseStyle.SuffixCase)) {
+ getTransform(CaseStyle.UpperCaseFloatExponentSeparator)),
+ Suffix(getTransform(CaseStyle.UpperCaseSuffix)) {
switch (Language) {
case FormatStyle::LK_CSharp:
case FormatStyle::LK_Java:
@@ -129,34 +133,35 @@ QuickNumericalConstantParser::QuickNumericalConstantParser(
void QuickNumericalConstantParser::parse() {
auto Cur = Formatted.begin();
- auto End = Formatted.cend();
+ const auto End = Formatted.end();
bool IsHex = false;
bool IsFloat = false;
// Find the range that contains the prefix.
PrefixBegin = Cur;
- if (*Cur != '0') {
- } else {
+ if (Cur != End && *Cur == '0') {
++Cur;
- const char C = *Cur;
- switch (C) {
- case 'x':
- case 'X':
- IsHex = true;
- ++Cur;
- break;
- case 'b':
- case 'B':
- ++Cur;
- break;
- case 'o':
- case 'O':
- // Javascript uses 0o as octal prefix.
- ++Cur;
- break;
- default:
- break;
+ if (Cur != End) {
+ const char C = *Cur;
+ switch (C) {
+ case 'x':
+ case 'X':
+ IsHex = true;
+ ++Cur;
+ break;
+ case 'b':
+ case 'B':
+ ++Cur;
+ break;
+ case 'o':
+ case 'O':
+ // Javascript uses 0o as octal prefix.
+ ++Cur;
+ break;
+ default:
+ break;
+ }
}
}
PrefixEnd = Cur;
@@ -164,87 +169,59 @@ void QuickNumericalConstantParser::parse() {
// Find the range that contains hex digits.
HexDigitBegin = Cur;
if (IsHex) {
- while (Cur != End) {
- const char C = *Cur;
- if (llvm::isHexDigit(C)) {
- } else if (C == Transforms.Separator) {
- } else if (C == '.') {
+ Cur = std::find_if_not(Cur, End, [this, &IsFloat](char C) {
+ if (C == '.') {
IsFloat = true;
- } else {
- break;
+ return true;
}
- ++Cur;
- }
+ return C == Transforms.Separator || llvm::isHexDigit(C);
+ });
}
HexDigitEnd = Cur;
- if (Cur == End)
- return;
// Find the range that contains a floating point exponent separator.
// Hex digits have already been scanned through the decimal point.
// Decimal/octal/binary literals must fast forward through the decimal first.
if (!IsHex) {
- while (Cur != End) {
- const char C = *Cur;
- if (llvm::isDigit(C)) {
- } else if (C == Transforms.Separator) {
- } else if (C == '.') {
+ Cur = std::find_if_not(Cur, End, [this, &IsFloat](char C) {
+ if (C == '.') {
IsFloat = true;
- } else {
- break;
+ return true;
}
- ++Cur;
- }
+ return C == Transforms.Separator || llvm::isDigit(C);
+ });
}
-
- const char LSep = IsHex ? 'p' : 'e';
- const char USep = IsHex ? 'P' : 'E';
// The next character of a floating point literal will either be the
// separator, or the start of a suffix.
FloatExponentSeparatorBegin = Cur;
if (IsFloat) {
- const char C = *Cur;
- if ((C == LSep) || (C == USep))
- ++Cur;
+ const char LSep = IsHex ? 'p' : 'e';
+ const char USep = IsHex ? 'P' : 'E';
+ Cur = std::find_if_not(
+ Cur, End, [LSep, USep](char C) { return C == LSep || C == USep; });
}
FloatExponentSeparatorEnd = Cur;
- if (Cur == End)
- return;
// Fast forward through the exponent part of a floating point literal.
if (!IsFloat) {
} else if (FloatExponentSeparatorBegin == FloatExponentSeparatorEnd) {
} else {
- while (Cur != End) {
- const char C = *Cur;
- if (llvm::isDigit(C)) {
- } else if (C == '+') {
- } else if (C == '-') {
- } else {
- break;
- }
- ++Cur;
- }
+ Cur = std::find_if_not(Cur, End, [](char C) {
+ return llvm::isDigit(C) || C == '+' || C == '-';
+ });
}
- if (Cur == End)
- return;
// Find the range containing a suffix if any.
SuffixBegin = Cur;
size_t const SuffixLen = End - Cur;
StringRef suffix(&(*SuffixBegin), SuffixLen);
if (!matchesReservedSuffix(suffix)) {
- while (Cur != End) {
- const char C = *Cur;
- if (C == '_') {
- // In C++, it is idiomatic, but NOT standard to define user-defined
- // literals with a leading '_'. Omit user defined literals from
- // transformation.
- break;
- } else {
- }
- ++Cur;
- }
+ Cur = std::find_if_not(Cur, End, [](char C) {
+ // In C++, it is idiomatic, but NOT standard to define user-defined
+ // literals with a leading '_'. Omit user defined literals from
+ // transformation.
+ return C != '_';
+ });
}
SuffixEnd = Cur;
}
@@ -254,23 +231,23 @@ void QuickNumericalConstantParser::applyFormatting() {
auto Start = Formatted.cbegin();
auto End = Formatted.cend();
- assert((Start <= PrefixBegin) && (End >= PrefixBegin) &&
+ assert(Start <= PrefixBegin && End >= PrefixBegin &&
"PrefixBegin is out of bounds");
- assert((Start <= PrefixEnd) && (End >= PrefixEnd) &&
+ assert(Start <= PrefixEnd && End >= PrefixEnd &&
"PrefixEnd is out of bounds");
- assert((Start <= HexDigitBegin) && (End >= HexDigitBegin) &&
+ assert(Start <= HexDigitBegin && End >= HexDigitBegin &&
"HexDigitBegin is out of bounds");
- assert((Start <= HexDigitEnd) && (End >= HexDigitEnd) &&
+ assert(Start <= HexDigitEnd && End >= HexDigitEnd &&
"HexDigitEnd is out of bounds");
- assert((Start <= FloatExponentSeparatorBegin) &&
- (End >= FloatExponentSeparatorBegin) &&
+ assert(Start <= FloatExponentSeparatorBegin &&
+ End >= FloatExponentSeparatorBegin &&
"FloatExponentSeparatorBegin is out of bounds");
- assert((Start <= FloatExponentSeparatorEnd) &&
- (End >= FloatExponentSeparatorEnd) &&
+ assert(Start <= FloatExponentSeparatorEnd &&
+ End >= FloatExponentSeparatorEnd &&
"FloatExponentSeparatorEnd is out of bounds");
- assert((Start <= SuffixBegin) && (End >= SuffixBegin) &&
+ assert(Start <= SuffixBegin && End >= SuffixBegin &&
"SuffixBegin is out of bounds");
- assert((Start <= SuffixEnd) && (End >= SuffixEnd) &&
+ assert(Start <= SuffixEnd && End >= SuffixEnd &&
"SuffixEnd is out of bounds");
std::transform(PrefixBegin, PrefixEnd, PrefixBegin, Transforms.Prefix);
@@ -294,26 +271,8 @@ std::optional<std::string> QuickNumericalConstantParser::formatIfNeeded() && {
std::pair<tooling::Replacements, unsigned>
NumericLiteralCaseFixer::process(const Environment &Env,
const FormatStyle &Style) {
- 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 {};
- }
const auto &CaseStyle = Style.NumericLiteralCase;
-
- const FormatStyle::NumericLiteralCaseStyle no_case_style{};
- const bool SkipCaseFormatting = CaseStyle == no_case_style;
-
- if (SkipCaseFormatting)
- return {};
-
const FormatParameters Transforms{Style.Language, CaseStyle};
const auto &SourceMgr = Env.getSourceManager();
@@ -330,6 +289,8 @@ NumericLiteralCaseFixer::process(const Environment &Env,
while (!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;
@@ -364,5 +325,23 @@ NumericLiteralCaseFixer::process(const Environment &Env,
return {Result, 0};
}
+bool NumericLiteralCaseFixer::isActive(const FormatStyle &Style) {
+
+ 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;
+ }
+
+ const FormatStyle::NumericLiteralCaseStyle LeaveAllCasesUntouched{};
+
+ return Style.NumericLiteralCase != LeaveAllCasesUntouched;
+}
} // namespace format
} // namespace clang
diff --git a/clang/lib/Format/NumericLiteralCaseFixer.h b/clang/lib/Format/NumericLiteralCaseFixer.h
index 265d7343c468b..d836e8d064b44 100644
--- a/clang/lib/Format/NumericLiteralCaseFixer.h
+++ b/clang/lib/Format/NumericLiteralCaseFixer.h
@@ -24,6 +24,9 @@ class NumericLiteralCaseFixer {
public:
std::pair<tooling::Replacements, unsigned> process(const Environment &Env,
const FormatStyle &Style);
+
+ /// Return true if this pass should be added to the formatting run.
+ static bool isActive(const FormatStyle &Style);
};
} // end namespace format
diff --git a/clang/unittests/Format/NumericLiteralCaseTest.cpp b/clang/unittests/Format/NumericLiteralCaseTest.cpp
index 3a86485191292..cf2b8ad7d7718 100644
--- a/clang/unittests/Format/NumericLiteralCaseTest.cpp
+++ b/clang/unittests/Format/NumericLiteralCaseTest.cpp
@@ -20,10 +20,12 @@ class NumericLiteralCaseTest : public FormatTestBase {};
TEST_F(NumericLiteralCaseTest, Prefix) {
FormatStyle Style = getLLVMStyle();
EXPECT_EQ(Style.Language, FormatStyle::LK_Cpp);
- EXPECT_EQ(Style.NumericLiteralCase.PrefixCase, 0);
- EXPECT_EQ(Style.NumericLiteralCase.HexDigitCase, 0);
- EXPECT_EQ(Style.NumericLiteralCase.FloatExponentSeparatorCase, 0);
- EXPECT_EQ(Style.NumericLiteralCase.SuffixCase, 0);
+ EXPECT_EQ(Style.NumericLiteralCase.UpperCasePrefix, FormatStyle::NLCS_Leave);
+ EXPECT_EQ(Style.NumericLiteralCase.UpperCaseHexDigit,
+ FormatStyle::NLCS_Leave);
+ EXPECT_EQ(Style.NumericLiteralCase.UpperCaseFloatExponentSeparator,
+ FormatStyle::NLCS_Leave);
+ EXPECT_EQ(Style.NumericLiteralCase.UpperCaseSuffix, FormatStyle::NLCS_Leave);
const StringRef Bin0{"b = 0b0'10'010uL;"};
const StringRef Bin1{"b = 0B010'010Ul;"};
@@ -34,7 +36,7 @@ TEST_F(NumericLiteralCaseTest, Prefix) {
verifyFormat(Hex0, Style);
verifyFormat(Hex1, Style);
- Style.NumericLiteralCase.PrefixCase = 1;
+ Style.NumericLiteralCase.UpperCasePrefix = FormatStyle::NLCS_Always;
verifyFormat("b = 0B0'10'010uL;", Bin0, Style);
verifyFormat(Bin1, Style);
verifyFormat("b = 0Xdead'BEEFuL;", Hex0, Style);
@@ -42,7 +44,7 @@ TEST_F(NumericLiteralCaseTest, Prefix) {
verifyFormat("i = 0XaBcD.a0Ebp123F;", Style);
verifyFormat("j = 0XaBcD.a0EbP123f;", Style);
- Style.NumericLiteralCase.PrefixCase = -1;
+ Style.NumericLiteralCase.UpperCasePrefix = FormatStyle::NLCS_Never;
verifyFormat(Bin0, Style);
verifyFormat("b = 0b010'010Ul;", Bin1, Style);
verifyFormat(Hex0, Style);
@@ -76,7 +78,7 @@ TEST_F(NumericLiteralCaseTest, HexDigit) {
verifyFormat(I, Style);
verifyFormat(J, Style);
- Style.NumericLiteralCase.HexDigitCase = 1;
+ Style.NumericLiteralCase.UpperCaseHexDigit = FormatStyle::NLCS_Always;
verifyFormat("a = 0xABC0'123FuL;", A, Style);
verifyFormat("b = 0XABC0'123FUl;", B, Style);
verifyFormat("c = 0xA'BC.0p12'3f32;", C, Style);
@@ -88,7 +90,7 @@ TEST_F(NumericLiteralCaseTest, HexDigit) {
verifyFormat("i = 0x.0000ABCp12'3F128;", I, Style);
verifyFormat("j = 0xAA1'FP12'3F128;", J, Style);
- Style.NumericLiteralCase.HexDigitCase = -1;
+ Style.NumericLiteralCase.UpperCaseHexDigit = FormatStyle::NLCS_Never;
verifyFormat("a = 0xabc0'123fuL;", A, Style);
verifyFormat("b = 0Xabc0'123fUl;", B, Style);
verifyFormat("c = 0xa'bc.0p12'3f32;", C, Style);
@@ -120,7 +122,8 @@ TEST_F(NumericLiteralCaseTest, FloatExponentSeparator) {
verifyFormat(F, Style);
verifyFormat(G, Style);
- Style.NumericLiteralCase.FloatExponentSeparatorCase = -1;
+ Style.NumericLiteralCase.UpperCaseFloatExponentSeparator =
+ FormatStyle::NLCS_Never;
verifyFormat(A, Style);
verifyFormat("b = .00'1e2F;", B, Style);
verifyFormat(C, Style);
@@ -129,7 +132,8 @@ TEST_F(NumericLiteralCaseTest, FloatExponentSeparator) {
verifyFormat("f = 0x.deEfp23;", F, Style);
verifyFormat(G, Style);
- Style.NumericLiteralCase.FloatExponentSeparatorCase = 1;
+ Style.NumericLiteralCase.UpperCaseFloatExponentSeparator =
+ FormatStyle::NLCS_Always;
verifyFormat("a = .0'01E-19f;", A, Style);
verifyFormat(B, Style);
verifyFormat("c = 10'2.E99;", C, Style);
@@ -160,7 +164,7 @@ TEST_F(NumericLiteralCaseTest, IntegerLiteralSuffix) {
verifyFormat(G, Style);
verifyFormat(H, Style);
- Style.NumericLiteralCase.SuffixCase = -1;
+ Style.NumericLiteralCase.UpperCaseSuffix = FormatStyle::NLCS_Never;
verifyFormat(A, Style);
verifyFormat("b = 0177u;", B, Style);
verifyFormat("c = 0b101'111llu;", C, Style);
@@ -170,7 +174,7 @@ TEST_F(NumericLiteralCaseTest, IntegerLiteralSuffix) {
verifyFormat("g = 0ull;", G, Style);
verifyFormat("h = 10'233'213'0101ull;", H, Style);
- Style.NumericLiteralCase.SuffixCase = 1;
+ Style.NumericLiteralCase.UpperCaseSuffix = FormatStyle::NLCS_Always;
verifyFormat("a = 102U;", A, Style);
verifyFormat(B, Style);
verifyFormat("c = 0b101'111LLU;", C, Style);
@@ -208,15 +212,15 @@ TEST_F(NumericLiteralCaseTest, FloatingPointLiteralSuffix) {
std::string UpperLine =
std::string{Statement} + std::string{Suffix.Upper} + ";";
- Style.NumericLiteralCase.SuffixCase = 0;
+ Style.NumericLiteralCase.UpperCaseSuffix = FormatStyle::NLCS_Leave;
verifyFormat(LowerLine, Style);
verifyFormat(UpperLine, Style);
- Style.NumericLiteralCase.SuffixCase = -1;
+ Style.NumericLiteralCase.UpperCaseSuffix = FormatStyle::NLCS_Never;
verifyFormat(LowerLine, Style);
verifyFormat(LowerLine, UpperLine, Style);
- Style.NumericLiteralCase.SuffixCase = 1;
+ Style.NumericLiteralCase.UpperCaseSuffix = FormatStyle::NLCS_Always;
verifyFormat(UpperLine, LowerLine, Style);
verifyFormat(UpperLine, Style);
}
@@ -225,10 +229,11 @@ TEST_F(NumericLiteralCaseTest, FloatingPointLiteralSuffix) {
TEST_F(NumericLiteralCaseTest, CppStandardAndUserDefinedLiteralsAreUntouched) {
FormatStyle Style = getLLVMStyle();
- Style.NumericLiteralCase.PrefixCase = 1;
- Style.NumericLiteralCase.HexDigitCase = 1;
- Style.NumericLiteralCase.FloatExponentSeparatorCase = 1;
- Style.NumericLiteralCase.SuffixCase = 1;
+ Style.NumericLiteralCase.UpperCasePrefix = FormatStyle::NLCS_Always;
+ Style.NumericLiteralCase.UpperCaseHexDigit = FormatStyle::NLCS_Always;
+ Style.NumericLiteralCase.UpperCaseFloatExponentSeparator =
+ FormatStyle::NLCS_Always;
+ Style.NumericLiteralCase.UpperCaseSuffix = FormatStyle::NLCS_Always;
// C++ user-defined suffixes begin with '_' or are reserved for the standard
// library.
@@ -255,16 +260,17 @@ TEST_F(NumericLiteralCaseTest, CppStandardAndUserDefinedLiteralsAreUntouched) {
"u = 0XBEAD1_spacebar;\n"};
verifyFormat(UDLiterals, Style);
- Style.NumericLiteralCase.SuffixCase = -1;
+ Style.NumericLiteralCase.UpperCaseSuffix = FormatStyle::NLCS_Never;
verifyFormat(UDLiterals, Style);
}
TEST_F(NumericLiteralCaseTest, FixRanges) {
FormatStyle Style = getLLVMStyle();
- Style.NumericLiteralCase.PrefixCase = -1;
- Style.NumericLiteralCase.HexDigitCase = -1;
- Style.NumericLiteralCase.FloatExponentSeparatorCase = -1;
- Style.NumericLiteralCase.SuffixCase = -1;
+ Style.NumericLiteralCase.UpperCasePrefix = FormatStyle::NLCS_Never;
+ Style.NumericLiteralCase.UpperCaseHexDigit = FormatStyle::NLCS_Never;
+ Style.NumericLiteralCase.UpperCaseFloatExponentSeparator =
+ FormatStyle::NLCS_Never;
+ Style.NumericLiteralCase.UpperCaseSuffix = FormatStyle::NLCS_Never;
const StringRef CodeBlock{"a = 0xFea3duLL;\n"
"b = 0X.aEbp-12f;\n"
@@ -307,10 +313,11 @@ TEST_F(NumericLiteralCaseTest, UnderScoreSeparatorLanguages) {
"h = 0B1_0;\n"};
auto TestUnderscore = [&](auto Language) {
Style.Language = Language;
- Style.NumericLiteralCase.PrefixCase = -1;
- Style.NumericLiteralCase.HexDigitCase = 1;
- Style.NumericLiteralCase.FloatExponentSeparatorCase = -1;
- Style.NumericLiteralCase.SuffixCase = 1;
+ Style.NumericLiteralCase.UpperCasePrefix = FormatStyle::NLCS_Never;
+ Style.NumericLiteralCase.UpperCaseHexDigit = FormatStyle::NLCS_Always;
+ Style.NumericLiteralCase.UpperCaseFloatExponentSeparator =
+ FormatStyle::NLCS_Never;
+ Style.NumericLiteralCase.UpperCaseSuffix = FormatStyle::NLCS_Always;
verifyFormat("a = 0xFEA_3DL;\n"
"b = 0123_345;\n"
"c = 0b11____00LU;\n"
@@ -321,10 +328,11 @@ TEST_F(NumericLiteralCaseTest, UnderScoreSeparatorLanguages) {
"h = 0b1_0;\n",
CodeBlock, Style);
- Style.NumericLiteralCase.PrefixCase = 1;
- Style.NumericLiteralCase.HexDigitCase = -1;
- Style.NumericLiteralCase.FloatExponentSeparatorCase = 1;
- Style.NumericLiteralCase.SuffixCase = -1;
+ Style.NumericLiteralCase.UpperCasePrefix = FormatStyle::NLCS_Always;
+ Style.NumericLiteralCase.UpperCaseHexDigit = FormatStyle::NLCS_Never;
+ Style.NumericLiteralCase.UpperCaseFloatExponentSeparator =
+ FormatStyle::NLCS_Always;
+ Style.NumericLiteralCase.UpperCaseSuffix = FormatStyle::NLCS_Never;
verifyFormat("a = 0Xfea_3dl;\n"
"b = 0123_345;\n"
@@ -342,9 +350,9 @@ TEST_F(NumericLiteralCaseTest, UnderScoreSeparatorLanguages) {
TestUnderscore(FormatStyle::LK_JavaScript);
Style.Language = FormatStyle::LK_JavaScript;
- Style.NumericLiteralCase.PrefixCase = 1;
+ Style.NumericLiteralCase.UpperCasePrefix = FormatStyle::NLCS_Always;
verifyFormat("o = 0O0_10_010;", "o = 0o0_10_010;", Style);
- Style.NumericLiteralCase.PrefixCase = -1;
+ Style.NumericLiteralCase.UpperCasePrefix = FormatStyle::NLCS_Never;
verifyFormat("o = 0o0_10_010;", "o = 0O0_10_010;", Style);
}
>From b562309b2bd0984490fb265629e92f08ea8ad956 Mon Sep 17 00:00:00 2001
From: Andy MacGregor <amacgregor.2018.comcast.net at gmail.com>
Date: Mon, 4 Aug 2025 14:13:19 -0400
Subject: [PATCH 3/3] fixup! [clang-format] Add an option to format integer
literal case
---
clang/docs/ClangFormatStyleOptions.rst | 78 +++++++++---------
clang/include/clang/Format/Format.h | 62 +++++++-------
clang/lib/Format/Format.cpp | 24 +++---
clang/lib/Format/NumericLiteralCaseFixer.cpp | 41 +++++-----
.../Format/NumericLiteralCaseTest.cpp | 82 +++++++++----------
5 files changed, 139 insertions(+), 148 deletions(-)
diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst
index ffe3ebbe6a711..5dc2e5ca2618b 100644
--- a/clang/docs/ClangFormatStyleOptions.rst
+++ b/clang/docs/ClangFormatStyleOptions.rst
@@ -5083,18 +5083,18 @@ the configuration (without a prefix: ``Auto``).
Nested configuration flags:
- Character case format for different components of a numeric literal.
+ Separate control for each numeric literal component.
- * ``NumericLiteralComponentStyle UpperCaseFloatExponentSeparator``
- Format floating point exponent separator character case.
+ * ``NumericLiteralComponentStyle ExponentLetter``
+ Format floating point exponent separator letter case.
- .. code-block:: text
+ .. code-block:: c++
- /* UpperCaseFloatExponentSeparator = Leave */
+ /* ExponentLetter = Leave */
float a = 6.02e23 + 1.0E10;
- /* UpperCaseFloatExponentSeparator = Always */
+ /* ExponentLetter = Upper */
float a = 6.02E23 + 1.0E10;
- /* UpperCaseFloatExponentSeparator = Never */
+ /* ExponentLetter = Lower */
float a = 6.02e23 + 1.0e10;
Possible values:
@@ -5102,23 +5102,23 @@ the configuration (without a prefix: ``Auto``).
* ``NLCS_Leave`` (in configuration: ``Leave``)
Leave this component of the literal as is.
- * ``NLCS_Always`` (in configuration: ``Always``)
- Always format this component with upper case characters.
+ * ``NLCS_Upper`` (in configuration: ``Upper``)
+ Format this component with upper case characters.
- * ``NLCS_Never`` (in configuration: ``Never``)
- Never format this component with upper case characters.
+ * ``NLCS_Lower`` (in configuration: ``Lower``)
+ Format this component with lower case characters.
- * ``NumericLiteralComponentStyle UpperCaseHexDigit``
+ * ``NumericLiteralComponentStyle HexDigit``
Format hexadecimal digit case.
- .. code-block:: text
+ .. code-block:: c++
- /* UpperCaseHexDigit = Leave */
+ /* HexDigit = Leave */
a = 0xaBcDeF;
- /* UpperCaseHexDigit = Always */
+ /* HexDigit = Upper */
a = 0xABCDEF;
- /* UpperCaseHexDigit = Never */
+ /* HexDigit = Lower */
a = 0xabcdef;
Possible values:
@@ -5126,23 +5126,23 @@ the configuration (without a prefix: ``Auto``).
* ``NLCS_Leave`` (in configuration: ``Leave``)
Leave this component of the literal as is.
- * ``NLCS_Always`` (in configuration: ``Always``)
- Always format this component with upper case characters.
+ * ``NLCS_Upper`` (in configuration: ``Upper``)
+ Format this component with upper case characters.
- * ``NLCS_Never`` (in configuration: ``Never``)
- Never format this component with upper case characters.
+ * ``NLCS_Lower`` (in configuration: ``Lower``)
+ Format this component with lower case characters.
- * ``NumericLiteralComponentStyle UpperCasePrefix``
+ * ``NumericLiteralComponentStyle Prefix``
Format integer prefix case.
- .. code-block:: text
+ .. code-block:: c++
- /* UpperCasePrefix = Leave */
+ /* Prefix = Leave */
a = 0XF0 | 0b1;
- /* UpperCasePrefix = Always */
+ /* Prefix = Upper */
a = 0XF0 | 0B1;
- /* UpperCasePrefix = Never */
+ /* Prefix = Lower */
a = 0xF0 | 0b1;
Possible values:
@@ -5150,24 +5150,24 @@ the configuration (without a prefix: ``Auto``).
* ``NLCS_Leave`` (in configuration: ``Leave``)
Leave this component of the literal as is.
- * ``NLCS_Always`` (in configuration: ``Always``)
- Always format this component with upper case characters.
+ * ``NLCS_Upper`` (in configuration: ``Upper``)
+ Format this component with upper case characters.
- * ``NLCS_Never`` (in configuration: ``Never``)
- Never format this component with upper case characters.
+ * ``NLCS_Lower`` (in configuration: ``Lower``)
+ Format this component with lower case characters.
- * ``NumericLiteralComponentStyle UpperCaseSuffix``
- Format suffix case. This option excludes case-specific reserved
+ * ``NumericLiteralComponentStyle Suffix``
+ Format suffix case. This option excludes case-sensitive reserved
suffixes, such as ``min`` in C++.
- .. code-block:: text
+ .. code-block:: c++
- /* UpperCaseSuffix = Leave */
+ /* Suffix = Leave */
a = 1uLL;
- /* UpperCaseSuffix = Always */
+ /* Suffix = Upper */
a = 1ULL;
- /* UpperCaseSuffix = Never */
+ /* Suffix = Lower */
a = 1ull;
Possible values:
@@ -5175,11 +5175,11 @@ the configuration (without a prefix: ``Auto``).
* ``NLCS_Leave`` (in configuration: ``Leave``)
Leave this component of the literal as is.
- * ``NLCS_Always`` (in configuration: ``Always``)
- Always format this component with upper case characters.
+ * ``NLCS_Upper`` (in configuration: ``Upper``)
+ Format this component with upper case characters.
- * ``NLCS_Never`` (in configuration: ``Never``)
- Never format this component with upper case characters.
+ * ``NLCS_Lower`` (in configuration: ``Lower``)
+ Format this component with lower case characters.
diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h
index bb6ba01fbf8fd..3a84ef4af4afd 100644
--- a/clang/include/clang/Format/Format.h
+++ b/clang/include/clang/Format/Format.h
@@ -3562,63 +3562,61 @@ struct FormatStyle {
enum NumericLiteralComponentStyle : int8_t {
/// Leave this component of the literal as is.
NLCS_Leave,
- /// Always format this component with upper case characters.
- NLCS_Always,
- /// Never format this component with upper case characters.
- NLCS_Never,
+ /// Format this component with upper case characters.
+ NLCS_Upper,
+ /// Format this component with lower case characters.
+ NLCS_Lower,
};
- /// Character case format for different components of a numeric literal.
+ /// Separate control for each numeric literal component.
struct NumericLiteralCaseStyle {
- /// Format floating point exponent separator character case.
- /// \code{.text}
- /// /* UpperCaseFloatExponentSeparator = Leave */
+ /// Format floating point exponent separator letter case.
+ /// \code
+ /// /* ExponentLetter = Leave */
/// float a = 6.02e23 + 1.0E10;
- /// /* UpperCaseFloatExponentSeparator = Always */
+ /// /* ExponentLetter = Upper */
/// float a = 6.02E23 + 1.0E10;
- /// /* UpperCaseFloatExponentSeparator = Never */
+ /// /* ExponentLetter = Lower */
/// float a = 6.02e23 + 1.0e10;
/// \endcode
- NumericLiteralComponentStyle UpperCaseFloatExponentSeparator;
+ NumericLiteralComponentStyle ExponentLetter;
/// Format hexadecimal digit case.
- /// \code{.text}
- /// /* UpperCaseHexDigit = Leave */
+ /// \code
+ /// /* HexDigit = Leave */
/// a = 0xaBcDeF;
- /// /* UpperCaseHexDigit = Always */
+ /// /* HexDigit = Upper */
/// a = 0xABCDEF;
- /// /* UpperCaseHexDigit = Never */
+ /// /* HexDigit = Lower */
/// a = 0xabcdef;
/// \endcode
- NumericLiteralComponentStyle UpperCaseHexDigit;
+ NumericLiteralComponentStyle HexDigit;
/// Format integer prefix case.
- /// \code{.text}
- /// /* UpperCasePrefix = Leave */
+ /// \code
+ /// /* Prefix = Leave */
/// a = 0XF0 | 0b1;
- /// /* UpperCasePrefix = Always */
+ /// /* Prefix = Upper */
/// a = 0XF0 | 0B1;
- /// /* UpperCasePrefix = Never */
+ /// /* Prefix = Lower */
/// a = 0xF0 | 0b1;
/// \endcode
- NumericLiteralComponentStyle UpperCasePrefix;
- /// Format suffix case. This option excludes case-specific reserved
+ NumericLiteralComponentStyle Prefix;
+ /// Format suffix case. This option excludes case-sensitive reserved
/// suffixes, such as ``min`` in C++.
- /// \code{.text}
- /// /* UpperCaseSuffix = Leave */
+ /// \code
+ /// /* Suffix = Leave */
/// a = 1uLL;
- /// /* UpperCaseSuffix = Always */
+ /// /* Suffix = Upper */
/// a = 1ULL;
- /// /* UpperCaseSuffix = Never */
+ /// /* Suffix = Lower */
/// a = 1ull;
/// \endcode
- NumericLiteralComponentStyle UpperCaseSuffix;
+ NumericLiteralComponentStyle Suffix;
bool operator==(const NumericLiteralCaseStyle &R) const {
- return UpperCaseFloatExponentSeparator ==
- R.UpperCaseFloatExponentSeparator &&
- UpperCaseHexDigit == R.UpperCaseHexDigit &&
- UpperCasePrefix == R.UpperCasePrefix &&
- UpperCaseSuffix == R.UpperCaseSuffix;
+ return ExponentLetter == R.ExponentLetter && HexDigit == R.HexDigit &&
+ Prefix == R.Prefix && Suffix == R.Suffix;
}
+
bool operator!=(const NumericLiteralCaseStyle &R) const {
return !(*this == R);
}
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index c07f5bc33b859..14deec8d492e8 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -477,19 +477,18 @@ template <>
struct ScalarEnumerationTraits<FormatStyle::NumericLiteralComponentStyle> {
static void enumeration(IO &IO,
FormatStyle::NumericLiteralComponentStyle &Value) {
- IO.enumCase(Value, "Leave", FormatStyle::NLCS_Leave);
- IO.enumCase(Value, "Always", FormatStyle::NLCS_Always);
- IO.enumCase(Value, "Never", FormatStyle::NLCS_Never);
+ 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("UpperCaseFloatExponentSeparatorCase",
- Base.UpperCaseFloatExponentSeparator);
- IO.mapOptional("UpperCaseHexDigit", Base.UpperCaseHexDigit);
- IO.mapOptional("UpperCasePrefix", Base.UpperCasePrefix);
- IO.mapOptional("UpperCaseSuffix", Base.UpperCaseSuffix);
+ IO.mapOptional("ExponentLetter", Base.ExponentLetter);
+ IO.mapOptional("HexDigit", Base.HexDigit);
+ IO.mapOptional("Prefix", Base.Prefix);
+ IO.mapOptional("Suffix", Base.Suffix);
}
};
@@ -1657,11 +1656,10 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
LLVMStyle.LineEnding = FormatStyle::LE_DeriveLF;
LLVMStyle.MaxEmptyLinesToKeep = 1;
LLVMStyle.NamespaceIndentation = FormatStyle::NI_None;
- LLVMStyle.NumericLiteralCase = {
- /*UpperCaseFloatExponentSeparator=*/FormatStyle::NLCS_Leave,
- /*UpperCaseHexDigit=*/FormatStyle::NLCS_Leave,
- /*UpperCasePrefix=*/FormatStyle::NLCS_Leave,
- /*UpperCaseSuffix=*/FormatStyle::NLCS_Leave};
+ 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;
diff --git a/clang/lib/Format/NumericLiteralCaseFixer.cpp b/clang/lib/Format/NumericLiteralCaseFixer.cpp
index 8a05a73ff5c65..b2e0dcc9db06b 100644
--- a/clang/lib/Format/NumericLiteralCaseFixer.cpp
+++ b/clang/lib/Format/NumericLiteralCaseFixer.cpp
@@ -25,7 +25,7 @@ using CharTransformFn = char (*)(char C);
namespace {
/// @brief Collection of std::transform predicates for each part of a numeric
-/// literal
+/// literal.
struct FormatParameters {
FormatParameters(FormatStyle::LanguageKind Language,
const FormatStyle::NumericLiteralCaseStyle &CaseStyle);
@@ -74,11 +74,12 @@ class QuickNumericalConstantParser {
static char noOpTransform(char C) { return C; }
-static CharTransformFn getTransform(int8_t config_value) {
- switch (config_value) {
- case FormatStyle::NLCS_Always:
+static CharTransformFn
+getTransform(FormatStyle::NumericLiteralComponentStyle ConfigValue) {
+ switch (ConfigValue) {
+ case FormatStyle::NLCS_Upper:
return llvm::toUpper;
- case FormatStyle::NLCS_Never:
+ case FormatStyle::NLCS_Lower:
return llvm::toLower;
case FormatStyle::NLCS_Leave:
default:
@@ -89,11 +90,15 @@ static CharTransformFn getTransform(int8_t config_value) {
/// @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 const std::array<StringRef, 11> SortedReservedSuffixes = {
+ static constexpr std::array<StringRef, 11> SortedReservedSuffixes = {
"d", "h", "i", "if", "il", "min", "ms", "ns", "s", "us", "y"};
- auto entry = std::lower_bound(SortedReservedSuffixes.cbegin(),
- SortedReservedSuffixes.cend(), Suffix);
+ // 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;
@@ -102,11 +107,10 @@ static bool matchesReservedSuffix(StringRef Suffix) {
FormatParameters::FormatParameters(
FormatStyle::LanguageKind Language,
const FormatStyle::NumericLiteralCaseStyle &CaseStyle)
- : Prefix(getTransform(CaseStyle.UpperCasePrefix)),
- HexDigit(getTransform(CaseStyle.UpperCaseHexDigit)),
- FloatExponentSeparator(
- getTransform(CaseStyle.UpperCaseFloatExponentSeparator)),
- Suffix(getTransform(CaseStyle.UpperCaseSuffix)) {
+ : Prefix(getTransform(CaseStyle.Prefix)),
+ HexDigit(getTransform(CaseStyle.HexDigit)),
+ FloatExponentSeparator(getTransform(CaseStyle.ExponentLetter)),
+ Suffix(getTransform(CaseStyle.Suffix)) {
switch (Language) {
case FormatStyle::LK_CSharp:
case FormatStyle::LK_Java:
@@ -203,9 +207,7 @@ void QuickNumericalConstantParser::parse() {
FloatExponentSeparatorEnd = Cur;
// Fast forward through the exponent part of a floating point literal.
- if (!IsFloat) {
- } else if (FloatExponentSeparatorBegin == FloatExponentSeparatorEnd) {
- } else {
+ if (IsFloat && FloatExponentSeparatorBegin != FloatExponentSeparatorEnd) {
Cur = std::find_if_not(Cur, End, [](char C) {
return llvm::isDigit(C) || C == '+' || C == '-';
});
@@ -263,9 +265,10 @@ std::optional<std::string> QuickNumericalConstantParser::formatIfNeeded() && {
parse();
applyFormatting();
- return (Formatted == IntegerLiteral)
- ? std::nullopt
- : std::make_optional<std::string>(std::move(Formatted));
+ if (Formatted == IntegerLiteral)
+ return std::nullopt;
+ else
+ return std::move(Formatted);
}
std::pair<tooling::Replacements, unsigned>
diff --git a/clang/unittests/Format/NumericLiteralCaseTest.cpp b/clang/unittests/Format/NumericLiteralCaseTest.cpp
index cf2b8ad7d7718..54fb12a7d7cde 100644
--- a/clang/unittests/Format/NumericLiteralCaseTest.cpp
+++ b/clang/unittests/Format/NumericLiteralCaseTest.cpp
@@ -20,12 +20,10 @@ class NumericLiteralCaseTest : public FormatTestBase {};
TEST_F(NumericLiteralCaseTest, Prefix) {
FormatStyle Style = getLLVMStyle();
EXPECT_EQ(Style.Language, FormatStyle::LK_Cpp);
- EXPECT_EQ(Style.NumericLiteralCase.UpperCasePrefix, FormatStyle::NLCS_Leave);
- EXPECT_EQ(Style.NumericLiteralCase.UpperCaseHexDigit,
- FormatStyle::NLCS_Leave);
- EXPECT_EQ(Style.NumericLiteralCase.UpperCaseFloatExponentSeparator,
- FormatStyle::NLCS_Leave);
- EXPECT_EQ(Style.NumericLiteralCase.UpperCaseSuffix, FormatStyle::NLCS_Leave);
+ 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);
const StringRef Bin0{"b = 0b0'10'010uL;"};
const StringRef Bin1{"b = 0B010'010Ul;"};
@@ -36,7 +34,7 @@ TEST_F(NumericLiteralCaseTest, Prefix) {
verifyFormat(Hex0, Style);
verifyFormat(Hex1, Style);
- Style.NumericLiteralCase.UpperCasePrefix = FormatStyle::NLCS_Always;
+ Style.NumericLiteralCase.Prefix = FormatStyle::NLCS_Upper;
verifyFormat("b = 0B0'10'010uL;", Bin0, Style);
verifyFormat(Bin1, Style);
verifyFormat("b = 0Xdead'BEEFuL;", Hex0, Style);
@@ -44,7 +42,7 @@ TEST_F(NumericLiteralCaseTest, Prefix) {
verifyFormat("i = 0XaBcD.a0Ebp123F;", Style);
verifyFormat("j = 0XaBcD.a0EbP123f;", Style);
- Style.NumericLiteralCase.UpperCasePrefix = FormatStyle::NLCS_Never;
+ Style.NumericLiteralCase.Prefix = FormatStyle::NLCS_Lower;
verifyFormat(Bin0, Style);
verifyFormat("b = 0b010'010Ul;", Bin1, Style);
verifyFormat(Hex0, Style);
@@ -78,7 +76,7 @@ TEST_F(NumericLiteralCaseTest, HexDigit) {
verifyFormat(I, Style);
verifyFormat(J, Style);
- Style.NumericLiteralCase.UpperCaseHexDigit = FormatStyle::NLCS_Always;
+ 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);
@@ -90,7 +88,7 @@ TEST_F(NumericLiteralCaseTest, HexDigit) {
verifyFormat("i = 0x.0000ABCp12'3F128;", I, Style);
verifyFormat("j = 0xAA1'FP12'3F128;", J, Style);
- Style.NumericLiteralCase.UpperCaseHexDigit = FormatStyle::NLCS_Never;
+ 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);
@@ -103,7 +101,7 @@ TEST_F(NumericLiteralCaseTest, HexDigit) {
verifyFormat("j = 0xaa1'fP12'3F128;", J, Style);
}
-TEST_F(NumericLiteralCaseTest, FloatExponentSeparator) {
+TEST_F(NumericLiteralCaseTest, ExponentLetter) {
FormatStyle Style = getLLVMStyle();
const StringRef A{"a = .0'01e-19f;"};
@@ -122,8 +120,7 @@ TEST_F(NumericLiteralCaseTest, FloatExponentSeparator) {
verifyFormat(F, Style);
verifyFormat(G, Style);
- Style.NumericLiteralCase.UpperCaseFloatExponentSeparator =
- FormatStyle::NLCS_Never;
+ Style.NumericLiteralCase.ExponentLetter = FormatStyle::NLCS_Lower;
verifyFormat(A, Style);
verifyFormat("b = .00'1e2F;", B, Style);
verifyFormat(C, Style);
@@ -132,8 +129,7 @@ TEST_F(NumericLiteralCaseTest, FloatExponentSeparator) {
verifyFormat("f = 0x.deEfp23;", F, Style);
verifyFormat(G, Style);
- Style.NumericLiteralCase.UpperCaseFloatExponentSeparator =
- FormatStyle::NLCS_Always;
+ Style.NumericLiteralCase.ExponentLetter = FormatStyle::NLCS_Upper;
verifyFormat("a = .0'01E-19f;", A, Style);
verifyFormat(B, Style);
verifyFormat("c = 10'2.E99;", C, Style);
@@ -143,7 +139,7 @@ TEST_F(NumericLiteralCaseTest, FloatExponentSeparator) {
verifyFormat("g = 0xe0E1.P-1;", G, Style);
}
-TEST_F(NumericLiteralCaseTest, IntegerLiteralSuffix) {
+TEST_F(NumericLiteralCaseTest, IntegerSuffix) {
FormatStyle Style = getLLVMStyle();
const StringRef A{"a = 102u;"};
@@ -164,7 +160,7 @@ TEST_F(NumericLiteralCaseTest, IntegerLiteralSuffix) {
verifyFormat(G, Style);
verifyFormat(H, Style);
- Style.NumericLiteralCase.UpperCaseSuffix = FormatStyle::NLCS_Never;
+ Style.NumericLiteralCase.Suffix = FormatStyle::NLCS_Lower;
verifyFormat(A, Style);
verifyFormat("b = 0177u;", B, Style);
verifyFormat("c = 0b101'111llu;", C, Style);
@@ -174,7 +170,7 @@ TEST_F(NumericLiteralCaseTest, IntegerLiteralSuffix) {
verifyFormat("g = 0ull;", G, Style);
verifyFormat("h = 10'233'213'0101ull;", H, Style);
- Style.NumericLiteralCase.UpperCaseSuffix = FormatStyle::NLCS_Always;
+ Style.NumericLiteralCase.Suffix = FormatStyle::NLCS_Upper;
verifyFormat("a = 102U;", A, Style);
verifyFormat(B, Style);
verifyFormat("c = 0b101'111LLU;", C, Style);
@@ -185,7 +181,7 @@ TEST_F(NumericLiteralCaseTest, IntegerLiteralSuffix) {
verifyFormat("h = 10'233'213'0101ULL;", H, Style);
}
-TEST_F(NumericLiteralCaseTest, FloatingPointLiteralSuffix) {
+TEST_F(NumericLiteralCaseTest, FloatingPointSuffix) {
FormatStyle Style = getLLVMStyle();
// Floating point literals without suffixes.
std::vector<StringRef> FloatingPointStatements = {
@@ -212,15 +208,15 @@ TEST_F(NumericLiteralCaseTest, FloatingPointLiteralSuffix) {
std::string UpperLine =
std::string{Statement} + std::string{Suffix.Upper} + ";";
- Style.NumericLiteralCase.UpperCaseSuffix = FormatStyle::NLCS_Leave;
+ Style.NumericLiteralCase.Suffix = FormatStyle::NLCS_Leave;
verifyFormat(LowerLine, Style);
verifyFormat(UpperLine, Style);
- Style.NumericLiteralCase.UpperCaseSuffix = FormatStyle::NLCS_Never;
+ Style.NumericLiteralCase.Suffix = FormatStyle::NLCS_Lower;
verifyFormat(LowerLine, Style);
verifyFormat(LowerLine, UpperLine, Style);
- Style.NumericLiteralCase.UpperCaseSuffix = FormatStyle::NLCS_Always;
+ Style.NumericLiteralCase.Suffix = FormatStyle::NLCS_Upper;
verifyFormat(UpperLine, LowerLine, Style);
verifyFormat(UpperLine, Style);
}
@@ -229,11 +225,10 @@ TEST_F(NumericLiteralCaseTest, FloatingPointLiteralSuffix) {
TEST_F(NumericLiteralCaseTest, CppStandardAndUserDefinedLiteralsAreUntouched) {
FormatStyle Style = getLLVMStyle();
- Style.NumericLiteralCase.UpperCasePrefix = FormatStyle::NLCS_Always;
- Style.NumericLiteralCase.UpperCaseHexDigit = FormatStyle::NLCS_Always;
- Style.NumericLiteralCase.UpperCaseFloatExponentSeparator =
- FormatStyle::NLCS_Always;
- Style.NumericLiteralCase.UpperCaseSuffix = FormatStyle::NLCS_Always;
+ 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.
@@ -260,17 +255,16 @@ TEST_F(NumericLiteralCaseTest, CppStandardAndUserDefinedLiteralsAreUntouched) {
"u = 0XBEAD1_spacebar;\n"};
verifyFormat(UDLiterals, Style);
- Style.NumericLiteralCase.UpperCaseSuffix = FormatStyle::NLCS_Never;
+ Style.NumericLiteralCase.Suffix = FormatStyle::NLCS_Lower;
verifyFormat(UDLiterals, Style);
}
TEST_F(NumericLiteralCaseTest, FixRanges) {
FormatStyle Style = getLLVMStyle();
- Style.NumericLiteralCase.UpperCasePrefix = FormatStyle::NLCS_Never;
- Style.NumericLiteralCase.UpperCaseHexDigit = FormatStyle::NLCS_Never;
- Style.NumericLiteralCase.UpperCaseFloatExponentSeparator =
- FormatStyle::NLCS_Never;
- Style.NumericLiteralCase.UpperCaseSuffix = FormatStyle::NLCS_Never;
+ Style.NumericLiteralCase.Prefix = FormatStyle::NLCS_Lower;
+ Style.NumericLiteralCase.HexDigit = FormatStyle::NLCS_Lower;
+ Style.NumericLiteralCase.ExponentLetter = FormatStyle::NLCS_Lower;
+ Style.NumericLiteralCase.Suffix = FormatStyle::NLCS_Lower;
const StringRef CodeBlock{"a = 0xFea3duLL;\n"
"b = 0X.aEbp-12f;\n"
@@ -313,11 +307,10 @@ TEST_F(NumericLiteralCaseTest, UnderScoreSeparatorLanguages) {
"h = 0B1_0;\n"};
auto TestUnderscore = [&](auto Language) {
Style.Language = Language;
- Style.NumericLiteralCase.UpperCasePrefix = FormatStyle::NLCS_Never;
- Style.NumericLiteralCase.UpperCaseHexDigit = FormatStyle::NLCS_Always;
- Style.NumericLiteralCase.UpperCaseFloatExponentSeparator =
- FormatStyle::NLCS_Never;
- Style.NumericLiteralCase.UpperCaseSuffix = FormatStyle::NLCS_Always;
+ 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"
@@ -328,11 +321,10 @@ TEST_F(NumericLiteralCaseTest, UnderScoreSeparatorLanguages) {
"h = 0b1_0;\n",
CodeBlock, Style);
- Style.NumericLiteralCase.UpperCasePrefix = FormatStyle::NLCS_Always;
- Style.NumericLiteralCase.UpperCaseHexDigit = FormatStyle::NLCS_Never;
- Style.NumericLiteralCase.UpperCaseFloatExponentSeparator =
- FormatStyle::NLCS_Always;
- Style.NumericLiteralCase.UpperCaseSuffix = FormatStyle::NLCS_Never;
+ 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"
@@ -350,9 +342,9 @@ TEST_F(NumericLiteralCaseTest, UnderScoreSeparatorLanguages) {
TestUnderscore(FormatStyle::LK_JavaScript);
Style.Language = FormatStyle::LK_JavaScript;
- Style.NumericLiteralCase.UpperCasePrefix = FormatStyle::NLCS_Always;
+ Style.NumericLiteralCase.Prefix = FormatStyle::NLCS_Upper;
verifyFormat("o = 0O0_10_010;", "o = 0o0_10_010;", Style);
- Style.NumericLiteralCase.UpperCasePrefix = FormatStyle::NLCS_Never;
+ Style.NumericLiteralCase.Prefix = FormatStyle::NLCS_Lower;
verifyFormat("o = 0o0_10_010;", "o = 0O0_10_010;", Style);
}
More information about the cfe-commits
mailing list