[clang] Handle __declspec() attributes in using
[llvm-project.git] / clang / lib / Format / IntegerLiteralSeparatorFixer.cpp
blob24e758e986cf954b2e6f49a619c839a2da4957fd
1 //===--- IntegerLiteralSeparatorFixer.cpp -----------------------*- C++ -*-===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8 ///
9 /// \file
10 /// This file implements IntegerLiteralSeparatorFixer that fixes C++ integer
11 /// literal separators.
12 ///
13 //===----------------------------------------------------------------------===//
15 #include "IntegerLiteralSeparatorFixer.h"
17 namespace clang {
18 namespace format {
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');
27 return Base::Decimal;
30 assert(IntegerLiteral[0] == '0');
32 switch (IntegerLiteral[1]) {
33 case 'b':
34 case 'B':
35 return Base::Binary;
36 case 'x':
37 case 'X':
38 return Base::Hex;
39 default:
40 return Base::Other;
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:
50 Separator = '\'';
51 break;
52 case FormatStyle::LK_CSharp:
53 case FormatStyle::LK_Java:
54 case FormatStyle::LK_JavaScript:
55 Separator = '_';
56 break;
57 default:
58 return {};
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)
70 return {};
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);
80 Token Tok;
81 tooling::Replacements Result;
83 for (bool Skip = false; !Lex.LexFromRawLexer(Tok);) {
84 auto Length = Tok.getLength();
85 if (Length < 2)
86 continue;
87 auto Location = Tok.getLocation();
88 auto Text = StringRef(SourceMgr.getCharacterData(Location), Length);
89 if (Tok.is(tok::comment)) {
90 if (isClangFormatOff(Text))
91 Skip = true;
92 else if (isClangFormatOn(Text))
93 Skip = false;
94 continue;
96 if (Skip || Tok.isNot(tok::numeric_constant) || Text[0] == '.' ||
97 !AffectedRangeMgr.affectsCharSourceRange(
98 CharSourceRange::getCharRange(Location, Tok.getEndLoc()))) {
99 continue;
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) {
107 continue;
109 if ((IsBase10 && Text.find_last_of(".eEfFdDmM") != StringRef::npos) ||
110 (IsBase16 && Text.find_last_of(".pP") != StringRef::npos)) {
111 continue;
113 if (((IsBase2 && Binary < 0) || (IsBase10 && Decimal < 0) ||
114 (IsBase16 && Hex < 0)) &&
115 Text.find(Separator) == StringRef::npos) {
116 continue;
118 const auto Start = Text[0] == '0' ? 2 : 0;
119 auto End = Text.find_first_of("uUlLzZn");
120 if (End == StringRef::npos)
121 End = Length;
122 if (Start > 0 || End < Length) {
123 Length = End - Start;
124 Text = Text.substr(Start, Length);
126 auto DigitsPerGroup = Decimal;
127 if (IsBase2)
128 DigitsPerGroup = Binary;
129 else if (IsBase16)
130 DigitsPerGroup = Hex;
131 if (DigitsPerGroup > 0 && checkSeparator(Text, DigitsPerGroup))
132 continue;
133 if (Start > 0)
134 Location = Location.getLocWithOffset(Start);
135 cantFail(Result.add(tooling::Replacement(SourceMgr, Location, Length,
136 format(Text, DigitsPerGroup))));
139 return {Result, 0};
142 bool IntegerLiteralSeparatorFixer::checkSeparator(
143 const StringRef IntegerLiteral, int DigitsPerGroup) const {
144 assert(DigitsPerGroup > 0);
146 int I = 0;
147 for (auto C : llvm::reverse(IntegerLiteral)) {
148 if (C == Separator) {
149 if (I < DigitsPerGroup)
150 return false;
151 I = 0;
152 } else {
153 ++I;
154 if (I == DigitsPerGroup)
155 return false;
159 return true;
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)
170 if (C != Separator)
171 Formatted.push_back(C);
172 return Formatted;
175 int DigitCount = 0;
176 for (auto C : IntegerLiteral)
177 if (C != Separator)
178 ++DigitCount;
180 int Remainder = DigitCount % DigitsPerGroup;
182 int I = 0;
183 for (auto C : IntegerLiteral) {
184 if (C == Separator)
185 continue;
186 if (I == (Remainder > 0 ? Remainder : DigitsPerGroup)) {
187 Formatted.push_back(Separator);
188 I = 0;
189 Remainder = 0;
191 Formatted.push_back(C);
192 ++I;
195 return Formatted;
198 } // namespace format
199 } // namespace clang