123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286 |
- //===--- IntegralLiteralExpressionMatcher.cpp - clang-tidy ----------------===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- #include "IntegralLiteralExpressionMatcher.h"
- #include <algorithm>
- #include <cctype>
- #include <stdexcept>
- namespace clang::tidy::modernize {
- // Validate that this literal token is a valid integer literal. A literal token
- // could be a floating-point token, which isn't acceptable as a value for an
- // enumeration. A floating-point token must either have a decimal point or an
- // exponent ('E' or 'P').
- static bool isIntegralConstant(const Token &Token) {
- const char *Begin = Token.getLiteralData();
- const char *End = Begin + Token.getLength();
- // Not a hexadecimal floating-point literal.
- if (Token.getLength() > 2 && Begin[0] == '0' && std::toupper(Begin[1]) == 'X')
- return std::none_of(Begin + 2, End, [](char C) {
- return C == '.' || std::toupper(C) == 'P';
- });
- // Not a decimal floating-point literal or complex literal.
- return std::none_of(Begin, End, [](char C) {
- return C == '.' || std::toupper(C) == 'E' || std::toupper(C) == 'I';
- });
- }
- bool IntegralLiteralExpressionMatcher::advance() {
- ++Current;
- return Current != End;
- }
- bool IntegralLiteralExpressionMatcher::consume(tok::TokenKind Kind) {
- if (Current->is(Kind)) {
- ++Current;
- return true;
- }
- return false;
- }
- bool IntegralLiteralExpressionMatcher::nonTerminalChainedExpr(
- bool (IntegralLiteralExpressionMatcher::*NonTerminal)(),
- const std::function<bool(Token)> &IsKind) {
- if (!(this->*NonTerminal)())
- return false;
- if (Current == End)
- return true;
- while (Current != End) {
- if (!IsKind(*Current))
- break;
- if (!advance())
- return false;
- if (!(this->*NonTerminal)())
- return false;
- }
- return true;
- }
- // Advance over unary operators.
- bool IntegralLiteralExpressionMatcher::unaryOperator() {
- if (Current->isOneOf(tok::TokenKind::minus, tok::TokenKind::plus,
- tok::TokenKind::tilde, tok::TokenKind::exclaim)) {
- return advance();
- }
- return true;
- }
- static LiteralSize literalTokenSize(const Token &Tok) {
- unsigned int Length = Tok.getLength();
- if (Length <= 1)
- return LiteralSize::Int;
- bool SeenUnsigned = false;
- bool SeenLong = false;
- bool SeenLongLong = false;
- const char *Text = Tok.getLiteralData();
- for (unsigned int End = Length - 1; End > 0; --End) {
- if (std::isdigit(Text[End]))
- break;
- if (std::toupper(Text[End]) == 'U')
- SeenUnsigned = true;
- else if (std::toupper(Text[End]) == 'L') {
- if (SeenLong)
- SeenLongLong = true;
- SeenLong = true;
- }
- }
- if (SeenLongLong) {
- if (SeenUnsigned)
- return LiteralSize::UnsignedLongLong;
- return LiteralSize::LongLong;
- }
- if (SeenLong) {
- if (SeenUnsigned)
- return LiteralSize::UnsignedLong;
- return LiteralSize::Long;
- }
- if (SeenUnsigned)
- return LiteralSize::UnsignedInt;
- return LiteralSize::Int;
- }
- static bool operator<(LiteralSize LHS, LiteralSize RHS) {
- return static_cast<int>(LHS) < static_cast<int>(RHS);
- }
- bool IntegralLiteralExpressionMatcher::unaryExpr() {
- if (!unaryOperator())
- return false;
- if (consume(tok::TokenKind::l_paren)) {
- if (Current == End)
- return false;
- if (!expr())
- return false;
- if (Current == End)
- return false;
- return consume(tok::TokenKind::r_paren);
- }
- if (!Current->isLiteral() || isStringLiteral(Current->getKind()) ||
- !isIntegralConstant(*Current)) {
- return false;
- }
- LargestSize = std::max(LargestSize, literalTokenSize(*Current));
- ++Current;
- return true;
- }
- bool IntegralLiteralExpressionMatcher::multiplicativeExpr() {
- return nonTerminalChainedExpr<tok::TokenKind::star, tok::TokenKind::slash,
- tok::TokenKind::percent>(
- &IntegralLiteralExpressionMatcher::unaryExpr);
- }
- bool IntegralLiteralExpressionMatcher::additiveExpr() {
- return nonTerminalChainedExpr<tok::plus, tok::minus>(
- &IntegralLiteralExpressionMatcher::multiplicativeExpr);
- }
- bool IntegralLiteralExpressionMatcher::shiftExpr() {
- return nonTerminalChainedExpr<tok::TokenKind::lessless,
- tok::TokenKind::greatergreater>(
- &IntegralLiteralExpressionMatcher::additiveExpr);
- }
- bool IntegralLiteralExpressionMatcher::compareExpr() {
- if (!shiftExpr())
- return false;
- if (Current == End)
- return true;
- if (Current->is(tok::TokenKind::spaceship)) {
- if (!advance())
- return false;
- if (!shiftExpr())
- return false;
- }
- return true;
- }
- bool IntegralLiteralExpressionMatcher::relationalExpr() {
- return nonTerminalChainedExpr<tok::TokenKind::less, tok::TokenKind::greater,
- tok::TokenKind::lessequal,
- tok::TokenKind::greaterequal>(
- &IntegralLiteralExpressionMatcher::compareExpr);
- }
- bool IntegralLiteralExpressionMatcher::equalityExpr() {
- return nonTerminalChainedExpr<tok::TokenKind::equalequal,
- tok::TokenKind::exclaimequal>(
- &IntegralLiteralExpressionMatcher::relationalExpr);
- }
- bool IntegralLiteralExpressionMatcher::andExpr() {
- return nonTerminalChainedExpr<tok::TokenKind::amp>(
- &IntegralLiteralExpressionMatcher::equalityExpr);
- }
- bool IntegralLiteralExpressionMatcher::exclusiveOrExpr() {
- return nonTerminalChainedExpr<tok::TokenKind::caret>(
- &IntegralLiteralExpressionMatcher::andExpr);
- }
- bool IntegralLiteralExpressionMatcher::inclusiveOrExpr() {
- return nonTerminalChainedExpr<tok::TokenKind::pipe>(
- &IntegralLiteralExpressionMatcher::exclusiveOrExpr);
- }
- bool IntegralLiteralExpressionMatcher::logicalAndExpr() {
- return nonTerminalChainedExpr<tok::TokenKind::ampamp>(
- &IntegralLiteralExpressionMatcher::inclusiveOrExpr);
- }
- bool IntegralLiteralExpressionMatcher::logicalOrExpr() {
- return nonTerminalChainedExpr<tok::TokenKind::pipepipe>(
- &IntegralLiteralExpressionMatcher::logicalAndExpr);
- }
- bool IntegralLiteralExpressionMatcher::conditionalExpr() {
- if (!logicalOrExpr())
- return false;
- if (Current == End)
- return true;
- if (Current->is(tok::TokenKind::question)) {
- if (!advance())
- return false;
- // A gcc extension allows x ? : y as a synonym for x ? x : y.
- if (Current->is(tok::TokenKind::colon)) {
- if (!advance())
- return false;
- if (!expr())
- return false;
- return true;
- }
- if (!expr())
- return false;
- if (Current == End)
- return false;
- if (!Current->is(tok::TokenKind::colon))
- return false;
- if (!advance())
- return false;
- if (!expr())
- return false;
- }
- return true;
- }
- bool IntegralLiteralExpressionMatcher::commaExpr() {
- auto Pred = CommaAllowed
- ? std::function<bool(Token)>(
- [](Token Tok) { return Tok.is(tok::TokenKind::comma); })
- : std::function<bool(Token)>([](Token) { return false; });
- return nonTerminalChainedExpr(
- &IntegralLiteralExpressionMatcher::conditionalExpr, Pred);
- }
- bool IntegralLiteralExpressionMatcher::expr() { return commaExpr(); }
- bool IntegralLiteralExpressionMatcher::match() {
- // Top-level allowed expression is conditionalExpr(), not expr(), because
- // comma operators are only valid initializers when used inside parentheses.
- return conditionalExpr() && Current == End;
- }
- LiteralSize IntegralLiteralExpressionMatcher::largestLiteralSize() const {
- return LargestSize;
- }
- } // namespace clang::tidy::modernize
|