mirror of
https://github.com/intel/llvm.git
synced 2026-02-04 03:26:06 +08:00
[clang-format] Add an option to format numeric literal case (#151590)
Some languages have the flexibility to use upper or lower case
characters interchangeably in integer and float literal definitions.
I'd like to be able to enforce a consistent case style in one of my
projects, so I added this clang-format style option to control it.
With this .clang-format configuration:
```yaml
NumericLiteralCaseStyle:
UpperCasePrefix: Never
UpperCaseHexDigit: Always
UpperCaseSuffix: Never
```
This line of code:
```C
unsigned long long 0XdEaDbEeFUll;
```
gets reformatted into this line of code:
```C
unsigned long long 0xDEAFBEEFull;
```
-----
I'm new to this project, so please let me know if I missed something in
the process. I modeled this PR from
[IntegerLiteralSeparatorFixer](https://reviews.llvm.org/D140543)
This commit is contained in:
@@ -5079,6 +5079,113 @@ the configuration (without a prefix: ``Auto``).
|
||||
|
||||
For example: TESTSUITE
|
||||
|
||||
.. _NumericLiteralCase:
|
||||
|
||||
**NumericLiteralCase** (``NumericLiteralCaseStyle``) :versionbadge:`clang-format 22` :ref:`¶ <NumericLiteralCase>`
|
||||
Capitalization style for numeric literals.
|
||||
|
||||
Nested configuration flags:
|
||||
|
||||
Separate control for each numeric literal component.
|
||||
|
||||
For example, the config below will leave exponent letters alone, reformat
|
||||
hexadecimal digits in lowercase, reformat numeric literal prefixes in
|
||||
uppercase, and reformat suffixes in lowercase.
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
NumericLiteralCase:
|
||||
ExponentLetter: Leave
|
||||
HexDigit: Lower
|
||||
Prefix: Upper
|
||||
Suffix: Lower
|
||||
|
||||
* ``NumericLiteralComponentStyle ExponentLetter``
|
||||
Format floating point exponent separator letter case.
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
float a = 6.02e23 + 1.0E10; // Leave
|
||||
float a = 6.02E23 + 1.0E10; // Upper
|
||||
float a = 6.02e23 + 1.0e10; // Lower
|
||||
|
||||
Possible values:
|
||||
|
||||
* ``NLCS_Leave`` (in configuration: ``Leave``)
|
||||
Leave this component of the literal as is.
|
||||
|
||||
* ``NLCS_Upper`` (in configuration: ``Upper``)
|
||||
Format this component with uppercase characters.
|
||||
|
||||
* ``NLCS_Lower`` (in configuration: ``Lower``)
|
||||
Format this component with lowercase characters.
|
||||
|
||||
|
||||
* ``NumericLiteralComponentStyle HexDigit``
|
||||
Format hexadecimal digit case.
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
a = 0xaBcDeF; // Leave
|
||||
a = 0xABCDEF; // Upper
|
||||
a = 0xabcdef; // Lower
|
||||
|
||||
Possible values:
|
||||
|
||||
* ``NLCS_Leave`` (in configuration: ``Leave``)
|
||||
Leave this component of the literal as is.
|
||||
|
||||
* ``NLCS_Upper`` (in configuration: ``Upper``)
|
||||
Format this component with uppercase characters.
|
||||
|
||||
* ``NLCS_Lower`` (in configuration: ``Lower``)
|
||||
Format this component with lowercase characters.
|
||||
|
||||
|
||||
* ``NumericLiteralComponentStyle Prefix``
|
||||
Format integer prefix case.
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
a = 0XF0 | 0b1; // Leave
|
||||
a = 0XF0 | 0B1; // Upper
|
||||
a = 0xF0 | 0b1; // Lower
|
||||
|
||||
Possible values:
|
||||
|
||||
* ``NLCS_Leave`` (in configuration: ``Leave``)
|
||||
Leave this component of the literal as is.
|
||||
|
||||
* ``NLCS_Upper`` (in configuration: ``Upper``)
|
||||
Format this component with uppercase characters.
|
||||
|
||||
* ``NLCS_Lower`` (in configuration: ``Lower``)
|
||||
Format this component with lowercase characters.
|
||||
|
||||
|
||||
* ``NumericLiteralComponentStyle Suffix``
|
||||
Format suffix case. This option excludes case-sensitive reserved
|
||||
suffixes, such as ``min`` in C++.
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
a = 1uLL; // Leave
|
||||
a = 1ULL; // Upper
|
||||
a = 1ull; // Lower
|
||||
|
||||
Possible values:
|
||||
|
||||
* ``NLCS_Leave`` (in configuration: ``Leave``)
|
||||
Leave this component of the literal as is.
|
||||
|
||||
* ``NLCS_Upper`` (in configuration: ``Upper``)
|
||||
Format this component with uppercase characters.
|
||||
|
||||
* ``NLCS_Lower`` (in configuration: ``Lower``)
|
||||
Format this component with lowercase characters.
|
||||
|
||||
|
||||
|
||||
.. _ObjCBinPackProtocolList:
|
||||
|
||||
**ObjCBinPackProtocolList** (``BinPackStyle``) :versionbadge:`clang-format 7` :ref:`¶ <ObjCBinPackProtocolList>`
|
||||
|
||||
@@ -468,6 +468,8 @@ AST Matchers
|
||||
clang-format
|
||||
------------
|
||||
- Add ``SpaceInEmptyBraces`` option and set it to ``Always`` for WebKit style.
|
||||
- Add ``NumericLiteralCase`` option for enforcing character case in numeric
|
||||
literals.
|
||||
|
||||
libclang
|
||||
--------
|
||||
|
||||
@@ -3558,6 +3558,73 @@ struct FormatStyle {
|
||||
/// \version 9
|
||||
std::vector<std::string> NamespaceMacros;
|
||||
|
||||
/// Control over each component in a numeric literal.
|
||||
enum NumericLiteralComponentStyle : int8_t {
|
||||
/// Leave this component of the literal as is.
|
||||
NLCS_Leave,
|
||||
/// Format this component with uppercase characters.
|
||||
NLCS_Upper,
|
||||
/// Format this component with lowercase characters.
|
||||
NLCS_Lower,
|
||||
};
|
||||
|
||||
/// Separate control for each numeric literal component.
|
||||
///
|
||||
/// For example, the config below will leave exponent letters alone, reformat
|
||||
/// hexadecimal digits in lowercase, reformat numeric literal prefixes in
|
||||
/// uppercase, and reformat suffixes in lowercase.
|
||||
/// \code
|
||||
/// NumericLiteralCase:
|
||||
/// ExponentLetter: Leave
|
||||
/// HexDigit: Lower
|
||||
/// Prefix: Upper
|
||||
/// Suffix: Lower
|
||||
/// \endcode
|
||||
struct NumericLiteralCaseStyle {
|
||||
/// Format floating point exponent separator letter case.
|
||||
/// \code
|
||||
/// float a = 6.02e23 + 1.0E10; // Leave
|
||||
/// float a = 6.02E23 + 1.0E10; // Upper
|
||||
/// float a = 6.02e23 + 1.0e10; // Lower
|
||||
/// \endcode
|
||||
NumericLiteralComponentStyle ExponentLetter;
|
||||
/// Format hexadecimal digit case.
|
||||
/// \code
|
||||
/// a = 0xaBcDeF; // Leave
|
||||
/// a = 0xABCDEF; // Upper
|
||||
/// a = 0xabcdef; // Lower
|
||||
/// \endcode
|
||||
NumericLiteralComponentStyle HexDigit;
|
||||
/// Format integer prefix case.
|
||||
/// \code
|
||||
/// a = 0XF0 | 0b1; // Leave
|
||||
/// a = 0XF0 | 0B1; // Upper
|
||||
/// a = 0xF0 | 0b1; // Lower
|
||||
/// \endcode
|
||||
NumericLiteralComponentStyle Prefix;
|
||||
/// Format suffix case. This option excludes case-sensitive reserved
|
||||
/// suffixes, such as ``min`` in C++.
|
||||
/// \code
|
||||
/// a = 1uLL; // Leave
|
||||
/// a = 1ULL; // Upper
|
||||
/// a = 1ull; // Lower
|
||||
/// \endcode
|
||||
NumericLiteralComponentStyle Suffix;
|
||||
|
||||
bool operator==(const NumericLiteralCaseStyle &R) const {
|
||||
return ExponentLetter == R.ExponentLetter && HexDigit == R.HexDigit &&
|
||||
Prefix == R.Prefix && Suffix == R.Suffix;
|
||||
}
|
||||
|
||||
bool operator!=(const NumericLiteralCaseStyle &R) const {
|
||||
return !(*this == R);
|
||||
}
|
||||
};
|
||||
|
||||
/// Capitalization style for numeric literals.
|
||||
/// \version 22
|
||||
NumericLiteralCaseStyle NumericLiteralCase;
|
||||
|
||||
/// Controls bin-packing Objective-C protocol conformance list
|
||||
/// items into as few lines as possible when they go over ``ColumnLimit``.
|
||||
///
|
||||
@@ -5469,6 +5536,7 @@ struct FormatStyle {
|
||||
MaxEmptyLinesToKeep == R.MaxEmptyLinesToKeep &&
|
||||
NamespaceIndentation == R.NamespaceIndentation &&
|
||||
NamespaceMacros == R.NamespaceMacros &&
|
||||
NumericLiteralCase == R.NumericLiteralCase &&
|
||||
ObjCBinPackProtocolList == R.ObjCBinPackProtocolList &&
|
||||
ObjCBlockIndentWidth == R.ObjCBlockIndentWidth &&
|
||||
ObjCBreakBeforeNestedBlockParam ==
|
||||
|
||||
@@ -13,6 +13,7 @@ add_clang_library(clangFormat
|
||||
MacroExpander.cpp
|
||||
MatchFilePath.cpp
|
||||
NamespaceEndCommentsFixer.cpp
|
||||
NumericLiteralCaseFixer.cpp
|
||||
NumericLiteralInfo.cpp
|
||||
ObjCPropertyAttributeOrderFixer.cpp
|
||||
QualifierAlignmentFixer.cpp
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "DefinitionBlockSeparator.h"
|
||||
#include "IntegerLiteralSeparatorFixer.h"
|
||||
#include "NamespaceEndCommentsFixer.h"
|
||||
#include "NumericLiteralCaseFixer.h"
|
||||
#include "ObjCPropertyAttributeOrderFixer.h"
|
||||
#include "QualifierAlignmentFixer.h"
|
||||
#include "SortJavaScriptImports.h"
|
||||
@@ -472,6 +473,25 @@ struct ScalarEnumerationTraits<FormatStyle::NamespaceIndentationKind> {
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ScalarEnumerationTraits<FormatStyle::NumericLiteralComponentStyle> {
|
||||
static void enumeration(IO &IO,
|
||||
FormatStyle::NumericLiteralComponentStyle &Value) {
|
||||
IO.enumCase(Value, "Leave", FormatStyle::NLCS_Leave);
|
||||
IO.enumCase(Value, "Upper", FormatStyle::NLCS_Upper);
|
||||
IO.enumCase(Value, "Lower", FormatStyle::NLCS_Lower);
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct MappingTraits<FormatStyle::NumericLiteralCaseStyle> {
|
||||
static void mapping(IO &IO, FormatStyle::NumericLiteralCaseStyle &Value) {
|
||||
IO.mapOptional("ExponentLetter", Value.ExponentLetter);
|
||||
IO.mapOptional("HexDigit", Value.HexDigit);
|
||||
IO.mapOptional("Prefix", Value.Prefix);
|
||||
IO.mapOptional("Suffix", Value.Suffix);
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct ScalarEnumerationTraits<FormatStyle::OperandAlignmentStyle> {
|
||||
static void enumeration(IO &IO, FormatStyle::OperandAlignmentStyle &Value) {
|
||||
IO.enumCase(Value, "DontAlign", FormatStyle::OAS_DontAlign);
|
||||
@@ -1121,6 +1141,7 @@ template <> struct MappingTraits<FormatStyle> {
|
||||
IO.mapOptional("MaxEmptyLinesToKeep", Style.MaxEmptyLinesToKeep);
|
||||
IO.mapOptional("NamespaceIndentation", Style.NamespaceIndentation);
|
||||
IO.mapOptional("NamespaceMacros", Style.NamespaceMacros);
|
||||
IO.mapOptional("NumericLiteralCase", Style.NumericLiteralCase);
|
||||
IO.mapOptional("ObjCBinPackProtocolList", Style.ObjCBinPackProtocolList);
|
||||
IO.mapOptional("ObjCBlockIndentWidth", Style.ObjCBlockIndentWidth);
|
||||
IO.mapOptional("ObjCBreakBeforeNestedBlockParam",
|
||||
@@ -1653,6 +1674,10 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
|
||||
LLVMStyle.LineEnding = FormatStyle::LE_DeriveLF;
|
||||
LLVMStyle.MaxEmptyLinesToKeep = 1;
|
||||
LLVMStyle.NamespaceIndentation = FormatStyle::NI_None;
|
||||
LLVMStyle.NumericLiteralCase = {/*ExponentLetter=*/FormatStyle::NLCS_Leave,
|
||||
/*HexDigit=*/FormatStyle::NLCS_Leave,
|
||||
/*Prefix=*/FormatStyle::NLCS_Leave,
|
||||
/*Suffix=*/FormatStyle::NLCS_Leave};
|
||||
LLVMStyle.ObjCBinPackProtocolList = FormatStyle::BPS_Auto;
|
||||
LLVMStyle.ObjCBlockIndentWidth = 2;
|
||||
LLVMStyle.ObjCBreakBeforeNestedBlockParam = true;
|
||||
@@ -3890,6 +3915,10 @@ reformat(const FormatStyle &Style, StringRef Code,
|
||||
return IntegerLiteralSeparatorFixer().process(Env, Expanded);
|
||||
});
|
||||
|
||||
Passes.emplace_back([&](const Environment &Env) {
|
||||
return NumericLiteralCaseFixer().process(Env, Expanded);
|
||||
});
|
||||
|
||||
if (Style.isCpp()) {
|
||||
if (Style.QualifierAlignment != FormatStyle::QAS_Leave)
|
||||
addQualifierAlignmentFixerPasses(Expanded, Passes);
|
||||
|
||||
177
clang/lib/Format/NumericLiteralCaseFixer.cpp
Normal file
177
clang/lib/Format/NumericLiteralCaseFixer.cpp
Normal file
@@ -0,0 +1,177 @@
|
||||
//===--- 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 literals.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "NumericLiteralCaseFixer.h"
|
||||
#include "NumericLiteralInfo.h"
|
||||
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace clang {
|
||||
namespace format {
|
||||
|
||||
static bool isNumericLiteralCaseFixerNeeded(const FormatStyle &Style) {
|
||||
// Check if language is supported.
|
||||
switch (Style.Language) {
|
||||
case FormatStyle::LK_C:
|
||||
case FormatStyle::LK_Cpp:
|
||||
case FormatStyle::LK_ObjC:
|
||||
case FormatStyle::LK_CSharp:
|
||||
case FormatStyle::LK_Java:
|
||||
case FormatStyle::LK_JavaScript:
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if style options are set.
|
||||
const auto &Option = Style.NumericLiteralCase;
|
||||
const auto Leave = FormatStyle::NLCS_Leave;
|
||||
return Option.Prefix != Leave || Option.HexDigit != Leave ||
|
||||
Option.ExponentLetter != Leave || Option.Suffix != Leave;
|
||||
}
|
||||
|
||||
static std::string
|
||||
transformComponent(StringRef Component,
|
||||
FormatStyle::NumericLiteralComponentStyle ConfigValue) {
|
||||
switch (ConfigValue) {
|
||||
case FormatStyle::NLCS_Upper:
|
||||
return Component.upper();
|
||||
case FormatStyle::NLCS_Lower:
|
||||
return Component.lower();
|
||||
default:
|
||||
// Covers FormatStyle::NLCS_Leave.
|
||||
return Component.str();
|
||||
}
|
||||
}
|
||||
|
||||
/// Test if Suffix matches a C++ literal reserved by the library.
|
||||
/// Matches against all suffixes reserved in the C++23 standard.
|
||||
static bool matchesReservedSuffix(StringRef Suffix) {
|
||||
static constexpr std::array<StringRef, 11> SortedReservedSuffixes = {
|
||||
"d", "h", "i", "if", "il", "min", "ms", "ns", "s", "us", "y",
|
||||
};
|
||||
|
||||
// This can be static_assert when we have access to constexpr is_sorted in
|
||||
// C++ 20.
|
||||
assert(llvm::is_sorted(SortedReservedSuffixes) &&
|
||||
"Must be sorted as precondition for lower_bound().");
|
||||
|
||||
auto entry = llvm::lower_bound(SortedReservedSuffixes, Suffix);
|
||||
if (entry == SortedReservedSuffixes.cend())
|
||||
return false;
|
||||
return *entry == Suffix;
|
||||
}
|
||||
|
||||
static std::string format(StringRef NumericLiteral, const FormatStyle &Style) {
|
||||
const char Separator = Style.isCpp() ? '\'' : '_';
|
||||
const NumericLiteralInfo Info(NumericLiteral, Separator);
|
||||
const bool HasBaseLetter = Info.BaseLetterPos != StringRef::npos;
|
||||
const bool HasExponent = Info.ExponentLetterPos != StringRef::npos;
|
||||
const bool HasSuffix = Info.SuffixPos != StringRef::npos;
|
||||
|
||||
std::string Formatted;
|
||||
|
||||
if (HasBaseLetter) {
|
||||
Formatted +=
|
||||
transformComponent(NumericLiteral.take_front(1 + Info.BaseLetterPos),
|
||||
Style.NumericLiteralCase.Prefix);
|
||||
}
|
||||
// Reformat this slice as HexDigit whether or not the digit has hexadecimal
|
||||
// characters because binary/decimal/octal digits are unchanged.
|
||||
Formatted += transformComponent(
|
||||
NumericLiteral.slice(HasBaseLetter ? 1 + Info.BaseLetterPos : 0,
|
||||
HasExponent ? Info.ExponentLetterPos
|
||||
: HasSuffix ? Info.SuffixPos
|
||||
: NumericLiteral.size()),
|
||||
Style.NumericLiteralCase.HexDigit);
|
||||
|
||||
if (HasExponent) {
|
||||
Formatted += transformComponent(
|
||||
NumericLiteral.slice(Info.ExponentLetterPos,
|
||||
HasSuffix ? Info.SuffixPos
|
||||
: NumericLiteral.size()),
|
||||
Style.NumericLiteralCase.ExponentLetter);
|
||||
}
|
||||
|
||||
if (HasSuffix) {
|
||||
StringRef Suffix = NumericLiteral.drop_front(Info.SuffixPos);
|
||||
if (matchesReservedSuffix(Suffix) || Suffix.front() == '_') {
|
||||
// In C++, it is idiomatic, but NOT standardized to define user-defined
|
||||
// literals with a leading '_'. Omit user defined literals and standard
|
||||
// reserved suffixes from transformation.
|
||||
Formatted += Suffix.str();
|
||||
} else {
|
||||
Formatted += transformComponent(Suffix, Style.NumericLiteralCase.Suffix);
|
||||
}
|
||||
}
|
||||
|
||||
return Formatted;
|
||||
}
|
||||
|
||||
std::pair<tooling::Replacements, unsigned>
|
||||
NumericLiteralCaseFixer::process(const Environment &Env,
|
||||
const FormatStyle &Style) {
|
||||
if (!isNumericLiteralCaseFixerNeeded(Style))
|
||||
return {};
|
||||
|
||||
const auto &SourceMgr = Env.getSourceManager();
|
||||
AffectedRangeManager AffectedRangeMgr(SourceMgr, Env.getCharRanges());
|
||||
|
||||
const auto ID = Env.getFileID();
|
||||
const auto LangOpts = getFormattingLangOpts(Style);
|
||||
Lexer Lex(ID, SourceMgr.getBufferOrFake(ID), SourceMgr, LangOpts);
|
||||
Lex.SetCommentRetentionState(true);
|
||||
|
||||
Token Tok;
|
||||
tooling::Replacements Result;
|
||||
|
||||
for (bool Skip = false; !Lex.LexFromRawLexer(Tok);) {
|
||||
// Skip tokens that are too small to contain a formattable literal.
|
||||
// Size=2 is the smallest possible literal that could contain formattable
|
||||
// components, for example "1u".
|
||||
auto Length = Tok.getLength();
|
||||
if (Length < 2)
|
||||
continue;
|
||||
|
||||
// Service clang-format off/on comments.
|
||||
auto Location = Tok.getLocation();
|
||||
auto Text = StringRef(SourceMgr.getCharacterData(Location), Length);
|
||||
if (Tok.is(tok::comment)) {
|
||||
if (isClangFormatOff(Text))
|
||||
Skip = true;
|
||||
else if (isClangFormatOn(Text))
|
||||
Skip = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Skip || Tok.isNot(tok::numeric_constant) ||
|
||||
!AffectedRangeMgr.affectsCharSourceRange(
|
||||
CharSourceRange::getCharRange(Location, Tok.getEndLoc()))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto Formatted = format(Text, Style);
|
||||
if (Formatted != Text) {
|
||||
cantFail(Result.add(
|
||||
tooling::Replacement(SourceMgr, Location, Length, Formatted)));
|
||||
}
|
||||
}
|
||||
|
||||
return {Result, 0};
|
||||
}
|
||||
|
||||
} // namespace format
|
||||
} // namespace clang
|
||||
32
clang/lib/Format/NumericLiteralCaseFixer.h
Normal file
32
clang/lib/Format/NumericLiteralCaseFixer.h
Normal file
@@ -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 literals.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#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
|
||||
@@ -28,6 +28,7 @@ add_distinct_clang_unittest(FormatTests
|
||||
MacroExpanderTest.cpp
|
||||
MatchFilePathTest.cpp
|
||||
NamespaceEndCommentsFixerTest.cpp
|
||||
NumericLiteralCaseTest.cpp
|
||||
NumericLiteralInfoTest.cpp
|
||||
ObjCPropertyAttributeOrderFixerTest.cpp
|
||||
QualifierFixerTest.cpp
|
||||
|
||||
346
clang/unittests/Format/NumericLiteralCaseTest.cpp
Normal file
346
clang/unittests/Format/NumericLiteralCaseTest.cpp
Normal file
@@ -0,0 +1,346 @@
|
||||
//===- 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) {
|
||||
constexpr StringRef Bin0("b = 0b0'10'010uL;");
|
||||
constexpr StringRef Bin1("b = 0B010'010Ul;");
|
||||
constexpr StringRef Hex0("b = 0xdead'BEEFuL;");
|
||||
constexpr StringRef Hex1("b = 0Xdead'BEEFUl;");
|
||||
verifyFormat(Bin0);
|
||||
verifyFormat(Bin1);
|
||||
verifyFormat(Hex0);
|
||||
verifyFormat(Hex1);
|
||||
|
||||
auto Style = getLLVMStyle();
|
||||
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);
|
||||
|
||||
Style.NumericLiteralCase.Prefix = FormatStyle::NLCS_Upper;
|
||||
verifyFormat("b = 0B0'10'010uL;", Bin0, Style);
|
||||
verifyFormat(Bin1, Style);
|
||||
verifyFormat("b = 0Xdead'BEEFuL;", Hex0, Style);
|
||||
verifyFormat(Hex1, Style);
|
||||
verifyFormat("i = 0XaBcD.a0Ebp123F;", Style);
|
||||
verifyFormat("j = 0XaBcD.a0EbP123f;", Style);
|
||||
|
||||
Style.NumericLiteralCase.Prefix = FormatStyle::NLCS_Lower;
|
||||
verifyFormat(Bin0, Style);
|
||||
verifyFormat("b = 0b010'010Ul;", Bin1, Style);
|
||||
verifyFormat(Hex0, Style);
|
||||
verifyFormat("b = 0xdead'BEEFUl;", Hex1, Style);
|
||||
}
|
||||
|
||||
TEST_F(NumericLiteralCaseTest, HexDigit) {
|
||||
constexpr StringRef A("a = 0xaBc0'123fuL;");
|
||||
constexpr StringRef B("b = 0XaBc0'123FUl;");
|
||||
constexpr StringRef C("c = 0xa'Bc.0p12'3f32;");
|
||||
constexpr StringRef D("d = 0xa'Bc.0P12'3F128;");
|
||||
constexpr StringRef E("e = 0b0011'00Ull;");
|
||||
constexpr StringRef F("f = 0B0100'000zu;");
|
||||
constexpr StringRef G("g = 0.123e-19f;");
|
||||
constexpr StringRef H("h = 0.12'3E-19F16;");
|
||||
constexpr StringRef I("i = 0x.0000aBcp12'3F128;");
|
||||
constexpr StringRef J("j = 0xaa1'fP12'3F128;");
|
||||
constexpr StringRef K("k = 0x0;");
|
||||
constexpr StringRef L("l = 0xA;");
|
||||
verifyFormat(A);
|
||||
verifyFormat(B);
|
||||
verifyFormat(C);
|
||||
verifyFormat(D);
|
||||
verifyFormat(E);
|
||||
verifyFormat(F);
|
||||
verifyFormat(G);
|
||||
verifyFormat(H);
|
||||
verifyFormat(I);
|
||||
verifyFormat(J);
|
||||
verifyFormat(K);
|
||||
verifyFormat(L);
|
||||
|
||||
auto Style = getLLVMStyle();
|
||||
Style.NumericLiteralCase.HexDigit = FormatStyle::NLCS_Upper;
|
||||
verifyFormat("a = 0xABC0'123FuL;", A, Style);
|
||||
verifyFormat("b = 0XABC0'123FUl;", B, Style);
|
||||
verifyFormat("c = 0xA'BC.0p12'3f32;", C, Style);
|
||||
verifyFormat("d = 0xA'BC.0P12'3F128;", D, Style);
|
||||
verifyFormat(E, Style);
|
||||
verifyFormat(F, Style);
|
||||
verifyFormat(G, Style);
|
||||
verifyFormat(H, Style);
|
||||
verifyFormat("i = 0x.0000ABCp12'3F128;", I, Style);
|
||||
verifyFormat("j = 0xAA1'FP12'3F128;", J, Style);
|
||||
verifyFormat(K, Style);
|
||||
verifyFormat(L, Style);
|
||||
|
||||
Style.NumericLiteralCase.HexDigit = FormatStyle::NLCS_Lower;
|
||||
verifyFormat("a = 0xabc0'123fuL;", A, Style);
|
||||
verifyFormat("b = 0Xabc0'123fUl;", B, Style);
|
||||
verifyFormat("c = 0xa'bc.0p12'3f32;", C, Style);
|
||||
verifyFormat("d = 0xa'bc.0P12'3F128;", D, Style);
|
||||
verifyFormat(E, Style);
|
||||
verifyFormat(F, Style);
|
||||
verifyFormat(G, Style);
|
||||
verifyFormat(H, Style);
|
||||
verifyFormat("i = 0x.0000abcp12'3F128;", I, Style);
|
||||
verifyFormat("j = 0xaa1'fP12'3F128;", J, Style);
|
||||
verifyFormat(K, Style);
|
||||
verifyFormat("l = 0xa;", Style);
|
||||
}
|
||||
|
||||
TEST_F(NumericLiteralCaseTest, ExponentLetter) {
|
||||
constexpr StringRef A("a = .0'01e-19f;");
|
||||
constexpr StringRef B("b = .00'1E2F;");
|
||||
constexpr StringRef C("c = 10'2.e99;");
|
||||
constexpr StringRef D("d = 123.456E-1;");
|
||||
constexpr StringRef E("e = 0x12abEe3.456p-10'0;");
|
||||
constexpr StringRef F("f = 0x.deEfP23;");
|
||||
constexpr StringRef G("g = 0xe0E1.p-1;");
|
||||
verifyFormat(A);
|
||||
verifyFormat(B);
|
||||
verifyFormat(C);
|
||||
verifyFormat(D);
|
||||
verifyFormat(E);
|
||||
verifyFormat(F);
|
||||
verifyFormat(G);
|
||||
|
||||
auto Style = getLLVMStyle();
|
||||
Style.NumericLiteralCase.ExponentLetter = FormatStyle::NLCS_Lower;
|
||||
verifyFormat(A, Style);
|
||||
verifyFormat("b = .00'1e2F;", B, Style);
|
||||
verifyFormat(C, Style);
|
||||
verifyFormat("d = 123.456e-1;", D, Style);
|
||||
verifyFormat(E, Style);
|
||||
verifyFormat("f = 0x.deEfp23;", F, Style);
|
||||
verifyFormat(G, Style);
|
||||
|
||||
Style.NumericLiteralCase.ExponentLetter = FormatStyle::NLCS_Upper;
|
||||
verifyFormat("a = .0'01E-19f;", A, Style);
|
||||
verifyFormat(B, Style);
|
||||
verifyFormat("c = 10'2.E99;", C, Style);
|
||||
verifyFormat(D, Style);
|
||||
verifyFormat("e = 0x12abEe3.456P-10'0;", E, Style);
|
||||
verifyFormat(F, Style);
|
||||
verifyFormat("g = 0xe0E1.P-1;", G, Style);
|
||||
}
|
||||
|
||||
TEST_F(NumericLiteralCaseTest, IntegerSuffix) {
|
||||
constexpr StringRef A("a = 102u;");
|
||||
constexpr StringRef B("b = 0177U;");
|
||||
constexpr StringRef C("c = 0b101'111llU;");
|
||||
constexpr StringRef D("d = 0xdead'BeefuZ;");
|
||||
constexpr StringRef E("e = 3lU;");
|
||||
constexpr StringRef F("f = 1zu;");
|
||||
constexpr StringRef G("g = 0uLL;");
|
||||
constexpr StringRef H("h = 10'233'213'0101uLL;");
|
||||
verifyFormat(A);
|
||||
verifyFormat(B);
|
||||
verifyFormat(C);
|
||||
verifyFormat(D);
|
||||
verifyFormat(E);
|
||||
verifyFormat(F);
|
||||
verifyFormat(G);
|
||||
verifyFormat(H);
|
||||
|
||||
auto Style = getLLVMStyle();
|
||||
Style.NumericLiteralCase.Suffix = FormatStyle::NLCS_Lower;
|
||||
verifyFormat(A, Style);
|
||||
verifyFormat("b = 0177u;", B, Style);
|
||||
verifyFormat("c = 0b101'111llu;", C, Style);
|
||||
verifyFormat("d = 0xdead'Beefuz;", D, Style);
|
||||
verifyFormat("e = 3lu;", E, Style);
|
||||
verifyFormat(F, Style);
|
||||
verifyFormat("g = 0ull;", G, Style);
|
||||
verifyFormat("h = 10'233'213'0101ull;", H, Style);
|
||||
|
||||
Style.NumericLiteralCase.Suffix = FormatStyle::NLCS_Upper;
|
||||
verifyFormat("a = 102U;", A, Style);
|
||||
verifyFormat(B, Style);
|
||||
verifyFormat("c = 0b101'111LLU;", C, Style);
|
||||
verifyFormat("d = 0xdead'BeefUZ;", D, Style);
|
||||
verifyFormat("e = 3LU;", E, Style);
|
||||
verifyFormat("f = 1ZU;", F, Style);
|
||||
verifyFormat("g = 0ULL;", G, Style);
|
||||
verifyFormat("h = 10'233'213'0101ULL;", H, Style);
|
||||
}
|
||||
|
||||
TEST_F(NumericLiteralCaseTest, FloatingPointSuffix) {
|
||||
auto Style = getLLVMStyle();
|
||||
// Floating point literals without suffixes.
|
||||
constexpr std::array<StringRef, 6> FloatingPointStatements = {
|
||||
"a = 0.", "b = 1.0", "c = .123'45E-10",
|
||||
"d = 12'3.0e1", "e = 0Xa0eE.P10", "f = 0xeE01.aFf3p6",
|
||||
};
|
||||
|
||||
// All legal floating-point literal suffixes defined in the C++23 standard in
|
||||
// lowercase.
|
||||
constexpr std::array<StringRef, 7> FloatingPointSuffixes = {
|
||||
"f", "l", "f16", "f32", "f64", "f128", "bf16",
|
||||
};
|
||||
|
||||
// Test all combinations of literals with suffixes.
|
||||
for (const auto &Statement : FloatingPointStatements) {
|
||||
for (const auto &Suffix : FloatingPointSuffixes) {
|
||||
const auto LowerLine = Statement.str() + Suffix.str() + ";";
|
||||
const auto UpperLine = Statement.str() + Suffix.upper() + ";";
|
||||
|
||||
Style.NumericLiteralCase.Suffix = FormatStyle::NLCS_Leave;
|
||||
verifyFormat(LowerLine, Style);
|
||||
verifyFormat(UpperLine, Style);
|
||||
|
||||
Style.NumericLiteralCase.Suffix = FormatStyle::NLCS_Lower;
|
||||
verifyFormat(LowerLine, Style);
|
||||
verifyFormat(LowerLine, UpperLine, Style);
|
||||
|
||||
Style.NumericLiteralCase.Suffix = FormatStyle::NLCS_Upper;
|
||||
verifyFormat(UpperLine, LowerLine, Style);
|
||||
verifyFormat(UpperLine, Style);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(NumericLiteralCaseTest, CppStandardAndUserDefinedLiteralsAreUntouched) {
|
||||
auto Style = getLLVMStyle();
|
||||
Style.NumericLiteralCase.Prefix = FormatStyle::NLCS_Upper;
|
||||
Style.NumericLiteralCase.HexDigit = FormatStyle::NLCS_Upper;
|
||||
Style.NumericLiteralCase.ExponentLetter = FormatStyle::NLCS_Upper;
|
||||
Style.NumericLiteralCase.Suffix = FormatStyle::NLCS_Upper;
|
||||
|
||||
// C++ user-defined suffixes begin with '_' or are reserved for the standard
|
||||
// library.
|
||||
constexpr StringRef UDLiterals("a = 12.if;\n"
|
||||
"b = -3i;\n"
|
||||
"c = 100'01il;\n"
|
||||
"d = 100'0.12il;\n"
|
||||
"e = 12h;\n"
|
||||
"f = 0XABE12h;\n"
|
||||
"g = 0XFA03min;\n"
|
||||
"h = 0X12B4Ds;\n"
|
||||
"i = 20.13E-1ms;\n"
|
||||
"j = 20.13E-1us;\n"
|
||||
"k = 20.13E-1ns;\n"
|
||||
"l = 20.13E-1y;\n"
|
||||
"m = 20.13E-1d;\n"
|
||||
"n = 20.13E-1d;\n"
|
||||
"o = 1d;\n"
|
||||
"p = 102_ffl_lzlz;\n"
|
||||
"q = 10.2_l;\n"
|
||||
"r = 0XABDE.0'1P-23_f;\n"
|
||||
"s = 102_foo_bar;\n"
|
||||
"t = 123.456_felfz_ballpen;\n"
|
||||
"u = 0XBEAD1_spacebar;");
|
||||
|
||||
verifyFormat(UDLiterals, Style);
|
||||
Style.NumericLiteralCase.Suffix = FormatStyle::NLCS_Lower;
|
||||
verifyFormat(UDLiterals, Style);
|
||||
}
|
||||
|
||||
TEST_F(NumericLiteralCaseTest, FixRanges) {
|
||||
auto Style = getLLVMStyle();
|
||||
Style.NumericLiteralCase.Prefix = FormatStyle::NLCS_Lower;
|
||||
Style.NumericLiteralCase.HexDigit = FormatStyle::NLCS_Lower;
|
||||
Style.NumericLiteralCase.ExponentLetter = FormatStyle::NLCS_Lower;
|
||||
Style.NumericLiteralCase.Suffix = FormatStyle::NLCS_Lower;
|
||||
|
||||
constexpr StringRef CodeBlock("a = 0xFea3duLL;\n"
|
||||
"b = 0X.aEbp-12f;\n"
|
||||
"c = 0uLL;\n"
|
||||
"// clang-format off\n"
|
||||
"e = 0xBeAdu;\n"
|
||||
"// clang-format on\n"
|
||||
"g = 0xabCDu;\n"
|
||||
"h = 0b010uL;\n"
|
||||
"// clang-format off\n"
|
||||
"i = 0B1010'000Zu;\n"
|
||||
"// clang-format on\n"
|
||||
"k = 0XaBuL;");
|
||||
|
||||
verifyFormat("a = 0xfea3dull;\n"
|
||||
"b = 0x.aebp-12f;\n"
|
||||
"c = 0ull;\n"
|
||||
"// clang-format off\n"
|
||||
"e = 0xBeAdu;\n"
|
||||
"// clang-format on\n"
|
||||
"g = 0xabcdu;\n"
|
||||
"h = 0b010ul;\n"
|
||||
"// clang-format off\n"
|
||||
"i = 0B1010'000Zu;\n"
|
||||
"// clang-format on\n"
|
||||
"k = 0xabul;",
|
||||
CodeBlock, Style);
|
||||
}
|
||||
|
||||
TEST_F(NumericLiteralCaseTest, UnderScoreSeparatorLanguages) {
|
||||
auto Style = getLLVMStyle();
|
||||
|
||||
constexpr StringRef CodeBlock("a = 0xFea_3dl;\n"
|
||||
"b = 0123_345;\n"
|
||||
"c = 0b11____00lU;\n"
|
||||
"d = 0XB_e_A_du;\n"
|
||||
"e = 123_456.333__456e-10f;\n"
|
||||
"f = .1_0E-10D;\n"
|
||||
"g = 1_0.F;\n"
|
||||
"h = 0B1_0;");
|
||||
auto TestUnderscore = [&](auto Language) {
|
||||
Style.Language = Language;
|
||||
Style.NumericLiteralCase.Prefix = FormatStyle::NLCS_Lower;
|
||||
Style.NumericLiteralCase.HexDigit = FormatStyle::NLCS_Upper;
|
||||
Style.NumericLiteralCase.ExponentLetter = FormatStyle::NLCS_Lower;
|
||||
Style.NumericLiteralCase.Suffix = FormatStyle::NLCS_Upper;
|
||||
verifyFormat("a = 0xFEA_3DL;\n"
|
||||
"b = 0123_345;\n"
|
||||
"c = 0b11____00LU;\n"
|
||||
"d = 0xB_E_A_DU;\n"
|
||||
"e = 123_456.333__456e-10F;\n"
|
||||
"f = .1_0e-10D;\n"
|
||||
"g = 1_0.F;\n"
|
||||
"h = 0b1_0;",
|
||||
CodeBlock, Style);
|
||||
|
||||
Style.NumericLiteralCase.Prefix = FormatStyle::NLCS_Upper;
|
||||
Style.NumericLiteralCase.HexDigit = FormatStyle::NLCS_Lower;
|
||||
Style.NumericLiteralCase.ExponentLetter = FormatStyle::NLCS_Upper;
|
||||
Style.NumericLiteralCase.Suffix = FormatStyle::NLCS_Lower;
|
||||
|
||||
verifyFormat("a = 0Xfea_3dl;\n"
|
||||
"b = 0123_345;\n"
|
||||
"c = 0B11____00lu;\n"
|
||||
"d = 0Xb_e_a_du;\n"
|
||||
"e = 123_456.333__456E-10f;\n"
|
||||
"f = .1_0E-10d;\n"
|
||||
"g = 1_0.f;\n"
|
||||
"h = 0B1_0;",
|
||||
CodeBlock, Style);
|
||||
};
|
||||
|
||||
TestUnderscore(FormatStyle::LK_CSharp);
|
||||
TestUnderscore(FormatStyle::LK_Java);
|
||||
TestUnderscore(FormatStyle::LK_JavaScript);
|
||||
|
||||
Style.Language = FormatStyle::LK_JavaScript;
|
||||
Style.NumericLiteralCase.Prefix = FormatStyle::NLCS_Upper;
|
||||
verifyFormat("o = 0O0_10_010;", "o = 0o0_10_010;", Style);
|
||||
Style.NumericLiteralCase.Prefix = FormatStyle::NLCS_Lower;
|
||||
verifyFormat("o = 0o0_10_010;", "o = 0O0_10_010;", Style);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace test
|
||||
} // namespace format
|
||||
} // namespace clang
|
||||
Reference in New Issue
Block a user