1 //===--- IntegralLiteralExpressionMatcher.cpp - clang-tidy ----------------===//
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 //===----------------------------------------------------------------------===//
9 #include "IntegralLiteralExpressionMatcher.h"
14 namespace clang::tidy::modernize
{
16 // Validate that this literal token is a valid integer literal. A literal token
17 // could be a floating-point token, which isn't acceptable as a value for an
18 // enumeration. A floating-point token must either have a decimal point or an
19 // exponent ('E' or 'P').
20 static bool isIntegralConstant(const Token
&Token
) {
21 const char *Begin
= Token
.getLiteralData();
22 const char *End
= Begin
+ Token
.getLength();
24 // Not a hexadecimal floating-point literal.
25 if (Token
.getLength() > 2 && Begin
[0] == '0' && std::toupper(Begin
[1]) == 'X')
26 return std::none_of(Begin
+ 2, End
, [](char C
) {
27 return C
== '.' || std::toupper(C
) == 'P';
30 // Not a decimal floating-point literal or complex literal.
31 return std::none_of(Begin
, End
, [](char C
) {
32 return C
== '.' || std::toupper(C
) == 'E' || std::toupper(C
) == 'I';
36 bool IntegralLiteralExpressionMatcher::advance() {
38 return Current
!= End
;
41 bool IntegralLiteralExpressionMatcher::consume(tok::TokenKind Kind
) {
42 if (Current
->is(Kind
)) {
50 template <typename NonTerminalFunctor
, typename IsKindFunctor
>
51 bool IntegralLiteralExpressionMatcher::nonTerminalChainedExpr(
52 const NonTerminalFunctor
&NonTerminal
, const IsKindFunctor
&IsKind
) {
58 while (Current
!= End
) {
59 if (!IsKind(*Current
))
72 template <tok::TokenKind Kind
, typename NonTerminalFunctor
>
73 bool IntegralLiteralExpressionMatcher::nonTerminalChainedExpr(
74 const NonTerminalFunctor
&NonTerminal
) {
75 return nonTerminalChainedExpr(NonTerminal
,
76 [](Token Tok
) { return Tok
.is(Kind
); });
79 template <tok::TokenKind K1
, tok::TokenKind K2
, tok::TokenKind
... Ks
,
80 typename NonTerminalFunctor
>
81 bool IntegralLiteralExpressionMatcher::nonTerminalChainedExpr(
82 const NonTerminalFunctor
&NonTerminal
) {
83 return nonTerminalChainedExpr(
84 NonTerminal
, [](Token Tok
) { return Tok
.isOneOf(K1
, K2
, Ks
...); });
87 // Advance over unary operators.
88 bool IntegralLiteralExpressionMatcher::unaryOperator() {
89 if (Current
->isOneOf(tok::TokenKind::minus
, tok::TokenKind::plus
,
90 tok::TokenKind::tilde
, tok::TokenKind::exclaim
)) {
97 static LiteralSize
literalTokenSize(const Token
&Tok
) {
98 unsigned int Length
= Tok
.getLength();
100 return LiteralSize::Int
;
102 bool SeenUnsigned
= false;
103 bool SeenLong
= false;
104 bool SeenLongLong
= false;
105 const char *Text
= Tok
.getLiteralData();
106 for (unsigned int End
= Length
- 1; End
> 0; --End
) {
107 if (std::isdigit(Text
[End
]))
110 if (std::toupper(Text
[End
]) == 'U')
112 else if (std::toupper(Text
[End
]) == 'L') {
121 return LiteralSize::UnsignedLongLong
;
123 return LiteralSize::LongLong
;
127 return LiteralSize::UnsignedLong
;
129 return LiteralSize::Long
;
132 return LiteralSize::UnsignedInt
;
134 return LiteralSize::Int
;
137 static bool operator<(LiteralSize LHS
, LiteralSize RHS
) {
138 return static_cast<int>(LHS
) < static_cast<int>(RHS
);
141 bool IntegralLiteralExpressionMatcher::unaryExpr() {
142 if (!unaryOperator())
145 if (consume(tok::TokenKind::l_paren
)) {
155 return consume(tok::TokenKind::r_paren
);
158 if (!Current
->isLiteral() || isStringLiteral(Current
->getKind()) ||
159 !isIntegralConstant(*Current
)) {
163 LargestSize
= std::max(LargestSize
, literalTokenSize(*Current
));
169 bool IntegralLiteralExpressionMatcher::multiplicativeExpr() {
170 return nonTerminalChainedExpr
<tok::TokenKind::star
, tok::TokenKind::slash
,
171 tok::TokenKind::percent
>(
172 [this] { return unaryExpr(); });
175 bool IntegralLiteralExpressionMatcher::additiveExpr() {
176 return nonTerminalChainedExpr
<tok::plus
, tok::minus
>(
177 [this] { return multiplicativeExpr(); });
180 bool IntegralLiteralExpressionMatcher::shiftExpr() {
181 return nonTerminalChainedExpr
<tok::TokenKind::lessless
,
182 tok::TokenKind::greatergreater
>(
183 [this] { return additiveExpr(); });
186 bool IntegralLiteralExpressionMatcher::compareExpr() {
192 if (Current
->is(tok::TokenKind::spaceship
)) {
203 bool IntegralLiteralExpressionMatcher::relationalExpr() {
204 return nonTerminalChainedExpr
<tok::TokenKind::less
, tok::TokenKind::greater
,
205 tok::TokenKind::lessequal
,
206 tok::TokenKind::greaterequal
>(
207 [this] { return compareExpr(); });
210 bool IntegralLiteralExpressionMatcher::equalityExpr() {
211 return nonTerminalChainedExpr
<tok::TokenKind::equalequal
,
212 tok::TokenKind::exclaimequal
>(
213 [this] { return relationalExpr(); });
216 bool IntegralLiteralExpressionMatcher::andExpr() {
217 return nonTerminalChainedExpr
<tok::TokenKind::amp
>(
218 [this] { return equalityExpr(); });
221 bool IntegralLiteralExpressionMatcher::exclusiveOrExpr() {
222 return nonTerminalChainedExpr
<tok::TokenKind::caret
>(
223 [this] { return andExpr(); });
226 bool IntegralLiteralExpressionMatcher::inclusiveOrExpr() {
227 return nonTerminalChainedExpr
<tok::TokenKind::pipe
>(
228 [this] { return exclusiveOrExpr(); });
231 bool IntegralLiteralExpressionMatcher::logicalAndExpr() {
232 return nonTerminalChainedExpr
<tok::TokenKind::ampamp
>(
233 [this] { return inclusiveOrExpr(); });
236 bool IntegralLiteralExpressionMatcher::logicalOrExpr() {
237 return nonTerminalChainedExpr
<tok::TokenKind::pipepipe
>(
238 [this] { return logicalAndExpr(); });
241 bool IntegralLiteralExpressionMatcher::conditionalExpr() {
242 if (!logicalOrExpr())
247 if (Current
->is(tok::TokenKind::question
)) {
251 // A gcc extension allows x ? : y as a synonym for x ? x : y.
252 if (Current
->is(tok::TokenKind::colon
)) {
267 if (!Current
->is(tok::TokenKind::colon
))
279 bool IntegralLiteralExpressionMatcher::commaExpr() {
280 auto NonTerminal
= [this] { return conditionalExpr(); };
282 return nonTerminalChainedExpr
<tok::TokenKind::comma
>(NonTerminal
);
283 return nonTerminalChainedExpr(NonTerminal
, [](Token
) { return false; });
286 bool IntegralLiteralExpressionMatcher::expr() { return commaExpr(); }
288 bool IntegralLiteralExpressionMatcher::match() {
289 // Top-level allowed expression is conditionalExpr(), not expr(), because
290 // comma operators are only valid initializers when used inside parentheses.
291 return conditionalExpr() && Current
== End
;
294 LiteralSize
IntegralLiteralExpressionMatcher::largestLiteralSize() const {
298 } // namespace clang::tidy::modernize