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....@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....@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....@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); } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits