Skip to content

Commit 220d705

Browse files
authored
[clang-format] Add an option to format numeric literal case (llvm#151590)
Some languages have the flexibility to use upper or lower case characters interchangeably in integer and float literal definitions. I'd like to be able to enforce a consistent case style in one of my projects, so I added this clang-format style option to control it. With this .clang-format configuration: ```yaml NumericLiteralCaseStyle: UpperCasePrefix: Never UpperCaseHexDigit: Always UpperCaseSuffix: Never ``` This line of code: ```C unsigned long long 0XdEaDbEeFUll; ``` gets reformatted into this line of code: ```C unsigned long long 0xDEAFBEEFull; ``` ----- I'm new to this project, so please let me know if I missed something in the process. I modeled this PR from [IntegerLiteralSeparatorFixer](https://reviews.llvm.org/D140543)
1 parent 5374f16 commit 220d705

File tree

9 files changed

+763
-0
lines changed

9 files changed

+763
-0
lines changed

clang/docs/ClangFormatStyleOptions.rst

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5079,6 +5079,113 @@ the configuration (without a prefix: ``Auto``).
50795079

50805080
For example: TESTSUITE
50815081

5082+
.. _NumericLiteralCase:
5083+
5084+
**NumericLiteralCase** (``NumericLiteralCaseStyle``) :versionbadge:`clang-format 22` :ref:`<NumericLiteralCase>`
5085+
Capitalization style for numeric literals.
5086+
5087+
Nested configuration flags:
5088+
5089+
Separate control for each numeric literal component.
5090+
5091+
For example, the config below will leave exponent letters alone, reformat
5092+
hexadecimal digits in lowercase, reformat numeric literal prefixes in
5093+
uppercase, and reformat suffixes in lowercase.
5094+
5095+
.. code-block:: c++
5096+
5097+
NumericLiteralCase:
5098+
ExponentLetter: Leave
5099+
HexDigit: Lower
5100+
Prefix: Upper
5101+
Suffix: Lower
5102+
5103+
* ``NumericLiteralComponentStyle ExponentLetter``
5104+
Format floating point exponent separator letter case.
5105+
5106+
.. code-block:: c++
5107+
5108+
float a = 6.02e23 + 1.0E10; // Leave
5109+
float a = 6.02E23 + 1.0E10; // Upper
5110+
float a = 6.02e23 + 1.0e10; // Lower
5111+
5112+
Possible values:
5113+
5114+
* ``NLCS_Leave`` (in configuration: ``Leave``)
5115+
Leave this component of the literal as is.
5116+
5117+
* ``NLCS_Upper`` (in configuration: ``Upper``)
5118+
Format this component with uppercase characters.
5119+
5120+
* ``NLCS_Lower`` (in configuration: ``Lower``)
5121+
Format this component with lowercase characters.
5122+
5123+
5124+
* ``NumericLiteralComponentStyle HexDigit``
5125+
Format hexadecimal digit case.
5126+
5127+
.. code-block:: c++
5128+
5129+
a = 0xaBcDeF; // Leave
5130+
a = 0xABCDEF; // Upper
5131+
a = 0xabcdef; // Lower
5132+
5133+
Possible values:
5134+
5135+
* ``NLCS_Leave`` (in configuration: ``Leave``)
5136+
Leave this component of the literal as is.
5137+
5138+
* ``NLCS_Upper`` (in configuration: ``Upper``)
5139+
Format this component with uppercase characters.
5140+
5141+
* ``NLCS_Lower`` (in configuration: ``Lower``)
5142+
Format this component with lowercase characters.
5143+
5144+
5145+
* ``NumericLiteralComponentStyle Prefix``
5146+
Format integer prefix case.
5147+
5148+
.. code-block:: c++
5149+
5150+
a = 0XF0 | 0b1; // Leave
5151+
a = 0XF0 | 0B1; // Upper
5152+
a = 0xF0 | 0b1; // Lower
5153+
5154+
Possible values:
5155+
5156+
* ``NLCS_Leave`` (in configuration: ``Leave``)
5157+
Leave this component of the literal as is.
5158+
5159+
* ``NLCS_Upper`` (in configuration: ``Upper``)
5160+
Format this component with uppercase characters.
5161+
5162+
* ``NLCS_Lower`` (in configuration: ``Lower``)
5163+
Format this component with lowercase characters.
5164+
5165+
5166+
* ``NumericLiteralComponentStyle Suffix``
5167+
Format suffix case. This option excludes case-sensitive reserved
5168+
suffixes, such as ``min`` in C++.
5169+
5170+
.. code-block:: c++
5171+
5172+
a = 1uLL; // Leave
5173+
a = 1ULL; // Upper
5174+
a = 1ull; // Lower
5175+
5176+
Possible values:
5177+
5178+
* ``NLCS_Leave`` (in configuration: ``Leave``)
5179+
Leave this component of the literal as is.
5180+
5181+
* ``NLCS_Upper`` (in configuration: ``Upper``)
5182+
Format this component with uppercase characters.
5183+
5184+
* ``NLCS_Lower`` (in configuration: ``Lower``)
5185+
Format this component with lowercase characters.
5186+
5187+
5188+
50825189
.. _ObjCBinPackProtocolList:
50835190

50845191
**ObjCBinPackProtocolList** (``BinPackStyle``) :versionbadge:`clang-format 7` :ref:`<ObjCBinPackProtocolList>`

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,8 @@ AST Matchers
468468
clang-format
469469
------------
470470
- Add ``SpaceInEmptyBraces`` option and set it to ``Always`` for WebKit style.
471+
- Add ``NumericLiteralCase`` option for enforcing character case in numeric
472+
literals.
471473

472474
libclang
473475
--------

clang/include/clang/Format/Format.h

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3558,6 +3558,73 @@ struct FormatStyle {
35583558
/// \version 9
35593559
std::vector<std::string> NamespaceMacros;
35603560

3561+
/// Control over each component in a numeric literal.
3562+
enum NumericLiteralComponentStyle : int8_t {
3563+
/// Leave this component of the literal as is.
3564+
NLCS_Leave,
3565+
/// Format this component with uppercase characters.
3566+
NLCS_Upper,
3567+
/// Format this component with lowercase characters.
3568+
NLCS_Lower,
3569+
};
3570+
3571+
/// Separate control for each numeric literal component.
3572+
///
3573+
/// For example, the config below will leave exponent letters alone, reformat
3574+
/// hexadecimal digits in lowercase, reformat numeric literal prefixes in
3575+
/// uppercase, and reformat suffixes in lowercase.
3576+
/// \code
3577+
/// NumericLiteralCase:
3578+
/// ExponentLetter: Leave
3579+
/// HexDigit: Lower
3580+
/// Prefix: Upper
3581+
/// Suffix: Lower
3582+
/// \endcode
3583+
struct NumericLiteralCaseStyle {
3584+
/// Format floating point exponent separator letter case.
3585+
/// \code
3586+
/// float a = 6.02e23 + 1.0E10; // Leave
3587+
/// float a = 6.02E23 + 1.0E10; // Upper
3588+
/// float a = 6.02e23 + 1.0e10; // Lower
3589+
/// \endcode
3590+
NumericLiteralComponentStyle ExponentLetter;
3591+
/// Format hexadecimal digit case.
3592+
/// \code
3593+
/// a = 0xaBcDeF; // Leave
3594+
/// a = 0xABCDEF; // Upper
3595+
/// a = 0xabcdef; // Lower
3596+
/// \endcode
3597+
NumericLiteralComponentStyle HexDigit;
3598+
/// Format integer prefix case.
3599+
/// \code
3600+
/// a = 0XF0 | 0b1; // Leave
3601+
/// a = 0XF0 | 0B1; // Upper
3602+
/// a = 0xF0 | 0b1; // Lower
3603+
/// \endcode
3604+
NumericLiteralComponentStyle Prefix;
3605+
/// Format suffix case. This option excludes case-sensitive reserved
3606+
/// suffixes, such as ``min`` in C++.
3607+
/// \code
3608+
/// a = 1uLL; // Leave
3609+
/// a = 1ULL; // Upper
3610+
/// a = 1ull; // Lower
3611+
/// \endcode
3612+
NumericLiteralComponentStyle Suffix;
3613+
3614+
bool operator==(const NumericLiteralCaseStyle &R) const {
3615+
return ExponentLetter == R.ExponentLetter && HexDigit == R.HexDigit &&
3616+
Prefix == R.Prefix && Suffix == R.Suffix;
3617+
}
3618+
3619+
bool operator!=(const NumericLiteralCaseStyle &R) const {
3620+
return !(*this == R);
3621+
}
3622+
};
3623+
3624+
/// Capitalization style for numeric literals.
3625+
/// \version 22
3626+
NumericLiteralCaseStyle NumericLiteralCase;
3627+
35613628
/// Controls bin-packing Objective-C protocol conformance list
35623629
/// items into as few lines as possible when they go over ``ColumnLimit``.
35633630
///
@@ -5469,6 +5536,7 @@ struct FormatStyle {
54695536
MaxEmptyLinesToKeep == R.MaxEmptyLinesToKeep &&
54705537
NamespaceIndentation == R.NamespaceIndentation &&
54715538
NamespaceMacros == R.NamespaceMacros &&
5539+
NumericLiteralCase == R.NumericLiteralCase &&
54725540
ObjCBinPackProtocolList == R.ObjCBinPackProtocolList &&
54735541
ObjCBlockIndentWidth == R.ObjCBlockIndentWidth &&
54745542
ObjCBreakBeforeNestedBlockParam ==

clang/lib/Format/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ add_clang_library(clangFormat
1313
MacroExpander.cpp
1414
MatchFilePath.cpp
1515
NamespaceEndCommentsFixer.cpp
16+
NumericLiteralCaseFixer.cpp
1617
NumericLiteralInfo.cpp
1718
ObjCPropertyAttributeOrderFixer.cpp
1819
QualifierAlignmentFixer.cpp

clang/lib/Format/Format.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "DefinitionBlockSeparator.h"
1717
#include "IntegerLiteralSeparatorFixer.h"
1818
#include "NamespaceEndCommentsFixer.h"
19+
#include "NumericLiteralCaseFixer.h"
1920
#include "ObjCPropertyAttributeOrderFixer.h"
2021
#include "QualifierAlignmentFixer.h"
2122
#include "SortJavaScriptImports.h"
@@ -472,6 +473,25 @@ struct ScalarEnumerationTraits<FormatStyle::NamespaceIndentationKind> {
472473
}
473474
};
474475

476+
template <>
477+
struct ScalarEnumerationTraits<FormatStyle::NumericLiteralComponentStyle> {
478+
static void enumeration(IO &IO,
479+
FormatStyle::NumericLiteralComponentStyle &Value) {
480+
IO.enumCase(Value, "Leave", FormatStyle::NLCS_Leave);
481+
IO.enumCase(Value, "Upper", FormatStyle::NLCS_Upper);
482+
IO.enumCase(Value, "Lower", FormatStyle::NLCS_Lower);
483+
}
484+
};
485+
486+
template <> struct MappingTraits<FormatStyle::NumericLiteralCaseStyle> {
487+
static void mapping(IO &IO, FormatStyle::NumericLiteralCaseStyle &Value) {
488+
IO.mapOptional("ExponentLetter", Value.ExponentLetter);
489+
IO.mapOptional("HexDigit", Value.HexDigit);
490+
IO.mapOptional("Prefix", Value.Prefix);
491+
IO.mapOptional("Suffix", Value.Suffix);
492+
}
493+
};
494+
475495
template <> struct ScalarEnumerationTraits<FormatStyle::OperandAlignmentStyle> {
476496
static void enumeration(IO &IO, FormatStyle::OperandAlignmentStyle &Value) {
477497
IO.enumCase(Value, "DontAlign", FormatStyle::OAS_DontAlign);
@@ -1121,6 +1141,7 @@ template <> struct MappingTraits<FormatStyle> {
11211141
IO.mapOptional("MaxEmptyLinesToKeep", Style.MaxEmptyLinesToKeep);
11221142
IO.mapOptional("NamespaceIndentation", Style.NamespaceIndentation);
11231143
IO.mapOptional("NamespaceMacros", Style.NamespaceMacros);
1144+
IO.mapOptional("NumericLiteralCase", Style.NumericLiteralCase);
11241145
IO.mapOptional("ObjCBinPackProtocolList", Style.ObjCBinPackProtocolList);
11251146
IO.mapOptional("ObjCBlockIndentWidth", Style.ObjCBlockIndentWidth);
11261147
IO.mapOptional("ObjCBreakBeforeNestedBlockParam",
@@ -1653,6 +1674,10 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
16531674
LLVMStyle.LineEnding = FormatStyle::LE_DeriveLF;
16541675
LLVMStyle.MaxEmptyLinesToKeep = 1;
16551676
LLVMStyle.NamespaceIndentation = FormatStyle::NI_None;
1677+
LLVMStyle.NumericLiteralCase = {/*ExponentLetter=*/FormatStyle::NLCS_Leave,
1678+
/*HexDigit=*/FormatStyle::NLCS_Leave,
1679+
/*Prefix=*/FormatStyle::NLCS_Leave,
1680+
/*Suffix=*/FormatStyle::NLCS_Leave};
16561681
LLVMStyle.ObjCBinPackProtocolList = FormatStyle::BPS_Auto;
16571682
LLVMStyle.ObjCBlockIndentWidth = 2;
16581683
LLVMStyle.ObjCBreakBeforeNestedBlockParam = true;
@@ -3890,6 +3915,10 @@ reformat(const FormatStyle &Style, StringRef Code,
38903915
return IntegerLiteralSeparatorFixer().process(Env, Expanded);
38913916
});
38923917

3918+
Passes.emplace_back([&](const Environment &Env) {
3919+
return NumericLiteralCaseFixer().process(Env, Expanded);
3920+
});
3921+
38933922
if (Style.isCpp()) {
38943923
if (Style.QualifierAlignment != FormatStyle::QAS_Leave)
38953924
addQualifierAlignmentFixerPasses(Expanded, Passes);

0 commit comments

Comments
 (0)