================ @@ -0,0 +1,347 @@ +//===--- 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::optional<> + /// 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 FormatStyle::NLCS_Always: + return llvm::toUpper; + case FormatStyle::NLCS_Never: + return llvm::toLower; + case FormatStyle::NLCS_Leave: + 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::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.UpperCasePrefix)), + HexDigit(getTransform(CaseStyle.UpperCaseHexDigit)), + FloatExponentSeparator( + getTransform(CaseStyle.UpperCaseFloatExponentSeparator)), + Suffix(getTransform(CaseStyle.UpperCaseSuffix)) { + 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(); + const auto End = Formatted.end(); + + bool IsHex = false; + bool IsFloat = false; + + // Find the range that contains the prefix. + PrefixBegin = Cur; + if (Cur != End && *Cur == '0') { + ++Cur; + 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; + + // Find the range that contains hex digits. + HexDigitBegin = Cur; + if (IsHex) { + Cur = std::find_if_not(Cur, End, [this, &IsFloat](char C) { + if (C == '.') { + IsFloat = true; + return true; + } + return C == Transforms.Separator || llvm::isHexDigit(C); + }); + } + HexDigitEnd = Cur; + + // 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) { + Cur = std::find_if_not(Cur, End, [this, &IsFloat](char C) { + if (C == '.') { + IsFloat = true; + return true; + } + return C == Transforms.Separator || llvm::isDigit(C); + }); + } + // 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 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; + + // Fast forward through the exponent part of a floating point literal. + if (!IsFloat) { + } else if (FloatExponentSeparatorBegin == FloatExponentSeparatorEnd) { + } else { ---------------- HazardyKnusperkeks wrote:
```suggestion if (IsFloat && FloatExponentSeparatorBegin != FloatExponentSeparatorEnd) { ``` Empty `if`s are a bad style (in my opinion). https://github.com/llvm/llvm-project/pull/151590 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits