brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.0 KiB · 862ca18 Raw
299 lines · cpp
1//===----------------------------------------------------------------------===//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-exception6//7//===----------------------------------------------------------------------===//8 9#include "IntegralLiteralExpressionMatcher.h"10 11#include <algorithm>12#include <cctype>13 14namespace clang::tidy::modernize {15 16// Validate that this literal token is a valid integer literal.  A literal token17// could be a floating-point token, which isn't acceptable as a value for an18// enumeration.  A floating-point token must either have a decimal point or an19// exponent ('E' or 'P').20static bool isIntegralConstant(const Token &Token) {21  const char *Begin = Token.getLiteralData();22  const char *End = Begin + Token.getLength();23 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';28    });29 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';33  });34}35 36bool IntegralLiteralExpressionMatcher::advance() {37  ++Current;38  return Current != End;39}40 41bool IntegralLiteralExpressionMatcher::consume(tok::TokenKind Kind) {42  if (Current->is(Kind)) {43    ++Current;44    return true;45  }46 47  return false;48}49 50template <typename NonTerminalFunctor, typename IsKindFunctor>51bool IntegralLiteralExpressionMatcher::nonTerminalChainedExpr(52    const NonTerminalFunctor &NonTerminal, const IsKindFunctor &IsKind) {53  if (!NonTerminal())54    return false;55  if (Current == End)56    return true;57 58  while (Current != End) {59    if (!IsKind(*Current))60      break;61 62    if (!advance())63      return false;64 65    if (!NonTerminal())66      return false;67  }68 69  return true;70}71 72template <tok::TokenKind Kind, typename NonTerminalFunctor>73bool IntegralLiteralExpressionMatcher::nonTerminalChainedExpr(74    const NonTerminalFunctor &NonTerminal) {75  return nonTerminalChainedExpr(NonTerminal,76                                [](Token Tok) { return Tok.is(Kind); });77}78 79template <tok::TokenKind K1, tok::TokenKind K2, tok::TokenKind... Ks,80          typename NonTerminalFunctor>81bool IntegralLiteralExpressionMatcher::nonTerminalChainedExpr(82    const NonTerminalFunctor &NonTerminal) {83  return nonTerminalChainedExpr(84      NonTerminal, [](Token Tok) { return Tok.isOneOf(K1, K2, Ks...); });85}86 87// Advance over unary operators.88bool IntegralLiteralExpressionMatcher::unaryOperator() {89  if (Current->isOneOf(tok::TokenKind::minus, tok::TokenKind::plus,90                       tok::TokenKind::tilde, tok::TokenKind::exclaim)) {91    return advance();92  }93 94  return true;95}96 97static LiteralSize literalTokenSize(const Token &Tok) {98  const unsigned int Length = Tok.getLength();99  if (Length <= 1)100    return LiteralSize::Int;101 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]))108      break;109 110    if (std::toupper(Text[End]) == 'U')111      SeenUnsigned = true;112    else if (std::toupper(Text[End]) == 'L') {113      if (SeenLong)114        SeenLongLong = true;115      SeenLong = true;116    }117  }118 119  if (SeenLongLong) {120    if (SeenUnsigned)121      return LiteralSize::UnsignedLongLong;122 123    return LiteralSize::LongLong;124  }125  if (SeenLong) {126    if (SeenUnsigned)127      return LiteralSize::UnsignedLong;128 129    return LiteralSize::Long;130  }131  if (SeenUnsigned)132    return LiteralSize::UnsignedInt;133 134  return LiteralSize::Int;135}136 137static bool operator<(LiteralSize LHS, LiteralSize RHS) {138  return static_cast<int>(LHS) < static_cast<int>(RHS);139}140 141bool IntegralLiteralExpressionMatcher::unaryExpr() {142  if (!unaryOperator())143    return false;144 145  if (consume(tok::TokenKind::l_paren)) {146    if (Current == End)147      return false;148 149    if (!expr())150      return false;151 152    if (Current == End)153      return false;154 155    return consume(tok::TokenKind::r_paren);156  }157 158  if (!Current->isLiteral() || isStringLiteral(Current->getKind()) ||159      !isIntegralConstant(*Current)) {160    return false;161  }162 163  LargestSize = std::max(LargestSize, literalTokenSize(*Current));164  ++Current;165 166  return true;167}168 169bool IntegralLiteralExpressionMatcher::multiplicativeExpr() {170  return nonTerminalChainedExpr<tok::TokenKind::star, tok::TokenKind::slash,171                                tok::TokenKind::percent>(172      [this] { return unaryExpr(); });173}174 175bool IntegralLiteralExpressionMatcher::additiveExpr() {176  return nonTerminalChainedExpr<tok::plus, tok::minus>(177      [this] { return multiplicativeExpr(); });178}179 180bool IntegralLiteralExpressionMatcher::shiftExpr() {181  return nonTerminalChainedExpr<tok::TokenKind::lessless,182                                tok::TokenKind::greatergreater>(183      [this] { return additiveExpr(); });184}185 186bool IntegralLiteralExpressionMatcher::compareExpr() {187  if (!shiftExpr())188    return false;189  if (Current == End)190    return true;191 192  if (Current->is(tok::TokenKind::spaceship)) {193    if (!advance())194      return false;195 196    if (!shiftExpr())197      return false;198  }199 200  return true;201}202 203bool IntegralLiteralExpressionMatcher::relationalExpr() {204  return nonTerminalChainedExpr<tok::TokenKind::less, tok::TokenKind::greater,205                                tok::TokenKind::lessequal,206                                tok::TokenKind::greaterequal>(207      [this] { return compareExpr(); });208}209 210bool IntegralLiteralExpressionMatcher::equalityExpr() {211  return nonTerminalChainedExpr<tok::TokenKind::equalequal,212                                tok::TokenKind::exclaimequal>(213      [this] { return relationalExpr(); });214}215 216bool IntegralLiteralExpressionMatcher::andExpr() {217  return nonTerminalChainedExpr<tok::TokenKind::amp>(218      [this] { return equalityExpr(); });219}220 221bool IntegralLiteralExpressionMatcher::exclusiveOrExpr() {222  return nonTerminalChainedExpr<tok::TokenKind::caret>(223      [this] { return andExpr(); });224}225 226bool IntegralLiteralExpressionMatcher::inclusiveOrExpr() {227  return nonTerminalChainedExpr<tok::TokenKind::pipe>(228      [this] { return exclusiveOrExpr(); });229}230 231bool IntegralLiteralExpressionMatcher::logicalAndExpr() {232  return nonTerminalChainedExpr<tok::TokenKind::ampamp>(233      [this] { return inclusiveOrExpr(); });234}235 236bool IntegralLiteralExpressionMatcher::logicalOrExpr() {237  return nonTerminalChainedExpr<tok::TokenKind::pipepipe>(238      [this] { return logicalAndExpr(); });239}240 241bool IntegralLiteralExpressionMatcher::conditionalExpr() {242  if (!logicalOrExpr())243    return false;244  if (Current == End)245    return true;246 247  if (Current->is(tok::TokenKind::question)) {248    if (!advance())249      return false;250 251    // A gcc extension allows x ? : y as a synonym for x ? x : y.252    if (Current->is(tok::TokenKind::colon)) {253      if (!advance())254        return false;255 256      if (!expr())257        return false;258 259      return true;260    }261 262    if (!expr())263      return false;264    if (Current == End)265      return false;266 267    if (!Current->is(tok::TokenKind::colon))268      return false;269 270    if (!advance())271      return false;272 273    if (!expr())274      return false;275  }276  return true;277}278 279bool IntegralLiteralExpressionMatcher::commaExpr() {280  auto NonTerminal = [this] { return conditionalExpr(); };281  if (CommaAllowed)282    return nonTerminalChainedExpr<tok::TokenKind::comma>(NonTerminal);283  return nonTerminalChainedExpr(NonTerminal, [](Token) { return false; });284}285 286bool IntegralLiteralExpressionMatcher::expr() { return commaExpr(); }287 288bool IntegralLiteralExpressionMatcher::match() {289  // Top-level allowed expression is conditionalExpr(), not expr(), because290  // comma operators are only valid initializers when used inside parentheses.291  return conditionalExpr() && Current == End;292}293 294LiteralSize IntegralLiteralExpressionMatcher::largestLiteralSize() const {295  return LargestSize;296}297 298} // namespace clang::tidy::modernize299