Skip to content

Commit 048ace1

Browse files
committed
[clang-format] Add functionality of getting info about numeric literals
1 parent d696f81 commit 048ace1

File tree

5 files changed

+174
-0
lines changed

5 files changed

+174
-0
lines changed

clang/lib/Format/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ add_clang_library(clangFormat
1313
MacroExpander.cpp
1414
MatchFilePath.cpp
1515
NamespaceEndCommentsFixer.cpp
16+
NumericLiteralInfo.cpp
1617
ObjCPropertyAttributeOrderFixer.cpp
1718
QualifierAlignmentFixer.cpp
1819
SortJavaScriptImports.cpp
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
//===--- NumericLiteralInfo.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 the functionality of getting information about a
11+
/// numeric literal string, including 0-based positions of the base letter, the
12+
/// decimal/hexadecimal point, the exponent letter, and the suffix, or npos if
13+
/// absent.
14+
///
15+
//===----------------------------------------------------------------------===//
16+
17+
#include "NumericLiteralInfo.h"
18+
#include "llvm/ADT/StringExtras.h"
19+
20+
namespace clang {
21+
namespace format {
22+
23+
using namespace llvm;
24+
25+
constexpr auto npos = StringRef::npos;
26+
27+
NumericLiteralInfo::NumericLiteralInfo(StringRef Text, char Separator) {
28+
assert(Text.size() > 1);
29+
30+
bool IsHex = false;
31+
BaseLetterPos = npos;
32+
if (Text[0] == '0') {
33+
switch (Text[1]) {
34+
case 'x':
35+
case 'X':
36+
IsHex = true;
37+
[[fallthrough]];
38+
case 'b':
39+
case 'B':
40+
case 'o':
41+
case 'O':
42+
BaseLetterPos = 1; // e.g. 0xF
43+
break;
44+
}
45+
}
46+
47+
DotPos = Text.find('.', BaseLetterPos == 1 ? 2 : 0); // e.g. 0x.1 or .1
48+
49+
// e.g. 1.e2 or 0xFp2
50+
const auto Pos = DotPos != npos ? DotPos + 1 : BaseLetterPos + 2;
51+
52+
ExponentLetterPos =
53+
// Trim C++ user-defined suffix as in `1_Pa`.
54+
(Separator == '\'' ? Text.substr(0, Text.find('_')) : Text)
55+
.find_insensitive(IsHex ? 'p' : 'e', Pos);
56+
57+
const bool HasExponent = ExponentLetterPos != npos;
58+
SuffixPos = Text.find_if_not(
59+
[&](char C) {
60+
return (HasExponent || !IsHex ? isDigit : isHexDigit)(C) ||
61+
C == Separator;
62+
},
63+
HasExponent ? ExponentLetterPos + 2 : Pos); // e.g. 1e-2f
64+
}
65+
66+
} // namespace format
67+
} // namespace clang

clang/lib/Format/NumericLiteralInfo.h

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
//===--- NumericLiteralInfo.h -----------------------------------*- 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+
#ifndef LLVM_CLANG_LIB_FORMAT_NUMERICLITERALINFO_H
10+
#define LLVM_CLANG_LIB_FORMAT_NUMERICLITERALINFO_H
11+
12+
#include "llvm/ADT/StringRef.h"
13+
14+
namespace clang {
15+
namespace format {
16+
17+
extern const size_t npos;
18+
19+
struct NumericLiteralInfo {
20+
size_t BaseLetterPos; // Position of the base letter.
21+
size_t DotPos; // Position of the decimal/hexadecimal point.
22+
size_t ExponentLetterPos; // Position of the exponent letter.
23+
size_t SuffixPos; // Starting position of the suffix.
24+
25+
NumericLiteralInfo(size_t BaseLetterPos = npos, size_t DotPos = npos,
26+
size_t ExponentLetterPos = npos, size_t SuffixPos = npos)
27+
: BaseLetterPos(BaseLetterPos), DotPos(DotPos),
28+
ExponentLetterPos(ExponentLetterPos), SuffixPos(SuffixPos) {}
29+
30+
NumericLiteralInfo(llvm::StringRef Text, char Separator);
31+
32+
bool operator==(const NumericLiteralInfo &R) const {
33+
return BaseLetterPos == R.BaseLetterPos && DotPos == R.DotPos &&
34+
ExponentLetterPos == R.ExponentLetterPos && SuffixPos == R.SuffixPos;
35+
}
36+
};
37+
38+
} // end namespace format
39+
} // end namespace clang
40+
41+
#endif

clang/unittests/Format/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ add_distinct_clang_unittest(FormatTests
2727
MacroExpanderTest.cpp
2828
MatchFilePathTest.cpp
2929
NamespaceEndCommentsFixerTest.cpp
30+
NumericLiteralInfoTest.cpp
3031
ObjCPropertyAttributeOrderFixerTest.cpp
3132
QualifierFixerTest.cpp
3233
SortImportsTestJS.cpp
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
//===- unittest/Format/NumericLiteralInfoTest.cpp -------------------------===//
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+
#include "../../lib/Format/NumericLiteralInfo.h"
10+
#include "gtest/gtest.h"
11+
12+
namespace clang {
13+
namespace format {
14+
namespace {
15+
16+
class NumericLiteralInfoTest : public testing::Test {
17+
protected:
18+
NumericLiteralInfo getInfo(llvm::StringRef Text, char Separator = '\'') {
19+
return NumericLiteralInfo(Text, Separator);
20+
}
21+
};
22+
23+
TEST_F(NumericLiteralInfoTest, IntegerLiteral) {
24+
// Decimal.
25+
EXPECT_EQ(getInfo("90"), NumericLiteralInfo());
26+
EXPECT_EQ(getInfo("9L"), NumericLiteralInfo(npos, npos, npos, 1));
27+
EXPECT_EQ(getInfo("9'0U"), NumericLiteralInfo(npos, npos, npos, 3));
28+
29+
// Octal.
30+
EXPECT_EQ(getInfo("07"), NumericLiteralInfo());
31+
EXPECT_EQ(getInfo("0z"), NumericLiteralInfo(npos, npos, npos, 1));
32+
// JavaScript.
33+
EXPECT_EQ(getInfo("0o7"), NumericLiteralInfo(1));
34+
EXPECT_EQ(getInfo("0O7_0", '_'), NumericLiteralInfo(1));
35+
36+
// Binary.
37+
EXPECT_EQ(getInfo("0b1"), NumericLiteralInfo(1));
38+
EXPECT_EQ(getInfo("0B1ul"), NumericLiteralInfo(1, npos, npos, 3));
39+
40+
// Hexadecimal.
41+
EXPECT_EQ(getInfo("0xF"), NumericLiteralInfo(1));
42+
EXPECT_EQ(getInfo("0XfZ"), NumericLiteralInfo(1, npos, npos, 3));
43+
}
44+
45+
TEST_F(NumericLiteralInfoTest, FloatingPointLiteral) {
46+
// Decimal.
47+
EXPECT_EQ(getInfo(".9"), NumericLiteralInfo(npos, 0));
48+
EXPECT_EQ(getInfo("9."), NumericLiteralInfo(npos, 1));
49+
EXPECT_EQ(getInfo("9.F"), NumericLiteralInfo(npos, 1, npos, 2));
50+
EXPECT_EQ(getInfo("9e9"), NumericLiteralInfo(npos, npos, 1));
51+
EXPECT_EQ(getInfo("9E-9f"), NumericLiteralInfo(npos, npos, 1, 4));
52+
EXPECT_EQ(getInfo("9.9e+9bf16"), NumericLiteralInfo(npos, 1, 3, 6));
53+
54+
// Hexadecimal.
55+
EXPECT_EQ(getInfo("0X.Fp9"), NumericLiteralInfo(1, 2, 4));
56+
EXPECT_EQ(getInfo("0xF.P9"), NumericLiteralInfo(1, 3, 4));
57+
EXPECT_EQ(getInfo("0xFp9"), NumericLiteralInfo(1, npos, 3));
58+
EXPECT_EQ(getInfo("0xFp+9F128"), NumericLiteralInfo(1, npos, 3, 6));
59+
EXPECT_EQ(getInfo("0xF.Fp-9_Pa"), NumericLiteralInfo(1, 3, 5, 8));
60+
}
61+
62+
} // namespace
63+
} // namespace format
64+
} // namespace clang

0 commit comments

Comments
 (0)