1 //===--- IntegerLiteralSeparatorFixer.cpp -----------------------*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
10 /// This file implements IntegerLiteralSeparatorFixer that fixes C++ integer
11 /// literal separators.
13 //===----------------------------------------------------------------------===//
15 #include "IntegerLiteralSeparatorFixer.h"
20 enum class Base
{ Binary
, Decimal
, Hex
, Other
};
22 static Base
getBase(const StringRef IntegerLiteral
) {
23 assert(IntegerLiteral
.size() > 1);
25 if (IntegerLiteral
[0] > '0') {
26 assert(IntegerLiteral
[0] <= '9');
30 assert(IntegerLiteral
[0] == '0');
32 switch (IntegerLiteral
[1]) {
44 std::pair
<tooling::Replacements
, unsigned>
45 IntegerLiteralSeparatorFixer::process(const Environment
&Env
,
46 const FormatStyle
&Style
) {
47 switch (Style
.Language
) {
48 case FormatStyle::LK_Cpp
:
49 case FormatStyle::LK_ObjC
:
52 case FormatStyle::LK_CSharp
:
53 case FormatStyle::LK_Java
:
54 case FormatStyle::LK_JavaScript
:
61 const auto &Option
= Style
.IntegerLiteralSeparator
;
62 const auto Binary
= Option
.Binary
;
63 const auto Decimal
= Option
.Decimal
;
64 const auto Hex
= Option
.Hex
;
65 const bool SkipBinary
= Binary
== 0;
66 const bool SkipDecimal
= Decimal
== 0;
67 const bool SkipHex
= Hex
== 0;
69 if (SkipBinary
&& SkipDecimal
&& SkipHex
)
72 const auto &SourceMgr
= Env
.getSourceManager();
73 AffectedRangeManager
AffectedRangeMgr(SourceMgr
, Env
.getCharRanges());
75 const auto ID
= Env
.getFileID();
76 const auto LangOpts
= getFormattingLangOpts(Style
);
77 Lexer
Lex(ID
, SourceMgr
.getBufferOrFake(ID
), SourceMgr
, LangOpts
);
78 Lex
.SetCommentRetentionState(true);
81 tooling::Replacements Result
;
83 for (bool Skip
= false; !Lex
.LexFromRawLexer(Tok
);) {
84 auto Length
= Tok
.getLength();
87 auto Location
= Tok
.getLocation();
88 auto Text
= StringRef(SourceMgr
.getCharacterData(Location
), Length
);
89 if (Tok
.is(tok::comment
)) {
90 if (isClangFormatOff(Text
))
92 else if (isClangFormatOn(Text
))
96 if (Skip
|| Tok
.isNot(tok::numeric_constant
) || Text
[0] == '.' ||
97 !AffectedRangeMgr
.affectsCharSourceRange(
98 CharSourceRange::getCharRange(Location
, Tok
.getEndLoc()))) {
101 const auto B
= getBase(Text
);
102 const bool IsBase2
= B
== Base::Binary
;
103 const bool IsBase10
= B
== Base::Decimal
;
104 const bool IsBase16
= B
== Base::Hex
;
105 if ((IsBase2
&& SkipBinary
) || (IsBase10
&& SkipDecimal
) ||
106 (IsBase16
&& SkipHex
) || B
== Base::Other
) {
109 if ((IsBase10
&& Text
.find_last_of(".eEfFdDmM") != StringRef::npos
) ||
110 (IsBase16
&& Text
.find_last_of(".pP") != StringRef::npos
)) {
113 if (((IsBase2
&& Binary
< 0) || (IsBase10
&& Decimal
< 0) ||
114 (IsBase16
&& Hex
< 0)) &&
115 Text
.find(Separator
) == StringRef::npos
) {
118 const auto Start
= Text
[0] == '0' ? 2 : 0;
119 auto End
= Text
.find_first_of("uUlLzZn");
120 if (End
== StringRef::npos
)
122 if (Start
> 0 || End
< Length
) {
123 Length
= End
- Start
;
124 Text
= Text
.substr(Start
, Length
);
126 auto DigitsPerGroup
= Decimal
;
128 DigitsPerGroup
= Binary
;
130 DigitsPerGroup
= Hex
;
131 if (DigitsPerGroup
> 0 && checkSeparator(Text
, DigitsPerGroup
))
134 Location
= Location
.getLocWithOffset(Start
);
135 cantFail(Result
.add(tooling::Replacement(SourceMgr
, Location
, Length
,
136 format(Text
, DigitsPerGroup
))));
142 bool IntegerLiteralSeparatorFixer::checkSeparator(
143 const StringRef IntegerLiteral
, int DigitsPerGroup
) const {
144 assert(DigitsPerGroup
> 0);
147 for (auto C
: llvm::reverse(IntegerLiteral
)) {
148 if (C
== Separator
) {
149 if (I
< DigitsPerGroup
)
154 if (I
== DigitsPerGroup
)
162 std::string
IntegerLiteralSeparatorFixer::format(const StringRef IntegerLiteral
,
163 int DigitsPerGroup
) const {
164 assert(DigitsPerGroup
!= 0);
166 std::string Formatted
;
168 if (DigitsPerGroup
< 0) {
169 for (auto C
: IntegerLiteral
)
171 Formatted
.push_back(C
);
176 for (auto C
: IntegerLiteral
)
180 int Remainder
= DigitCount
% DigitsPerGroup
;
183 for (auto C
: IntegerLiteral
) {
186 if (I
== (Remainder
> 0 ? Remainder
: DigitsPerGroup
)) {
187 Formatted
.push_back(Separator
);
191 Formatted
.push_back(C
);
198 } // namespace format