13
13
// ===----------------------------------------------------------------------===//
14
14
15
15
#include " NumericLiteralCaseFixer.h"
16
+ #include " NumericLiteralInfo.h"
16
17
17
18
#include " llvm/ADT/StringExtras.h"
18
19
21
22
namespace clang {
22
23
namespace format {
23
24
24
- using CharTransformFn = char (*)(char C);
25
- namespace {
26
-
27
- // / @brief Collection of std::transform predicates for each part of a numeric
28
- // / literal.
29
- struct FormatParameters {
30
- FormatParameters (FormatStyle::LanguageKind Language,
31
- const FormatStyle::NumericLiteralCaseStyle &CaseStyle);
32
-
33
- CharTransformFn Prefix;
34
- CharTransformFn HexDigit;
35
- CharTransformFn FloatExponentSeparator;
36
- CharTransformFn Suffix;
37
-
38
- char Separator;
39
- };
40
-
41
- // / @brief Parse a single numeric constant from text into ranges that are
42
- // / appropriate for applying NumericLiteralCaseStyle rules.
43
- class QuickNumericalConstantParser {
44
- public:
45
- QuickNumericalConstantParser (const StringRef &IntegerLiteral,
46
- const FormatParameters &Transforms);
47
-
48
- // / @brief Reformats the numeric constant if needed.
49
- // / Calling this method invalidates the object's state.
50
- // / @return std::nullopt if no reformatting is required. std::optional<>
51
- // / containing the reformatted string otherwise.
52
- std::optional<std::string> formatIfNeeded () &&;
53
-
54
- private:
55
- const StringRef &IntegerLiteral;
56
- const FormatParameters &Transforms;
57
-
58
- std::string Formatted;
59
-
60
- std::string::iterator PrefixBegin;
61
- std::string::iterator PrefixEnd;
62
- std::string::iterator HexDigitBegin;
63
- std::string::iterator HexDigitEnd;
64
- std::string::iterator FloatExponentSeparatorBegin;
65
- std::string::iterator FloatExponentSeparatorEnd;
66
- std::string::iterator SuffixBegin;
67
- std::string::iterator SuffixEnd;
68
-
69
- void parse ();
70
- void applyFormatting ();
71
- };
72
-
73
- } // namespace
74
-
75
- static char noOpTransform (char C) { return C; }
76
-
77
- static CharTransformFn
78
- getTransform (FormatStyle::NumericLiteralComponentStyle ConfigValue) {
25
+ static std::string
26
+ transformComponent (StringRef Component,
27
+ FormatStyle::NumericLiteralComponentStyle ConfigValue) {
79
28
switch (ConfigValue) {
80
29
case FormatStyle::NLCS_Upper:
81
- return llvm::toUpper ;
30
+ return Component. upper () ;
82
31
case FormatStyle::NLCS_Lower:
83
- return llvm::toLower ;
32
+ return Component. lower () ;
84
33
case FormatStyle::NLCS_Leave:
85
34
default :
86
- return noOpTransform ;
35
+ return Component. str () ;
87
36
}
88
37
}
89
38
@@ -104,14 +53,10 @@ static bool matchesReservedSuffix(StringRef Suffix) {
104
53
return *entry == Suffix;
105
54
}
106
55
107
- FormatParameters::FormatParameters (
108
- FormatStyle::LanguageKind Language,
109
- const FormatStyle::NumericLiteralCaseStyle &CaseStyle)
110
- : Prefix(getTransform(CaseStyle.Prefix)),
111
- HexDigit (getTransform(CaseStyle.HexDigit)),
112
- FloatExponentSeparator(getTransform(CaseStyle.ExponentLetter)),
113
- Suffix(getTransform(CaseStyle.Suffix)) {
114
- switch (Language) {
56
+ static std::optional<std::string> formatIfNeeded (StringRef IntegerLiteral,
57
+ const FormatStyle &Style) {
58
+ char Separator;
59
+ switch (Style.Language ) {
115
60
case FormatStyle::LK_CSharp:
116
61
case FormatStyle::LK_Java:
117
62
case FormatStyle::LK_JavaScript:
@@ -123,161 +68,57 @@ FormatParameters::FormatParameters(
123
68
default :
124
69
Separator = ' \' ' ;
125
70
}
126
- }
127
-
128
- QuickNumericalConstantParser::QuickNumericalConstantParser (
129
- const StringRef &IntegerLiteral, const FormatParameters &Transforms)
130
- : IntegerLiteral(IntegerLiteral), Transforms(Transforms),
131
- Formatted(IntegerLiteral), PrefixBegin(Formatted.begin()),
132
- PrefixEnd(Formatted.begin()), HexDigitBegin(Formatted.begin()),
133
- HexDigitEnd(Formatted.begin()),
134
- FloatExponentSeparatorBegin(Formatted.begin()),
135
- FloatExponentSeparatorEnd(Formatted.begin()),
136
- SuffixBegin(Formatted.begin()), SuffixEnd(Formatted.begin()) {}
137
-
138
- void QuickNumericalConstantParser::parse () {
139
- auto Cur = Formatted.begin ();
140
- const auto End = Formatted.end ();
141
-
142
- bool IsHex = false ;
143
- bool IsFloat = false ;
144
-
145
- // Find the range that contains the prefix.
146
- PrefixBegin = Cur;
147
- if (Cur != End && *Cur == ' 0' ) {
148
- ++Cur;
149
- if (Cur != End) {
150
- const char C = *Cur;
151
- switch (C) {
152
- case ' x' :
153
- case ' X' :
154
- IsHex = true ;
155
- ++Cur;
156
- break ;
157
- case ' b' :
158
- case ' B' :
159
- ++Cur;
160
- break ;
161
- case ' o' :
162
- case ' O' :
163
- // Javascript uses 0o as octal prefix.
164
- ++Cur;
165
- break ;
166
- default :
167
- break ;
168
- }
169
- }
170
- }
171
- PrefixEnd = Cur;
71
+ const NumericLiteralInfo N{IntegerLiteral, Separator};
172
72
173
- // Find the range that contains hex digits.
174
- HexDigitBegin = Cur;
175
- if (IsHex) {
176
- Cur = std::find_if_not (Cur, End, [this , &IsFloat](char C) {
177
- if (C == ' .' ) {
178
- IsFloat = true ;
179
- return true ;
180
- }
181
- return C == Transforms.Separator || llvm::isHexDigit (C);
182
- });
183
- }
184
- HexDigitEnd = Cur;
73
+ std::string Formatted{" " };
185
74
186
- // Find the range that contains a floating point exponent separator.
187
- // Hex digits have already been scanned through the decimal point.
188
- // Decimal/octal/binary literals must fast forward through the decimal first.
189
- if (!IsHex) {
190
- Cur = std::find_if_not (Cur, End, [this , &IsFloat](char C) {
191
- if (C == ' .' ) {
192
- IsFloat = true ;
193
- return true ;
194
- }
195
- return C == Transforms.Separator || llvm::isDigit (C);
196
- });
75
+ if (N.BaseLetterPos != llvm::StringRef::npos) {
76
+ Formatted +=
77
+ transformComponent (IntegerLiteral.take_front (1 + N.BaseLetterPos ),
78
+ Style.NumericLiteralCase .Prefix );
197
79
}
198
- // The next character of a floating point literal will either be the
199
- // separator, or the start of a suffix.
200
- FloatExponentSeparatorBegin = Cur;
201
- if (IsFloat) {
202
- const char LSep = IsHex ? ' p' : ' e' ;
203
- const char USep = IsHex ? ' P' : ' E' ;
204
- Cur = std::find_if_not (
205
- Cur, End, [LSep, USep](char C) { return C == LSep || C == USep; });
80
+ // reformat this slice as HexDigit whether or not the digit has hexadecimal
81
+ // characters because binary/decimal/octal digits are unchanged
82
+ Formatted += transformComponent (
83
+ IntegerLiteral.slice (
84
+ N.BaseLetterPos == llvm::StringRef::npos ? 0 : 1 + N.BaseLetterPos ,
85
+ N.ExponentLetterPos == llvm::StringRef::npos
86
+ ? N.SuffixPos == llvm::StringRef::npos ? IntegerLiteral.size ()
87
+ : N.SuffixPos
88
+ : N.ExponentLetterPos ),
89
+ Style.NumericLiteralCase .HexDigit );
90
+
91
+ if (N.ExponentLetterPos != llvm::StringRef::npos) {
92
+ Formatted += transformComponent (
93
+ IntegerLiteral.slice (N.ExponentLetterPos ,
94
+ N.SuffixPos == llvm::StringRef::npos
95
+ ? IntegerLiteral.size ()
96
+ : N.SuffixPos ),
97
+ Style.NumericLiteralCase .ExponentLetter );
206
98
}
207
- FloatExponentSeparatorEnd = Cur;
208
99
209
- // Fast forward through the exponent part of a floating point literal.
210
- if (IsFloat && FloatExponentSeparatorBegin != FloatExponentSeparatorEnd) {
211
- Cur = std::find_if_not (Cur, End, [](char C) {
212
- return llvm::isDigit (C) || C == ' +' || C == ' -' ;
213
- });
100
+ if (N.SuffixPos != llvm::StringRef::npos) {
101
+ StringRef Suffix = IntegerLiteral.drop_front (N.SuffixPos );
102
+ if (matchesReservedSuffix (Suffix) || Suffix.front () == ' _' ) {
103
+ // In C++, it is idiomatic, but NOT standardized to define user-defined
104
+ // literals with a leading '_'. Omit user defined literals and standard
105
+ // reserved suffixes from transformation.
106
+ Formatted += Suffix.str ();
107
+ } else {
108
+ Formatted += transformComponent (Suffix, Style.NumericLiteralCase .Suffix );
109
+ }
214
110
}
215
111
216
- // Find the range containing a suffix if any.
217
- SuffixBegin = Cur;
218
- size_t const SuffixLen = End - Cur;
219
- StringRef suffix (&(*SuffixBegin), SuffixLen);
220
- if (!matchesReservedSuffix (suffix)) {
221
- Cur = std::find_if_not (Cur, End, [](char C) {
222
- // In C++, it is idiomatic, but NOT standard to define user-defined
223
- // literals with a leading '_'. Omit user defined literals from
224
- // transformation.
225
- return C != ' _' ;
226
- });
227
- }
228
- SuffixEnd = Cur;
229
- }
230
-
231
- void QuickNumericalConstantParser::applyFormatting () {
232
-
233
- auto Start = Formatted.cbegin ();
234
- auto End = Formatted.cend ();
235
-
236
- assert (Start <= PrefixBegin && End >= PrefixBegin &&
237
- " PrefixBegin is out of bounds" );
238
- assert (Start <= PrefixEnd && End >= PrefixEnd &&
239
- " PrefixEnd is out of bounds" );
240
- assert (Start <= HexDigitBegin && End >= HexDigitBegin &&
241
- " HexDigitBegin is out of bounds" );
242
- assert (Start <= HexDigitEnd && End >= HexDigitEnd &&
243
- " HexDigitEnd is out of bounds" );
244
- assert (Start <= FloatExponentSeparatorBegin &&
245
- End >= FloatExponentSeparatorBegin &&
246
- " FloatExponentSeparatorBegin is out of bounds" );
247
- assert (Start <= FloatExponentSeparatorEnd &&
248
- End >= FloatExponentSeparatorEnd &&
249
- " FloatExponentSeparatorEnd is out of bounds" );
250
- assert (Start <= SuffixBegin && End >= SuffixBegin &&
251
- " SuffixBegin is out of bounds" );
252
- assert (Start <= SuffixEnd && End >= SuffixEnd &&
253
- " SuffixEnd is out of bounds" );
254
-
255
- std::transform (PrefixBegin, PrefixEnd, PrefixBegin, Transforms.Prefix );
256
- std::transform (HexDigitBegin, HexDigitEnd, HexDigitBegin,
257
- Transforms.HexDigit );
258
- std::transform (FloatExponentSeparatorBegin, FloatExponentSeparatorEnd,
259
- FloatExponentSeparatorBegin,
260
- Transforms.FloatExponentSeparator );
261
- std::transform (SuffixBegin, SuffixEnd, SuffixBegin, Transforms.Suffix );
262
- }
263
-
264
- std::optional<std::string> QuickNumericalConstantParser::formatIfNeeded () && {
265
- parse ();
266
- applyFormatting ();
267
-
268
112
if (Formatted == IntegerLiteral)
269
113
return std::nullopt;
270
114
else
271
- return std::move ( Formatted) ;
115
+ return Formatted;
272
116
}
273
117
274
118
std::pair<tooling::Replacements, unsigned >
275
119
NumericLiteralCaseFixer::process (const Environment &Env,
276
120
const FormatStyle &Style) {
277
121
278
- const auto &CaseStyle = Style.NumericLiteralCase ;
279
- const FormatParameters Transforms{Style.Language , CaseStyle};
280
-
281
122
const auto &SourceMgr = Env.getSourceManager ();
282
123
AffectedRangeManager AffectedRangeMgr (SourceMgr, Env.getCharRanges ());
283
124
@@ -315,8 +156,7 @@ NumericLiteralCaseFixer::process(const Environment &Env,
315
156
continue ;
316
157
}
317
158
318
- const auto Formatted =
319
- QuickNumericalConstantParser (Text, Transforms).formatIfNeeded ();
159
+ const auto Formatted = formatIfNeeded (Text, Style);
320
160
if (Formatted) {
321
161
assert (*Formatted != Text && " QuickNumericalConstantParser returned an "
322
162
" unchanged value instead of nullopt" );
0 commit comments